JAVA之图形用户界面(GUI)

您所在的位置:网站首页 java用户图形界面设计房子 JAVA之图形用户界面(GUI)

JAVA之图形用户界面(GUI)

2024-01-05 06:33| 来源: 网络整理| 查看: 265

write:2022-3-24

文章目录 1. 基本的图形用户组件1.1 GUI的基本类库1.1.1 Component组件类1.1.2 Container类 1.2 AWT组件和Swing组件1.3 创建图形用户界面的基本步骤1.3.1:创建一个简单的Frame窗体1.3.2:创建一个包含按钮的Frame窗体1.3.3设置关闭窗体的操作 2. 布局管理器2.1 布局管理器种类2.1.1 FlowLayout布局管理器2.1.2 BorderLayout布局管理器2.1.3 GridLayout布局管理器2.1.4 同时使用多个布局管理器 3. 事件处理机制3.1 事件类和事件监听接口3.2 使用监听接口的适配器 4. 绘图4.1 调用paint()方法的时机4.2 JComponent类的绘图方法4.3 Graphics类 5. 课堂小结

1. 基本的图形用户组件

GUI的基本类库位于java.awt包中,这个包也被称为抽象窗口工具箱(AWT,Abstract Window Toolkit)。 AWT按照面向对象的思想来创建GUI,它提供了容器类、众多的组件类和布局管理器类。 在这里插入图片描述

1.1 GUI的基本类库

在这里插入图片描述 Component类:抽象组件类(所有组件类的父类)——Container子类:容器类

1.1.1 Component组件类

Component类中声明了所有组件都拥有的方法: getBackground():返回组件的背景色。 getGraphics():返回组件使用的画笔。 isVisible():判断组件是否可见。 setBackground(Color c):设置组件的背景色。 setForeground(Color c):设置组件的前景色。 setVisible(boolean b):设置组件是否可见。

1.1.2 Container类

Container类表示容器,继承了Component类。容器用来存放别的组件,有两种类型的容器: Window(窗口)类:Window是不依赖于其他容器而独立存在的容器。Window 有两个子类:Frame(窗体)类和Dialog(对话框)类。Frame带有标题,而且可以调整大小。Dialog可以被移动,但是不能改变大小。 Panel(面板)类:Panel不能单独存在,只能存在于其他容器(Window或其子类)中。一个Panel对象代表了一个长方形的区域,在这区域中可以容纳其他的组件。 在这里插入图片描述

1.2 AWT组件和Swing组件

在java.awt包中,还提供了可以加入到容器类组件中的各种具体组件,如按钮Button、文本框TextField和文本区域TextArea等。AWT组件的优点是简单、稳定,兼容于任何一个JDK版本,缺点是依赖于本地操作系统的GUI,缺乏平台独立性。由于AWT组件与本地平台的GUI绑定,因此用AWT组件创建的图形界面在不同的操作系统中会有不同的外观。 为了使用Java语言创建的图形界面也能够跨平台,即在不同操作系统中保持相同的外观,从JDK1.2版本开始引入了Swing组件,这些Swing组件位于javax.swing包中。

Swing组件类框图:(Swing组件都以字母“J”开头) 在这里插入图片描述

1.3 创建图形用户界面的基本步骤

JFrame窗体类有一个构造方法JFrame(String title),通过它可以创建一个以参数为标题的JFrame对象。 当JFrame被创建后,它是不可见的,必须通过以下方式使JFrame成为可见的: 1)先调用setSize(int width,int height)显式设置JFrame的大小,或者调用pack()方法自动确定JFrame的大小,pack()方法会确保JFrame容器中的组件都会有与布局相适应的合理大小。 2)然后调用setVisible(true)方法使JFrame成为可见的。

