GUI学习日记

GUI编程

什么是GUI?

图形用户界面编程,GUI的核心开发技术是Swing和AWT,但是快被淘汰了,因为界面不美观,需要JRE环境(200+M),用处是可以写出自己自己想要的小玩意,工作的时候可能会维护到swing界面(概率很小),了解MVC架构,了解监听!

AWT

AWT介绍

  1. 包含了很多类和接口
  2. 元素:窗口,按钮,文本框
  3. java.awt

在这里插入图片描述

窗口(Frame)

窗口的创建过程如下:

在这里插入图片描述

如果有哪里不清楚,我们可以通过new Frame(),查看Frame类的源码来解决,大部分方法还是比较好理解的

面板(Panel)

面板的位置是相对于窗口的

实验的时候发现了问题

在这里插入图片描述

这是添加了setLayout的结果
在这里插入图片描述

这是没有setLayout的结果

等学到布局再详细探究这个问题吧

布局(Layout)

Frame通过setLayout()来设置布局

布局类型有绝对布局(null),流式布局(FlowLayout),东西南北中布局(BorderLayout),表格布局(GridLayout)(…)

布局可以嵌套举例:

在这里插入图片描述

public class Myframe extends Frame{
    static int id=0; //用于标记窗口和统计窗口数量
    public Myframe(int x, int y, int h, int w, Color color) {
        super("Myframe" + (++id));
        setLayout(new GridLayout(2, 1));
        setBounds(y, x, w, h);//设置窗口位置和宽高
        setBackground(color);//设置窗口背景颜色
        setResizable(true);//设置窗口能否重新调整大小
        Panel panel1 = new Panel(new BorderLayout());//上面
        Panel panel2 = new Panel(new GridLayout(2, 1));//上面中间
        Panel panel3 = new Panel(new BorderLayout());//下面
        Panel panel4 = new Panel(new GridLayout(2, 2));//下面中间

        panel1.add(new Button("1"), BorderLayout.WEST);
        panel2.add(new Button("2"));
        panel2.add(new Button("3"));
        panel1.add(panel2, BorderLayout.CENTER);
        panel1.add(new Button("4"), BorderLayout.EAST);
        add(panel1);
        panel3.add(new Button("5"), BorderLayout.WEST);
        for(int i=6;i<=9;i++)
            panel4.add(new Button(Integer.toString(i)));
        panel3.add(panel4, BorderLayout.CENTER);
        panel3.add(new Button("10"), BorderLayout.EAST);
        add(panel3);
        panel1.setBackground(Color.red);
        panel3.setBackground(Color.blue);
        panel2.setBackground(Color.yellow);
        panel4.setBackground(Color.green);
        setVisible(true);//设置窗口能否被用户看到
        pack();
        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                super.windowClosing(e);
                System.exit(0);
            }
        });
    }

}

一定要给每个panel设置布局…不然会出问题的…

监听事件(Listener)

某个事件发生时,程序干什么的问题

frame.addWindowListener(WindowListener name);

frame.addMouseListener(MouseListener name);

但是如图所见
在这里插入图片描述

WindowListener是个接口,要实现的话要把所有的方法都实现了…

所以我们可以采用JAVA自带的适配器模式 例如

addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                super.windowClosing(e);
                System.exit(0);
            }
});

其中

在这里插入图片描述

类的妙用!

我们只需要重写我们想要的方法就好了.

然后我们就可以关掉窗口啦!

按钮(Button)事件:addActionLinstener()点击触发ActionLinstener

文本框(Textfield)常用方法: addActionLinstener()回车触发ActionLinstener, setEchoChar()将字符改为想要的样子

ActionEvent.getSource()可以获得触发监听事件的组件,不过它的返回类型为Object,所以我们要强制类型转换(向下转型)才能更好地使用它

应用:

在这里插入图片描述
在这里插入图片描述

public class Myframe extends Frame {
    public Myframe(){
        setLayout(new FlowLayout());
        //三个文本框
        TextField textField1 = new TextField(10);
        TextField textField2 = new TextField(10);
        TextField textField3 = new TextField(15);
        //一个按钮
        Button button=new Button("=");
        //一个lable
        Label label1 = new Label("+");
        //构建页面
        add(textField1);
        add(label1);
        add(textField2);
        add(button);
        add(textField3);
        pack();//自适应化
        setVisible(true);//显示页面
        frameClose(this);//添加关闭事件

        button.addActionListener(new MyActionListener(textField1,textField2,textField3));


    }

