Java学习 - GUI 设计
Java学习 - GUI设计
1.图形界面工具介绍
\(AWT \rarr SWING \rarr WindowBuilder\) 并非完全不相同的工具,后者是前者的功能扩充
2.顶层容器: JFrame 和 JDialog: 窗口容器和对话框容器
在Swing中,任何其他组件(Component)都必须位于一个顶层容器中.
JFrame
窗口 和 JDialog
面板是常用的顶层容器.
本节以JFrame为代表介绍顶层容的两点特性: 内容窗格(ContentPane)和窗口关闭方式(CloseOperation)
JFrame用来设计类似于Windows系统中窗口形式的界面.它的构造方法有如下两种:
JFrame() // 构造一个初始时不可见的窗体
JFrame(String title) // 构造一个标题为'title'的初始时不可见的窗体
当创建一个JFrame类的实例化对象后,其他组件并不能够直接放在JFrame上面.而是需要先为JFrame对象添加一个内容窗格(ContentPane).
public class TestFrame extends JFrame{ // 创建一个JFrame子类,代表一类具有共同特点的JFrame窗口
private JPanel contentPane;
// 为其添加内容窗格
}
JFrame的常用方法:
示例
public class TestFrame extends JFrame{
public static void main(String[] args){
new TestFrame();
}
public TestFrame() {
setTitle("Java的第一个GUI程序");
setSize(400,200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container c = getContentPane();
// import java.awt.Container ,获取JFrame对象的内容窗格
JLabel jl = new JLabel("这是放在JFrame的内容窗格上的标签");
// import javax.swing.JLabel , 创建一个标签
c.add(jl);
setVisible(true);
}
}
3.中间容器: JPanel面板
JPanel是一种中间容器,它能够容纳组件并将组件组合在一起,但它本身必须添加到其他(顶层)容器中使用,它的构造方法有两种
JPanel() // 使用默认的布局管理器创建新面板,默认的布局管理器为FlowLayout
JPanel(LayoutManager layout) // 创建指定布局管理器的JPanel对象
JPanel的常用方法:
示例
package myFirstAttempt;
import java.awt.*;
import javax.swing.*;
public class DemoClass {
public static void main(String[] args) {
JFrame jf = new JFrame("Java的第二个GUI程序");
jf.setBounds(300,100,400,200);
JPanel jp = new JPanel();
JLabel jl = new JLabel("这是一个放在JPanel上的标签");
jp.setBackground(Color.white);
jp.add(jl);
jf.add(jp);
jf.setVisible(true);
}
}
4. 布局管理器 LayoutManager
Java的布局管理器用于方便开发人员向容器中添加组件时,更加合理地进行布局.
-
边框布局管理器(BorderLayout)
边框布局管理器(BorderLayout)是Window,JFrame,JDialog的默认布局管理器.
BorderLayout 分为5个区域:North,South,East,West,Center.如图所示
后添加的组件如果和原有的组件位置重复,则会覆盖原有的组件
BorderLayout布局管理器的两种构造方法如下:
BorderLayout() //创建一个Border布局,组件之间没有间隙
BorderLayout(int hgap,int vgap); // 创建一个Border布局,其中hgap表示组件之间的横向距离,vgap表示纵向距离,单位为像素
示例
package myFirstAttempt;
import java.awt.*;
import javax.swing.*;
public class DemoClass {
public static void main(String[] args) {
JFrame jf = new JFrame("Java的第三个GUI程序");
jf.setSize(400,200);
jf.setLayout(new BorderLayout());
JButton bt1 = new JButton("上");
JButton bt2 = new JButton("左");
JButton bt3 = new JButton("中");
JButton bt4 = new JButton("下");
JButton bt5 = new JButton("右");
jf.add(bt1,BorderLayout.NORTH);
jf.add(bt2,BorderLayout.WEST);
jf.add(bt3,BorderLayout.CENTER);
jf.add(bt4,BorderLayout.SOUTH);
jf.add(bt5,BorderLayout.EAST);
jf.setBounds(300,200,600,300);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
-
流布局管理器(FlowLayout)
FlowLayout(流式布局管理器)是 JPanel 和 JApplet 的默认布局管理器。FlowLayout 会将组件按照从上到下、从左到右的放置规律逐行进行定位。与其他布局管理器不同的是,FlowLayout 布局管理器不限制它所管理组件的大小,而是允许它们有自己的最佳大小。
FlowLayout 布局管理器的构造方法如下。
FlowLayout() // 创建一个布局管理器,使用默认的居中对齐方式和默认 5 像素的水平和垂直间隔。 FlowLayout(int align) //创建一个布局管理器,使用默认 5 像素的水平和垂直间隔。其中,align 表示组件的对齐方式,对齐的值必须FlowLayoutLEFT、FlowLayout.RIGHT 和 FlowLayout.CENTER,指定组件在这一行的位置是居左对齐、居右对齐或居中对齐。 FlowLayout(int align, int hgap,int vgap) // 创建一个布局管理器,其中 align 表示组件的对齐方式;hgap 表示组件之间的横向间隔;vgap 表示组件之间的纵向间隔,单位是像素。
package myFirstAttempt;
import java.awt.*;
import javax.swing.*;
public class DemoClass {
public static void main(String[] args) {
JFrame jf = new JFrame("Java的第四个GUI程序");
JPanel jp = new JPanel();
JButton bt1 = new JButton("1");
JButton bt2 = new JButton("2");
JButton bt3 = new JButton("3");
JButton bt4 = new JButton("4");
JButton bt5 = new JButton("5");
JButton bt6 = new JButton("6");
JButton bt7 = new JButton("7");
JButton bt8 = new JButton("8");
JButton bt9 = new JButton("9");
jp.add(bt1);
jp.add(bt2);
jp.add(bt3);
jp.add(bt4);
jp.add(bt5);
jp.add(bt6);
jp.add(bt7);
jp.add(bt8);
jp.add(bt9);
jp.setLayout(new FlowLayout(FlowLayout.LEADING,20,20));
jp.setBackground(Color.white);
jf.add(jp);
jf.setBounds(300,200,300,150);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
卡片布局管理器(CardLayout)
卡片布局管理器用于多种组件分时享有同一块空间,就行卡片一样,第一张卡片显示一组组件,当需要显示另一组组件的时候,切换到另一张卡片.
其构造方法如下:
CardLayout() //构造一个新的布局,默认间隔为0
CardLayout(int hgap,int vgap) // 创建布局管理器,指定水平间隔hgap和垂直间隔vgap
示例
package myFirstAttempt;
import java.awt.*;
import javax.swing.*;
public class DemoClass {
public static void main(String[] args) {
JFrame jf = new JFrame("Java第五个GUI程序");
JPanel p1 = new JPanel();
JPanel p2 = new JPanel();
JPanel cards = new JPanel(new CardLayout());
p1.add(new JButton("登录"));
p1.add(new JButton("注册"));
p1.add(new JButton("找回密码"));
p2.add(new JTextField("用户名",20));
p2.add(new JTextField("密码",20));
p2.add(new JTextField("验证码",20));
CardLayout c1 = (CardLayout)(cards.getLayout());
cards.add(p1,"card1");
cards.add(p1,"card2");
c1.show(cards,"card1"); // 可改为card2
jf.add(cards);
jf.setBounds(300,200,400,200);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
5.基本组件
基本组件包括非交互组件和交互组件
在添加了容器并指定了布局管理器后,便可以向容器中添加各种展示类的组件,像
- 标签(JLabel)
- 按钮(JButton)
- 单行文本框(JTextField)
- 文本域(JTextArea)
- 单选按钮(JToggleButton)
- 复选框(JCheckBox)
- 下拉列表(JComboBox)
- 列表框(JList)
本节仅介绍标签,其余组件可看http://c.biancheng.net/view/1216.html
标签是一种可以包含文本和图片的非交互组件,其中文本可以是单行文本,也可以是HTML文本. 对于只包含文本的标签可以使用JLabel类,其构造方法包括
JLabel() //无图像,标题为空字符串
JLabel(icon image) // 具有指定图像
JLabel(String text) // 具有指定文本
JLabel(String textjcon,int horizontalAlignment) // 创建具有指定文本、图像和水平对齐方式的 JLabel,horizontalAlignment 的取值有 3 个,即 JLabel.LEFT、JLabel.RIGHT 和 JLabel.CENTER。
JLabel的常用构造方法:
按钮
单行文本框
文本域
复选框
单选按钮
下拉列表
列表框
6. 章节小结: 实现计算器布局
package myFirstAttempt;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import java.awt.GridBagLayout;
import javax.swing.JTextField;
import java.awt.GridLayout;
import javax.swing.border.CompoundBorder;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Color;
public class TestFrame extends JFrame {
private JTextField textField;
public static void main(String[] args) {
new TestFrame();
}
public TestFrame() {
setForeground(Color.GRAY);
setBounds(600,400,400,350);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setTitle("\u8BA1\u7B97\u5668\u5E03\u5C40\u8BBE\u8BA1");
setVisible(true);
JPanel panel = new JPanel();
getContentPane().add(panel, BorderLayout.NORTH);
textField = new JTextField();
panel.add(textField);
textField.setColumns(30);
JPanel panel_1 = new JPanel();
panel_1.setBorder(new CompoundBorder());
getContentPane().add(panel_1, BorderLayout.CENTER);
panel_1.setLayout(new GridLayout(4, 4, 5, 5));
JButton btnNewButton_1 = new JButton("7");
btnNewButton_1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
}
});
panel_1.add(btnNewButton_1);
JButton btnNewButton = new JButton("8");
panel_1.add(btnNewButton);
JButton btnNewButton_2 = new JButton("9");
panel_1.add(btnNewButton_2);
JButton btnNewButton_4 = new JButton("+");
panel_1.add(btnNewButton_4);
JButton btnNewButton_3 = new JButton("4");
panel_1.add(btnNewButton_3);
JButton btnNewButton_6 = new JButton("5");
panel_1.add(btnNewButton_6);
JButton btnNewButton_9 = new JButton("6");
panel_1.add(btnNewButton_9);
JButton btnNewButton_8 = new JButton("-");
panel_1.add(btnNewButton_8);
JButton btnNewButton_5 = new JButton("1");
panel_1.add(btnNewButton_5);
JButton btnNewButton_12 = new JButton("2");
panel_1.add(btnNewButton_12);
JButton btnNewButton_7 = new JButton("3");
panel_1.add(btnNewButton_7);
JButton btnNewButton_10 = new JButton("*");
panel_1.add(btnNewButton_10);
JButton btnNewButton_11 = new JButton("0");
panel_1.add(btnNewButton_11);
JButton btnNewButton_13 = new JButton("*");
panel_1.add(btnNewButton_13);
JButton btnNewButton_14 = new JButton("=");
panel_1.add(btnNewButton_14);
JButton btnNewButton_15 = new JButton("/");
panel_1.add(btnNewButton_15);
}
}
整体思路
-
创建窗口JFrame,设置其大小,背景色,标题,关闭选项,可见
-
在窗口上方新建一个面板,然后在这个面板中添加文本域
-
在窗口中部新建一个面板
-
在新建的面板添加布局管理器为网格布局管理器,在代码区修改其参数为(4,4,5,5)
然后在设计区为其添加16个按钮,在代码区为其重命名
- 最终效果
7. 事件监听
事件表示程序和用户之间的交互,例如在文本框中输入,在列表框或组合框中选择,选中复选框和单选框,单击按钮等。事件处理表示程序对事件的响应,对用户的交互或者说对事件的处理是事件处理程序完成的。
当事件发生时,系统会自动捕捉这一事件,创建表示动作的事件对象并把它们分派给程序内的事件处理程序代码。这种代码确定了如何处理此事件以使用户得到相应的回答。
监听器
由于同一个事件源上可能发生多种事件,因此,Java 采取了授权模型(Delegation Model),事件源可以把在其自身上所有可能发生的事件分别授权给不同的事件处理者来处理。例如,在 Panel 对象上既可能发生鼠标事件,也可能发生键盘事件,该 Panel 对象可以授权给事件处理者 a 来处理鼠标事件,同时授权给事件处理者 b 来处理键盘事件。
有时也将事件处理者称为监听器,主要原因在于监听器时刻监听事件源上所有发生的事件类型,一旦该事件类型与自己所负责处理的事件类型一致,就马上进行处理。授权模型把事件的处理委托给外部的处理实体进行处理,实现了将事件源和监听器分开的机制。
事件处理者(监听器)通常是一个类,该类如果能够处理某种类型的事件,就必须实现与该事件类型相对的接口。例如,一个 ButtonHandler 类之所以能够处理 ActionEvent 事件,原因在于它实现了与 ActionEvent 事件对应的接口 ActionListener。每个事件类都有一个与之相对应的接口。
动作事件监听器
动作事件监听器是Swing中比较常用的事件监听器,很多组件的动作都会使用它监听,像按钮被里击、列表框中选择一项等。与动作事件监听器有关的信息如下。
- 事件名称:ActionEvent。
- 事件监听接口: ActionListener。
- 事件相关方法:addActionListener() 添加监听,removeActionListener() 删除监听。
- 涉及事件源:JButton、JList、JTextField 等。
示例:
package myFirstAttempt;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ActionListenerDemo extends JFrame {
JList list;
JLabel label;
JButton button1;
int clicks = 0;
public ActionListenerDemo() {
setTitle("动作事件监听器示例");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100,100,400,200);
JPanel contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5,5,5,5));
contentPane.setLayout(new BorderLayout(0,0));
setContentPane(contentPane);
label = new JLabel(" ");
label.setFont(new Font("楷体",Font.BOLD,16));
contentPane.add(label,BorderLayout.SOUTH);
button1 = new JButton("计数按钮");
button1.setFont(new Font("楷体",Font.BOLD,16));
button1.addActionListener(new ActionListener() { // 匿名内部类
@Override
public void actionPerformed(ActionEvent arg0) {
label.setText("按钮被单击了 " + (++clicks) + " 次") ;
}
});
contentPane.add(button1);
}
class button1ActionListener implements ActionListener{ // 实现类,可以多次调用
@Override
public void actionPerformed(ActionEvent e) {
label.setText("按钮被单击了 " + (++clicks) + " 次");
}
}
public static void main(String args[]) {
ActionListenerDemo frame = new ActionListenerDemo();
frame.setVisible(true);
}
}
简单来说,这个代码重点在于为button添加动作事件监听.
结果:
焦点事件监听器
除了单击事件外,焦点事件监听器在实际项目中应用也比较广泛,例如将光标离开文本框时弹出对话框,或者将焦点返回给文本框等。
与焦点事件监听器有关的信息如下。
- 事件名称:FocusEvent。
- 事件监听接口: FocusListener。
- 事件相关方法:addFocusListener() 添加监听,removeFocusListener() 删除监听。
- 涉及事件源:Component 以及派生类。
FocusEvent 接口定义了两个方法,分别为 focusGained() 方法和 focusLost() 方法,其中 focusGained() 方法是在组件获得焦点时执行,focusLost() 方法是在组件失去焦点时执行。
package myFirstAttempt;
import java.awt.*;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class FocusListenerDemo extends JFrame {
JList list;
JLabel label;
JButton button1;
JTextField txtfield1;
public FocusListenerDemo() {
setTitle("焦点事件监听器示例");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100,100,400,200);
JPanel contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5,5,5,5));
contentPane.setLayout(new BorderLayout(0,0));
setContentPane(contentPane);
label = new JLabel(" ");
label.setFont(new Font("楷体",Font.BOLD,16));
contentPane.add(label,BorderLayout.SOUTH);
txtfield1 = new JTextField();
txtfield1.setFont(new Font("黑体",Font.BOLD,16));
txtfield1.addFocusListener(new FocusListener() {
@Override
public void focusLost(FocusEvent arg0) {
label.setText(label.getText() + "x ");
}
@Override
public void focusGained(FocusEvent arg0) {
// TODO Auto-generated method stub
label.setText(label.getText() + "o ");
}
});
contentPane.add(txtfield1);
}
public static void main(String[] args) {
FocusListenerDemo f = new FocusListenerDemo();
f.setVisible(true);
}
}
示例:
监听列表项选择事件
列表框控件 JList 会显示很多项供用户选择,通常在使用时会根据用户选择的列表项完成不同的操作。
本案例将介绍如何监听列表项的选择事件,以及事件监听器的处理方法,实现过程如下。
package myFirstAttempt;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
public class JListDemo2 extends JFrame {
JList list;
JLabel label;
protected void do_list_valueChanged(ListSelectionEvent arg0) {
label.setText("您选中了 " + list.getSelectedValue());
}
public JListDemo2() {
setTitle("监听列表项选择事件");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100,100,400,200);
JPanel contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5,5,5,5));
contentPane.setLayout(new BorderLayout(0,0));
setContentPane(contentPane);
label = new JLabel(" ");
contentPane.add(label,BorderLayout.SOUTH);
JScrollPane scrollPane = new JScrollPane();
contentPane.add(scrollPane,BorderLayout.CENTER);
list = new JList();
scrollPane.setViewportView(list);
String[] listData = new String[7];
listData[0]="《一点就通学Java》";
listData[1]="《一点就通学PHP》";
listData[2]="《一点就通学Visual Basic)》";
listData[3]="《一点就通学Visual C++)》";
listData[4]="《Java编程词典》";
listData[5]="《PHP编程词典》";
listData[6]="《C++编程词典》";
list.setListData(listData);
list.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent arg0) {
// TODO Auto-generated method stub
do_list_valueChanged(arg0);
}
});
}
public static void main(String[] args) {
JListDemo2 f = new JListDemo2();
f.setVisible(true);
}
}