1.3.1:创建一个简单的Frame窗体 public static void main(String[] args) { JFrame jFrame = new JFrame("perth"); //设置标题 jFrame.setSize(300,100); //设置高宽 jFrame.setVisible(true); //设置可见 }

运行结果: 在这里插入图片描述

1.3.2:创建一个包含按钮的Frame窗体 public static void main(String[] args) { JFrame jFrame = new JFrame("perth"); //设置窗体标题 JButton jButton = new JButton("Swing Button"); //设置Button中的文字 jButton.setMnemonic('i'); //设置快捷键:用户按钮Alt-i键等价于点击该Button jButton.setToolTipText("Press me"); //设置鼠标移动到该Button时的提示信息 jFrame.add(jButton); //将Button加入到该窗体,默认加入到中央区域 jFrame.setDefaultCloseOperation(jFrame.EXIT_ON_CLOSE); //当用户选择窗体的关闭图标,将结束程序 jFrame.pack(); //自动确定JFrame的大小 jFrame.setVisible(true); //设置窗体可见 }

运行结果: 在这里插入图片描述

1.3.3设置关闭窗体的操作

JFrame的setDefaultCloseOperation(int operation)方法用来决定如何响应用户关闭窗体的操作,参数operation有以下可选值: JFrame.DO_NOTHING_ON_CLOSE:什么也不做。 JFrame.HIDE_ON_CLOSE :隐藏窗体,这是JFrame的默认选项。 (看不见,但存在) JFrame.DISPOSE_ON_CLOSE:销毁窗体。(看不见,再也不存在,程序仍在运行中) JFrame.EXIT_ON_CLOSE :结束程序。

2. 布局管理器

当一个容器被创建后,它们有相应的默认布局管理器。JFrame的默认布局管理器是BorderLayout,这意味着与它关联的内容面板的布局管理器也是BorderLayout。JPanel的默认布局管理器是FlowLayout。 程序可以通过容器类的setLayout(Layout layout)方法来重新设置容器的布局管理器。例如以下代码把JFrame的布局管理器设为FlowLayout: JFrame jFrame=new JFrame(“Hello”); jFrame.setLayout(new FlowLayout()) ;

2.1 布局管理器种类

java.awt包提供了5种布局管理器: FlowLayout 流式布局管理器 BorderLayout边界布局管理器 GridLayout网格布局管理器 CardLayout卡片布局管理器 GridBagLayout网格包布局管理器。 另外,javax.swing包还提供了一种BoxLayout布局管理器

此处重点讲解前3中布局管理器:

2.1.1 FlowLayout布局管理器

FlowLayout是最简单的布局管理器,按照组件的添加次序将它们从左到右地放置在容器中。当到达容器边界时,组件将放置在下一行中。FlowLayout允许以左对齐、居中对齐(默认方式)或右对齐的方式排列组件。FlowLayout的特性如下: 1)不限制它所管理的组件的大小,而是允许它们有自己的最佳大小。 2)当容器被缩放时,组件的位置可能会变化,但组件的大小不改变。 eg:

