11 图形化Swing

javax.swing

11.1 基础GUI

  • JFrame是个代表屏幕上window的对象。

    • 可以把buttoncheckboxtext字段等放在window上面
    • 长相会根据所处平台有所不同
  • 组件widget

    • 所有的组件都是继承自javax.swing.JComponent

    • 组件是可以嵌套的,大致分为交互组件和背景组件(除了JFrame外,差异不明确);

    • 常用组件:

      • JButton

      • JRadioButton

      • JCheckBox

        • 复选框

        • JCheckBox check = new JCheckBox("Goes to 11");
          check.addItemListener(this);
          
          public void itemStateChanged(ItemEvent ev){
              String onOrOff = "off";
              if(check.isSelected())onOrOff = "on";
              System.out.println("Check box is " + onOrOff);
          }
          
          check.setSelected(true);
          check.setSelected(false);
          
      • JLabel

      • JList

        • JList的构造函数需要一个任意类型的数组

        • String[] listEntries = {/*...*/};
          list = new JList(listEntries);
          
          //让list显示垂直的滚动条和下面是一样的
          //把text改成list即可
          
          list.setVisibleRowCount(4);//设定显示的行数
          
          list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
          //限制用户只能选取一个项目
          
      • JScrollPane

        • JScrollPane scroller = new JScrollPane(text);
          
          scroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
          
          scroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
          //上面两句指定只使用垂直的滚动条
          
          panel.add(scroller);
          
      • JSlider

      • JTextArea

        • 可以有超过一行以上的文字,但没有滚动条功能;

        • JTextArea text = new JTextArea(10, 20);
          text.setText();
          text.append();
          text.selectAll();
          text.requestFocus();
          text.setLineWrap(true);//自动换行
          
      • JTextField

        • JTextField field = new JTextField(20);//字宽
          JTextField field = new JTextField("You Name");
          field.getText();
          field.setText();
          field.selectAll();
          field.requestFocus();
          
      • JTable

    • 组件不是直接加到JFrame上,JFrame可以看成window的框,组件是加到windowpane上面的。

  • //非常简单的GUI
    import javax.swing.*;
    
    public class SimpleGui1{
        public static void main(String[] args){
            JFrame frame = new Frame();
            JButton button = new JButton("click me");
            
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            //这一行程序在window关闭时把程序结束掉
            
            //放置widget
            frame.getContentPane().add(button);
            
            frame.setSize(300, 300);
            
            frame.setVisible(true);//把frame显示出来
        }
    }
    
  • frame上放置多个widget

    • GUI的布局(layout)
    • frame.getContentPane().add(BorderLayout.CENTER, button);
      • BorderLayout.CENTE
      • BorderLayout.NORTH
      • BorderLayout.WEST
      • BorderLayout.EAST
      • BorderLayout.SOUTH
  • 绘图组件JPanel

    • 创建自己的子类并覆盖掉paintComponent()这个方法;

    • import java.awt.*;
      import javax.swing.*;
      
      class MyDrawPanel extends JPanel{
          public void paintComponent(Graphics g){
              //参数是跟实际屏幕有关的Graphics对象
              //无法取得这个对象
              g.setColor(Color.orange);
              g.fillRect(20, 50, 100, 100);
          }
      }
      
    • 无法调用这个方法,只能由系统来调用。

    • repaint()来要求系统重新绘制显示装置,然后才会产生paintComponent()的调用。

11.2 布局管理器

  • 可以控制Java的GUI上的widget的大小和位置的对象;

  • 与特定组件相关联的Java对象,它大多数是背景组件。

  • 布局管理器用来控制所关联组件上携带的其他组件。

    • 如果某个框架带有面板,而面板带有按钮;
    • 则面板的布局管理器控制着按钮的大小与位置,而框架的布局管理器控制着面板的大小与位置。
  • 布局管理器有几种不同的类型,每个背景组件都可以有自定义规则的布局管理器。

  • //嵌套布局的例子
    JPanel panelA = new JPanel();
    JPanel panelB = new JPanel();
    
    panelB.add(new JButton("button 1"));
    panelB.add(new JButton("button 2"));
    panelB.add(new JButton("button 3"));
    
    panelA.add(panelB);
    