    private void frameClose(Frame frame){
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                super.windowClosing(e);
                System.exit(0);
            }
        });
    }
    private class MyActionListener implements ActionListener{
        TextField textField1;
        TextField textField2;
        TextField textField3;
        public MyActionListener(TextField t1,TextField t2,TextField t3)
        {
            textField1=t1;
            textField2=t2;
            textField3=t3;
        }
        @Override
        public void actionPerformed(ActionEvent e) {
            int num1;
            int num2;
            try {
                num1=Integer.parseInt(textField1.getText());
                num2=Integer.parseInt(textField2.getText());
                textField3.setText(Integer.toString(num1+num2));
            }catch (Exception error){
                System.out.println("something wrong!!!!");
                return ;
            }finally {
                textField1.setText("");
                textField2.setText("");
            }
        }
    }

}

但是这么做不是oop的做法(不够抽象,方法的针对性太强)

于是我们可以对它做一下调整:

public class Myframe extends Frame {
    TextField textField1;
    TextField textField2;
    TextField textField3;
    public void loadMyframe(){
        setLayout(new FlowLayout());
        //三个文本框
        textField1 = new TextField(10);
        textField2 = new TextField(10);
        textField3 = new TextField(15);
        //一个按钮
        Button button=new Button("=");
        //一个lable
        Label label1 = new Label("+");
        button.addActionListener(new MyActionListener(this));
        //构建页面
        add(textField1);
        add(label1);
        add(textField2);
        add(button);
        add(textField3);
        pack();//自适应化
        setVisible(true);//显示页面
        frameClose(this);//添加关闭事件
    }

    private void frameClose(Frame frame){
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                super.windowClosing(e);
                System.exit(0);
            }
        });
    }
    private class MyActionListener implements ActionListener{
        Myframe myframe=null;
        public MyActionListener(Myframe myframe)
        {
            this.myframe=myframe;
        }
        @Override
        public void actionPerformed(ActionEvent e) {
            int num1;
            int num2;
            try {
                num1=Integer.parseInt(myframe.textField1.getText());
                num2=Integer.parseInt(myframe.textField2.getText());
                myframe.textField3.setText(Integer.toString(num1+num2));
            }catch (Exception error){
                System.out.println("something wrong!!!!");
                return ;
            }finally {
                myframe.textField1.setText("");
                myframe.textField2.setText("");
            }
        }
    }
}

但是这依然不是最优解,最优解是内部类–>因为内部类最大的好处就是可以使用外部类定义的变量

public class Myframe extends Frame {
    TextField textField1;
    TextField textField2;
    TextField textField3;
    public void loadMyframe() {
        //内部监听类
        class MyActionListener implements ActionListener {
            @Override
            public void actionPerformed(ActionEvent e) {
                int num1;
                int num2;
                try {
                    num1 = Integer.parseInt(textField1.getText());
                    num2 = Integer.parseInt(textField2.getText());
                    textField3.setText(Integer.toString(num1 + num2));
                } catch (Exception error) {
                    System.out.println("something wrong!!!!");
                    return;
                } finally {
                    textField1.setText("");
                    textField2.setText("");
                }
            }
        }
        setLayout(new FlowLayout());
        //三个文本框
        textField1 = new TextField(10);
        textField2 = new TextField(10);
        textField3 = new TextField(15);
        textField2.addActionListener(new MyActionListener());//oop的好处就是可以随手加上一个已经写过的功能hhhh
        //一个按钮
        Button button = new Button("=");
        button.addActionListener(new MyActionListener());
        //一个lable
        Label label1 = new Label("+");

        //构建页面
        add(textField1);
        add(label1);
        add(textField2);
        add(button);
        add(textField3);
        pack();//自适应化
        setVisible(true);//显示页面
        frameClose(this);//添加关闭事件
    }
    private void frameClose(Frame frame) {
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                super.windowClosing(e);
                System.exit(0);
            }
        });
    }
}

画笔(paint)

这个不是类,而是Frame里一个方法,可以被重写,里面的Graphics g才是真正的画笔

例子:

在这里插入图片描述

public class Mypaint extends Frame {
    public void loadFrame(){
        setBounds(200,200,600,500);
        setVisible(true);
        frameClose(this);
    }
    //画笔
    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.setColor(Color.red);
        g.fillOval(100,100,100,100);//实心椭圆
        g.drawOval(200,100,100,100);//空心椭圆
        g.setColor(Color.green);
        g.fillRect(150,200,200,200);//实心长方形
        //画笔用完要洗掉-->变回最开始的颜色(黑色)
    }

    private void frameClose(Frame frame) {
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                super.windowClosing(e);
                System.exit(0);
            }
        });
    }
}