import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class FlowLayoutDemo { public static void main(String[] args) { final JFrame jFrame = new JFrame("FlowLayout"); //创建面板 JPanel jPanel = new JPanel(); final FlowLayout f1 = (FlowLayout) jPanel.getLayout(); jFrame.setContentPane(jPanel); //JFrame以JPanel作为内容面板(可理解为将JPanel加入JFrame) JButton leftButton = new JButton("left"); leftButton.addActionListener(new ActionListener() { //注册事件监听器 @Override public void actionPerformed(ActionEvent e) { f1.setAlignment(FlowLayout.LEFT); //设置对齐方式为左对齐 f1.layoutContainer(jPanel); //使面板重新布局 } }); JButton centerButton = new JButton("center"); centerButton.addActionListener(new ActionListener() { //注册事件监听器 @Override public void actionPerformed(ActionEvent e) { f1.setAlignment(FlowLayout.CENTER); //设置对齐方式为居中对齐 f1.layoutContainer(jPanel); //使面板重新布局 } }); JButton rightButton = new JButton("right"); rightButton.addActionListener(new ActionListener() { //注册事件监听器 @Override public void actionPerformed(ActionEvent e) { f1.setAlignment(FlowLayout.RIGHT); //设置对齐方式为右对齐 f1.layoutContainer(jPanel); //使面板重新布局 } }); //加入按钮 jFrame.add(leftButton); jFrame.add(centerButton); jFrame.add(rightButton); jFrame.setDefaultCloseOperation(jFrame.EXIT_ON_CLOSE); //当用户选择窗体的关闭图标,将结束程序 jFrame.setSize(400,100); jFrame.setVisible(true); //设置窗体可见 } }

运行结果: 在这里插入图片描述 按下left按钮: 在这里插入图片描述 按下right按钮: 在这里插入图片描述 当窗体大小发生改变时: 在这里插入图片描述 默认情况下,FlowLayout采用居中对齐方式,如果改变JFrame的大小,每个JButton的尺寸保持不变,不过JButton与JFrame之间的相对位置会发生变化

2.1.2 BorderLayout布局管理器

BorderLayout为在容器中放置组件提供了一个稍微复杂的布局方案。BorderLayout把容器分为五个区域:东、南、西、北和中。北占据容器的上方,东占据容器的右侧,以此类推。中间区域是在东、南、西和北都填满后剩下的区域。 在这里插入图片描述 BorderLayout的特性如下:

位于东和西区域的组件保持最佳宽度,高度被垂直拉伸至和所在区域一样高;位于南和北区域的组件保持最佳的高度,宽度被水平拉伸至和所在区域一样宽;位于中部区域的组件的宽度和高度都被拉伸至和所在区域一样大小。当窗口垂直拉伸时,东、西和中区域也拉伸;而当窗口水平拉伸时,南、北和中区域也拉伸。对于容器的东、南、西和北区域,如果某个区域没有组件,这个区域面积为零;对于中部区域,不管有没有组件,BorderLayout都会为它分配空间,如果该区域没有组件,那么在中部区域显示容器的背景颜色。当容器被缩放时,组件所在的相对位置不变化,但组件大小改变。如果在某个区域添加的组件不止一个,只有最后添加的一个是可见的。

eg:简单案例 在这里插入图片描述 因为东南西北4个区域没有组件,所以中间区域占据整个窗体,按钮的添加默认居中,所以b1被遮挡,只显示b2;

eg:更复杂案例

import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class BorderLayoutDemo extends JFrame{ private final String names[]={"Hide North","Hide South", "Hide East","Hide West","Hide Center"}; private final String locations[]={BorderLayout.NORTH,BorderLayout.SOUTH, BorderLayout.EAST, BorderLayout.WEST,BorderLayout.CENTER}; private JButton[] buttons=new JButton[5]; public BorderLayoutDemo(String title){ super(title); final BorderLayout layout=(BorderLayout)this.getLayout(); ActionListener listener=new ActionListener(){ //事件监听器 public void actionPerformed(ActionEvent event){ for(int i=0;i new BorderLayoutDemo("Hello"); } }

运行结果: 在这里插入图片描述

2.1.3 GridLayout布局管理器

GridLayout将容器分割成许多行和列,组件被填充到每个网格中。添加到容器中的组件首先放置在左上角的网格中,然后从左到右放置其他组件,只至占满该行的所有网格,接着继续在下一行中从左到右地放置组件。 在这里插入图片描述 GridLayout的特性如下:

组件的相对位置不随区域的缩放而改变,但组件的大小会随之改变。组件始终占据网格的整个区域。GridLayout总是忽略组件的最佳大小,所有组件的宽度相同,高度也相同。将组件用add()方法添加到容器中的先后顺序决定了它们占据哪个网格。GridLayout从左到右,从上到下将组件填充到容器的网格中。

GridLayout的构造方法: GridLayout(a,b,c,d) :a ——行数 b ——列数 c ——水平格子间距离 d ——垂直格子间距离 GridLayout(a,b) :a ——行数 b ——列数 (因为此时格子间距离为0,格子间紧紧靠在一起,c,d可不写) 在这里插入图片描述 eg:

import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class GridLayoutDemo extends JFrame { private final String names[]={"one","two","three","four","five","six"}; private JButton[] buttons=new JButton[6]; private boolean flag=true; final GridLayout layout1 = new GridLayout(2,3,5,10); final GridLayout layout2 = new GridLayout(3,2); public GridLayoutDemo(String title){ super(title); setLayout(); ActionListener listener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setLayout(); //切换网格布局 GridLayoutDemo.this.validate(); //使新的布局生效 } }; for (int i = 0; i if (flag) setLayout(layout1); else setLayout(layout2); flag=!flag; } public static void main(String[] args) { new GridLayoutDemo("Hello"); } }

运行结果: 在这里插入图片描述 按下任意按钮: 在这里插入图片描述

2.1.4 同时使用多个布局管理器 3. 事件处理机制

事件:点击按钮,选择一个菜单,点击键盘,移动鼠标 事件源:每一个可以触发事件的组件被当作事件源。 事件监听器:每一种事件都对应专门的监听器。监听器负责接收和处理这种事件。 一个事件源可以触发多种事件,如果它注册了某种事件的监听器,那么这种事件就会被接收和处理。由于事件源本身不处理事件,而是委托相应的事件监听器来处理,这种设计模式被称为委托模式。 在这里插入图片描述

3.1 事件类和事件监听接口

每个具体的事件都是某种事件类的实例,事件类包括:ActionEvent、ItemEvent、MouseEvent、KeyEvent、FocusEvent和WindowEvent等。 每个事件类对应一个事件监听接口,例如ActionEvent 对应ActionListener,ItemEvent对应ItemListener、MouseEvent对应MouseListener,KeyEvent对应KeyListener。

eg:为JButton注册ActionEvent的监听器

import javax.swing.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; public class OuterCounter extends JFrame { private JButton jButton = new JButton("1"); public OuterCounter(String title){ super(title); //把MyListener的实例注册为JButton的监听器 jButton.addActionListener(new MyListener(2)); add(jButton); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(100,100); setVisible(true); } public static void main(String[] args) { new OuterCounter("Hello"); } } class MyListener implements ActionListener{ private int step; //决定JButton上的标号每次增加的步长 public MyListener(int step) { this.step = step; } @Override public void actionPerformed(ActionEvent e) { JButton button=(JButton)e.getSource(); //获得事件源 int count=Integer.parseInt(button.getText()); button.setText(new Integer(step+count).toString()); //把JButton上的标号加step } }

运行结果:(每按一次,标号就递增2) 在这里插入图片描述 在这里插入图片描述

3.2 使用监听接口的适配器

接口MouseListener一共定义了五个方法:mousePressed()、mouseReleased()、mouseEntered()、mouseExited()和mouseClicked()。而在实际应用中,往往不需要实现接口中所有的方法。为了编程的方便,AWT为部分方法比较多的监听接口提供了适配器类,这些类尽管实现了监听接口的所有方法,但实际上方法体都为空。 区别:若写实现MouseListener接口,则需要在实现类中重写所有的方法,但若写子类继承MouseAdapter类,可有选择的重写其中的方法 比如MouseListener的适配器类为MouseAdapter,它的定义如下: public abstract class MouseAdapter implements MouseListener { public void mouseClicked(MouseEvent e) {} public void mousePressed(MouseEvent e) {} public void mouseReleased(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} }

eg:

import javax.swing.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; public class AdapterCounter extends JFrame { private JButton button = new JButton("1"); public AdapterCounter(String title){ super(title); button.addMouseListener(new MyMouseListener(2)); add(button); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(100,100); setVisible(true); } public static void main(String args[]){ new AdapterCounter("hello"); } } class MyMouseListener extends MouseAdapter{ //注意:此处是继承适配器,因此只需重写需要的方法即可 private int step; //决定JButton上的标号每次增加的步长 public MyMouseListener(int step) { this.step = step; } @Override public void mousePressed(MouseEvent e){ //重写鼠标按下方法 JButton button=(JButton)e.getSource(); //获得事件源 int count=Integer.parseInt(button.getText()); button.setText(new Integer(step+count).toString()); //把JButton上的标号加step } }

运行结果同上。

4. 绘图

在Component类中提供了以下与绘图有关的方法: paint (Graphics g):绘制组件的外观。 repaint():调用paint()方法,刷新组件的外观。

4.1 调用paint()方法的时机

除了main主线程外,程序还会创建一个AWT线程: 在这里插入图片描述 因为paint方法绘制外观,因此paint方法由AWT线程执行;

在以下几种情况,AWT线程会执行组件的paint()方法: 当组件第一次在屏幕上显示时,AWT线程会自动调用paint()方法来绘制组件。 用户在屏幕上伸缩组件,使组件的大小发生变化,此时AWT线程会自动调用组件的paint()方法,刷新组件的外观。 用户在屏幕上最小化界面,然后又恢复界面,此时AWT线程会自动调用组件的paint()方法,重新显示组件的外观。 程序中调用repaint()方法,该方法会促使AWT线程尽可能快地执行组件的paint()方法。

4.2 JComponent类的绘图方法

JComponent类覆盖了Component类的paint()方法。JComponent类的paint()方法把绘图任务委派给三个protected类型的方法来完成: paintComponent():画当前组件。 paintBorder():画组件的边界。 paintChildren():如果组件为容器,则画容器所包含的组件。

对于自定义的Swing组件,如果需要绘制图形,只需要覆盖paintComponent()方法。 JComponent类的paintComponent()方法会以组件的背景色来覆盖整个组件区域。

4.3 Graphics类

Component类的paint(Graphics g)方法有一个java.awt.Graphics类型的参数。Graphics类代表画笔,提供了绘制各种图形的方法,常见的有: drawLine(int x1,int y1,int x2, int y2) :画一条直线。参数(x1,y1)和(x2,y2)设定直线的起始和终止坐标。 drawString(String string,int left,int bottom) :写一个字符串。 drawImage(Image image,int left, int top, ImageObserver observer) :画一个图片。 drawRect(int left,int top,int width,int height):画一个矩形。 drawOval(int x, int y, int width, int height) :画一个椭圆。 fillRect(int left,int top,int width,int height):填充一个矩形。 fillOval(int x, int y, int width, int height):填充一个椭圆。

eg:

import javax.swing.*; import java.awt.*; public class OvalDrawer extends JPanel implements Runnable { private Color[] colors={Color.RED,Color.BLACK,Color.BLUE, Color.GREEN,Color.DARK_GRAY}; private Color color; //当前要绘制的图形的颜色 private int x=10,y=10,width=10,height=10; public OvalDrawer(){ new Thread(this).start(); } @Override public void run() { while(true){ x=(int)(Math.random()*300); //random():0-1的随机数 y=(int)(Math.random()*300); width=(int)(Math.random()*100); height=(int)(Math.random()*100); color=colors[(int)(Math.random()*(colors.length-1))]; repaint(); try{Thread.sleep(400); } catch(InterruptedException e){ throw new RuntimeException(e); } } } public void paintComponent(Graphics g){ //调用父类的paintComponent(g)方法会导致先清空面板, //使得上次所画的椭圆被删除。 //super.paintComponent(g); g.setColor(color); g.fillOval(x,y,width,height); //画椭圆 } public static void main(String[] args) { JPanel panel = new OvalDrawer(); JFrame frame = new JFrame("Hello"); frame.setContentPane(panel); //panel不能独立存在,放在窗口中 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(300,300); frame.setVisible(true); } }

运行结果: 在这里插入图片描述

5. 课堂小结 Component组件类可分为Container容器类与其他非容器类。Container容器类分为两种:Window和Panel。Window是可以不依赖于其他容器而独立存在的容器,Window 有两个子类:Frame和Dialog。Panel只能存在于其他的容器(Window或其子类)中。java.awt包中的AWT组件依赖于本地操作系统的GUI,缺乏平台独立性。而Swing组件可以跨平台运行,是一种轻量级组件。Swing组件位于javax.swing包中,多数Swing组件类都以大写字母“J”开头。除JFrame和JDialog以外,其余的Swing组件都继承了JComponent类。Window、Frame和Dialog、JFrame和JDialog的默认布局管理器是BorderLayout,Panel和JPanel的默认布局管理器是FlowLayout。可以通过容器类的setLayout(Layout)方法来改变容器的布局管理器。FlowLayout布局管理器会始终保证每个组件的最佳尺寸,BorderLayout把容器分为五个区域,如果在同一个区域加入多个组件,只有最后一个组件是可见的。AWT处理事件采用委托模式。组件本身不处理事件,而是委托监听器来处理。在Component类中提供了与绘图有关的方法:负责绘制组件外观的paint()方法和刷新组件外观的repaint()方法。JComponent类覆盖了Component类的paint()方法。JComponent类的paint()方法把绘图任务委派给三个protected类型的方法来完成: 负责画当前组件的paintComponent()方法 负责画组件边界的paintBorder()方法 负责画容器所包含组件的paintChildren()方法对于用户自定义的Swing组件,如果需要绘制特定的图形,只需要覆盖paintComponent()方法。


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3