因为要给前面制作的游戏制作一个简单的游戏界面:类似开始游戏,关闭游戏,设置之类,所以学习GUI,并做了一些笔记,这次内容有关如何创建一个窗口,如何建立按钮,如何捕获事件,还有如何创建文本区域的:
在这里,我们先建立一个简单的窗口:
import javax.swing.*;
public class JFRAME {
public static void main(String[] args) {
//建立一个窗口,标题名字叫Hello Swing
JFrame frame = new JFrame("Hello Swing");
//设置默认的关闭动作
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//定义这个窗口的大小
frame.setSize(300,100);
//设置窗口为可视
frame.setVisible(true);
}
}
setDefaultCloseOperation()告诉JFrame当前的用户执行关闭操作时应该做些什么,而EXIT_ON_CLOSE是个常量,这个常量是用来告诉它要怎么退出这个程序。
再在这个内容里添加一个JLabel
import javax.swing.*;
import java.util.concurrent.TimeUnit;
public class JFRAME {
public static void main(String[] args) throws InterruptedException {
//建立一个窗口,标题名字叫Hello Swing
JFrame frame = new JFrame("Hello Swing");
//建立一个标签
JLabel lable = new JLabel("A Label");
//在这个窗口里增加这个标签
frame.add(lable);
//设置窗口默认的关闭动作
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//定义这个窗口的大小
frame.setSize(300,100);
//设置窗口为可视
frame.setVisible(true);
//一秒钟之后会产生变化
TimeUnit.SECONDS.sleep(1);
lable.setText("HEY!This is different!");
}
}
但是上述方法可能产生冲突和死锁(对于主线程来讲直接对GUI组件编写代码并非是一种很好的想法)
所以我们需要其他线程。
在这里我们不用直接操作JLabel,而是提交一个Runnable,当事件分发线程在事件队列中获取这项任务时,它将执行实际的操作,并且执行这个Runnable时,不会做其他任何事情。
import javax.swing.*;
import java.util.concurrent.TimeUnit;
public class JFRAME {
public static void main(String[] args) throws InterruptedException {
//建立一个窗口,标题名字叫Hello Swing
JFrame frame = new JFrame("Hello Swing");
//建立一个标签
JLabel lable = new JLabel("A Label");
//在这个窗口里增加这个标签
frame.add(lable);
//设置默认的关闭动作
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//定义这个窗口的大小
frame.setSize(300,100);
//设置窗口为可视
frame.setVisible(true);
//一秒钟之后会产生变化
TimeUnit.SECONDS.sleep(1);
//通过事件分发线程将任务放置到(最终将执行得到的)待执行的事件队列中
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
lable.setText("HEY!This is different!");
}
});
}
}
将这个代码重新整理之后:
import javax.swing.*;
import java.util.concurrent.TimeUnit;
//将刚才那些主类里定义的元素,定义为构造函数内容
public class JFRAME extends JFrame {
JLabel label;
public JFRAME(){
super("Hello Swing");
label = new JLabel("A label");
add(label);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300,100);
setVisible(true);
}
static JFRAME jframe;
public static void main(String[] args) throws InterruptedException {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
jframe = new JFRAME();
}
});
TimeUnit.SECONDS.sleep(1);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
jframe.label.setText("HEY!This is different!");
}
});
}
}
注意!对sleep()的调用不能再构造器的内部,不然初始文本就永远都不会出现。
因为,构造器在sleep()调用完毕和新的标签插入之前不会结束,如果sleep()在内部,那么在sleep()期间将会中止其他进程。
而且可以一直增加标签(因为是添加是动态的)
import javax.swing.*;
import java.util.concurrent.TimeUnit;
//将刚才那些主类里定义的元素,定义为构造函数内容
public class JFRAME extends JFrame {
JLabel label;
public JFRAME(){
super("Hello Swing");
label = new JLabel("A label");
add(label);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(300,100);
setVisible(true);
}
static JFRAME jframe;
public static void main(String[] args) throws InterruptedException {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
jframe = new JFRAME();
}
});
TimeUnit.SECONDS.sleep(1);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
jframe.label.setText("HEY!This is different!");
}
});
TimeUnit.SECONDS.sleep(1);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
jframe.label.setText("HAHA");
}
});
}
}
1.1 创建显示框架
创建一个显示框架,结合上面代码,减少冗余代码:
import javax.swing.*;
public class JFRAME extends JFrame {
public static void run(final JFrame f,final int width,final int height){
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
f.setTitle(f.getClass().getSimpleName());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(width,height);
f.setVisible(true);
}
});
}
}
只要调用JButton的构造器即可
import javax.swing.*;
import java.awt.*;
public class BUTTON extends JFrame {
//建立两个按钮
private JButton
b1 = new JButton("Button 1"),
b2 = new JButton("Button 2");
//将按钮加入布局中
public BUTTON(){
setLayout(new FlowLayout());
add(b1);
add(b2);
}
public static void main(String[] args) {
JFRAME.run(new BUTTON(),200,100);
}
}
创建的按钮图片如下:
在添加新的组件之前,我们要给出一个新的FlowLayout类型的布局管理器
它是面板用来隐式地决定控件在窗体上的位置的工具。
JFrame通常使用的的BorderLayout管理布局,但这里不能使用,因为它的默认行为是每加入一个控件,将完全覆盖其他附件。
FlowLayout使得控件可以在窗体上从左到右,从上到下连续均匀分布。
我们在这里要使用到JTextField。这个组件支持用户输入文本。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class BUTTON extends JFrame {
//建立两个按钮
private JButton
b1 = new JButton("Button 1"),
b2 = new JButton("Button 2");
private JTextField txt = new JTextField(10);
//getSource()方法产生的对象表明了事件的来源
//getText()方法返回的是按钮上的文本
class ButtonListener implements ActionListener{
public void actionPerformed(ActionEvent e){
String name = ((JButton)e.getSource()).getText();
txt.setText(name);
}
}
private ButtonListener bl = new ButtonListener();
public BUTTON(){
b1.addActionListener(bl);
b2.addActionListener(bl);
setLayout(new FlowLayout());
add(b1);
add(b2);
add(txt);
}
public static void main(String[] args) {
JFRAME.run(new BUTTON(),200,150);
}
}
我在这里创建了一个ButtonListener对象,实现了ActionListener的接口。
actionPerformed()的方法的参数是ActionEvent类型,它包含事件和事件源的所有信息。
通常,把ActionListener实现成匿名内部类会更方便。尤其是对每个监听器类只使用一个实例的时候更是如此。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class BUTTON extends JFrame {
//建立两个按钮
private JButton
b1 = new JButton("Button 1"),
b2 = new JButton("Button 2");
private JTextField txt = new JTextField(10);
//定义一个匿名内部类
private ActionListener bl = new ActionListener() {
@Override
//getSource()方法产生的对象表明了事件的来源
//getText()方法返回的是按钮上的文本
public void actionPerformed(ActionEvent e) {
String name = ((JButton)e.getSource()).getText();
txt.setText(name);
}
};
public BUTTON(){
b1.addActionListener(bl);
b2.addActionListener(bl);
setLayout(new FlowLayout());
add(b1);
add(b2);
add(txt);
}
public static void main(String[] args) {
JFRAME.run(new BUTTON(),200,150);
}
}
除了可以有多行文本以及更多的功能不同之外,JTextArea与JTextField在其他方面都很相似。
append()作为JTextArea的其中之一的常用方法,可以实现往回滚动。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;
public class TEXTAREA extends JFrame {
private JButton
b = new JButton("Add Data"),
c = new JButton("Clear Data");
private JTextArea t = new JTextArea(20,40);
public TEXTAREA(){
b.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
t.setText("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
}
});
c.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
t.setText("");
}
});
setLayout(new FlowLayout());
add(new JScrollPane(t));
add(b);
add(c);
}
public static void main(String[] args) {
JFRAME.run(new TEXTAREA(),475,425);
}
}
在JTextArea被添加到JFrame之前,先被包装进了JScrollPane(当屏幕上文字过多,使用它就可以滚动了)
点击Add Data之后的变化 :
点击Clear Data之后的变化:
以上是今天学习的内容。
学习的书籍是 Java编程思想。
使用的笔记软件是印象笔记(非常好用!)。