加入一个计时器,每次都洗掉并重新画一次图形就可以做出类似动画的效果了

鼠标监听

例子:使用鼠标画画(其实是点点…)

效果图:

在这里插入图片描述

public class Mypaint extends Frame {
    private ArrayList points;
    //鼠标单击监听事件
    private class MyMouseLinsener extends MouseAdapter {
        @Override
        public void mousePressed(MouseEvent e) {
            Mypaint mypaint=(Mypaint) e.getSource();//获取发生点击事件的窗体
            Point now=new Point(e.getX(),e.getY());//记录点击发生的位置
            points.add(now);//添加进所有发生点击的坐标中
            mypaint.repaint();//这个函数会将窗体清空并重新画
        }
    }
    public void loadFrame(){
        points=new ArrayList();
        setBounds(200,200,600,500);
        setVisible(true);
        frameClose(this);//给窗体设置关闭事件
        addMouseListener(new MyMouseLinsener());//给窗体设置点击事件
    }
    //画笔
    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.setColor(Color.red);//设置画笔颜色慰绿色
        Iterator iterator=points.iterator();
        while(iterator.hasNext()){
            Point now=(Point)iterator.next();
            /*
                    这里记录一下iterator的用法:
                    可迭代对象.iterator()会返回一个指向头的迭代器,这个迭代器指向的是第一个元素的前一位
                    我们每调用一次.next()方法迭代器会先前进一位再返回值,所以我们一定要配合.hasNext()方法使用防止出现类似越界的异常  
            */
            g.fillOval(now.x,now.y,10,10);//在点集中点的位置画一个比较小的实心圆当做点
        }
    }
    private void frameClose(Frame frame) {
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                super.windowClosing(e);
                System.exit(0);
            }
        });
    }
}

窗口监听

常用的是激活窗口(windowActivated)和关闭窗口(windowClosed)

点×时触发关闭窗口事件,窗口从后台调到前台时触发激活窗口

其他的都和上面没啥区别…

键盘监听

这是打游戏用的!很重要!(敲黑板!)

其实也没啥就一个keyListener;

上面的会了,这个直接贴代码自己领会吧

在这里插入图片描述

总结

  1. Frame是一个顶级窗口
  2. panel无法单独显示(要放在某个容器中)
  3. 布局管理器!!!Frame和panel一定要添加,不然会出错
  4. 大小,颜色,定位,可见性,监听

swing

其实就是把AWT封装了一下,让他变得更好用了

窗口(JFrame)

一个基本的实现了窗口关闭的JFrame实例

要注意的是JFrame内置了一个容器我们可以通过getContainer()方法来获取它,下面是个例子(仔细看能看出有个红边,那是Jframe的background)

在这里插入图片描述

居中显示一个标签

JLabel jLabel=new JLabel("这是一个标签");
jLabel.setHorizontalAlignment(JLabel.CENTER);
add(jLabel);

弹窗(JDialog)

和窗体没啥区别,挺好玩的就是

在这里插入图片描述

代码:

public class MyDialog extends JDialog {
    private String title="";
    static private int num=0;
    public void init(){
        setTitle(title);
        setVisible(true);
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        setBackground(Color.yellow);
        JLabel label=new JLabel("这是第"+(++num)+"个弹窗");
        label.setHorizontalAlignment(JLabel.CENTER);
        add(label);
        setBounds(num*100%1020,num*100%680,100,100);
        pack();
    }
    public MyDialog(){}
    public MyDialog(String title){this.title=title;}

}
public class MyFrame extends JFrame {

    private class MyActionListener implements ActionListener{

        @Override
        public void actionPerformed(ActionEvent e) {
            new MyDialog("hhh").init();
        }
    }

    public void init(){
        setTitle("hhh");
        setVisible(true);
        JButton jButton=new JButton("点击弹出一个弹窗");
        jButton.addActionListener(new MyActionListener());
        jButton.setHorizontalAlignment(JButton.CENTER);
        add(jButton);
        pack();
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    }
}

标签(JLabe)

图标 ICON:

在这里插入图片描述

例子:

public class My_Icon extends JFrame implements Icon{
    private int width;
    private int height;
    public My_Icon(){};
    public My_Icon(int width,int height){
        this.width=width;
        this.height=height;
    };
    public void init(){
        My_Icon myIcon=new My_Icon(15,15);
        JLabel label=new JLabel("ICONtest",myIcon,SwingConstants.CENTER);
        Container container=getContentPane();
        container.add(label);
        setVisible(true);
    }

    @Override
    public void paintIcon(Component c, Graphics g, int x, int y) {
        g.setColor(Color.green);
        g.fillOval(x,y,width,height);
    }

