GUI的全称为Graphical User Interface,图形化界面或图形用户接口,是指采用图形方式显示的计算机操作环境用户接口。与早期计算机使用的命令行界面相比,图形界面对于用户来说更为简便易用。GUI的广泛应用是当今计算机发展的重大成就之一,它极大地方便了非专业用户的使用人们从此不再需要死记硬背大量的命令,取而代之的是通过窗口、菜单、按键等方式来方便地进行操作。而嵌入式GUI具有下面几个方面的基本要求:轻型、占用资源少、高性能、高可靠性、便于移植、可配置等特点。
AWT(Abstract Window Toolkit),中文译为抽象窗口工具包,该包提供了一套与本地图形界面进行交互的接口,是Java提供的用来建立和设置Java的图形用户界面的基本工具。其中包含了许多类和接口以及众多元素如窗口、按钮、文本框等,且包都在java.awt
包下,Container和Component是AWT中的两个核心类。
所有的可以显示出来的图形元素都称为Component,Component代表了所有的可见的图形元素, Component里面有一种比较特殊的图形元素叫Container,Container(容器)在图形界面里面是一种可以 容纳其它Component元素的一种容器,Container本身也是一种Component的,Container里面也可以 容纳别的Container。
Container里面又分为Window和Panel,Window是可以独立显示出来的,平时我们看到的各种各样的 应用程序的窗口都可以称为Window,Window作为一个应用程序窗口独立显示出来,Panel也可以容 纳其它的图形元素,但一般看不见Panel,Panel不能作为应用程序的独立窗口显示出来,Panel要想 显示出来就必须得把自己装入到Window里面才能显示出来。
Panel应用比较典型的就是Applet(JAVA的页面小应用程序),现在基本上已经不用了,AJAX和 JAVASCRIPT完全取代了它的应用。
Window本身又可以分为Frame和Dialog,Frame就是我们平时看到的一般的窗口,而Dialog则是那 些需要用户进行了某些操作(如点击某个下拉菜单的项)才出现的对话框,这种对话框就是Dialog。
Component & Container |
---|
1. Java图形用户界面最基本的组成部分是Component,Component类及其子类的对象用来描述以图形化的方式显示在屏幕上并能与用户进行交互的GUI元素,例如,一个按钮、一个标签等; 2. 一般的 Component 对象不能独立地显示出来,必须将“放在”某一Container对象中才可以显示出来 |
1. Container 是 Component 的子类,Container 子类对象可以“容纳”别的 Component 对象; 2. Container 对象可使用方法 add()向其中添加其他 Component 对象; 3. Container 是 Component 的子类,因此 Container 对象也可以被当做 Component 对象添加到其他 Container 对象中 4. 有两种常用的 Container: Window和Panel,前者表示自由停泊的顶级窗口,后者对象则可用作容纳其他的 Component 对象,但不能独立存在,必须被添加到其他 Container 中(如Window或Applet) |
Frame 是 Window 的子类,由 Frame 或其子类创建的对象为一个窗体,其主要有以下常用方法:
Frame()
:无参构造器Frame(String s)
:有参构造器创建标题栏为字符串s的窗体setSize(int width, int height)
:设置窗体的大小,参数分别为宽度和高度setLocation(int x, int y)
:设置窗体的位置,参数为左上角坐标setBounds(int x, int y, int width, int height)
:设置窗体的位置和大小,参数分别为左上角坐标、宽度和高度setBackground(Color c)
:设置背景颜色,参数为Color对象setVisible(boolean b)
:设置可见性, 默认为falsesetTitle(String name) / String getTile()
:设置标题以及获得窗体的标题setResizable(boolean b)
:设置是否可以调整大小,默认为truepublic static void main(String[] args) { Frame frame = new Frame(); frame.setTitle("First"); frame.setBackground(Color.PINK); frame.setBounds(100, 100, 500, 500); frame.setResizable(false); frame.setVisible(true); //监听鼠标关闭窗口事件从而结束程序 frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.exit(0); } }); MyFrame frame1 = new MyFrame(300, 300, 500, 500, new Color(0xFFEBC8)); MyFrame frame2 = new MyFrame(300, 300, 500, 500, new Color(11, 43,102)); MyFrame frame3 = new MyFrame(300, 300, 500, 500, new Color(0xC8FFE7)); } /* 自定义一个类MyFrame,并且从Frame类继承 这样MyFrame类就拥有了Frame类的一切属性和方法,并且MyFrame类还可以自定义属性和方法 因此使用从Frame类继承而来的自定义类来创建图形窗口比直接使用Frame类来创建图形窗口要灵活 所以一般使用从Frame类继承而来的自定义类创建图形窗口界面比较好 不推荐直接使用Frame类来创建图形窗口界面 */ class MyFrame extends Frame { static int id = 0; public MyFrame(int x, int y, int w, int h, Color color) { super("MyFrame" + id++); setBounds(x, y, w, h); setBackground(color); setLayout(null); setVisible(true); } }
Panel 对象可以看成可以容纳Component的空间,并且可以拥有自己的布局管理器,其常用方法有:
Panel()
:使用默认FlowLayout类布局管理器初始化;Panel(LayoutManager layout)
:使用指定的布局管理器进行初始化setBounds(int x, int y, int widtth, int height)
setSize(int width, int height)
setLocation(int x, inty)
setBackgroud(Color c)
setLayout(LayoutManager mgr)
:设置布局管理器public static void main(String[] args) { Frame frame = new Frame("Java Frame with Panel"); Panel panel = new Panel(null); //可传参布局 //这里设置的坐标是相对于整个屏幕的 frame.setBounds(300, 300, 500, 500); //设置背景颜色使用三原色进行调色(RGB) frame.setBackground(new Color(227, 227, 252)); //这里设置的坐标是相对于Frame窗体的 panel.setBounds(50, 50, 400, 400); panel.setBackground(Color.PINK); //把Panel容器装入Frame容器中 frame.add(panel); //设置frame窗体的可见性 frame.setVisible(true); //监听鼠标点击关闭事件 frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.exit(0); } }); }
Java语言中,提供了布局管理类的对象可以管理。当需要管理Component在Container中的布局时,不必直接设置Component位置和大小。每个Container都会有一个布局管理器对象,当容器需要对某个组件进行定位或判断其大小尺寸时,就会调用其对应的布局管理器,调用Container的setLayout方法改变其布局管理器对象。在AWT中提供了5种布局管理器:
FlowLayout是Panel类的默认布局管理器,其对组件逐行定位,行内从左到右,一行排满后换行。流式布局不改变组件的大小,按组建原有的尺寸显示组件,可设置不同的组件间距、行距以及其对齐方式,默认的对齐方式为居中(CENTER),主要的构造方法如下:
@Test public void FlowLayout() { Frame frame = new Frame("FlowLayout"); //使用Button类创建按钮 //按钮类的其中一个构造方法:Button(String label) label为按钮显示的文本 Button button1 = new Button("button1"); Button button2 = new Button("button2"); Button button3 = new Button("button3"); //调用Frame的setLayout()方法设置流式布局 //setLayout()方法的定义:public void setLayout(LayoutManager mgr),若是无参构造器的话则为水平居中模式 frame.setLayout(new FlowLayout(FlowLayout.CENTER, 20, 40)); //通过构造器设置左对齐,这里使用到了FlowLayout.LEFT常量 //frame.setLayout(new FlowLayout(FlowLayout.LEFT)); //通过构造器设置右对齐,这里使用到了FlowLayout.RIGHT常量 //frame.setLayout(new FlowLayout(FlowLayout.RIGHT)); frame.setSize(500, 500); //将创建出来的按钮放置在Frame窗体中,按钮的大小与位置设置都是由布局管理器来做的 frame.add(button1); frame.add(button2); frame.add(button3); frame.setVisible(true); }
BorderLayout是Frame类的默认布局管理器,它将整个容器的布局划分为东西南北中五个区域,组件只能被添加到指定的区域,如果不指定组件加入的部位,将会默认加入到CENTER区。值得注意的是每个区域只能加入一个组件,如加入多个,则先前加入的会被覆盖
BorderLayout型布局容器尺寸缩放原则如下:
- 南北两个区域在水平方向上缩放
- 东西两个区域在垂直方向上缩放
- 中部可在两个方向上缩放
@Test public void BorderLayout() { Frame frame = new Frame("BorderLayout"); Button buttonEast = new Button("EAST"); Button buttonWest = new Button("WEST"); Button buttonSouth = new Button("SOUTH"); Button buttonNorth = new Button("NORTH"); Button buttonCenter = new Button("CENTER"); //把按钮放置到Frame窗体是按照东西南北中五个方向排序好 frame.add(buttonEast, BorderLayout.EAST); frame.add(buttonWest, BorderLayout.WEST); frame.add(buttonSouth, BorderLayout.SOUTH); frame.add(buttonNorth, BorderLayout.NORTH); frame.add(buttonCenter, BorderLayout.CENTER); //也可以使用这样的方式排列按钮 在把按钮放置到Frame窗体时使用方向定位的字符串指定按钮的放置位置 //这种使用方向定位的字符串指定按钮的放置方式不推荐使用 一旦写错了方向字符串就不好检查出来 //因为即使是写错了仍然可以编译通过 /* frame.add(buttonEast,"EAST"); frame.add(buttonWest,"West"); frame.add(buttonSouth,"South"); frame.add(buttonNorth,"North"); frame.add(buttonCenter,"Center"); */ frame.setSize(500, 500); frame.setVisible(true); }
GridLayout型布局管理器将空间划分成规则的矩形网格,每个单元格区域大小相等。组件被添加到每个单元格中,先从左到右填满一行后换行,再从上到下。
在GridLayout构造方法中指定分割的行数缓和列数
- GridLayout(3, 4)
@Test public void GridLayout() { Frame frame = new Frame("GridLayout"); Button button1 = new Button("btn1"); Button button2 = new Button("btn2"); Button button3 = new Button("btn3"); Button button4 = new Button("btn4"); Button button5 = new Button("btn5"); Button button6 = new Button("btn6"); Button button7 = new Button("btn7"); frame.setLayout(new GridLayout(2, 4)); //会根据给定的行进行自适应的调度布局 frame.setSize(500, 500); frame.add(button1); frame.add(button2); frame.add(button3); frame.add(button4); frame.add(button5); frame.add(button6); frame.add(button7); frame.pack(); frame.setVisible(true); }
@Test public void LayoutTest() { Frame frame = new Frame("LayoutTest"); //对显示窗体进行设置 frame.setLayout(new GridLayout(2,1)); frame.setSize(400, 300); frame.setBackground(Color.pink); frame.setVisible(true); Panel panel1 = new Panel(new BorderLayout()); //上面的二分一 Panel panel2 = new Panel(new BorderLayout()); //下面的二分一 Panel panel3 = new Panel(new GridLayout(2, 1)); //上面二分一的中间部分 Panel panel4 = new Panel(new GridLayout(2, 2)); //下面二分一的中间部分 panel1.add(new Button("btn-p1-west"), BorderLayout.WEST); //上面二分一的左边 panel1.add(new Button("btn-p1-east"), BorderLayout.EAST); //上面二分一的右边 panel3.add(new Button("btn-p3-0")); //上面二分一中间部分的第一个按钮 panel3.add(new Button("btn-p3-1")); //上面二分一中间部分的第二个按钮 panel1.add(panel3); //上面二分一的中间 panel2.add(new Button("btn-p2-west"), BorderLayout.WEST); //下面二分一的左边 panel2.add(new Button("btn-p2-east"), BorderLayout.EAST); //下面二分一的右边 for (int i = 0; i < 4; i++) { //通过循环添加下面二分一中间部分的按钮 panel4.add(new Button("btn-p4-" + i)); } panel2.add(panel4); //下面二分一的中间 frame.add(panel1); //将上半部分面板添加到窗体中 frame.add(panel2); //将下半部分面板添加到窗体中 }
setLayout(null)
在时间监听中,事件源可以注册事件监听器对象,并可以向事件监听器对象发送事件对象,事件发生后,事件源将事件对象发给已经注册的所有事件监听器,监听器对象随后会根据事件对象内的相应方法响应这个事件。下面对涉及到的术语进行一个介绍:
java.util.EventObject
对象,由开发者自行定义实现;java.util.EventListener
这个标识接口,实现事件监听。public class ButtonEventTest { public static void main(String[] args) { Frame frame = new Frame("ButtonEvent"); Button btnStart = new Button("start"); Button btnStop = new Button("stop"); MyActionListener listener = new MyActionListener(); btnStart.addActionListener(listener); btnStop.addActionListener(listener); frame.setLayout(new FlowLayout()); frame.add(btnStart); frame.add(btnStop); addWindowClosingEvent(frame); frame.setSize(300, 300); frame.setVisible(true); } //点击窗体上的关闭按钮关闭窗体 private static void addWindowClosingEvent(Frame frame) { frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.exit(0); } }); } } //自定义监听类(Monitor)实现事件监听接口ActionListener class MyActionListener implements ActionListener { //重写ActionListener接口里面的actionPerformed(ActionEvent e)方法,将触发事件时需要执行的语句放在里面 @Override public void actionPerformed(ActionEvent e) { System.out.println("Button " + e.getActionCommand() + " has been Pressed"); } }
TextField对象可能发生Action(光标在文本框内敲回车)事件。与该事件对应的事件类是java.awt.event.ActionEvent
。
java.awt.event.ActionListener
接口并且实现了接口内方法public void actionPerformed(ActionEvent e)
的对象;public class TextFieldTest { public static void main(String[] args) { new MyFrameTextField("Test", 300, 300); } } class MyFrameTextField extends Frame { public MyFrameTextField() { TextField textField = new TextField(); add(textField); textField.addActionListener(new MyMonitor()); textField.setEchoChar('*'); //设置在输入框中显示的字符,在打印的时候依然可以看到输入的内容 setVisible(true); pack(); } public MyFrameTextField(String title, int width, int height){ this(); setTitle(title); setSize(width, height); } } class MyMonitor implements ActionListener { /* 时间的相关信息都封装在了对象e里面,通过对象e的相关方法就可以获取事件的相关信息 e.getSource()方法是拿到事件源,返回的是Object类型的,因此调用时返回值需要进行强转 textField.getText和textField.setText方法是获取和设置文本框数据的 */ @Override public void actionPerformed(ActionEvent e) { TextField textField = (TextField) e.getSource(); System.out.println(textField.getText()); textField.setText(""); //清空文本框内容 } }
思路:
public class CalculatorTest { public static void main(String[] args) { new Calculator().launchFrame(); } } class Calculator extends Frame { private TextField num1; private TextField num2; private TextField sum; public void launchFrame() { //创建文本框 num1 = new TextField(10); num2 = new TextField(10); sum = new TextField(15); //创建加号Label Label labelPlus = new Label("+"); //创建等号按钮并绑定事件 Button btnEqual = new Button("="); btnEqual.addActionListener(new CalcMonitor()); //设置布局管理器并添加组件 setLayout(new FlowLayout()); add(num1); add(labelPlus); add(num2); add(btnEqual); add(sum); //窗体设置 pack(); setVisible(true); addWindowClosingEvent(this); } public TextField getNum1() { return num1; } public TextField getNum2() { return num2; } public TextField getSum() { return sum; } //实现ActionListener接口,完成加法操作 private class CalcMonitor implements ActionListener { @Override public void actionPerformed(ActionEvent e) { //获取加数和被加数并转换成整形 int num1 = Integer.parseInt(Calculator.this.num1.getText()); int num2 = Integer.parseInt(Calculator.this.num2.getText()); //输入sum,并清空前面两个文本框 sum.setText(String.valueOf(num1+num2)); System.out.println(sum.getText()); Calculator.this.num1.setText(""); Calculator.this.num2.setText(""); } } //监听关闭窗口事件 private void addWindowClosingEvent(Frame frame) { frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.exit(0); } }); } }
每个Component都有一个paint(Graphic g)
用于实现绘图目的,每次重画该Component时都会自动调用paint方法。paint方法是一个特殊的方法,在创建Frame窗体时会自动隐式调用,因此在主函数里面并没有显示调用paint(Graphic g)
方法。当我们把Frame窗体最小化再打开时,又会再次调用**paint()方法重新把圆和矩形在Frame窗体上画出来,即每次需要重画Frame窗体时就会自动调用paint()**方法。
public class PaintTest { public static void main(String[] args) { new MyPaint().launchFrame(); } } class MyPaint extends Frame { public void launchFrame() { setBounds(200, 200, 400, 500); setVisible(true); pack(); } //参数Graphics g可以看着是一个画笔,我们可以通过设置这个画笔的属性画出我们想要的各种各样的形状 @Override public void paint(Graphics g) { Color color = g.getColor(); g.setColor(Color.PINK); //设置画笔的颜色 g.fillOval(100, 100, 100, 50); //画一个实心的椭圆 g.setColor(Color.yellow); //设置画笔的颜色 g.fillRect(150, 200, 200, 200); //画一个实心的矩形 g.setColor(color); } }
值得注意的是,在画笔这一块有一个良好的编程习惯推荐,即在使用完画笔之后,应该把画笔的初始颜色恢复过来,这就相当于画家在用完画笔之后会把画笔上的颜料清理掉一样。
抽象类java.awt.event.MouseAdapter
实现了MouseListener接口,可以使用其子类作为MouseEvent的监听器,只要重写其相应的方法即可。当然,对于其他的监听器,只要重写其相对应的方法即可。使用适配器可以有小米面监听器定义没有必要的空方法。
public class MouseAdapterTest { public static void main(String[] args) { new MyMouseFrame("drawing"); } } class MyMouseFrame extends Frame { ArrayList points = null; public MyMouseFrame() { points = new ArrayList(); setLayout(null); setBounds(200,200,300,300); setBackground(new Color(204,204,255)); setVisible(true); // pack(); addWindowClosingEvent(this); } public MyMouseFrame(String title) { this(); setTitle(title); addMouseListener(new Monitor()); } @Override public void paint(Graphics g) { Iterator iterator = points.iterator(); // 迭代器 while (iterator.hasNext()) { Point point = (Point)iterator.next(); // 获取集合中的点 g.setColor(Color.PINK); // 设置画笔的颜色 g.fillOval(point.x, point.y, 10, 10); // 根据获取点的x,y坐标画半径为5的圆 } } private void addWindowClosingEvent(Frame frame) { frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.exit(0); } }); } private class Monitor extends MouseAdapter { @Override public void mousePressed(MouseEvent e) { MyMouseFrame frame = (MyMouseFrame) e.getSource(); // 获取事件源 points.add(new Point(e.getX(), e.getY())); //根据事件源即鼠标按压时的坐标生成一个点,并将其加到集合中 frame.repaint(); //刷新一下界面实现重绘 } } }
public void windowActivated(WindowEvent e); public void windowClosed(WindowEvent e); public void windowClosing(WindowEvent e); public void windowDeactivated(WindowEvent e); public void windowDeiconified(WindowEvent e); public void windowIconified(WindowEvent e); public void windowOpened(WindowEvent e);
public class TestWindowClose{ public static void main(String args[]){ new WindowFrame("关闭WindowFrame"); } } class WindowFrame extends Frame{ public WindowFrame(String s){ super(s); setBounds(200,200,400,300); setLayout(null); setBackground(new Color(204,204,255)); setVisible(true); this.addWindowListener(new WindowMonitor()); /*监听本窗体的动作,把所有的动作信息封装成一个对象传递到监听类里面*/ /* 在一个方法里面定义一个类,这个类称为局部类,也叫匿名的内部类, 这里的{……代码……}里面的代码很像一个类的类体,只不过这个类没有名字,所以叫匿名类 在这里是把这个匿名类当成WindowAdapter类来使用,语法上这样写的本质意义是相当于这 个匿名类 从WindowAdapter类继承,现在new了一个匿名类的对象出来然后把这个对象当成 WindowAdapter来使用 这个匿名类出了()就没有人认识了 */ this.addWindowListener( new WindowAdapter(){ public void windowClosing(WindowEvent e){ setVisible(false); System.exit(-1); } } ); } /*这里也是将监听类定义为内部类*/ class WindowMonitor extends WindowAdapter{ /* WindowAdapter(Window适配器)类实现了WindowListener监听接口 重写了WindowListener接口里面的所有方法 如果直接使用自定义WindowMonitor类直接去 实现WindowListener接口,那么就得要重写WindowListener接口 里面的所有方法,但现在只需要用到这些方法里面的其中一个方法 所以采用继承实现WindowListener监听接口的一个子类 并重写这个子类里面需要用到的那个方法即可 这种做法比直接实现WindowListener监听接口要重写很多个用不到的方法要简洁方便得多 */ /*重写需要用到的windowClosing(WindowEvent e)方法*/ public void windowClosing(WindowEvent e){ setVisible(false); /*将窗体设置为不显示,即可实现窗体关闭*/ System.exit(0); /*正常退出*/ } } }
键盘的处理事件是这样的:每一个键都对应着一个虚拟的码,当按下某一个键时,系统就会去找这个键对应的虚拟的码,以此来确定当前按下的是哪个键
public class TestKeyEvent{ public static void main(String args[]){ new KeyFrame("键盘响应事件"); } } class KeyFrame extends Frame{ public KeyFrame(String s){ super(s); setBounds(200,200,400,300); setLayout(null); setVisible(true); addKeyListener(new KeyMonitor()); } /* 把自定义的键盘的监听类定义为内部类 这个监听类从键盘适配器KeyAdapter类继承 从KeyAdapter类继承也是为了可以简洁方便 只需要重写需要用到的方法即可,这种做法比 直接实现KeyListener接口要简单方便,如果 直接实现KeyListener接口就要把KeyListener 接口里面的所有方法重写一遍,但真正用到的 只有一个方法,这样重写其他的方法但又用不到 难免会做无用功 */ class KeyMonitor extends KeyAdapter { public void keyPressed(KeyEvent e){ int keycode = e.getKeyCode(); // 使用getKeyCode()方法获取按键的虚拟码 /* 如果获取到的键的虚拟码等于up键的虚拟码 则表示当前按下的键是up键 KeyEvent.VK_UP表示取得up键的虚拟码 键盘中的每一个键都对应有一个虚拟码 这些虚拟码在KeyEvent类里面都被定义为静态常量 所以可以使用“类名.静态常量名”的形式访问得到这些静态常量 */ if(keycode == KeyEvent.VK_UP){ System.out.println("你按的是up键"); } } } }
Swing
是GUI(图形用户界面)开发工具包
,内容有很多,这里会分块编写,但在进阶篇中只编写 Swing中的基本要素,包括容器、组件和布局等,更深入的内容这里就不介绍了。想深入学习的朋友们可查阅有关资料或图书,比如《Java Swing图形界面开发与案例详解》——清华大学出版社。
早期的AWT(抽象窗口工具包)组件开发的图形用户界面,要依赖本地系统,当把AWT组件开发的应用程序移植到其他平台的系统上运行时,不能保证其外观风格,因此AWT是依赖于本地系统平台的。 而使用Swing开发的Java应用程序,其界面是不受本地系统平台限制的,也就是说Swing开发的Java应用程序移植到其他系统平台上时,其界面外观是不会改变的。但要注意的是,虽然Swing提供的组件可以方便开发Java应用程序,但是Swing并不能取代AWT,在开发Swing程序时通常要借助与AWT的一些对象 来共同完成应用程序的设计。
JFrame
窗体是一个容器,在Swing开发中我们经常要用到,它是Swing程序中各个组件的载体。
在JFrame对象创建完成后,需要调用getContentPane()
方法将窗体转换为容器,然后在容器中添加组件 或设置布局管理器,通常这个容器用来包含和显示组件。如果需要将组件添加至容器,可以使用来自 Container类的add()方法
进行设置。
public class JFrameDemo { public static void main(String[] args) { new JFrameDemo().CreateJFrame(); } public void CreateJFrame() { JFrame jFrame = new JFrame("这是一个JFrame窗口"); jFrame.setVisible(true); jFrame.setBounds(100, 100, 300, 300); jFrame.setBackground(Color.pink); // 设置窗体关闭方式 jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); } }
当然,在开发中更常用的方式是通过继承``java.swing.JFrame`类创建一个窗体,可通过this关键字调用其方法。
public class JFrameDemo2 extends JFrame { public void init() { setVisible(true); setBounds(100, 100, 300, 300); setTitle("JFrame窗口"); setDefaultCloseOperation(EXIT_ON_CLOSE); // 创建一个JLabel标签 JLabel jLabel = new JLabel("这是一个JLabel标签"); // 使JLabel标签居中 jLabel.setHorizontalAlignment(SwingConstants.CENTER); // 获取一个容器 Container container = getContentPane(); // 将标签添加到容器中 container.add(jLabel); // 设置容器的背景颜色 container.setBackground(Color.pink); } public static void main(String[] args) { new JFrameDemo2().init(); } }
JDialog窗体是Swing组件中的对话框,继承了AWT组件中的java.awt.Dialog
类。功能是从一个窗体中弹出另一个窗体。
public class JDialogDemo extends JDialog{ static MyJFrame jFrame; //定义一个对话框的父窗体 // 实例化一个JDialog类对象,指定其父窗体、窗口标题和类型 public JDialogDemo() { super(jFrame, "这是一个JDialog窗体", true); Container container = getContentPane(); JLabel jLabel = new JLabel("这是一个JLabel"); jLabel.setHorizontalAlignment(SwingConstants.CENTER); container.add(jLabel); setBounds(350, 350, 300, 300); } public static void main(String[] args) { jFrame = new MyJFrame(); } } class MyJFrame extends JFrame { public MyJFrame() { setBounds(250, 250, 500, 500); setVisible(true); setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); Container container = getContentPane(); container.setLayout(null); JButton jButton = new JButton("点击弹出对话框"); jButton.setBounds(30, 30, 200, 50); jButton.setHorizontalAlignment(SwingConstants.CENTER); jButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { new JDialogDemo().setVisible(true); } }); container.add(jButton); } }
在Swing中显示文本或提示信息的方法是使用标签,它支持文本字符串和图标。
标签由JLabel类定义,可以显示一行只读文本、一个图像或带图像的文本。
JLabel类提供了许多构造方法,可查看API选择需要的使用,如显示只有文本的标签、只有图标的标签或包含文本与图标的标签等。常用的语法如下,创建的是一个不带图标和文本的Label对象
JLabel jl = new JLabel();
Swing中的图标可以放置在按钮、标签等组件上,用于描述组件的用途。图标可以用Java支持的图片文件类型进行创建,也可以使用java.awt.Graphics
类提供的功能方法来创建。在Swing中通过Icon接口来创建图标,可以在创建时给定图标的大小、颜色等特性。
注意,Icon是接口,在使用Icon接口的时候,必须实现Icon接口的三个方法:
- public int getIconWidth() // 获取图片的宽度
- public int getIconHeight() // 获取图片的高度
- public void paintIcon(Component arg(), Graphics arg1, int arg2, int arg3) // 用于实现在指定坐标位置上画图
public class IconDemo extends JFrame implements Icon { private int width; private int height; public IconDemo() {} public IconDemo(int width, int height) { this.width = width; this.height = height; } public void init() { IconDemo iconDemo = new IconDemo(15, 15); JLabel jLabel = new JLabel("iconDemo", iconDemo, SwingConstants.CENTER); Container container = getContentPane(); container.add(jLabel); setBounds(300, 300, 300, 300); setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); setVisible(true); } @Override public void paintIcon(Component c, Graphics g, int x, int y) { g.fillOval(x, y, width, height); //画一个位于(x, y),宽度width,高度height的圆 } @Override public int getIconWidth() { return width; } @Override public int getIconHeight() { return height; } public static void main(String[] args) { new IconDemo().init(); } }
Swing中的图标除了可以绘制之外,还可以使用某个特定的图片创建。利用javax.swing.ImageIcon
类根据现有图片创建图标。
public class ImageIconDemo extends JFrame { public ImageIconDemo() { URL url = ImageIconDemo.class.getResource("ImageIconTest.jpg"); // 获取照片所在URL(file:/E:/Program%20Files%20(x86)/IDEA/MyJava/JavaSE/out/production/GUI/com/atfunny/gui/swingtest/ImageIconTest.jpg),也可自己写相对位置 System.out.println(url); ImageIcon imageIcon = new ImageIcon(url); imageIcon.setImage(imageIcon.getImage().getScaledInstance(150, 150, Image.SCALE_DEFAULT)); // 可用以下三条语句代替 // Image img = image.getImage(); // 获取当前照片 // img = img.getScaledInstance(width, height, Image.SCALE_DEFAULT); // 使用默认的图片缩放算法将照片设置成自定义的宽高 // image.setImage(img); // 设置此图标显示的图像 JLabel jLabel = new JLabel("JLabel标签,旁边的是照片", imageIcon, SwingConstants.CENTER); // 为标签设置照片 jLabel.setOpaque(true); // 设置标签为不透明状态 Container container = getContentPane(); container.add(jLabel); setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); setSize(500, 500); setVisible(true); } public static void main(String[] args) { new ImageIconDemo(); } }
Swing中,每个组件在容器中都有一个具体的位置和大小,在容器中摆放各自组建时很难判断其具体位置和大小,这里我们就要引入布局管理器了。它提供了基本的布局功能,可以有效的处理整个窗体的布局。常用的布局管理器包括流式布局管理器、边界布局管理器、网格布局管理器等。
绝对布局是硬性制定组件在容器中的位置和大小,可以使用绝对坐标的方式来指定组件的位置。具体步骤如下
Container.setLayout(null)
方法取消布局管理器Container.setBounds()
方式设置每一个组件的位置和大小public void absoluteLayoutTest() throws InterruptedException { JFrame jFrame = new JFrame(); Container container = jFrame.getContentPane(); container.setLayout(null); // 取消默认布局管理器 jFrame.setBounds(30, 30, 300, 300); jFrame.setVisible(true); jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); Thread.sleep(10000); }
流布局管理器是布局管理器中最基本的布局管理器,使用FlowLayout类,像“流”一样从左到右摆放 组件,直到占据了这一行的所有空间,再向下移动一行。组件在每一行的位置默认居中排列,要更改位置可自行设置。
在FlowLayout的有参构造方法中,alignment设置为0时,每一行的组件将被指定左对齐排列;当 alignment被设置为2时,每一行的组件将被指定右对齐排列;而为1时是默认的居中排列。
@Test public void flowLayoutTest() throws InterruptedException { JFrame jFrame = new JFrame("流式布局"); Container container = jFrame.getContentPane(); // alignment设置为0时,每一行的组件将被指定左对齐排列;当alignment被设置为2时,每一行的组件将被指定右对齐排列;而为1时是默认的居中排列。 container.setLayout(new FlowLayout(2, 10, 110)); // 设置流式布局管理器,2是右对齐,后两个参数分别为组件间的水平间隔和垂直间隔 for (int i = 0; i < 10; i++) { container.add(new JButton("按钮" + (i+1))); } jFrame.setSize(300, 300); jFrame.setVisible(true); jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); Thread.sleep(10000); }
在不指定窗体布局时,Swing组件默认的布局管理器是边界布局管理器,使用的是BorderLayout
类。在上面的例子中,一个JLabel标签占据了整个空间,实质上是默认使用了边界布局管理器。边界布局管理器还可以容器分为东、南、西、北、中五个区域,可以将组件加入这五个区域中。
public void BorderLayoutTest() throws InterruptedException { // 定义以下两个数组用于循环添加按钮时使用 // 此数组用于存放组件摆放位置 String[] border = {BorderLayout.CENTER, BorderLayout.NORTH, BorderLayout.SOUTH, BorderLayout.WEST, BorderLayout.EAST}; // 此数组用于存放按钮名称 String[] button = {"中", "北", "南", "西", "东"}; JFrame jFrame = new JFrame("边界布局"); Container container = jFrame.getContentPane(); container.setLayout(new BorderLayout()); // 设置容器为边界布局管理器 for (int i = 0; i < button.length; i++) { container.add(border[i], new JButton(button[i])); // 左参数为设置布局,右参数为创建按钮 } jFrame.setSize(300, 300); jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); jFrame.setVisible(true); Thread.sleep(10000); }
网格布局管理器将容器划分为网格,组件按行按列排列,使用GridLayout
类。在此布局管理器中,每个 组件的大小都相同,且会填满整个网格,改变窗体大小,组件也会随之改变。
public void GridLayoutTest() throws InterruptedException { JFrame jFrame = new JFrame("边界布局"); Container container = jFrame.getContentPane(); container.setLayout(new GridLayout(7, 3, 5, 5)); // 设置容器为网格布局管理器,前两个参数为7行3列,后两个参数为网格间的间距 for (int i = 0; i < 20; i++) { container.add(new JButton("按钮" + (i+1))); } jFrame.setSize(300, 300); jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); jFrame.setVisible(true); Thread.sleep(10000); }
面板也是一个容器,可作为容器容纳其他组件,但耶必须被添加到其他容器中。Swing中常用面板有JPanel面板和JScrollPane面板。
JPanel面板可以聚集一些组件来布局。继承自java.awt.Container
类。
public class JPanelDemo extends JFrame { public JPanelDemo() { Container container = getContentPane(); container.setLayout(new GridLayout(2, 1, 10, 10)); // 设置网格为两行一列,水平和垂直间距分别为10和10 JPanel jPanel = new JPanel(new GridLayout(1, 3)); // 初始化一个面板,设置1行3列的网格布局 JPanel jPane2 = new JPanel(new GridLayout(1, 2)); // 初始化一个面板,设置1行2列的网格布局 JPanel jPane3 = new JPanel(new GridLayout(2, 1)); // 初始化一个面板,设置2行1列的网格布局 JPanel jPane4 = new JPanel(new GridLayout(3, 2)); // 初始化一个面板,设置3行2列的网格布局 for (int i = 0; i < 3; i++) { jPanel.add(new JButton("1")); } for (int i = 0; i < 2; i++) { jPane2.add(new JButton("2")); } for (int i = 0; i < 2; i++) { jPane3.add(new JButton("3")); } for (int i = 0; i < 6; i++) { jPane4.add(new JButton("4")); } container.add(jPanel); // 在容器中添加面板1 container.add(jPane2); // 在容器中添加面板2 container.add(jPane3); // 在容器中添加面板3 container.add(jPane4); // 在容器中添加面板4 setSize(300, 300); setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); setVisible(true); } public static void main(String[] args) { new JPanelDemo(); } }
若遇到一个较小的容器窗体中显示一个较大部分内容的情况,可用JScrollPane面板。这是一个带滚动条的面板,就像平时浏览网页,经常遇到的滚动条一样。
如果需要在JScrollPane面板中放置多个组件,需将这多个组件放置在JPanel面板上,然后将JPanel 面板作为一个整体组件添加在JScrollPane面板上。
public class JScrollPaneDemo extends JFrame { public JScrollPaneDemo() { Container container = getContentPane(); JTextArea jTextArea = new JTextArea(20, 50); // 设置初始界面显示20行50列 jTextArea.setText("欢迎来到陈宝子的练习"); JScrollPane jScrollPane = new JScrollPane(jTextArea); container.add(jScrollPane); setSize(300, 300); setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); setVisible(true); } public static void main(String[] args) { new JScrollPaneDemo(); } }
JButton是较为常用的组件,用于触发特定动作。可以在按钮上显示文本标签,还可以显示图标。
public class JButtonTest extends JFrame { public JButtonTest() { Container container = getContentPane(); ImageIcon imageIcon = new ImageIcon(JButtonTest.class.getResource("ImageIconTest.jpg")); imageIcon.setImage(imageIcon.getImage().getScaledInstance(300, 300, Image.SCALE_DEFAULT)); // 利用默认照片缩放算法将照片设置成150*150 JButton jButton = new JButton(); jButton.setIcon(imageIcon); jButton.setToolTipText("照片按钮"); // 设置按钮提示 container.add(jButton); setSize(300, 300); setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); setVisible(true); } public static void main(String[] args) { new JButtonTest(); } }
默认情况下,单选按钮显示一个圆形图标,通常在其旁放置一些说明性文字。当用户选中某个单选按钮后,按钮组中其它按钮将被自动取消,这时就需要按钮组(ButtonGroup)来将同组按钮放在一起,该按钮组中的按钮只能选择一个,而不在此按钮中的按钮不受影响。
public class JRadioButtonTest extends JFrame { public JRadioButtonTest() { Container container = getContentPane(); // 单选框 JRadioButton jRadioButton1 = new JRadioButton("JRadioButton1"); JRadioButton jRadioButton2 = new JRadioButton("JRadioButton2"); JRadioButton jRadioButton3 = new JRadioButton("JRadioButton3"); // 按钮组,将单选框添加到按钮组中,按钮组中的单选框只能选择一个,默认情况下三个都没有选择 ButtonGroup buttonGroup = new ButtonGroup(); buttonGroup.add(jRadioButton1); buttonGroup.add(jRadioButton2); buttonGroup.add(jRadioButton3); container.add(jRadioButton1, BorderLayout.CENTER); container.add(jRadioButton2, BorderLayout.NORTH); container.add(jRadioButton3, BorderLayout.SOUTH); setSize(300, 300); setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); setVisible(true); } public static void main(String[] args) { new JRadioButtonTest(); } }
复选框是一个方块图标,外加一段描述性文字,与单选按钮的区别就是可以多选。每一个复选框都提供“选中”与“不选中”两种状态。
public class JCheckBoxTest extends JFrame { public JCheckBoxTest() { Container container = getContentPane(); // 多选框 JCheckBox jCheckBox1 = new JCheckBox("JCheckBox1"); JCheckBox jCheckBox2 = new JCheckBox("JCheckBox2"); // 如果将多选框加入到ButtonGroup中去仍然只能做到单选效果 container.add(jCheckBox1); container.add(jCheckBox2, BorderLayout.NORTH); setSize(300, 300); setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); setVisible(true); } public static void main(String[] args) { new JCheckBoxTest(); } }
@Test public void jComboBoxTest() throws InterruptedException { JFrame jFrame = new JFrame("JComboBoxTest"); Container container = jFrame.getContentPane(); JComboBox jComboBox = new JComboBox(); // 添加列表中的选项,参数类型为Object jComboBox.addItem("正在上映"); jComboBox.addItem(null); jComboBox.addItem("即将上映"); jComboBox.addItem("已经下架"); container.add(jComboBox); jFrame.setBounds(300, 300, 300, 300); jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); jFrame.setVisible(true); Thread.sleep(10000); }
列表框只是在窗体上占据固定的大小,如果要使列表框具有滚动效果,可以将列表框放入滚动面板中。
使用数组初始化列表框的参数如下:
@Test public void jListTest() throws InterruptedException { JFrame jFrame = new JFrame("JListTest"); Container container = jFrame.getContentPane(); String[] contents = {"1", "2", "3"}; JList jList = new JList(contents); container.add(jList); jFrame.setBounds(300, 300, 300, 300); jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); jFrame.setVisible(true); Thread.sleep(10000); }
使用集合初始化列表框的参数如下:
@Test public void jListByVectorTest() throws InterruptedException { JFrame jFrame = new JFrame("jListByVectorTest"); Container container = jFrame.getContentPane(); // 利用集合初始化列表框 Vector vector = new Vector(); JList jList = new JList(vector); vector.addAll(Arrays.asList("1", "2", "3")); container.add(jList); jFrame.setBounds(300, 300, 300, 300); jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); jFrame.setVisible(true); Thread.sleep(10000); }
文本框通常用来显示或编辑一个单行文本
@Test public void JTextFieldTest() throws InterruptedException { JFrame jFrame = new JFrame("JTextFieldTest"); Container container = jFrame.getContentPane(); container.setLayout(new FlowLayout()); JTextField jTextField = new JTextField("这是一个文本框", 20); // 创建一个文本框,长度为20,默认值为“这是一个文本框” container.add(jTextField); jFrame.setBounds(300, 300, 300, 300); jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); jFrame.setVisible(true); Thread.sleep(10000); }
密码框与文本框的定义与用法类似,其继承于JTextField
类,但会使用户输入的字符串以某种符号进行加密。
@Test public void jPasswordFieldTest() throws InterruptedException { JFrame jFrame = new JFrame("JPasswordFieldTest"); Container container = jFrame.getContentPane(); container.setLayout(new FlowLayout()); JPasswordField jPasswordField = new JPasswordField("123456", 20); // 创建一个密码框,长度为20,默认密码为123456 jPasswordField.setEchoChar('*'); // 设置回显符号 System.out.println(jPasswordField.getPassword()); container.add(jPasswordField); jFrame.setBounds(300, 300, 300, 300); jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); jFrame.setVisible(true); Thread.sleep(10000); }
在文本域中可以输入多行多列的值,其和JTextField
一样继承了JTextComponent
@Test public void jTextAreaTest() throws InterruptedException { JFrame jFrame = new JFrame("JTextAreaTest"); Container container = jFrame.getContentPane(); container.setLayout(new FlowLayout()); JTextArea jTextArea = new JTextArea("这是一个文本域", 10, 50); // 创建一个文本域,设置初始默认显示为10行50列,默认值为“这是一个文本域” container.add(jTextArea); jFrame.setBounds(300, 300, 300, 300); jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); jFrame.setVisible(true); Thread.sleep(10000); }