十一:Java之GUI图形Awt和Swing
一. AWT和 Swing
AWT
和 Swing 是 Java 设计 GUI用户界面的基础。与 AWT 的重量级组件不同,Swing 中大部分是轻量级组件。正是这个原因,Swing 差点儿无所不能,不但有各式各样先进的组件,并且更为美观易用。所以一開始使用AWT 的程序猿非常快就转向使用 Swing 了。
那为什么 AWT组件没有消亡呢?由于 Swing 是架构在 AWT 之上的,没有 AWT 就没有Swing。所以程序猿能够依据自己的习惯选择使用 AWT 或者是 Swing。可是,最好不要二者混用——除开显示风格不同不说,还非常可能造成层次 (Z-Order) 错乱,比方下例:
<span style="font-size:18px;">import java.awt.BorderLayout;
import java.awt.Button; import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JPanel; public final class AwtSwing { public static void main(String[] args) {
AwtSwing as = new AwtSwing();
as.show();
} JFrame frame = new JFrame("Test AWT and SWING"); JDesktopPane jdp = new JDesktopPane(); JInternalFrame jif1 = new JInternalFrame("controls"); JInternalFrame jif2 = new JInternalFrame("cover"); public AwtSwing() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(jdp); jif1.setContentPane(new JPanel());
jif2.setContentPane(new JPanel()); jif1.getContentPane().setLayout(new BorderLayout());
jif1.getContentPane().add(new Button("AWT Button"), BorderLayout.WEST);
jif1.getContentPane().add(new JButton("Swing Button"),
BorderLayout.EAST); jif1.setSize(200, 100);
jif2.setSize(200, 100); jdp.add(jif1);
jdp.add(jif2); frame.setSize(240, 140);
} public void show() {
frame.setVisible(true);
jif1.setVisible(true);
jif2.setVisible(true);
} }</span>
执行这个程序,并用鼠标拖动那个名为“cover”的子窗体,我们会发现一个很有趣的现象
显然 cover子窗体是在 controls 子窗体之上的,可是它仅仅罩盖住了 Swing Button,没有罩盖住 AWT Button。再看一会儿,你是不是有这样一种感觉:Swing Button 是“画”上去的,而 AWT Button 则是“贴”上去的。这就是二者混用造成层次错乱的一个样例。
Swing
组件有美观、易用、组件量大等特点,也有缺点——使用 Swing 组件的程序一般会比使用 AWT 组件的程序执行更慢。可是大家都还是更喜欢用 Swing 组件,原因何在?由于随着计算机硬件的升级,一点点速度已经不是问题。相反的,用户更须要美观的用户界面,开发者则更须要易用的开发组件。
二.框架、监听器和事件
框架 (Frame, JFrame)是 Java 图形用户界面的基础,它就是我们通常所说的窗体,是 Windows/XWindow 应用程序的典型特征。说到Windows/XWindow,大家非常easy联想到“事件(Event) 驱动”。Java 的图形用户界面正是事件驱动的,而且由各种各样的监听器 (Listener) 负责捕捉各种事件。
假设我们须要对某一个组件的某种事件进行捕捉和处理时,就须要为其加入监听器。比方,我们要在一个窗体 (JFrame)激活时改变它的标题,我们就须要为这个窗体 (JFrame 对象) 加入一个能够监听到“激活窗体”这一事件的监听器——WindowListener。
怎么加入监听器呢?这通常由组件类提供的一个 addXxxxxListener的方法来完毕。比方 JFrame 就提供有 addWindowListener 方法加入窗体监听器(WindowListener)。
一个监听器经常不仅仅监听一个事件,而是能够监听相关的多个事件。比方 WindowListener除了监听窗体激活事件 (windowActivate) 之外,还能够监听窗体关闭事件 (windowClosing) 等。那么这些事件怎么区分呢?就靠重载监听器类(Class) 的多个方法 (Method) 了。监听器监听到某个事件后,会自己主动调用相关的方法。因此我们仅仅要重载这种方法,就能够处理对应的事件了。
最好还是先看一个样例:
<span style="font-size:18px;">import javax.swing.*;
import java.awt.event.*; public class TestFrame extends JFrame { private int counter = 0; public TestFrame() {
/* 使用匿名类加入一个窗体监听器 */
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.out.println(
"Exit when Closed event");
//退出应用程序
System.exit(0);
} public void windowActivated(WindowEvent e) {
// 改变窗体标题
setTitle("Test Frame " + counter++);
}
}); // 设置窗体为固定大小
setResizable(false);
setSize(200, 150);
} public static void main(String[] args) {
TestFrame tf = new TestFrame();
tf.show();
} }</span>
这个样例中,我们设计了一个窗体类(public class TestFrame extends JFrame { ... }),而且为这个窗体加入了一个窗体监听器 (addWindowListener(new WindowAdapter() ...)。而我们加入的这个窗体监听器主要监听了两个事件:窗体关闭 (public void windowClosing(WindowEvent
e) ...) 和窗体激活 (public void windowActivated(WindowEvent e) ...)。在窗体关闭事件中我们退出了整个应用程序(System.exit(0);),而在窗体激活事件中,我们改变了窗体的标题(setTitle("Test Frame " + counter++);)。最后,我们在main 方法中显示了这窗体类的一个实例
这个程序的执行结果就是一个什么东西都没有加的框架,也就是一个空窗体。那么,你知道显示一个窗体最基本的几句代码吗?不知道没关系,我来告诉你,显示一个窗体仅仅须要做三件事:生成实例(对象)→设置大小→显示,对应的,就是以下的三句代码:
JFrame frame = new JFrame("Frame's Title");
frame.setSize(400, 300);
frame.setVisible(true);
或许你会说:第一句的意思我清楚,第三句的意思我也明确,为什么一定要第二句呢?事实上想想也就明确了,叫你画一个没法有大小的矩形你能画出来吗?不能。相同,没有大小的窗体,怎么显示?所以我们须要用 setSize(int width, int height)方法为其设置大小。我们还有还有一种方法:用 JFrame 的 pack() 方法让它自己适配一个大小。pack()
在多数时候是令人惬意的,但有时,它也会让你哭笑不得——多试试就知道了。
在 JFrame中,我们使用 addWindowListener 方法增加一个监听器 WindowListener (addWindowListener(new WindowAdapter() ...) 去监听发生在 JFrame 上的窗体事件。WindowListener 是一个接口,在 java.awt.event 这个包中,可是上例中好象并没有使用WindowListener,而是使用的
WindowsAdapter 吧,这是怎么回事?
WindowAdapter是 WindowsListener 接口的一个最简单的实现,也在 java.awt.event 包中。假设我们直接使用 WindowListener 产生一个类,须要实现它的每个方法 (一共 7 个)。但 WindowAdapter 作为 WindowListener 最简单的实现,已经实现了它的每个方法为空方法 (即仅仅包括空语句,或者说没有语句的方法)。用
WindowAdapter 就仅仅须要重载可能用到的方法 (上例中仅仅有 2 个) 即可了,而不须要再去实现每个方法。长处显而易见——降低编码量。
在 JFrame上发生的窗体事件 (WindowEvent) 包含:
windowActivated(WindowEvent e) |
窗体得到焦点时触发 |
windowClosed(WindowEvent e) |
窗体关闭之后触发 |
windowClosing(WindowEvent e) |
窗体关闭时触发 |
windowDeactivated(WindowEvent e) |
窗体失去焦点时触发 |
windowDeiconified(WindowEvent e) |
|
windowIconified(WindowEvent e) |
|
windowOpened(WindowEvent e) |
窗体打开之后触发 |
上例重载了当中两个方法。假设在上例执行产生的窗体和另外一个应用程序窗体之间来回切换 (在 Windows 操作系统中你能够使用 Alt+Tab 进行切换)……试试看,你发现了什么?有没有现我们的演示样例窗体标题上的数字一直在添加,这便是在 windowActivated 事件中 setTitle("TestFrame " + counter++) 的功劳。
而还有一个事件处理函数 windowClosing中的 System.exit(0) 则保证了当窗体被关闭时退出当前的 Java 应用程序。假设不作这种处理会如何呢?试验之后你会发现,窗体尽管关闭了,但程序并没有结束,但此时,除了使用 Ctrl+C 强行结束之外,恐怕也没有其他办法了。所以,这一点很重要:你想在关闭窗体的时候退出应用程序,那就须要处理
windowClosing 事件。……也不尽然,事实上还有另外一个更简单的办法,让 JFrame 自己处理这件事——你仅仅须要例如以下调用 JFrame 的 setDefaultCloseOperation 就可以:
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
在产生 JFrame对象之后运行上述语句,就能够不用处理 windowsClosing 事件来退出程序了。
我们能够在 JFrame对象中加入 AWT 或者Swing 组件。可是,尽管它有 add 方法,却不能直接用于加入组件,否则崤壮鲆斐!恍啪褪允浴T斐烧飧鱿窒蟮脑蛑挥幸桓鼋馐停篔Frame不是一个容器,它仅仅是一个框架。那么,应该怎么加入组件呢?
JFrame有一个 Content Pane,窗体是显示的全部组件都是加入在这个 Content Pane 中。JFrame 提供了两个方法:getContentPane 和 setContentPane 就是用于获取和设置其 Content Pane 的。通常我们不须要又一次设置 JFrame 的 Content Pane,仅仅须要直接获取默认的 Content
Pane 来加入组件等。如:(new JFrame()).getContentPane().add(new Button("testbutton"))。
三.button、切换button、复选button和单选button
button……就是button,不会连button都不知道吧?
切换button,有两种状态的button,即按下状态和弹起状态,若称为选择状态或未选择状态。
复选button,又叫复选框,用一个小方框中是否打勾来表示两种状态。
单选button,又叫收音机button,以小圆框打点表示被选中。常成组出现,一组单选button中仅仅有一个能被选中。
发现什么了吗?——对了,这一部分是在讲各种各样的button,并且后三种button都有两种状态。先看看这些button都长成什么样:
上图中,从上到下,依次就是button、切换button、复选button和单选button。图示的窗体,就是以下这个样例的执行结果:
<span style="font-size:18px;">import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener; import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JRadioButton;
import javax.swing.JToggleButton; public final class TestButtons { public static void main(String[] args) {
TestButtons tb = new TestButtons();
tb.show();
} JFrame frame = new JFrame("Test Buttons"); JButton jButton = new JButton("JButton"); // button JToggleButton toggle = new JToggleButton("Toggle Button"); // 切换button JCheckBox checkBox = new JCheckBox("Check Box"); // 复选button JRadioButton radio1 = new JRadioButton("Radio Button 1"); // 单选button JRadioButton radio2 = new JRadioButton("Radio Button 2"); JRadioButton radio3 = new JRadioButton("Radio Button 3"); JLabel label = new JLabel("Here is Status, look here."); // 不是button,是静态文本 public TestButtons() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new java.awt.FlowLayout()); // 为一般button加入动作监听器
jButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
label.setText("You clicked jButton");
}
}); // 为切换button加入动作监听器
toggle.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
JToggleButton toggle = (JToggleButton) ae.getSource();
if (toggle.isSelected()) {
label.setText("You selected Toggle Button");
} else {
label.setText("You deselected Toggle Button");
}
}
}); // 为复选button加入条目监听器
checkBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
JCheckBox cb = (JCheckBox) e.getSource();
label.setText("Selected Check Box is " + cb.isSelected());
}
}); // 用一个button组对象包容一组单选button
ButtonGroup group = new ButtonGroup();
// 生成一个新的动作监听器对象,备用
ActionListener al = new ActionListener() {
public void actionPerformed(ActionEvent ae) {
JRadioButton radio = (JRadioButton) ae.getSource();
if (radio == radio1) {
label.setText("You selected Radio Button 1");
} else if (radio == radio2) {
label.setText("You selected Radio Button 2");
} else {
label.setText("You selected Radio Button 3");
}
}
};
// 为各单选button加入动作监听器
radio1.addActionListener(al);
radio2.addActionListener(al);
radio3.addActionListener(al);
// 将单选button加入到button组中
group.add(radio1);
group.add(radio2);
group.add(radio3); frame.getContentPane().add(jButton);
frame.getContentPane().add(toggle);
frame.getContentPane().add(checkBox);
frame.getContentPane().add(radio1);
frame.getContentPane().add(radio2);
frame.getContentPane().add(radio3);
frame.getContentPane().add(label); frame.setSize(200, 250);
} public void show() {
frame.setVisible(true);
} }</span>
除一般button外,其余三种button都有两种状态,即选择 (按下) 状态和未选择 (弹起) 状态。那么我们又该怎样推断呢?切换button (JToggleButton) 提供了一个 isSelected() 方法用来推断当前所处的状态,返回值为真 (true) 时表示它处于选择状态,返回值为假 (false) 时表示它处于未选择状态。而复选button (JCheckBox)
和单选button (JRadioButton) 都是从 JToggleButton 继承的,所以也具有 isSelected() 方法。如上例中 if(toggle.isSelected()) { ... } 等。
单选button由自身的特点决定了它们必须成组出现,并且一组中仅仅能有一个能被选中。因此我们须要用一个专门的类,ButtonGroup来管理。加入到 ButtonGroup 的多个单选button中,假设有一个被选择中,同组中的其他单选button都会自己主动改变其状态为未选择状态。在 ButtonGroup 中加入button,是使用它的 add 方法,如上例中的 group.add(radio1);。
既然我们已经将多个单选button加入到一个 ButtonGroup中了,那么我们是不是能够将一个包括多个单选button的ButtonGroup 对象加入到 JFrame 的Content Pane 中,以达到加入当中全部单选button的目的呢?不行!ButtonGroup 不是一个可显示的组件,它仅用于管理。所以,在往 JFrame 中加入一组 JRadioButton
的时候,须要一个一个的加入 JRadioButton,而不是笼统的加入一个 ButtonGroup。
上例中还用到了 JLabel,这不是button,而是一个静态文本组件,主要用于显示提示文本。要获得一个JLabel 对象当前显示的文本内容,能够使用它的 getText() 方法;反之,要改变一个 JLabel 对象显示的文本,要使用它的 setText(String text) 方法,如上例中的 label.setText("You selected
Toggle Button")。
事实上这两个方法相同能够用于 JButton等类。比方上例中我们使用 newJButton("JButton") 构造了一个button jButton,假设使用 jButton.getText() 就能够得到字符串"JButton"。而 jButton.setText("AButton"),则能够改变button上显示的文字为 "A Button"。这两句代码没有在演示样例中写出来,你能够自己试试。
上例中大量使用了动作监听器 (ActionListener)。ActionListener 仅仅监听一个事件,这个事件在其相关组件上产生了动作时被触发,因此叫作动作事件 (ActionEvent)。ActionListener 仅仅有一个方法须要实现,就是 actionPerformed(ActionEvent event)。button、切换button和单选button被单击时都会触发动作事件,引起动作监听器调用
actionPerformed 方法。因此,假设你想在单击button之后做什么事,当然应该重载 ActionListener 的 actionPerformed 方法了。各种button都提供了 addActionListener 方法以加入动作监听器。
复选框就要特殊一些。尽管它也有 addActionListener方法,意味着能够使用动作监听器,可是使用之后你会发现动作监听器并没有起到预想的作用。为什么?原来,单击一个复选button,触发的不是动作事件,而是条目事件 (ItemEvent) 中的状态变化 (itemStateChanged),由条目监听器 (ItemListener) 监听,对应须要重载的方法是
ItemListener 的 itemStateChanged 方法。
上例中我们将一个名为 al的 ActionListener 加入到了每个单选button中,怎样推断是哪个单选button触发了事件并被 al 监听到了呢?我们能够从 ActionEvent 的 getSource() 方法得到触发事件单选button。因为 getSource() 返回的是一个 Object 引用,尽管这个引用指向的是一个单选button的实例,但我们还是须要将这个引用的类型转换为
JRadioButton,如上例中的:JRadioButton radio =(JRadioButton) ae.getSource(),仅仅有这样我们才干调用 JRadioButton 有而 Object 没有的方法。
同一时候,还须要说明的一点是,每一个单选button都能够加入一个单独的 ActionListener实例,而不一定要加入同一个。相同的道理,若干毫不相干的、须要加入 ActionListener 的若干组件,也能够加入同一个ActionListener 实例。关键在于编程者对 actionPerformed 方法的重载。比方以下这段代码就为一个 JButton
对象和一个 JRadioButton 对象加入了同一个动作监听器实例:
<span style="font-size:18px;">import javax.swing.*;
import java.awt.event.*; public class Test { JButton b;
JRadioButton rb; public Test() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().setLayout(
new java.awt.FlowLayout());
b = new JButton("JButton");
rb = new JRadioButton("RadioButton");
ActionListener a = new ActionListener() {
public void actionPerformed(ActionEvent ae) {
if (ae.getSource() == b) {
System.out.println(
"You clicked the JButton");
} else {
System.out.println(
"You clicked the RadioButton");
}
}
};
b.addActionListener(a);
rb.addActionListener(a);
f.getContentPane().add(b);
f.getContentPane().add(rb);
f.pack();
f.show();
} public static void main(String[] args) {
new Test();
} }</span>
执行程序后,分别单击两个button,对应的,在控制台能分别得到例如以下输出:
You clicked the JButton
You clicked the RadioButton
这说明多个不用的组件加入同一个监听器是可行的——只是前提是这些组件都能加入这个监听器。
四.文本输入框、password输入框
文本输入框包含两种,单行文本输入框 (JTextField)和多行文本输入框 (JTextArea)。password输入框则仅仅有一种 (JPasswordField)。JPasswordField 是 JTextField 的子类,它们的主要差别是 JPasswordField 不会显示出用户输入的东西,而仅仅会显示出程序猿设定的一个固定字符,比方 '*' 或者
'#'。
以下的演示样例图和代码是 JTextField、JPasswordField 和 JTextArea 的演示样例:
<span style="font-size:18px;">import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPasswordField;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener; public final class TestTexts extends JFrame { public static void main(String[] args) {
TestTexts tt = new TestTexts();
tt.setVisible(true);
} private JLabel label = new JLabel("Status"); private JTextField textField; private JPasswordField pwdField; private JTextArea textArea; public TestTexts() {
super("Test Texts");
setDefaultCloseOperation(EXIT_ON_CLOSE);
getContentPane().setLayout(new java.awt.FlowLayout()); textField = new JTextField(15);
/* 监听文本光标移动事件 */
textField.addCaretListener(new CaretListener() {
public void caretUpdate(CaretEvent e) {
// 假设改变了内容,就能够即时更新 label 显示的内容
label.setText(textField.getText());
}
}); pwdField = new JPasswordField(15);
pwdField.setEchoChar('#'); textArea = new JTextArea(5, 15);
textArea.setLineWrap(true); getContentPane().add(textField);
getContentPane().add(pwdField);
getContentPane().add(textArea);
getContentPane().add(label); setSize(200, 200);
} }</span>
上例中,我们构造了一个宽度为 15个字符的单行文本框 (textField = newJTextField(15);),并使用 addCaretListener 方法加入了一个 CaretListener (textField.addCaretListener ...)。CaretListener 监听文本光标的移动事件。当用户使用键盘、鼠标等移动了文本光标在
JTextField 中的位置时触发这个事件。我们须要重载caretUpdate(CaretEvent e) 对事件进行处理 (public voidcaretUpdate(CaretEvent e) ...)。这样,我们能够在这里做类似 VB 中 TextBox 的 OnChange 事件中做的事情。
JTextField有 5 个构造方法,经常使用当中的四个:
JTextField()
JTextField(int columns),如上例 textField = newJTextField(15);
JTextField(String text)
JTextField(String text, int columns)
当中,參数 text是单行文本框的初始内容,而 columns 指定了单行文本框的宽度,以字符为单位。JTextField 中的文本内容能够用 getText() 方法获得。也能够用 setText 方法指定 JTextField 中的文本内容。
JPasswordField是 JTextField 的子类,其构造方法也是类似的。JPasswordField 提供了 setEchoChar(char ch) 方法设置为了隐藏password而显示的字符,默觉得 '*' 字符,上例中则设置为了 '#' 字符 (pwdField.setEchoChar('#');)。与 JTextField 一样,JPasswordField
也用 getText 方法和 setText 获得或者设置文本内容 (当然在用户界面上是隐藏的)。
JTextField是单行文本框,不能显示多行文本,假设想要显示多行文本,就仅仅好使用多行文本框 JTextArea 了。JTextArea 有六个构造方法,经常使用的也是四个:
JTextArea()
JTextArea(int rows, int columns)
JTextArea(String text)
JTextArea(String text, int rows, int columns)
text
为 JTextArea 的初始化文本内容;rows 为 JTextArea 的高度,以行为单位;columns 为 JTextArea 的宽度,以字符为单位。如上例中就构造了一个高 5 行,宽 15 个字符的多行文本框(textArea = new JTextArea(5, 15);)。
多行文本框默认是不会自己主动折行的 (只是能够输入回车符换行),我们能够使用 JTextArea 的 setLineWrap 方法设置是否同意自己主动折行。setLineWrap(true) 是同意自己主动折行,setLineWrap(false)则是不同意自己主动折行。多行文本框会依据用户输入的内容自己主动扩展大小,不信,自己做个实验——假设不自己主动折行,那么多行文本框的宽度由最长的一行文字确定的;假设行数据超过了预设的行数,则多行文本框会扩展自身的高度去适应。换句话说,多行文本框不会自己主动产生滚动栏。怎么办?后面讲到滚动窗格
(JScrollPane) 的时候,你就知道了。
多行文本框里文本内容的获得和设置,相同能够使用 getText和 setText 两个方法来完毕。
五.窗格、滚动窗格和布局管理
窗格 (JPanel)和滚动窗格 (JScrollPane) 在图形用户界面设计中大量用于各种组件在窗体上的布置和安排。这里所谓的布置和安排,就是布局 (Layout),因此不得不先说说布局。
将增加到容器(通常为窗体等) 的组件依照一定的顺序和规则放置,使之看起来更美观,这就是布局。布局由布局管理器 (Layout Manager) 来管理。那么,我们在什么时候应该使用布局管理器?应用选择哪种布局管理器?又该如何使用布局管理器呢?
往往,我们设计一个窗体,当中是要加入若干组件的。为了管理好这些管理的布局,我们就要使用布局管理器。比方说,设计一个简单的编辑器,这个编辑器中仅仅须要放置两个button和一个多行文本框。这些组件是让 Java自己随意安排呢?还是依照一定的位置关系较规范的安排呢?当然应该选择后者。那么,为了依照一定的位置关系安排这些组件,我们就须要用到布局管理器了。
然后我们遇到了一个选择题——使用哪种布局管理器。为此,我们首先要知道有些什么布局管理器,它们的布局特点是什么。经常使用的布局管理器有: FlowLayout、BorderLayout、GridLayout、BoxLayout 等,当中 FlowLayout 和 BorderLayout 最经常使用,本文主要也就仅仅谈谈这两种布局管理器。以下列表说明它们的布局特点:
布局管理器布局特点
FlowLayout |
将组件按从左到右从上到下的顺序依次排列,一行不能放完则折到下一行继续放置 |
BorderLayout |
将组件按东(右)、南(下)、西(左)、北(上)、中五个区域放置,每一个方向最多仅仅能放置一个组件(或容器)。 |
GridLayout |
形似一个无框线的表格,每一个单元格中放一个组件 |
BoxLayout |
就像整齐放置的一行或者一列盒子,每一个盒子中一个组件 |
就上述的编辑器为例,假设选用 FlowLayout,那么两个button和一个多行文本框就会排列在一行——当然这是窗体足够宽的情况;假设窗体稍窄一些,则可能分两行排列,第一行有两个button,而第二行是多行文本框——这是最理想的情况;假设窗体再窄一些,就可能分三行排列,第一行和第二行分别放置一个button,第三行放置多行文本框。因此,假设窗体大小能够改变,那么三个组件的位置关系也可能随着窗体大小的变化而变化。事实上上面所举的例程中,大部分都是用的
FlowLayout,那是由于我们没有要求组件的布局。
假设选用 BorderLayout的情况又怎样呢?我们能够试着增加一个窗格 (JPanel,稍后解说),并将两个button放置在当中,然后将这个窗格增加到 BorderLayout 的北部 (即上部);再将多行文本框增加到BorderLayout 中部。结果类似使用 FlowLayout 的另外一种可能,是最理想的情况。并且,假设改变窗体大小,它们的位置关系仍然是北-中的关系,不会随之改变。
剩下的两种布局管理器,加以窗格 (JPanel)的配合,也可以非常好的安排上述编辑器所需的三个组件。可是因为它们的使用稍为复杂一些,所以就不讲了。以下就讲讲怎样使用 FlowLayout 和 BorderLayout。
不论什么布局管理器,都须要用在容器上,比方 JFrame的 Content Pane 和以下要说的 JPanel 都是容器(JFrame 默认的 Content Pane 实际就是一个 JPanel)。容器组件提供了一个 setLayout 方法,就是用来改变其布局管理器的。默认情况下,JFrame 的 Content Pane 使用的是 BorderLayout,而一个新产生的
JPanel 对象使用的是 FlowLayout。但无论如何,我们都能够调用它们的 setLayout 方法来改变其布局管理器。比方上述的编辑器中,我们要让窗体(JFrame 对象,如果为 frame) 使用BorderLayout,就能够使用 frame.getContentPane().setLayout(newBorderLayout()); 来改变其布局管理器为一个新的 BorderLayout 对象。
然后,我们对布局管理器的直接操作就结束了,剩下的仅仅须要往容器里加入组件。假设使用 FlowLayout,我们仅仅须要使用容器的 add(Component c) 方法加入组件即可了。可是,假设使用 BorderLayout 就不一样了,由于要指定是把组件加入到哪个区域啊。那我们就使用容器的 add(Component c, Object o) 方法加入组件,该方法的第二个參数就是指明加入到的区域用的。比如,上述编辑器中要加入一个多行文本框到
BorderLayout 的中部,就能够用 frame.getContentPane().add(newJTextArea(5, 15), BorderLayout.CENTER) 来实现。
BorderLayout的五个区域各自是用下列五个常量来描写叙述的:
BorderLayout.EAST |
东(右) |
BorderLayout.SOUTH |
南(下) |
BorderLayout.WEST |
西(左) |
BorderLayout.NORTH |
北(上) |
BorderLayout.CENTER |
中 |
刚才已经提到了使用 JPanel。JPanel 作为一个容器,能够包容一些组件,然后将这个 JPanel 对象作为一个组件加入到还有一个容器 (称作父容器) 中。这个功能有什么优点呢?
上面不是提到 BorderLayout的一个区域中仅仅能加入一个组件吗?可是我们的编辑器须要加入两个button到它的北部,怎么办?以下的样例中,我们就会用的一个 JPanel 包容了这两个button,然后再将这个 JPanel 对象作为一个组件加入到设置布局管理器为 BorderLayout 的 Content Pane 中。
上面说到各布局管理器的布局特点的时候,差点儿每一种都是一个区域仅仅能加入一个组件,那我们想加入多个组件到一个区域的时候,就要用到 JPanel了。假设还没有明确,稍后看一段程序可能更易于理解。
而滚动窗格 (JScrollPane)呢?它是一个可以自己产生滚动栏的容器,通常仅仅包容一个组件,而且依据这个组件的大小自己主动产生滚动栏。比方上面讲 JTextArea 的时候提到:JTextAera 会随用户输入的内容自己主动扩展大小,非常easy打破各组件的布局。可是,假设我们将它包容在一个滚动窗格中,它的扩展就不会直接反映在大小的变化上,而会反映在滚动窗格的滚动栏上,也就不会打破各组件的布局了。稍后的样例会让你清清楚楚。
是不是等着看样例了?好,样例来了:
<span style="font-size:18px;">import java.awt.BorderLayout; import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea; public final class TestPanels extends JFrame { public static void main(String[] args) {
TestPanels tp = new TestPanels();
tp.setVisible(true);
} public TestPanels() {
setDefaultCloseOperation(EXIT_ON_CLOSE); JPanel panel = new JPanel();
for (int i = 0; i < 2; i++) {
panel.add(new JButton("Button 00" + i));
} JTextArea textArea = new JTextArea(5, 15);
textArea.setLineWrap(true);
JScrollPane scrollPane = new JScrollPane(textArea);
getContentPane().add(panel, BorderLayout.NORTH);
getContentPane().add(scrollPane, BorderLayout.CENTER); pack();
} }</span>
这个样例的执行结果例如以下图,正是我们想要的结果——上面两个button,以下是一个能够滚动的多行文本框:
上例中首先产生了一个 JPanel对象 (JPanel panel = new JPanel();),然后将两个button置于当中 (panel.add ...);然后产生了一个多行文本框 (JTextAreatextArea = new JTextArea(5, 15);),并使用一个滚动窗格将它包裹起来(JScrollPane scrollPane
= new JScrollPane(textArea);),使之成为能够滚动的多行文本框。最后将两个容器 (JPanel 对象和 JScrollPane 对象) 分别加入到了窗体的北部 (getContentPane().add(panel,BorderLayout.NORTH);) 和中部 (也就是剩余部分,getContentPane().add(scrollPane, BorderLayout.CENTER);)。
好像有点不正确劲,是什么呢?对了,我们没有设置 Content Pane的布局管理器为 BorderLayout 啊,为什么……刚才不是说了吗,JFrame 的Content Pane 的默认布局管理器就是 BorderLayout,所以不用再设置了。
十一:Java之GUI图形Awt和Swing的更多相关文章
- java中GUI的awt和Swing的知识点
刚刚学习了java的GUI,写了几个程序,基本熟悉了awt和Swing,下面和大家分享一下知识点 1.JFrame的层次结构 参考:http://tieba.baidu.com/p/200421612 ...
- 浅谈JAVA GUI中,AWT与Swing的区别、联系及优缺点
浅谈JAVA GUI中,AWT与Swing的区别.联系及优缺点 A.区别 1.发布的时间 AWT是在JDK 1.0版本时提出的 Swing是在AWT之后提出的(JAVA 2) 2. ”重量” AWT是 ...
- Java的GUI框架如何选择? Swing、SWT、AWT、SwingX、JGoodies、JavaFX、Apache Pivot、BeautyEye框架(美观)?
AWT 是swing的基础,运行良好,但缺少高级组件.如果您打算创建丰富的应用程序,那么AWT可能不是最好的方法.但是对于不需要丰富用户界面的较小gui应用程序来说.这可能非常适合,因为它是一个久经考 ...
- Java中AWT、Swing与SWT三大GUI技术的原理与效率差异
Java中AWT.Swing与SWT三大GUI技术的原理与效率差异 转 https://blog.csdn.net/weixin_37703598/article/details/81843810 ...
- AWT是Java基础类 (JFC)的一部分,为Java程序提供图形用户界面(GUI)的标准API
抽象窗口工具包 (Abstract Windowing Toolkit) (AWT)是Java的平台独立的窗口系统,图形和用户界面器件工具包. AWT是Java基础类 (JFC)的一部分,为Java程 ...
- 第58节:Java中的图形界面编程-GUI
欢迎到我的简书查看我的文集 前言: GUI是图形用户界面,在Java中,图形用户界面我们用GUI表示,而GUI的完整英文为: Graphical User Interface(图形用户接口), 所谓图 ...
- java第八节 GUI/图形用户界面
/* *第8讲 GUI/图形用户界面 * AWT的基础知识 * GUI全称是Graphical User Interface,即图形用户界面 * JDK中提供了AWT和Swing两个包,用于GUI程序 ...
- java之 22天 GUI 图形界面编程(一)
转自:http://takeme.iteye.com/blog/1876850 GUI(图形用户界面) import java.awt.Button; import java.awt.FlowLayo ...
- java GUI(图形用户界面)
GUI Graphical User Interface(图形用户接口). 用图形的方式,来显示计算机操作的界面,这样更方便更直观. CLI Command line User Interface ( ...
随机推荐
- 应用层open(read、write、close)怎样调用驱动open(read、write、close)函数的?
应用层open(read.write.close)怎样调用驱动open(read.write.close)函数的? 华清远见2014-09-29 北京海淀区 张俊浩 三大数据结构关系图
- Android 调用谷歌语音识别
調用谷歌语音识别其实很简单,直接利用 intent 跳转到手机里面的谷歌搜索 代码也很简单,直接调用方法 startVoiceRecognitionActivity() 如果大家手机里面没有谷歌搜索, ...
- WPF案例 (六) 动态切换UI布局
原文:WPF案例 (六) 动态切换UI布局 这个Wpf示例对同一个界面支持以ListView或者CardView的布局方式呈现界面,使用控件ItemsControl绑定数据源,使用DataTempla ...
- poj 1659 Frogs' Neighborhood (度序列)
Frogs' Neighborhood Time Limit: 5000MS Memory Limit: 10000K Total Submissions: 7295 Accepted: 31 ...
- DIV+CSS 入门
玩一小会儿前csdn什么时候,页面上的加qq而微博,我认为这是美好的.牛腩完成.运营商也开始了他真正的学习B/S之旅. 刚開始的时候,我不知道<div>是什么 也不清楚CSS用来干什么的, ...
- H3C SecPath F100-C 防火墙配置说明
最近的工作需要,将H3C SecPath F100-C天津联通的房间防火墙配置: 网络拓扑例如,下面的: 进入系统管理界面: 默认登陆地址:192.168.0.1 截图由于涉及公司信息就没有上传.大家 ...
- LeetCode——Rotate List
Given a list, rotate the list to the right by k places, where k is non-negative. For example: Given ...
- xcode target
A target specifies a product to build and contains the instructions for building the product from a ...
- SE 2014年5月6日
如图配置: 三台交换机两两相连接,构成一二层环路,同时为了保证链路的较为可靠,使用双线链接 请用自己的语言描述以上拓扑搭建的优劣势:并使用哪些技术较为合理,请描述并实施 SW3为接入层交换机,下链接三 ...
- [置顶] JQuery实战总结三 标签页效果图实现
在浏览网站时我们会看到当我们鼠标移到多个选项卡上时,不同的选项卡会出现自己对应的界面的要求,在同一个界面上表达了尽量多的信息.大大额提高了空间的利用率.界面的切换效果也是不错的哦,这次自己可以实现啦. ...