java GUI学习笔记(一)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/ECHONnn/article/details/102761477

因为要给前面制作的游戏制作一个简单的游戏界面:类似开始游戏,关闭游戏,设置之类,所以学习GUI,并做了一些笔记,这次内容有关如何创建一个窗口,如何建立按钮,如何捕获事件,还有如何创建文本区域的:

一 、Swing基础

在这里,我们先建立一个简单的窗口:

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);
    }


}

点击 Button1后文本框里出现相应的文字:
按Button1之后文本框里出现文字

四、文本区域

除了可以有多行文本以及更多的功能不同之外,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之后的变化 :
点击Add Data之后
点击Clear Data之后的变化:
点击Clear Data之后

以上是今天学习的内容。
学习的书籍是 Java编程思想。
使用的笔记软件是印象笔记(非常好用!)。

猜你喜欢

转载自blog.csdn.net/ECHONnn/article/details/102761477