几种不同的布局管理器:

  • BorderLayout

    • 把背景组件分割成五个区域,每个区域只能放一个组件;
    • 框架(JFrame)默认的布局管理器。
    • frame.getContentPane().add(BorderLayout.EAST, button1);
    • 南北使用理想高度,东西使用理想宽度,中间用剩下的。
  • FlowLayout

    • 从左到右依照加入的顺序以可能会换行的方式排列;

    • 面板(JPanel)默认的布局管理器。

    • JFrame frame = new JFrame();
      JPanel panel = new JPanel();
      
      JButton button = new JButton("shock me");
      JButton button1 = new JButton("shock you");
      //面板默认就是FlowLayout
      panel.add(button);
      panel.add(button1);
      frame.getContentPane().add(BorderLayout.EAST, panel);
      
  • BoxLayout

    • 以垂直的方式来排列,按照加入的顺序;

    • 插入某种换行的机制来强制组件从新的一行进行排列。

    • //把面板的布局管理器从默认的FLowLayout改成BoxLayout
      
      JFrame frame = new JFrame();
      JPanel panel = new JPanel();
      
      panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
      //参数:管理哪个组件、使用哪个轴
      
      JButton button = new JButton("shock me");
      JButton button1 = new JButton("shock you");
      panel.add(button);
      panel.add(button1);
      frame.getContentPane().add(BorderLayout.EAST, panel);
      

几个关键问答:

框架为什么不能像面板一样直接地加上组件?

  • JFrame这么特殊是因为它是让事物显示在画面上的接点。
  • Swing组件纯由Java构成,JFrame必须要连接到底层的操作系统以便来存取显示装置。
  • 可以把面板想作安置在JFrame上的100%纯Java层,或者把JFrame看作支撑面板的框架。
  • 可以用自定义的JPanel来替换掉框架的面板。
    • myFrame.setContentPane(myPanel);

如何替换掉框架的布局管理器?想让框架使用顺序替换边界呢?

  • 最简单的方法,是创建一个JPanel(面板),让此面板称为框架的ContentPane
  • 只需改变面板的布局管理器即可。
  • 可以调用setLayout(null)直接设定画面位置和大小。

11.3 监听和事件处理

在Java中,取得和处理用户操作事件的过程称为even-handling

监听接口是介于监听(你)与事件源(按钮)之间的桥梁。

Swing的GUI组件是事件的来源。

  • 事件来源是可以用户操作(点击鼠标、按键、关闭窗口等)转换成事件的对象
  • 在Java中,事件几乎都是以对象来表示。
    • java.awt.event这个包中存在一组事件的类。
  • 事件源(例如按钮)会在用户做出相关动作时(按下按钮)产生事件对象

每个事件类型都有相对应的监听者接口

  • 例如想要接收MouseEvent,就要实现MouseListener接口。

大致发生顺序图:

  • //代码举例
    
    import javax.swing.*;
    import java.awt.event.*;
    
    public class SimpleGui1B implements ActionListener{
        JButton button;
        public static void main(String[] args){
            SimpleGui1B gui = new SimpleGui1B();
            gui.go();
        }
        
        
        public void go(){
            JFrame frame = new Frame();
            button = new JButton("Click me");
            
            button.addActionListener(this);//向按钮注册,this表示该程序监听
            
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(button);
            frame.setSize(300, 300);
            frame.setVisible(true);
        }
        
        //实现接口上的方法,这是真正处理事件的方法
        public void actionPerformed(ActionEvent event){
            //按钮会议ActionEvent为参数来调用次方法
            button.setText("I've been clicked");
        }
    }
    

多重监听:

比如有两个按钮。

  • 可以对两个按钮注册一个接口,用if判断,但是这样不面向对象。
  • 创建不同的监听器,即ActionListener,但是这些类没办法存取到所需的变量

——> 内部类

  • 内部类可以使用外部的所有方法和变量,就算是private也一样。

  • 内部类实例一定会绑在外部类的实例上。

  • import javax.swing.*;
    import java.awt.event.*;
    
    public class TwoButtons{
        JFrame frame;
        JLabel label;
        
        public static void main(String[] args){
            TwoButtons gui = new TwoButtons();
            gui.go();
        }
        
        
        public void go(){
            frame = new Frame();
            JButton labelButton = new JButton("Change Label");
            labelButton.addActionListener(new LabelListener());//向按钮注册
            
            JButton colorButton = new JButton("Change Circle");
            colorButton.addActionListener(new ColorListener());//向按钮注册
            
            label = new JLabel("I'm a label");
            MyDrawPanel drawPanel = new MyDrawPanel();
            
            frame.getContentPane().add(BorderLayout.SOUTH, colorButton);
            frame.getContentPane().add(BorderLayout.CENTER, drawPanel);
            frame.getContentPane().add(BorderLayout.EAST, labelButton);
            frame.getContentPane().add(BorderLayout.WEST, label);
            
            
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            
            frame.setSize(300, 300);
            frame.setVisible(true);
        }
        
        class LabelListener implements ActionListener{
            public void actionPerformed(ActionEvent event){
                label.setText("Ouch!");
            }
        }
        
        class ColorListener implements ActionListener{
            public void actionPerformed(ActionEvent event){
                frame.repaint();
            }
        }
    }
    
posted @   杨大康  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示