一切都从window开始:
JFrame是一个代表屏幕上window的对象。你可以把button、checkbox、text字段等接口放在window上面。标准的menu也可以放在上面,并且能够带最小化、最大化、关闭等图标。JFrame的长相会根据所处的平台不同而有所区别。
将组建加到window上:
一旦创建出JFrame后,你就可以把组件(widget)加到上面。有很多的swing可以使用,它们在javax.swing这个包之中。最常用的组件包括:JButton、JRadioButton、JCheckBox、JLabel、JList、JScrollPane、JSlider、JTextArea、JTextField和JTable等。大部分都是很容易使用的,但是像JTable就有一点小复杂了。
创建一个GUI的app需要4个步骤:
1.创建frame;
2.创建widget;
3.将widget加入到frame;
4.显示出来。
见以下的demo:
import javax.swing.JButton;
import javax.swing.JFrame;
public class GUIDemo01 {
public static void main(String[] args) {
// 1.创建Frame
JFrame frame = new JFrame();
// 2.创建widget
JButton button = new JButton("有种就点击我!");
// 3.把widget添加到frame上
/*组件不会直接加到frame上,你可以把frame想象成window的框,
* 组件是加到window的pane上面
*/
frame.getContentPane().add(button);
// 4.显示出来
frame.setSize(300, 300);
frame.setVisible(true);
}
}
以上程序的效果:
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
则无论用户怎么点击(除非用taskmgr强制关闭,否则怎么关闭都关不掉,我想有些流氓软件大致就是采用的这种思路吧)。
如果你想要实现用户点击按钮的时候,按钮中的文字改变 ,就需要实现一个监听器:
如果想要知道按钮的事件,就会监听事件的接口
监听接口是介于监听(你)与事件源(按钮)之间的桥梁。swing的GUI组件是事件源。以java术语来说:事件源是可以将用户的操作装换成事件的对象。对java而言,事件几乎都是以对象类表示。它会是某种事件类的对象。如果你查询API中的java.awt.evet这个包,你就会看到一组事件的类(名称中有Event)。你会看到MouseEvent、KeyEvent、WindowEvent、ActionEvent等等。
事件源(例如:按钮)会在用户做出相关动作的时候(按下按钮)产生事件对象。你的程序在大多数情况下是事件的接收方而不是创建方。也就是说:你会花较多的时间当监听者而不是时间的来源。
每个事件类型都有相应的监听者接口。要想接收MouseEvent的话就要实现MouseListener接口。想要WindowEvent么?实现WindowListener。
监听:
如果类想要知道按钮的ActionEvent,就得实现ActionListener这个接口。按钮需要知道你关注的部分,因此要通过调用addActionListener(this)并传入ActionListener的引用来向按钮注册。按钮会在该事件发生的时候调用该接口上的方法。而作为一个ActionListener,编译器会确保你实现此接口的actionPerformed()。
事件源:
按钮时ActionEvent的来源,因此它必须要知道有哪些对象是需要事件通知的。此按钮有个addActionListener()方法可以提供对事件有兴趣的对象(listener)一种表达此兴趣的方法。当按钮的addActionListener()方法被调用时(因为某个listener的调用),它的参数会被按钮存到清单中。当用户按下按钮时,按钮会通过调用清单上每个监听的actionPerformed()来启动事件。
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class GUIDemo implements ActionListener { //实现ActionListener接口
JButton button;
public static void main(String[] args) {
GUIDemo gui = new GUIDemo();
gui.go();
}
public void go() {
JFrame frame = new JFrame();
button = new JButton("你有种你就点击我!");
button.addActionListener(this); // 向按钮注册
frame.getContentPane().add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(640, 320);
frame.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
button.setText("我被点击了!");
}
}
效果图:
如果窗体中有两个按钮,怎么为它们分别添加点击事件?你可以采用以下的方法:
import java.awt.BorderLayout;
import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class SimpleGUI implements ActionListener {
JFrame frame;
JButton button,button2;
Label label;
public static void main(String[] args) {
SimpleGUI gui = new SimpleGUI();
gui.go();
}
private void go() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
button = new JButton("按钮一");
button2 = new JButton("按钮二");
label = new Label("显示相关信息");
button.addActionListener(this);//给按钮添加监听器,该类要实现ActionListener接口
button2.addActionListener(this);
frame.getContentPane().add(BorderLayout.NORTH,button);
frame.getContentPane().add(BorderLayout.SOUTH,button2);
frame.getContentPane().add(BorderLayout.CENTER,label);
frame.setSize(300, 300);
frame.setVisible(true);
}
Override
public void actionPerformed(ActionEvent arg0) {
if (arg0.getSource()==button) {
label.setText("按钮一被点击了!");
else {
label.setText("按钮二被点击了!");
}
}
}
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);"> </span><span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">用单一的事件处理程序来对付不同的东西就意味着要执行太多种不同工作的方法。如果想要改变某个工作,很可能会把全部工作都弄乱,这样的解决会对程序的可读性和维护性产生危害。有一点偏离了面向对象。</span>
方式二:使用匿名内部类:
import java.awt.BorderLayout;
import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class SimpleGUI {
JFrame frame;
Label label;
public static void main(String[] args) {
SimpleGUI gui = new SimpleGUI();
gui.go();
}
private void go() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton button = new JButton("按钮一");
JButton button2 = new JButton("按钮二");
label = new Label("显示相关信息");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
label.setText("按钮一被点击了!");
}
});
button2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
label.setText("按钮二被点击了!");
}
});
frame.getContentPane().add(BorderLayout.NORTH, button);
frame.getContentPane().add(BorderLayout.SOUTH, button2);
frame.getContentPane().add(BorderLayout.CENTER, label);
frame.setSize(300, 300);
frame.setVisible(true);
}
}
布局管理器(LayoutManager)
布局管理器是个与特定组件相关联的java对象,它大多数是背景组件。布局管理器用来控制所关联组件上携带的其他组件。也就是说:如果某个框架带有面板,而面板带有按钮,则面板的布局管理器控制着按钮的大小和位置,而框架的布局管理器则控制着面板的大下和位置。按钮因为没有携带其他组件,所以不需要布局管理器。
布局管理器主要有3种:BorderLayout、flowLayout、BoxLayout
BorderLayout:
这个布局管理器会将背景组件分割成5个区域。每个被管理对象的区域只能放上一个组件。因此管理员安排的组件通常不会取得默认的大小。这是JFrame默认的布局管理器。
顺序——南北区--->东西区---->中间区
FlowLayout:
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
public class SimpleGUI {
JFrame frame;
public static void main(String[] args) {
SimpleGUI gui = new SimpleGUI();
gui.go();
}
private void go() {
frame = new JFrame("FlowLayout布局");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout(FlowLayout.LEFT)); //流式布局并左对齐
JButton []b = new JButton[10];
for (int i = 0; i < b.length; i++) {
b[i] = new JButton(i+"");
frame.getContentPane().add(b[i]);
}
frame.setVisible(true);
}
}
运行结果:
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
public class SimpleGUI {
JFrame frame;
public static void main(String[] args) {
SimpleGUI gui = new SimpleGUI();
gui.go();
}
private void go() {
frame = new JFrame("FlowLayout布局");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout(FlowLayout.LEFT)); //流式布局并左对齐
JButton []b = new JButton[10];
for (int i = 0; i < b.length; i++) {
b[i] = new JButton(i+"");
frame.getContentPane().add(b[i]);
}
frame.setVisible(true);
}
}
这个布局管理器的行为和文字处理程序的版面配置方式差不多。每个组件会依照理想的大小呈现,并且会按照从左到右的顺序加入元素(当一行放不下的时候会被放到下一行),这是Pannel默认的布局管理器。调整窗口的大小,组件的位置会变化。
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class SimpleGUI {
JFrame frame;
public static void main(String[] args) {
SimpleGUI gui = new SimpleGUI();
gui.go();
}
private void go() {
frame = new JFrame("BorderLayout布局");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setBackground(Color.BLUE);
JButton button1 = new JButton("第一个按钮");
JButton button2 = new JButton("第二个按钮");
panel.add(button1); //将按钮加入面板
panel.add(button2);
frame.getContentPane().add(BorderLayout.EAST, panel); //将面板加入到窗体上
frame.setSize(300, 300);
frame.setVisible(true);
}
}
运行结果:
frame的默认布局是BorderLayout,pannel的默认布局是FlowLayout,所以想pannel中加入组件的时候Pannel会自动变宽。
BoxLayout:
它就像FlowLayout一样让每个组件使用默认的大小,并且按照加入的顺序以垂直的方式来排列(也可以水平,但是通常我们只在乎垂直的方式)。不像FlowLayout会自动换行,它让你插入某种类似换行的机制来强制组件从新的一行开始排列。
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;
public class SimpleGUI {
JFrame frame;
public static void main(String[] args) {
SimpleGUI gui = new SimpleGUI();
gui.go();
}
private void go() {
frame = new JFrame("BoxLayout布局");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Box box = Box.createVerticalBox();
JButton []b = new JButton[10];
for (int i = 0; i < b.length; i++) {
b[i] = new JButton(i+"");
box.add(b[i]);
}
frame.getContentPane().add(box);
frame.setVisible(true);
}
}
运行结果:
为按钮上的文字设置样式(字体、风格、大小)
import javax.swing.JButton;
import javax.swing.JFrame;
public class SimpleGUI {
JFrame frame;
public static void main(String[] args) {
SimpleGUI gui = new SimpleGUI();
gui.go();
}
private void go() {
frame = new JFrame("BorderLayout布局");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton button = new JButton("不悔梦归处,只恨太匆匆");
button.setFont(new Font("楷体", Font.BOLD, 20));
frame.getContentPane().add(BorderLayout.NORTH, button);
frame.setSize(300, 300);
frame.setVisible(true);
}
}
运行结果:
强制使面板使用BoxLayout(默认的面板使用FlowLayout).
import java.awt.BorderLayout;
import java.awt.Color;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class SimpleGUI {
JFrame frame;
public static void main(String[] args) {
SimpleGUI gui = new SimpleGUI();
gui.go();
}
private void go() {
frame = new JFrame("BorderLayout布局");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setBackground(Color.BLUE);
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));//将Panel的布局改为垂直的
JButton button1 = new JButton("第一个按钮");
JButton button2 = new JButton("第二个按钮");
JButton button3 = new JButton("第三个按钮");
JButton button4 = new JButton("第四个按钮");
panel.add(button1); //将按钮加入面板
panel.add(button2);
panel.add(button3);
panel.add(button4);
frame.getContentPane().add(BorderLayout.EAST, panel); //将面板加入到窗体上
frame.setSize(300, 300);
frame.setVisible(true);
}
}
运行结果:
Q1:框架为什么不能像面板那样直接加上组件?
A1:JFrame会这么特殊是因为它是让事物显示在画面上的接点。因为Swing的组件纯粹是由java构成的,JFrame必须要连接到底层的操作系统以便来存取显示装置。我们可以将面板想象成事先安置在JFrame上的100%纯java层。或者把JFrame想作是支撑面板的框架。你甚至可以用自定义的JPannel来换掉框架的面板。
当某个组件加入到背景组件的上面的时候,被加入的组件是由背景组件的布局管理器所管理的。