    @Override
    public int getIconWidth() {
        return this.width;
    }

    @Override
    public int getIconHeight() {
        return this.height;
    }
}

带图像的图标(ImageICON)

因为图片放的不和谐,就不放结果了

写的时候遇到了问题:明明路径下有资源而且也能打开,就是找不到,很玄学,重命名下就好了(而且有提示是否要把传的参数一起改了…无语)

另外可以通过(类名).class.getResource("").getpath的方法来找到当前类的路径,很方便

因为ImageIcon是Icon的封装,所以也就不用实现Icon接口了,直接用就OK

public class Image_Icon extends JFrame {
    public Image_Icon(){
        //获取图片地址
        System.out.println(Image_Icon.class.getResource("").getPath());
        URL url=Image_Icon.class.getResource("jiao.jpg");
        System.out.println(url);
        ImageIcon image=new ImageIcon(url);
        JLabel label=new JLabel("imageIcontest",image,SwingConstants.CENTER);
        add(label);
        setVisible(true);

    };

}

面板(JPanel)

没啥好说的…

实例:
在这里插入图片描述

public class Test extends JFrame {
    public Test(){
        Container container=getContentPane();
        container.setLayout(new GridLayout(1,2,10,10));//1行两列行间距和列间距都是10,超出的组件/容器会自动扩展出列来存放
        JPanel panel=new JPanel(new GridLayout(1,3));
        JPanel panel2=new JPanel(new GridLayout(1,2));
        JPanel panel3=new JPanel(new GridLayout(2,3));
        JPanel panel4=new JPanel(new GridLayout(3,2));
        panel.add(new JButton("1"));
        panel.add(new JButton("1"));
        panel.add(new JButton("1"));
        panel2.add(new JButton("2"));
        panel2.add(new JButton("2"));
        panel3.add(new JButton("3"));
        panel3.add(new JButton("3"));
        panel4.add(new JButton("4"));
        panel4.add(new JButton("4"));
        panel4.add(new JButton("4"));
        panel4.add(new JButton("4"));
        panel4.add(new JButton("4"));
        panel4.add(new JButton("4"));
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        setVisible(true);
        add(panel);
        add(panel2);
        add(panel3);
        add(panel4);
        setSize(500,500);
        pack();
    }

}

有边框(滚动条)的面板:JScrollpane

在这里插入图片描述

外层的滚动条是JScrollpane的,内层的滚动条是TextArea的

代码:

public class Scrolltest extends JFrame {
    public Scrolltest(){
        super("titile");
        setBounds(100,100,1000,600);
        TextArea area=new TextArea(20,20);
        area.setText("这是个s本域\n\n\n'");
        area.setBounds(0,0,500,300);
        JScrollPane pane=new JScrollPane(area);
        Container container=getContentPane();
        container.add(pane);
        setVisible(true);
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    }


}

列表

  • 下拉框(JComboBox)
  • 列表框(JList)

按钮

  • 单选按钮(JRadioButton) 没啥好说的,记得用ButtonGroup吧JRadioButton包进去就行
  • 复选按钮(JcheckBox)连ButtonGrop都不需要了…下面上代码自己看下就行,就是还不清楚和后台怎么联动

首先是图片按钮,和上面的标签没啥区别…,多学了一个方法,放在代码注释里了因为一些原因,不方便放效果图(逃~~)

public class MyButton extends JFrame {
    public MyButton(){
        Container container=getContentPane();
        URL url=MyButton.class.getResource("jiao.jpg");
        JButton button=new JButton();
        button.setIcon(new ImageIcon(url));
        button.setToolTipText("图片按钮");//鼠标悬停上去后显示的文字
        container.add(button);
        setVisible(true);
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    }
}

单选按钮例子:

在这里插入图片描述

注意!!!,当一个窗体/面板有多个组件而又不想用绝对定位时,一定要setLayout,否则多个组件会堆叠在一起看着就像是只有一个组件显示了一样

public class MyRadioButton extends JFrame {
    public MyRadioButton(){
        Container container=getContentPane();
        container.setLayout(new FlowLayout());
        JRadioButton[] radioButtons=new JRadioButton[4];
        ButtonGroup group=new ButtonGroup();
        for(int i=0;i<4;i++) {
            radioButtons[i] = new JRadioButton("Button" + (i + 1));
            group.add(radioButtons[i]);
        }
        for(int i=0;i<4;i++)
        container.add(radioButtons[i]);
        pack();
        setVisible(true);
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    }
}

多选框:
在这里插入图片描述

文本框(JTextField)

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值