Java图形化界面编程——AWT概论 笔记

2.3 Container容器

2.3.1 Container继承体系

请添加图片描述

  • Winow是可以独立存在的顶级窗口,默认使用BorderLayout管理其内部组件布局;
  • Panel可以容纳其他组件,但不能独立存在,它必须内嵌其他容器中使用,默认使用FlowLayout管理其内部组件布局;
  • ScrollPane 是 一个带滚动条的容器,它也不能独立存在,默认使用 BorderLayout 管理其内部组件布局;

2.3.2 常见API

Component作为基类,提供了如下常用的方法来设置组件的大小、位置、可见性等。

方法签名方法功能
setLocation(int x, int y)设置组件的位置。
setSize(int width, int height)设置组件的大小。
setBounds(int x, int y, int width, int height)同时设置组件的位置、大小。
setVisible(Boolean b):设置该组件的可见性。

Container作为容器根类,提供了如下方法来访问容器中的组件

方法签名方法功能
Component add(Component comp)向容器中添加其他组件 (该组件既可以是普通组件,也可以 是容器) , 并返回被添加的组件 。
Component getComponentAt(int x, int y):返回指定点的组件 。
int getComponentCount():返回该容器内组件的数量 。
Component[] getComponents():返回该容器内的所有组件 。

2.3.3 容器演示

2.3.3.1 Window
import java.awt.*;public class FrameDemo {public static void main(String[] args) {//1.创建第一个窗口Frame frame = new Frame("这是第一个窗口Frame");//2.设置窗口的大小和位置frame.setBounds(100,100,500,300);//3.设置窗口的可见性frame.setVisible(true);}
}

请添加图片描述

2.3.3.2 Panel
import java.awt.*;public class PanelDemo {public static void main(String[] args) {//1.创建窗口对象Frame frame = new Frame("这里测试Fanel");//2.创建内容面板Panel panel = new Panel();//3.添加一个文本到面板里面panel.add(new Label("这是一个测试文本"));//4.添加一个按钮到面板里面panel.add(new Button("这是一个测试按钮"));//5.把面板添加(容纳)到窗口中frame.add(panel);//6.设置窗口的位置大小frame.setBounds(100,100,500,300);//7.设置窗口的可见性frame.setVisible(true);}
}

在这里插入图片描述
由于IDEA默认使用utf-8进行编码,但是当前我们执行代码是是在windows系统上,而windows操作系统的默认编码是gbk,所以会乱码,如果出现了乱码,那么只需要在运行当前代码前,设置一个jvm参数 -Dfile.encoding=gbk即可。

步骤:
在这里插入图片描述
点那个下三角选择Edit Configurations。

在这里插入图片描述
来到这个界面点击Modify options,选择ADD VM Options。

在这里插入图片描述
在这里添加-Dfile.encoding=gbk即可。

结果:

在这里插入图片描述

2.3.3.3 ScrollPane
import java.awt.*;public class ScrollPaneDemo {public static void main(String[] args) {//1.创建Frame窗口对象Frame frame = new Frame("这里测试ScrollPane");//2.创建一个ScrollPane滚动面板对象,参数ScrollPane.SCROLLBARS_ALWAYS意味默认带有滚动条ScrollPane scrollPane = new ScrollPane(ScrollPane.SCROLLBARS_ALWAYS);//3.添加一个文本到滚动面板scrollPane.add(new Label("这是一个测试文本"));//4.添加一个按钮到滚动面板scrollPane.add(new Button("这是一个测试按钮"));//5.将scrollPane添加到frame里面frame.add(scrollPane);//6.设窗口的位置大小frame.setBounds(100,100,500,300);//7.设置窗口的可见性frame.setVisible(true);}
}

(配置与上面同理)

程序明明向 ScrollPane 容器中添加了 一个文本框和一个按钮,但只能看到 一个按钮,却看不到文本框 ,这是为什么 呢?

这是因为ScrollPane 使用 BorderLayout 布局管理器的缘故,而 BorderLayout 导致了该容器中只有一个组件被显示出来 。 下一节将向详细介绍布局管理器的知识 。

2.4 LayoutManager布局管理器

之前,我们介绍了Component中有一个方法 setBounds() 可以设置当前容器的位置和大小,但是我们需要明确一件事,如果我们手动的为组件设置位置和大小的话,就会造成程序的不通用性,例如:

Label label = new Label("你好,世界");

创建了一个lable组件,很多情况下,我们需要让lable组件的宽高和“你好,世界”这个字符串自身的宽高一致,这种大小称为最佳大小

由于操作系统存在差异,例如在windows上,我们要达到这样的效果,需要把该Lable组件的宽和高分别设置为100px,20px,但是在Linux操作系统上,可能需要把Lable组件的宽和高分别设置为120px,24px,才能达到同样的效果。

如果要让我么的程序在不同的操作系统下,都有相同的使用体验,那么手动设置组件的位置和大小,无疑是一种灾难,因为有太多的组件,需要分别设置不同操作系统下的大小和位置。为了解决这个问题,Java提供了LayoutManager布局管理器,可以根据运行平台来自动调整组件大小,程序员不用再手动设置组件的大小和位置了,只需要为容器选择合适的布局管理器即可。

在这里插入图片描述

也就是说布局管理器可以实现不同环境下,让面板中的组件位置自动最佳,不用手动调节组建的大小位置了。

2.4.1 FlowLayout

​ 在 FlowLayout 布局管理器 中,组件像水流一样向某方向流动 (排列) ,遇到障碍(边界)就折回,重头开始排列 。在默认情况下, FlowLayout 布局管理器从左向右排列所有组件,遇到边界就会折回下一行重新开始。

构造方法方法功能
FlowLayout()使用默认 的对齐方式及默认的垂直间距、水平间距创建 FlowLayout 布局管理器。
FlowLayout(int align)使用指定的对齐方式及默认的垂直间距、水平间距创建 FlowLayout 布局管理器。
FlowLayout(int align,int hgap,int vgap)使用指定的对齐方式及指定的垂直问距、水平间距创建FlowLayout 布局管理器。

FlowLayout 中组件的排列方向(从左向右、从右向左、从中间向两边等) , align参数应该使用FlowLayout类的静态常量 : FlowLayout. LEFT 、 FlowLayout. CENTER 、 FlowLayout. RIGHT ,默认是左对齐。

FlowLayout 中组件中间距通过整数设置,单位是像素,默认是5个像素。

import java.awt.*;public class FlowLayoutDemo {public static void main(String[] args) {//1.创建窗口Frame对象Frame frame = new Frame("这里测试FlowLayout");//2.修改Frame容器对象中的布局管理器为FlowLayoutframe.setLayout(new FlowLayout(FlowLayout.LEFT,20,20));//setLayout函数接收一个布局管理器对象(接口),因此跟之前添加组件一样,new一个FlowLayout//3.往Frame窗口对象中添加100个buttonfor(int i = 0; i < 100; i++) {frame.add(new Button("按钮"+i));}//4.设置Frame为最佳大小frame.pack();//通常在创建完窗口的所有子组件后,调用pack函数可以确保窗口的大小适合所有子组件//5.设置窗口的可见性frame.setVisible(true);}
}

特点:

  1. frame.setLayout(new FlowLayout(FlowLayout.LEFT,20,20));
    //setLayout函数接收一个布局管理器对象(接口),因此跟之前添加组件一样,new一个FlowLayout

  2. frame.pack();
    //通常在创建完窗口的所有子组件后,调用pack函数可以确保窗口的大小适合所有子组件

在这里插入图片描述

在这里插入图片描述

2.4.2 BorderLayout

BorderLayout 将容器分为 EAST 、 SOUTH 、 WEST 、 NORTH 、 CENTER五个区域,普通组件可以被放置在这 5 个区域的任意一个中 。 BorderLayout布局 管理器的布局示意图如图所示 。

在这里插入图片描述

当改变使用 BorderLayout 的容器大小时, NORTH 、 SOUTH 和 CENTER区域水平调整(左右拉伸),而 EAST 、 WEST 和 CENTER 区域垂直调整(上下拉伸)。

使用BorderLayout 有如下两个注意点:

  1. 当向使用 BorderLayout 布局管理器的容器中添加组件时 , 需要指定要添加到哪个区域中 。 如果没有指定添加到哪个区域中,则默认添加到中间区域中;

  2. 如果向同一个区域中添加多个组件时 , 后放入的组件会覆盖先放入的组件

    (是2.3.3.3 程序明明向 ScrollPane 容器中添加了 一个文本框和一个按钮,但只能看到 一个按钮,却看不到文本框问题的原因)

构造方法方法功能
BorderLayout()使用默认的水平间距、垂直 间距创建 BorderLayout 布局管理器 。
BorderLayout(int hgap,int vgap):使用指定的水平间距、垂直间距创建 BorderLayout 布局管理器。

代码一:

import java.awt.*;public class BorderLayoutDemo {public static void main(String[] args) {//1.创建一个窗口Frame对象Frame frame = new Frame();//2.Frame默认的布局管理器就是BorderLayout,所以重点是规定水平间距和垂直间距frame.setLayout(new BorderLayout(30,5));//3.往五个方向区域都添加一个按钮组件//这里add(Component comp,int index)frame.add(new Button("东侧按钮"),BorderLayout.EAST);frame.add(new Button("西侧按钮"),BorderLayout.WEST);frame.add(new Button("南侧按钮"),BorderLayout.SOUTH);frame.add(new Button("北侧按钮"),BorderLayout.NORTH);frame.add(new Button("中间按钮"),BorderLayout.CENTER);//4.设置Frame为最佳大小frame.pack();//5.设置Frame的可见性frame.setVisible(true);}
}

在这里插入图片描述

如果不往某个区域中放入组件,那么该区域不会空白出来,而是会被其他区域占用

代码二:

import java.awt.*;public class BorderLayoutDemo2 {public static void main(String[] args) {//1.创建Frame对象Frame frame = new Frame();//2.Frame默认的布局管理器就是BorderLayout,所以重点是规定水平间距和垂直间距frame.setLayout(new BorderLayout(30,5));//3.往五个方向区域都添加一个按钮组件frame.add(new Button("南侧按钮"),BorderLayout.SOUTH);frame.add(new Button("北侧按钮"),BorderLayout.NORTH);//4.使用panel实现中间区域可以存在两个组件Panel panel = new Panel();panel.add(new Button("中间按钮"));panel.add(new TextField("测试文本框"));frame.add(panel);//这里我们可以得到Frame对象的默认添加区域是中间区域//5.设置Frame为最佳大小frame.pack();//6.设置Frame的可见性frame.setVisible(true);}
}

在这里插入图片描述

2.4.3 GridLayout

​ GridLayout 布局管理器将容器分割成纵横线分隔的网格 , 每个网格所占的区域大小相同。当向使用 GridLayout 布局管理器的容器中添加组件时, 默认从左向右、 从上向下依次添加到每个网格中 。 与 FlowLayout不同的是,放置在 GridLayout 布局管理器中的各组件的大小由组件所处的区域决定(每个组件将自动占满整个区域) ,也就是网格大小为组件大小

构造方法方法功能
GridLayout(int rows,in t cols)采用指定的行数、列数,以及默认的横向间距、纵向间距将容器 分割成多个网格
GridLayout(int rows,int cols,int hgap,int vgap)采用指定 的行数、列 数 ,以及指定的横向间距 、 纵向间距将容器分割成多个网格。

案例:

​ 使用Frame+Panel,配合FlowLayout和GridLayout完成一个计算器效果。
在这里插入图片描述

代码:

import java.awt.*;public class GridLayoutDemo {public static void main(String[] args) {//1.创建Frame对象,并把标题设置为计算器Frame frame = new Frame("计算器");//2.创建一个Panel对象,往其加入一个TextField文本框组件,并把文本宽度设置为30个字符Panel panel1 = new Panel();panel1.add(new TextField(30));//3.把文本面板Panel1放置在Frame的北侧区域frame.add(panel1, BorderLayout.NORTH);//4.创建一个Panel对象,并设置其布局管理器为GridLayout,来存放计算机按钮Panel panel2 = new Panel();panel2.setLayout(new GridLayout(3,5,4,4));//三行五列,横向、纵向间距都为4//5.往面板二添加按钮for(int i = 0; i < 10; i++) {panel2.add(new Button(i+""));   //+"" 将i转化为字符串类型}panel2.add(new Button("+"));panel2.add(new Button("-"));panel2.add(new Button("*"));panel2.add(new Button("/"));panel2.add(new Button("."));//6.将计算机面板放置在Frame的中间区域frame.add(panel2,BorderLayout.CENTER);//7.设置Frame为最佳大小frame.pack();//8.设置Frame可见frame.setVisible(true);}

2.4.4 GridBagLayout

GridBagLayout 布局管理器的功能最强大 , 但也最复杂。

(简单带过,在spring会有更强大的布局管理器)在这里插入图片描述

与 GridLayout 布局管理器不同的是, 在GridBagLayout 布局管理器中,一个组件可以跨越一个或多个网格 , 并可以设置各网格的大小互不相同,从而增加了布局的灵活性 。

当窗口的大小发生变化时 , GridBagLayout 布局管理器也可以准确地控制窗口各部分的拉伸 。

由于在GridBagLayout 布局中,每个组件可以占用多个网格,此时,我们往容器中添加组件的时候,就需要具体的控制每个组件占用多少个网格,java提供的GridBagConstaints类,与特定的组件绑定,可以完成具体大小和跨越性的设置。

GridBagConstraints API:

成员变量含义
gridx设置受该对象控制的GUI组件左上角所在网格的横向索引
gridy设置受该对象控制的GUI组件左上角所在网格的纵向索引
gridwidth设置受该对象控制的 GUI 组件横向跨越多少个网格,如果属性值为 GridBagContraints.REMAIND,则表明当前组件是横向最后一个组件,如果属性值为GridBagConstraints.RELATIVE,表明当前组件是横向倒数第二个组件。
gridheight设置受该对象控制的 GUI 组件纵向跨越多少个网格,如果属性值为 GridBagContraints.REMAIND,则表明当前组件是纵向最后一个组件,如果属性值为GridBagConstraints.RELATIVE,表明当前组件是纵向倒数第二个组件。
fill当"显示区域"大于"组件"的时候,如何调整组件 :
GridBagConstraints.NONE : GUI 组件不扩大
GridBagConstraints.HORIZONTAL: GUI 组件水平扩大 以 占据空白区域
GridBagConstraints.VERTICAL: GUI 组件垂直扩大以占据空白区域
GridBagConstraints.BOTH: GUI 组件水平 、 垂直同时扩大以占据空白区域.
ipadx设置受该对象控制的 GUI 组件横向内部填充的大小,即 在该组件最小尺寸的基础上还需要增大多少.
ipady设置受该对象控制的 GUI 组件纵向内部填充的大小,即 在该组件最小尺寸的基础上还需要增大多少.
insets设置受该对象控制 的 GUI 组件的 外部填充的大小 , 即该组件边界和显示区 域边界之间的 距离 .
weightx设置受该对象控制 的 GUI 组件占据多余空间的水平比例, 假设某个容器 的水平线上包括三个 GUI 组件, 它们的水平增加比例分别是 1 、 2 、 3 , 但容器宽度增加 60 像素 时,则第一个组件宽度增加 10 像素 , 第二个组件宽度增加 20 像素,第三个组件宽度增加 30 像 素。 如 果其增 加比例为 0 , 则 表示不会增加 。
weighty设置受该对象控制 的 GUI 组件占据多余空间的垂直比例
anchor设置受该对象控制 的 GUI 组件在其显示区域中的定位方式:
GridBagConstraints .CENTER (中 间 )
GridBagConstraints.NORTH (上中 )
GridBagConstraints.NORTHWEST (左上角)
GridBagConstraints.NORTHEAST (右上角)
GridBagConstraints.SOUTH (下中)
GridBagConstraints.SOUTHEAST (右下角)
GridBagConstraints.SOUTHWEST (左下角)
GridBagConstraints.EAST (右中)
GridBagConstraints.WEST (左中)

GridBagLayout使用步骤:

1.创建GridBagLaout布局管理器对象,并给容器设置该布局管理器对象;2.创建GridBagConstraints对象,并设置该对象的控制属性:gridx: 用于指定组件在网格中所处的横向索引;gridy: 用于执行组件在网格中所处的纵向索引;gridwidth: 用于指定组件横向跨越多少个网格;gridheight: 用于指定组件纵向跨越多少个网格;3.调用GridBagLayout对象的setConstraints(Component c,GridBagConstraints gbc )方法,把即将要添加到容器中的组件c和GridBagConstraints对象关联起来;4. 把组件添加到容器中;

案例:

​ 使用Frame容器,设置GridBagLayout布局管理器,实现下图中的效果:

在这里插入图片描述

import java.awt.*;public class GridBagLayoutDemo {public static void main(String[] args) {//1.创建Frame对象Frame frame = new Frame("这里是GridBayLayout测试");//2.创建GridBagLayout对象GridBagLayout gridBagLayout = new GridBagLayout();//3.把Frame对象的布局管理器设置为GridBagLayoutframe.setLayout(gridBagLayout);//4.创建GridBagConstraints对象GridBagConstraints gridBagConstraints = new GridBagConstraints();//5.创建容量为10的数组Button[] bs = new Button[10];//6.遍历数组,初始化每一个Buttonfor (int i = 0; i < 10; i++) {bs[i] = new Button("按钮"+(i+1));}//7.设置所有的GridBagConstraints对象的fill属性为GridBagConstraints.BOTH,当有空白区域时,组件自动扩大占满空白区域gridBagConstraints.fill = GridBagConstraints.BOTH;// GUI 组件水平 、 垂直同时扩大以占据空白区域.//8.设置GridBagConstraints对象的weightx设置为1,表示横向扩展比例为1gridBagConstraints.weightx=1;//9.往frame中添加数组中的前3个ButtonaddComponent(frame,bs[0],gridBagLayout,gridBagConstraints);addComponent(frame,bs[1],gridBagLayout,gridBagConstraints);addComponent(frame,bs[2],gridBagLayout,gridBagConstraints);//10.把GridBagConstraints的gridwidth设置为GridBagConstraints.REMAINDER,则表明当前组件是横向最后一个组件gridBagConstraints.gridwidth=GridBagConstraints.REMAINDER;//11.把button数组中第四个按钮添加到frame中addComponent(frame,bs[3],gridBagLayout,gridBagConstraints);//12.把GridBagConstraints的weighty设置为1,表示纵向扩展比例为1gridBagConstraints.weighty=1;//13.把button数组中第5个按钮添加到frame中addComponent(frame,bs[4],gridBagLayout,gridBagConstraints);//14.把GridBagConstaints的gridheight和gridwidth设置为2,表示纵向和横向会占用两个网格gridBagConstraints.gridheight=2;gridBagConstraints.gridwidth=2;//15.把button数组中第6个按钮添加到frame中addComponent(frame,bs[5],gridBagLayout,gridBagConstraints);//16.把GridBagConstaints的gridheight和gridwidth设置为1,表示纵向会占用1个网格gridBagConstraints.gridwidth=1;gridBagConstraints.gridheight=1;//17.把button数组中第7个按钮添加到frame中addComponent(frame,bs[6],gridBagLayout,gridBagConstraints);//18.把GridBagConstraints的gridwidth设置为GridBagConstraints.REMAINDER,则表明当前组件是横向最后一个组件gridBagConstraints.gridwidth=GridBagConstraints.REMAINDER;//19.把button数组中第8个按钮添加到frame中addComponent(frame,bs[7],gridBagLayout,gridBagConstraints);//20.把GridBagConstaints的gridwidth设置为1,表示纵向会占用1个网格gridBagConstraints.gridwidth=1;//21.把button数组中第9、10个按钮添加到frame中addComponent(frame,bs[8],gridBagLayout,gridBagConstraints);addComponent(frame,bs[9],gridBagLayout,gridBagConstraints);//22.设置frame为最佳大小frame.pack();//23.设置frame可见frame.setVisible(true);}public static void addComponent(Container container,Component c,GridBagLayout gridBagLayout,GridBagConstraints gridBagConstraints){gridBagLayout.setConstraints(c,gridBagConstraints);container.add(c);}
}

2.4.5 CardLayout

CardLayout 布局管理器以时间而非空间来管理它里面的组件,它将加入容器的所有组件看成一叠卡片(每个卡片其实就是一个组件),每次只有最上面的那个 Component 才可见。就好像一副扑克牌,它们叠在一起,每次只有最上面的一张扑克牌才可见.

方法名称方法功能
CardLayout()创建默认的 CardLayout 布局管理器。
CardLayout(int hgap,int vgap)通过指定卡片与容器左右边界的间距 C hgap) 、上下边界 Cvgap) 的间距来创建 CardLayout 布局管理器.
first(Container target)显示target 容器中的第一张卡片.
last(Container target)显示target 容器中的最后一张卡片.
previous(Container target)显示target 容器中的前一张卡片.
next(Container target)显示target 容器中的后一张卡片.
show(Container taget,String name)显 示 target 容器中指定名字的卡片.

案例:

​ 使用Frame和Panel以及CardLayout完成下图中的效果,点击底部的按钮,切换卡片

在这里插入图片描述

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;public class GardLayoutDemo {public static void main(String[] args) {//1.创建Frame对象Frame frame = new Frame("这里测试CardLayout");//2.创建一个String数组,用来存储不同卡片的名字String[] names = {"第一张", "第二张", "第三张", "第四张", "第五张"};//3.创建一个面板panel1,设置它的布局管理器为CardLayout,用来存放卡片CardLayout cardLayout = new CardLayout();  //这里需要创建CardLayout对象在后按钮事件会用到Panel panel1= new Panel();panel1.setLayout(cardLayout);//4.往卡片面板panel1中添加五个Button按钮,名字从String数组中取for (int i = 0; i < 5; i++) {panel1.add(names[i], new Button(names[i]));//这里add函数原型为 add(String name, Component comp)}//5.创建一个面板panel2,用来存储五个按钮,实现卡片的切换Panel panel2 = new Panel();//6.创建五个卡片切换按钮,并给按钮设置监听器Button button1 = new Button("上一张");Button button2 = new Button("下一张");Button button3 = new Button("第一张");Button button4 = new Button("最后一张");Button button5 = new Button("第三张");ActionListener listener = new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {String command = e.getActionCommand();  //这个字符串就是按钮上的文字switch (command) {case "上一张":cardLayout.previous(panel1);break;case "下一张":cardLayout.next(panel1);break;case "第一张":cardLayout.first(panel1);break;case "最后一张":cardLayout.last(panel1);break;case "第三张":cardLayout.show(panel1,"第三张");break;}}};button1.addActionListener(listener);button2.addActionListener(listener);button3.addActionListener(listener);button4.addActionListener(listener);button5.addActionListener(listener);//7.将五个卡片切换按钮添加到面板二中panel2.add(button1);panel2.add(button2);panel2.add(button3);panel2.add(button4);panel2.add(button5);//8.把面板一添加到frame的中间区域frame.add(panel1);//9.把面板二添加到frame的底部区域frame.add(panel2, BorderLayout.SOUTH); //Frame默认BorderLayout布局//10.设置frame为最佳大小并可见frame.pack();frame.setVisible(true);}
}

2.4.6 BoxLayout

为了简化开发,Swing 引入了 一个新的布局管理器 : BoxLayout 。 BoxLayout 可以在垂直和 水平两个方向上摆放 GUI 组件, BoxLayout 提供了如下一个简单的构造器:

方法名称方法功能
BoxLayout(Container target, int axis)指定创建基于 target 容器的 BoxLayout 布局管理器,该布局管理器里的组件按 axis 方向排列。其中 axis 有 BoxLayout.X_AXIS( 横向)和 BoxLayout.Y _AXIS (纵向〉两个方向。

案例1:

​ 使用Frame和BoxLayout完成下图效果:

在这里插入图片描述

import javax.swing.*;
import java.awt.*;public class BoxLayoutDemo {public static void main(String[] args) {//1.创建Frame对象Frame frame = new Frame("这里测试BoxLayout");//2.创建BoxLayout布局管理器,并指定容器为上面的frame对象,和指定组件的排列方向为纵向BoxLayout boxLayout = new BoxLayout(frame, BoxLayout.Y_AXIS);frame.setLayout(boxLayout);//3.往frame对象中添加两个按钮frame.add(new Button("按钮1"));frame.add(new Button("按钮2"));//4.设置frame为最佳大小并可见frame.pack();frame.setVisible(true);}
}

案例二:使用Frame和Box,完成下图效果:

在这里插入图片描述

import javax.swing.*;
import java.awt.*;public class BoxLayoutDemo2 {public static void main(String[] args) {//1.创建Frame对象Frame frame = new Frame("这里测试BoxLayout");//2.创建一个横向的Box,并添加两个按钮Box box1 = Box.createHorizontalBox();box1.add(new Button("水平按钮一"));box1.add(new Button("水平按钮二"));//3.创建一个纵向的Box,并添加两个按钮Box box2 = Box.createVerticalBox();box2.add(new Button("垂直按钮一"));box2.add(new Button("垂直按钮二"));//4.把box容器添加到frame的两个区域frame.add(box1,BorderLayout.NORTH);frame.add(box2);//5.设置frame为最佳大小并可见frame.pack();frame.setVisible(true);}
}

通过之前的两个BoxLayout演示,我们会发现,被它管理的容器中的组件之间是没有间隔的,不是特别的美观,但之前学习的几种布局,组件之间都会有一些间距,那使用BoxLayout如何给组件设置间距呢?

其实很简单,我们只需要在原有的组件需要间隔的地方,添加间隔即可,而每个间隔可以是一个组件,只不过该组件没有内容,仅仅起到一种分隔的作用。

在这里插入图片描述

Box类中,提供了5个方便的静态方法来生成这些间隔组件:

方法名称方法功能
static Component createHorizontalGlue()创建一条水平 Glue (可在两个方向上同时拉伸的间距)
static Component createVerticalGlue()创建一条垂直 Glue (可在两个方向上同时拉伸的间距)
static Component createHorizontalStrut(int width)创建一条指定宽度(宽度固定了,不能拉伸)的水平Strut (可在垂直方向上拉伸的间距)
static Component createVerticalStrut(int height)创建一条指定高度(高度固定了,不能拉伸)的垂直Strut (可在水平方向上拉伸的间距)

案例3:

使用Frame和Box,完成下图效果:

在这里插入图片描述

import javax.swing.*;
import java.awt.*;public class BoxLayoutDemo3 {public static void main(String[] args) {//1.创建Frame对象Frame frame = new Frame();//2.创建一个横向的Box,并添加两个按钮Box hBox = Box.createHorizontalBox();hBox.add(new Button("水平按钮一"));hBox.add(Box.createHorizontalGlue());hBox.add(new Button("水平按钮二"));hBox.add(Box.createHorizontalStrut(10));hBox.add(new Button("水平按钮三"));//3.创建一个纵向的Box,并添加两个按钮Box vBox = Box.createVerticalBox();vBox.add(new Button("垂直按钮一"));vBox.add(Box.createHorizontalGlue());vBox.add(new Button("垂直按钮二"));vBox.add(Box.createHorizontalStrut(10));vBox.add(new Button("垂直按钮三"));//4.把box容器添加到frame容器中frame.add(hBox,BorderLayout.NORTH);frame.add(vBox);//5.设置frame为最佳大小并可见frame.pack();frame.setVisible(true);}
}

2.5 AWT中常用组件

2.5.1 基本组件

组件名功能
ButtonButton
Canvas用于绘图的画布
Checkbox复选框组件(也可当做单选框组件使用)
CheckboxGroup选项组,用于将多个Checkbox 组件组合成一组, 一组 Checkbox 组件将只有一个可以 被选中 , 即全部变成单选框组件
Choice下拉选择框
Frame窗口 , 在 GUI 程序里通过该类创建窗口
Label标签类,用于放置提示性文本
List列表框组件,可以添加多项条目
Panel不能单独存在基本容器类,必须放到其他容器中
Scrollbar滑动条组件。如果需要用户输入位于某个范围的值 , 就可以使用滑动条组件 ,比如调 色板中设置 RGB 的三个值所用的滑动条。当创建一个滑动条时,必须指定它的方向、初始值、 滑块的大小、最小值和最大值。
ScrollPane带水平及垂直滚动条的容器组件
TextArea多行文本域
TextField单行文本框

这些 AWT 组件的用法比较简单,可以查阅 API 文档来获取它们各自的构方法、成员方法等详细信息。

案例:

​ 实现下图效果:

在这里插入图片描述

import javax.swing.*;
import java.awt.*;
public class BasicComponentDemo {//之前我们演示的时候,是在main函数里面完成的。但现在我们要做的界面比之前的界面要复杂很多,所以我们重新设计一下//未来我们设计复杂界面时,会把组件在成员变量处组建,来方便使用,//若多个组件来组成一个子界面时,可以设计一个方法来组装界面。然后在main函数中调用这个方法。Frame frame = new Frame("这里测试基本组件");//创建组件TextArea ta = new TextArea(5,20);//一个五行二十列的文本框Choice colorChooser = new Choice();//包含颜色的下拉选择框CheckboxGroup cbg = new CheckboxGroup();//性别单选框Checkbox male = new Checkbox("男", cbg, true);Checkbox female = new Checkbox("女", cbg, false);Checkbox isMarried = new Checkbox("是否已婚?");  //复选框TextField tf = new TextField(50); //20宽单行文本框Button ok = new Button("确认");  //确认按钮List colorlist = new List(6,true);//六行的列表框,不写ture是单选,写true是多选public void init() {//组装界面//组装底部Box bBox = Box.createHorizontalBox();bBox.add(tf);bBox.add(ok);frame.add(bBox,BorderLayout.SOUTH);//组装选择部分colorChooser.add("红色");colorChooser.add("蓝色");colorChooser.add("绿色");Box cBox = Box.createHorizontalBox();cBox.add(colorChooser);cBox.add(male);cBox.add(female);cBox.add(isMarried);//组装文本域和选择部分Box topLeft = Box.createVerticalBox();topLeft.add(ta);topLeft.add(cBox);//组装顶部左边和列表框colorlist.add("红色");colorlist.add("蓝色");colorlist.add("绿色");Box top = Box.createHorizontalBox();top.add(topLeft);top.add(colorlist);frame.add(top);//设置frame为最佳大小和可见性frame.pack();frame.setVisible(true);}public static void main(String[] args) {new BasicComponentDemo().init();}
}

2.5.2 对话框Dialog

2.5.2.1 Dialog

Dialog 是 Window 类的子类,是 一个容器类,属于特殊组件 。 对话框是可以独立存在的顶级窗口, 因此用法与普通窗口的用法几乎完全一样,但是使用对话框需要注意下面两点:

  • 但对话框通常依赖于其他窗口,就是通常需要有一个父窗口
  • 对话框有非模式(non-modal)模式(modal)两种,当某个模式对话框被打开后,该模式对话框总是位于它的父窗口之上,在模式对话框被关闭之前,父窗口无法获得焦点。
方法名称方法功能
Dialog(Frame owner, String title, boolean modal)创建一个对话框对象:
owner:当前对话框的父窗口
title:当前对话框的标题
modal:当前对话框是否是模式对话框,true/false

案例1:

​ 通过Frame、Button、Dialog实现下图效果:

在这里插入图片描述

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;public class DialogDemo {public static void main(String[] args) {Frame frame = new Frame("这里测试Dialog");//1.创建对话框Dialog对象(一个模式一个非模式)Dialog d1 = new Dialog(frame, "模式对话框", true);Dialog d2 = new Dialog(frame, "非模式对话框", false);//2.通过setBounds方法设置对话框的位置和大小d1.setBounds(20,30,300,200);d2.setBounds(20,30,300,200);//3.创建两个按钮Button b1 = new Button("打开模式对话框");Button b2 = new Button("打开非模式对话框");//4.给这两个按钮添加点击后的行为(事件)b1.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {d1.setVisible(true);}});b2.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {d2.setVisible(true);}});//5.把按钮添加到frame中frame.add(b1,BorderLayout.NORTH);frame.add(b2);frame.pack();frame.setVisible(true);}
}

在Dialog对话框中,可以根据需求,自定义内容

案例:

​ 点击按钮,弹出一个模式对话框,其内容如下:在这里插入图片描述

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;public class DialogDemo2 {public static void main(String[] args) {Frame frame = new Frame("这里测试Dialog");//1.创建对话框Dialog对象Dialog d1 = new Dialog(frame, "模式对话框", true);//创建一个垂直的Box容器,把一个文本框和一个按钮添加到Box容器中Box vBox = Box.createVerticalBox();vBox.add(new TextField(20));vBox.add(new Button("确认"));//把Box容器添加到Dialog中d1.add(vBox);//2.通过setBounds方法设置对话框的位置和大小d1.setBounds(20,30,300,200);//3.创建按钮Button b1 = new Button("打开模式对话框");//4.给按钮添加点击后的行为(事件)b1.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {d1.setVisible(true);}});//5.把按钮添加到frame中frame.add(b1,BorderLayout.NORTH);frame.pack();frame.setVisible(true);}
}
2.5.2.1 FileDialog

Dialog 类还有 一个子类 : FileDialog ,它代表一个文件对话框,用于 打开或者保存 文件,需要注意的是FileDialog无法指定模态或者非模态,这是因为 FileDialog 依赖于运行平台的实现,如果运行平台的文件对话框是模态的,那么 FileDialog 也是模态的;否则就是非模态的 。

方法名称方法功能
FileDialog(Frame parent, String title, int mode)创建一个文件对话框:
parent:指定父窗口
title:对话框标题
mode:文件对话框类型,如果指定为FileDialog.load,用于打开文件,如果指定为FileDialog.SAVE,用于保存文件
String getDirectory()获取被打开或保存文件的绝对路径
String getFile()获取被打开或保存文件的文件名

案例2:

​ 使用 Frame、Button和FileDialog完成下图效果:

在这里插入图片描述

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;public class FileDialogDemo {public static void main(String[] args) {Frame frame = new Frame();//1.创建两个FileDialog对象FileDialog f1 = new FileDialog(frame, "选择要打开的文件", FileDialog.LOAD);FileDialog f2 = new FileDialog(frame, "选择要保存的文件", FileDialog.SAVE);//2.创建两个按钮Button b1 = new Button("打开文件");Button b2 = new Button("保存文件");//3.给这两个按钮设置点解后的行为:获取打开或保存的路径文件名b1.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {f1.setVisible(true);//代码会停到这里//获取选择的路径及文件String directory = f1.getDirectory();String file = f1.getFile();System.out.println("打开的文件路径为"+directory);System.out.println("打开的文件名称为"+file);}});b2.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {f2.setVisible(true);//获取选择的路径及文件String directory = f1.getDirectory();String file = f1.getFile();System.out.println("保存的文件路径为"+directory);System.out.println("保存的文件名称为"+file);}});//4.把按钮添加到Frame中frame.add(b1,BorderLayout.NORTH);frame.add(b2);//设置frame为最佳大小和可见性frame.pack();frame.setVisible(true);}
}

2.6 事件处理

前面介绍了如何放置各种组件,从而得到了丰富多彩的图形界面,但这些界面还不能响应用户的任何操作。比如单击前面所有窗口右上角的“X”按钮,但窗口依然不会关闭。因为在 AWT 编程中 ,所有用户的操作,都必须都需要经过一套事件处理机制来完成,而 Frame 和组件本身并没有事件处理能力 。

2.6.1 GUI事件处理机制

定义:

​ 当在某个组件上发生某些操作的时候,会自动的触发一段代码的执行

在GUI事件处理机制中涉及到4个重要的概念需要理解:

事件源(Event Source):操作发生的场所,通常指某个组件,例如按钮、窗口等;
事件(Event):在事件源上发生的操作可以叫做事件,GUI会把事件都封装到一个Event对象中,如果需要知道该事件的详细信息,就可以通过Event对象来获取。
事件监听器(Event Listener):当在某个事件源上发生了某个事件,事件监听器就可以对这个事件进行处理。

注册监听:把某个事件监听器(A)通过某个事件(B)绑定到某个事件源©上,当在事件源C上发生了事件B之后,那么事件监听器A的代码就会自动执行
请添加图片描述

请添加图片描述

使用步骤:

1.创建事件源组件对象;

2.自定义类,实现XxxListener接口,重写方法;

3.创建事件监听器对象(自定义类对象)

4.调用事件源组件对象的addXxxListener方法完成注册监听

案例:

**请添加图片描述
**

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;public class EventDemo1 {Frame frame = new Frame("这里测试事件处理");TextField tf = new TextField(30);//事件源Button ok = new Button("确定");public void init() {//组装视图//监听器//MyListener myListener = new MyListener();//注册监听ok.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {System.out.println("ok按钮被点击了...");tf.setText("Hello World");}});//把tf和ok放入到frame中frame.add(tf, BorderLayout.NORTH);frame.add(ok);//设置最佳大小和可见性frame.pack();frame.setVisible(true);}/*private class MyListener implements ActionListener {@Overridepublic void actionPerformed(ActionEvent e) {tf.setText("Hello World");}}*/public static void main(String[] args) {new EventDemo1().init();}
}

2.6.2 GUI中常见事件和事件监听器

事件监听器必须实现事件监听器接口, AWT 提供了大量的事件监听器接口用于实现不同类型的事件监听器,用于监听不同类型的事件 。 AWT 中提供了丰富的事件类,用于封装不同组件上所发生的特定操作, AWT 的事件类都是 AWTEvent 类的子类 , AWTEvent是 EventObject 的子类。

2.6.2.1 事件

AWT把事件分为了两大类:

​ 1.低级事件:这类事件是基于某个特定动作的事件。比如进入、点击、拖放等动作的鼠标事件,再比如得到焦点和失去焦点等焦点事件。

指向性明确:进入、点击、拖放等

事件触发时机
ComponentEvent组件事件 , 当 组件尺寸发生变化、位置发生移动、显示/隐藏状态发生改变时触发该事件。
ContainerEvent容器事件 , 当容器里发生添加组件、删除组件时触发该事件 。
WindowEvent窗口事件, 当窗 口状态发生改变 ( 如打开、关闭、最大化、最 小化)时触发该事件 。
FocusEvent焦点事件 , 当组件得到焦点或失去焦点 时触发该事件 。
KeyEvent键盘事件 , 当按键被按下、松开、单击时触发该事件。
MouseEvent鼠标事件,当进行单击、按下、松开、移动鼠标等动作 时触发该事件。
PaintEvent组件绘制事件 , 该事件是一个特殊的事件类型 , 当 GUI 组件调 用 update/paint 方法 来呈现自身时触发该事件,该事件并非专用于事件处理模型 。

​ 2.高级事件:这类事件并不会基于某个特定动作,而是根据功能含义定义的事件。

事件触发时机
ActionEvent动作事件 ,当按钮、菜单项被单击,在 TextField 中按 Enter 键时触发
AjustmentEvent调节事件,在滑动条上移动滑块以调节数值(颜色、亮度)时触发该事件。
ltemEvent选项事件,当用户选中某项, 或取消选中某项时触发该事件 。
TextEvent文本事件, 当文本框、文本域里的文本发生改变时触发该事件。
2.6.2 事件监听器

不同的事件需要使用不同的监听器监听,不同的监听器需要实现不同的监听器接口, 当指定事件发生后 , 事件监听器就会调用所包含的事件处理器(实例方法)来处理事件 。

Event—>Listener

事件类别描述信息监听器接口名
ActionEvent激活组件ActionListener
ItemEvent选择了某些项目ItemListener
MouseEvent鼠标移动MouseMotionListener
MouseEvent鼠标点击等MouseListener
KeyEvent键盘输入KeyListener
FocusEvent组件收到或失去焦点FocusListener
AdjustmentEvent移动了滚动条等组件AdjustmentListener
ComponentEvent对象移动缩放显示隐藏等ComponentListener
WindowEvent窗口收到窗口级事件WindowListener
ContainerEvent容器中增加删除了组件ContainerListener
TextEvent文本字段或文本区发生改变TextListener

2.6.3 案例

案例一:

​ 通过ContainerListener监听Frame容器添加组件;

​ 通过TextListener监听TextFiled内容变化;

​ 通过ItemListener监听Choice条目选中状态变化;

请添加图片描述
请添加图片描述

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;public class ListenerDemo1 {public static void main(String[] args) {//处理控制台乱码的问题try {System.setOut(new PrintStream(System.out, true, "GBK")); // 设置控制台输出编码为GBK} catch (UnsupportedEncodingException e) {// 处理异常的代码}Frame frame = new Frame("这里测试监听器");//创建组件 (事件源)TextField tf = new TextField(30);   //30宽度的文本框Choice names = new Choice();  //下拉选择框names.add("柳岩");names.add("舒淇");names.add("闫妮");//给文本域添加TextListener,监听内容的变化tf.addTextListener(new TextListener() {@Overridepublic void textValueChanged(TextEvent e) {String text = tf.getText();   //得到文本域中的内容System.out.println("当前文本框中的内容为:" + text);}});//给下拉选择框添加ItemListener,监听条目选项的变化names.addItemListener(new ItemListener() {@Overridepublic void itemStateChanged(ItemEvent e) {Object item = e.getItem();    //得到当前选择框的条目内容System.out.println("当前选中的条目为:" + item);}});//给frame注册ContainerListener监听器,监听容器中组件的添加frame.addContainerListener(new ContainerListener() {@Overridepublic void componentAdded(ContainerEvent e) {Component child = e.getChild();System.out.println("frame中添加了:" + child);}@Overridepublic void componentRemoved(ContainerEvent e) {}});//添加到frame中Box hBox = Box.createHorizontalBox();//横向hBox.add(names);hBox.add(tf);frame.add(hBox);//设置frame最佳大小并可见frame.pack();frame.setVisible(true);}
}

案例2:

​ 给Frame设置WindowListner,监听用户点击 X 的动作,如果用户点击X,则关闭当前窗口。

import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;public class ListenerDemo2 {public static void main(String[] args) {Frame frame = new Frame("这里测试WindowListener");//设置WindowListener,监听用户点击X的动作,如果点击X,则关闭窗口frame.addWindowListener(new WindowAdapter() {   //WindowAdapter可以只重写一个操作方法@Overridepublic void windowClosing(WindowEvent e) {//停止当前程序System.exit(0);}});frame.setBounds(300,300,500,200);frame.setVisible(true);}
}

2.7 菜单组件

​ 前面讲解了如果构建GUI界面,其实就是把一些GUI的组件,按照一定的布局放入到容器中展示就可以了。在实际开发中,除了主界面,还有一类比较重要的内容就是菜单相关组件,可以通过菜单相关组件很方便的使用特定的功能,在AWT中,菜单相关组件的使用和之前学习的组件是一模一样的,只需要把菜单条、菜单、菜单项组合到一起,按照一定的布局,放入到容器中即可。

请添加图片描述

下表中给出常见的菜单相关组件:

菜单组件名称功能
MenuBar菜单条 , 菜单的容器 。
Menu菜单组件 , 菜单项的容器 。 它也是Menultem的子类 ,所以可作为菜单项使用
PopupMenu上下文菜单组件(鼠标右键菜单组件)
Menultem菜单项组件
CheckboxMenuItem复选框菜单项组件

下图是常见菜单相关组件集成体系图:

请添加图片描述

菜单相关组件使用:

1.准备菜单项组件,这些组件可以是MenuItem及其子类对象

2.准备菜单组件Menu或者PopupMenu(右击弹出子菜单),把第一步中准备好的菜单项组件添加进来;

3.准备菜单条组件MenuBar,把第二步中准备好的菜单组件Menu添加进来;

4.把第三步中准备好的菜单条组件添加到窗口对象中显示。

小技巧:

1.如果要在某个菜单的菜单项之间添加分割线,那么只需要调用**Menu的add(new MenuItem(“-”))**即可。

2.如果要给某个菜单项关联快捷键功能,那么只需要在创建菜单项对象时设置即可,例如给菜单项关联 ctrl+shif+/ 快捷键,只需要:new MenuItem(“菜单项名字”,new MenuShortcut(KeyEvent.VK_Q,true);

案例1:

​ 使用awt中常用菜单组件,完成下图效果

请添加图片描述

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;public class SimpleMenu {//创建窗口Frame frame = new Frame("这里测试菜单相关组件");//创建菜单条MenuBar menuBar = new MenuBar();//创建菜单组件Menu fileMenu = new Menu("文件");Menu editMenu = new Menu("编辑");Menu formatMenu = new Menu("格式");//菜单项组件MenuItem auto =  new MenuItem("自动换行");MenuItem copy = new MenuItem("复制");MenuItem paste = new MenuItem("粘贴");MenuItem comment = new MenuItem("注释 Ctrl+Shift+Q", new MenuShortcut(KeyEvent.VK_Q,true)); //关联快捷键ctrl+shift+QMenuItem cancelComment= new MenuItem("取消注释");TextArea ta = new TextArea(6,40);   //六行四十列的文本框public void init() {//组装视图comment.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {ta.append("您点击了菜单项:" + e.getActionCommand());    //将事件发生地方的内容加入到文本框中}});formatMenu.add(comment);formatMenu.add(cancelComment);//组装编辑菜单条editMenu.add(auto);editMenu.add(copy);editMenu.add(paste);editMenu.add(new MenuItem("-"));editMenu.add(formatMenu);//组装菜单条menuBar.add(fileMenu);menuBar.add(editMenu);//把菜单条放入到Frame中frame.setMenuBar(menuBar);frame.add(ta);//设置frame最佳大小并可见frame.pack();frame.setVisible(true);}public static void main(String[] args) {new SimpleMenu().init();}
}

请添加图片描述

案例2:

​ 通过PopupMenu实现下图效果:

在这里插入图片描述

实现思路:

1.创建PopubMenu菜单组件;

2.创建多个MenuItem菜单项,并添加到PopupMenu中;

3.将PopupMenu添加到目标组件中;

4.为需要右击出现PopubMenu菜单的组件,注册鼠标监听事件,当监听到用户释放右键时,弹出菜单。

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;public class PopupMenuDemo {Frame frame = new Frame("这里测试PopupMenu");//创建文本域TextArea ta = new TextArea("我爱中华",6,40);//创建panel容器Panel panel = new Panel();//创建PopupMenuPopupMenu popupMenu = new PopupMenu();//创建菜单项MenuItem comment = new MenuItem("注释");MenuItem cancelComment = new MenuItem("取消注释");MenuItem copy = new MenuItem("复制");MenuItem save = new MenuItem("保存");public void init() {//创建一个事件监听器ActionListener listener = new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {String actionCommand = e.getActionCommand();ta.append("您点击了:" + actionCommand + "\n");}};//每个菜单项都进行了事件处理comment.addActionListener(listener);cancelComment.addActionListener(listener);copy.addActionListener(listener);save.addActionListener(listener);//组装视图popupMenu.add(comment);popupMenu.add(cancelComment);popupMenu.add(copy);popupMenu.add(save);panel.add(popupMenu);//设置Panel的大小panel.setPreferredSize(new Dimension(400,300));//给Panel注册鼠标事件,监听用户释放鼠标的动作,展示菜单panel.addMouseListener(new MouseAdapter() {@Overridepublic void mouseReleased(MouseEvent e) {boolean flag = e.isPopupTrigger();if(flag) {//显示PopupMenupopupMenu.show(panel,e.getX(),e.getY());}}});frame.add(ta);frame.add(panel,BorderLayout.SOUTH);//设置frame最佳大小并可见frame.pack();frame.setVisible(true);}public static void main(String[] args) {new PopupMenuDemo().init();}
}

请添加图片描述

2.8 绘图

​ 很多程序如各种小游戏都需要在窗口中绘制各种图形,除此之外,即使在开发JavaEE项目时, 有 时候也必须"动态"地向客户 端生成各种图形、图表,比如 图形验证码、统计图等,这都需要利用AWT的绘图功能。

2.8.1 组件绘图原理

​ 之前我们已经学习过很多组件,例如Button、Frame、Checkbox等等,不同的组件,展示出来的图形都不一样,其实这些组件展示出来的图形,其本质就是用AWT的绘图来完成的。

​ 在AWT中,真正提供绘图功能的是Graphics对象,那么Component组件和Graphics对象存在什么关系,才能让Component绘制自身图形呢?在Component类中,提供了下列三个方法来完成组件图形的绘制与刷新:

paint(Graphics g):绘制组件的外观;

update(Graphics g):内部调用paint方法,刷新组件外观;

repaint():调用update方法,刷新组件外观;

请添加图片描述

一般情况下,update和paint方法是由AWT系统负责调用,如果程序要希望系统重新绘制组件,可以调用repaint方法完成。

手动重绘:reqaint方法

自己绘制组件:重写paint方法

2.8.2 Graphics类的使用

​ 实际生活中如果需要画图,首先我们得准备一张纸,然后在拿一支画笔,配和一些颜色,就可以在纸上画出来各种各样的图形,例如圆圈、矩形等等。

请添加图片描述

程序中绘图也一样,也需要画布,画笔,颜料等等。AWT中提供了Canvas类充当画布,提供了Graphics类来充当画笔,通过调用Graphics对象的setColor()方法可以给画笔设置颜色

画图的步骤:

1.自定义类,继承Canvas类重写paint(Graphics g)方法(桥梁)完成画图;

2.在paint方法内部,真正开始画图之前调用Graphics对象的setColor()、setFont()等方法设置画笔的颜色、字体等属性;

3.调用**Graphics画笔的drawXxx()**方法开始画图。

其实画图的核心就在于使用Graphics画笔在Canvas画布上画出什么颜色、什么样式的图形,所以核心在画笔上,下表中列出了Graphics类中常用的一些方法:

方法名称方法功能
setColor(Color c)设置颜色
setFont(Font font)设置字体
drawLine()绘制直线
drawRect()绘制矩形
drawRoundRect()绘制圆角矩形
drawOval()绘制椭圆形
drawPolygon()绘制多边形
drawArc()绘制圆弧
drawPolyline()绘制折线
fillRect()填充矩形区域
fillRoundRect()填充圆角矩形区域
fillOval()填充椭圆区域
fillPolygon()填充多边形区域
fillArc()填充圆弧对应的扇形区域
drawImage()绘制位图

案例:

​ 使用AWT绘图API,完成下图效果

请添加图片描述

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;public class SimpleDraw {private final String RECT_SHAPE = "rect";private final String OVAL_SHAPE = "oval";//组件private Frame frame = new Frame("这里测试绘图");Button btnRect = new Button("绘制矩形");Button btnOval = new Button("绘制椭圆");//定义一个变量,记录当前要绘制的是椭圆还是矩形private String shape = "";//画布//自定义类,继承Canvas类,重写paint(Graphics g)方法完成画图private class MyCanvas extends Canvas {@Overridepublic void paint(Graphics g) {//绘制不同的图形if(shape.equals(RECT_SHAPE)){//绘制矩形g.setColor(Color.black);//设置画笔的颜色为黑色g.drawRect(100,100,150,100);}else if(shape.equals(OVAL_SHAPE)){//绘制椭圆g.setColor(Color.red);g.drawOval(100,100,150,100);}}}//创建自定义的画布对象(也是组件)MyCanvas drawArea = new MyCanvas();public void init() {//组装视图btnRect.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {//修改标记的值为rectshape = RECT_SHAPE;drawArea.repaint();  //刷新重新画,不是调用paint函数}});btnOval.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {//修改标记的值为ovalshape = OVAL_SHAPE;drawArea.repaint();}});//创建面板承载按钮//Panel的默认管理器为FlowLayout,默认横向布局Panel panel = new Panel();panel.add(btnRect);panel.add(btnOval);frame.add(panel,BorderLayout.SOUTH);//画布drawArea的大小需要设置drawArea.setPreferredSize(new Dimension(300,300));frame.add(drawArea);frame.pack();frame.setVisible(true);}public static void main(String[] args) {new SimpleDraw().init();}
}

Java也可用于开发一些动画。所谓动画,就是间隔一定的时间(通常小于0 . 1秒 )重新绘制新的图像,两次绘制的图像之间差异较小,肉眼看起来就成了所谓的动画 。

​ 为了实现间隔一定的时间就重新调用组件的 repaint()方法,可以借助于 Swing 提供的Timer类,Timer类是一个定时器, 它有如下一个构造器 :
Timer(int delay, ActionListener listener): 每间隔 delay 毫秒,系统自动触发 ActionListener 监听器里的事件处理器方法,在方法内部我们就可以调用组件的repaint方法,完成组件重绘。

案例2:

​ 使用AWT画图技术及Timer定时器,完成下图中弹球小游戏。

请添加图片描述
请添加图片描述

使用键盘左右键来控制粉色球拍的水平移动,小球碰到窗口边界和球拍会反弹,并且落到球拍下方就会游戏结束并出现结束界面。

package Draw;import java.awt.*;
import java.awt.event.*;
import javax.swing.*;public class PinBall {//创建窗口对象private Frame frame = new Frame("弹球游戏");//1.设置桌面和球拍各自的宽度和高度private final int TABLE_WIDTH = 300;private final int TABLE_HEIGHT = 400;private final int RACKET_WIDTH = 60;private final int RACKET_HEIGHT = 20;//2.设置小球的大小,即小球的直径private final int BALL_SIZE = 16;//3.记录小球的坐标//注意坐标原点是窗口左上角private int ballX = 120;    //并且初始化小球的坐标private int ballY = 20;//4.设置小球在X和Y方向上分别移动的速度private int speedY = 10;private int speedX = 5;//5.记录球拍的坐标private int racketX = 120;private final int racketY = 340;       //球拍的Y坐标一直不变,即球拍一直在水平移动//6.游戏是否结束的标识private boolean isOver = false;//7.定时器:声明一个定时器private Timer timer;//8.画布:自定义一个类,继承Canvas,充当画布//只实现画面的绘制,不管游戏逻辑的变换private class MyCanvas extends Canvas {@Overridepublic void paint(Graphics g) {//TODO 在这里绘制内容if(isOver){//游戏结束g.setColor(Color.BLUE);    //设置字体颜色g.setFont(new Font("Times", Font.BOLD,30));   //设置字体样式g.drawString("游戏结束!",50,200);    //设置内容和位置(位置大概居中)}else {//游戏中//绘制小球g.setColor(Color.RED);     //设置小球的颜色g.fillOval(ballX,ballY,BALL_SIZE,BALL_SIZE);  //设置小球的坐标和大小//绘制球拍g.setColor(Color.pink);    //设置球拍的颜色g.fillRect(racketX,racketY,RACKET_WIDTH,RACKET_HEIGHT);  //设置球拍的坐标和大小}}}//9.画笔:创建绘画区域MyCanvas drawArea = new MyCanvas();public void init() {//组装视图,游戏逻辑的控制//如何控制小球和球拍的变换//10.完成球拍坐标的变化,通过键盘左右键来实现KeyListener listener = new KeyAdapter() {@Overridepublic void keyPressed(KeyEvent e) {//获取当前按下的键int keyCode = e.getKeyCode();if(keyCode == KeyEvent.VK_LEFT) { //这个KeyEvent.VK_LEFT意味这是键盘的左箭头//向左移动//TODOif(racketX <= 10) racketX = 0;else racketX -= 10;}if(keyCode == KeyEvent.VK_RIGHT) {//向右移动if(racketX > (TABLE_WIDTH - RACKET_WIDTH - 10)) racketX = TABLE_WIDTH - RACKET_WIDTH;else racketX += 10;}}};//给Frame和drawArea注册监听器frame.addKeyListener(listener);drawArea.addKeyListener(listener);//11.小球坐标的控制ActionListener task = new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {//更新小球的坐标,重绘界面//根据边界范围,修正小球的速度 ,即碰到边界会反弹if(ballX <= 0 || ballX >= (TABLE_WIDTH-BALL_SIZE)) {//碰到左边界和右边界speedX = -speedX;}if(ballY <= 0 || (ballY>racketY-BALL_SIZE && ballX>=racketX && ballX <racketX+RACKET_WIDTH)) {//碰到上边界,以及碰到球拍,判定条件是小球y>球拍y,并且小球在球拍宽度的范围内speedY = -speedY;}if(ballY>racketY-BALL_SIZE && (ballX < racketX || ballX >racketX+RACKET_WIDTH)){//当前小球超出了球拍能接到的范围,游戏结束//停止定时器timer.stop();//修改游戏结束的标记isOver = true;//重绘界面drawArea.repaint();}ballX += speedX;ballY += speedY;//重绘界面drawArea.repaint();}};timer = new Timer(100,task);  //一百毫秒执行一次timer.start();//组装界面drawArea.setPreferredSize(new Dimension(TABLE_WIDTH,TABLE_HEIGHT));frame.add(drawArea);//设置frame最佳大小和可见性frame.pack();frame.setVisible(true);}public static void main(String[] args) {new PinBall().init();}
}

2.8.3 处理位图

​ 如果仅仅绘制一些简单的几何图形,程序的图形效果依然比较单调 。 AWT 也允许在组件上绘制位图, Graphics 提供了 drawlmage() 方法用于绘制位图,该方法需要一个Image参数一一代表位图,通过该方法就可 以绘制出指定的位图 。

位图使用步骤:

1.创建Image的子类对象BufferedImage(int width,int height,int ImageType),创建时需要指定位图的宽高及类型属性;此时相当于在内存中生成了一张图片

2.调用BufferedImage对象的getGraphics()方法获取画笔缓冲区的画笔),此时就可以往内存中的这张图片上绘图了,绘图的方法和之前学习的一模一样;

3.调用组件paint方法中提供的Graphics对象(最终画布上的画笔)的drawImage()方法,一次性的内存中的图片BufferedImage绘制到特定的组件上。

使用位图绘制组件的好处:

使用位图来绘制组件,相当于实现了图的缓冲区,此时绘图时没有直接把图形绘制到组件上,而是先绘制到内存中的BufferedImage上,等全部绘制完毕,再一次性的图像显示到组件上即可,这样用户的体验会好一些。

案例:

​ 通过BufferedImage实现一个简单的手绘程序:通过鼠标可以在窗口中画图。请添加图片描述

package Draw;import javax.swing.plaf.ComboBoxUI;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;public class HandDraw {//定义窗口对象private Frame frame = new Frame("简单手绘程序");//定义画图区的宽高private final int AREA_WIDHT = 500;private final int AREA_HEIGHT = 400;//定义一个右键菜单,用于设置画笔的颜色private PopupMenu colorMenu = new PopupMenu();private MenuItem redItem = new MenuItem("红色");private MenuItem greenItem = new MenuItem("绿色");private MenuItem blueItem = new MenuItem("蓝色");//定义一个变量来记录当前画笔的颜色private Color forceColor = Color.BLACK;//创建BufferedImage位图对象,缓冲区BufferedImage image = new BufferedImage(AREA_WIDHT,AREA_HEIGHT,BufferedImage.TYPE_INT_RGB);//通过位图,获取关联的Graphics对象,画笔Graphics g = image.getGraphics();//自定义一个类来继承Canvas,画布private class MyCanvas extends Canvas {@Overridepublic void paint(Graphics g) {g.drawImage(image,0,0,null);}}MyCanvas drawArea = new MyCanvas();//定义变量,来记录鼠标拖动过程中,上一次所处的坐标private int preX = -1;private int preY = -1;public void init() {//组装视图,逻辑控制//实现右键菜单更换画笔颜色的逻辑//先创建事件监听器ActionListener listener = new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {String actionCommand = e.getActionCommand();  //获取上面的条目switch (actionCommand) {case "红色":forceColor = Color.RED;break;case "绿色" :forceColor = Color.GREEN;break;case "蓝色" :forceColor = Color.BLUE;break;}}};//将监听器添加到菜单组件中redItem.addActionListener(listener);greenItem.addActionListener(listener);blueItem.addActionListener(listener);colorMenu.add(redItem);colorMenu.add(greenItem);colorMenu.add(blueItem);//实现右键出现菜单条的逻辑//把colorMenu添加给绘图区域drawArea.add(colorMenu);//在drawArea中注册鼠标事件监听器drawArea.addMouseListener(new MouseAdapter() {@Overridepublic void mouseReleased(MouseEvent e) {  //当释放鼠标键时被调用boolean popupTrigger = e.isPopupTrigger();  //获取点击的是鼠标的哪个键if(popupTrigger) {                     //true则说明是右键colorMenu.show(drawArea,e.getX(),e.getY());}else {//倘若不是右键,则说明监听到拖动结束的标志了//重置preX和preYpreX = -1;preY = -1;}}});//实现绘图的逻辑//先设置位图的背景为白色g.setColor(Color.WHITE);g.fillRect(0,0,AREA_WIDHT,AREA_HEIGHT);//通过监听鼠标的移动,完成线条绘制drawArea.addMouseMotionListener(new MouseMotionAdapter() {//该方法,当鼠标左键按下,并进行拖动时,会被调用@Overridepublic void mouseDragged(MouseEvent e) {//注意这里是画在缓冲区//判断一下是否第一次拖动if(preX>0 && preY>0) {//画线条,需要两组坐标,分别是线条的起点和终点, e.getX()和 e.getY()可以获取鼠标坐标//这里是终点的坐标,因此需要先记录起点的坐标g.setColor(forceColor);g.drawLine(preX, preY, e.getX(), e.getY());}//修正preX和preY的值preX = e.getX();preY = e.getY();//重绘组件,到画布中drawArea.repaint();}});drawArea.setPreferredSize(new Dimension(AREA_WIDHT,AREA_HEIGHT));frame.add(drawArea);//设置窗口最佳大小和可见性frame.pack();frame.setVisible(true);}public static void main(String[] args) {new HandDraw().init();}
}

2.8.4 ImageIO的使用

在实际生活中,很多软件都支持打开本地磁盘已经存在的图片,然后进行编辑,编辑完毕后,再重新保存到本地磁盘。如果使用AWT要完成这样的功能,那么需要使用到ImageIO这个类,可以操作本地磁盘的图片文件。

方法名称方法功能
static BufferedImage read(File input)读取本地磁盘图片文件
static BufferedImage read(InputStream input)读取本地磁盘图片文件
static boolean write(RenderedImage im, String formatName, File output)往本地磁盘中输出图片文件

案例:

​ 编写图片查看程序,支持另存操作

请添加图片描述

package Draw;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;public class ReadAndSaveImage {private Frame frame = new Frame("图片查看器");//创建菜单组件MenuBar menuBar = new MenuBar();Menu menu = new Menu("文件");MenuItem open = new MenuItem("打开");MenuItem save = new MenuItem("另存为");//声明BufferedImage对象,作为缓冲区记录本地读取的内存中的图片BufferedImage image;     //不用初始化,等打开图片时再初始化//自定义类继承Canvas,把图片绘制出来private class MyCanvas extends Canvas {@Overridepublic void paint(Graphics g) {g.drawImage(image,0,0,null);}}MyCanvas drawArea = new MyCanvas();public void init() throws Exception {//组装视图//实现打开文件和保持文件的逻辑//给open组件注册监听器open.addActionListener(e ->  {       //gdk9//打开一个文件对话框FileDialog fileDialog = new FileDialog(frame,"打开图片",FileDialog.LOAD);fileDialog.setVisible(true);//获取用户选择的图片路径以及名称String dir = fileDialog.getDirectory();String fileName = fileDialog.getFile();try {image = ImageIO.read(new File(dir,fileName));drawArea.repaint();} catch (IOException ex) {throw new RuntimeException(ex);}});//给save注册监听器save.addActionListener(e -> {//打开保存图片的对话框FileDialog fileDialog = new FileDialog(frame,"保存图片",FileDialog.SAVE);fileDialog.setVisible(true);//获取用户选择的保存路径和文件名称String dir = fileDialog.getDirectory();String fileName = fileDialog.getFile();try {ImageIO.write(image,"JPEG", new File(dir,fileName));} catch (IOException ex) {throw new RuntimeException(ex);}});//将菜单组件添加到菜单条组件中menu.add(open);menu.add(save);//将菜单条组件添加到菜单条中menuBar.add(menu);//将菜单条,画布放入到窗口中frame.setMenuBar(menuBar);frame.add(drawArea);//设置窗口大小和可见性frame.setBounds(200,200,740,508);frame.setVisible(true);//监听窗口关闭frame.addWindowListener(new WindowAdapter() {@Overridepublic void windowClosing(WindowEvent e) {System.exit(0);}});}public static void main(String[] args) throws Exception {new ReadAndSaveImage().init();}
}

请添加图片描述

2.8.5 五子棋

接下来,我们使用之前学习的绘图技术,做一个五子棋的游戏。
在这里插入图片描述
注意,这个代码只实现了五子棋的落子、删除棋子和动画等逻辑实现,并没有把五子棋的游戏逻辑编写完整,比较简单易上手。

图片素材
请添加图片描述
请添加图片描述
请添加图片描述
请添加图片描述


package Draw;import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.awt.image.BufferedImage;
import java.io.File;public class Gobang {//定义五子棋游戏窗口private JFrame jframe = new JFrame("五子棋游戏"); //改动一,使用swing中的JFrame解决画面闪烁//声明四个BufferedImage对象,分别记录四张图片BufferedImage table;BufferedImage black;BufferedImage white;BufferedImage selected;//声明棋盘的宽和高(与棋盘图片的宽和高一致)private final int TABLE_WIDTH = 535;private final int TABLE_HEIGHT = 536;//声明棋盘横向和纵向分别可以下多少子,它们的值都为十五(多少行多少列)final int BOARD_SIZE =15;//声明每个棋子占用棋盘的比率final int RATE = TABLE_WIDTH/BOARD_SIZE;//声明变量记录棋子对于x方向和y方向的偏移量,在像素中量出来的final int X_OFFSET = 5;final int Y_OFFSET = 6;//声明一个二维数组,记录当前位置棋子的状态,如果索引[i][j]的值为 0-没有棋子, 1-白棋, 2-黑棋int[][] board = new int[BOARD_SIZE][BOARD_SIZE];//声明红色选择框的坐标,也是二维数组中的索引int selected_X = -1;int selected_Y = -1;//自定义类继承Canvas,充当画布private class ChessBoard extends JPanel{   //改动二,继承swing中JPanel而不是Canvas,解决画面闪烁@Overridepublic void paint(Graphics g) {//绘图//绘制棋盘g.drawImage(table,0,0,null);//绘制选择框if(selected_X>0 && selected_Y>0) //判断有移动时再开始绘制//注意索引与真实位置的转换g.drawImage(selected,selected_X*RATE+X_OFFSET,selected_Y*RATE+Y_OFFSET,null);//绘制棋子for (int i = 0; i < BOARD_SIZE; i++) {for (int j = 0; j < BOARD_SIZE; j++) {//绘制黑棋if(board[i][j] == 2) g.drawImage(black,i*RATE+X_OFFSET,j*RATE+Y_OFFSET,null);//绘制白棋if(board[i][j] == 1) g.drawImage(white,i*RATE+X_OFFSET,j*RATE+Y_OFFSET,null);}}}}ChessBoard chessBoard = new ChessBoard();//声明变量,记录当前下棋的颜色,1-白棋, 2-黑棋int board_type = 2;//声明底部需要用的组件Panel p = new Panel();Button whiteBtn = new Button("白棋");Button blackBtn = new Button("黑棋");Button deleteBtn = new Button("删除");public void refreshBtnColor(Color whitBtnColor, Color blackBtnColor, Color deleteBtnColor) {         //用来刷新按钮的颜色whiteBtn.setBackground(whitBtnColor); //setBackground来设置按钮(背景)颜色blackBtn.setBackground(blackBtnColor);deleteBtn.setBackground(deleteBtnColor);}public void init() throws Exception{//组装视图,编写逻辑//编写白棋按钮的逻辑whiteBtn.addActionListener(e->{//修改当前要下的棋子的标志为1,对应下白棋。board_type = 1;//刷新按钮的颜色refreshBtnColor(Color.GREEN,Color.GRAY,Color.GRAY);});//黑棋和清除按钮的逻辑blackBtn.addActionListener(e->{//修改当前要下的棋子的标志为2,对应下黑棋。board_type = 2;//刷新按钮的颜色refreshBtnColor(Color.GRAY,Color.GREEN,Color.GRAY);});deleteBtn.addActionListener(e->{//修改当前要下的棋子的标志为0,对应着删除board_type = 0;//刷新按钮的颜色refreshBtnColor(Color.GRAY,Color.GRAY,Color.GREEN);});//将按钮添加到面板中p.add(whiteBtn);p.add(blackBtn);p.add(deleteBtn);//将面板添加到frame的南部区域jframe.add(p,BorderLayout.SOUTH);//组装棋盘//初始化图片//这里保存图片时需要在项目里建立一个文件夹,来存放图片,不然放在其他地方好像都读不到。。table = ImageIO.read(new File("E:\\java_untitled\\calculatoe\\img\\table.jpg"));black = ImageIO.read(new File("E:\\java_untitled\\calculatoe\\img\\black.gif"));white = ImageIO.read(new File("E:\\java_untitled\\calculatoe\\img\\white.gif"));selected = ImageIO.read(new File("E:\\java_untitled\\calculatoe\\img\\selected.gif"));//处理棋盘的游戏逻辑,如红色选择框随鼠标移动,鼠标点击便下子//处理鼠标移动chessBoard.addMouseMotionListener(new MouseMotionAdapter() {//当鼠标移动时会调用该方法@Overridepublic void mouseMoved(MouseEvent e) {selected_X = (e.getX()-X_OFFSET)/RATE;//获取此时鼠标的坐标-偏移量/比率,就能得到下棋子的坐标selected_Y = (e.getY()-Y_OFFSET)/RATE;chessBoard.repaint();}});//处理鼠标点击chessBoard.addMouseListener(new MouseAdapter() {//当鼠标被点击后会调用该方法@Overridepublic void mouseClicked(MouseEvent e) {int xPos = (e.getX()-X_OFFSET)/RATE;//跟上面一样得到真实坐标int yPos = (e.getY()-Y_OFFSET)/RATE;board[xPos][yPos] = board_type;//更新坐标中的标记意味已经下子了chessBoard.repaint();}//当鼠标退出区域时,重置界面,使selected_X和selected_Y为-1@Overridepublic void mouseExited(MouseEvent e) {selected_X = -1;selected_Y = -1;chessBoard.repaint();}});chessBoard.setPreferredSize(new Dimension(TABLE_WIDTH,TABLE_HEIGHT));//设置画布jframe.add(chessBoard);//设置frame最佳大小并可见jframe.pack();jframe.setVisible(true);}public static void main(String[] args) throws Exception {new Gobang().init();}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/685085.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

交通管理|交通管理在线服务系统|基于Springboot的交通管理系统设计与实现(源码+数据库+文档)

交通管理在线服务系统目录 目录 基于Springboot的交通管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户信息管理 2、驾驶证业务管理 3、机动车业务管理 4、机动车业务类型管理 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计…

MySQL学习Day15——MySQL安装与使用

一、Linux下的MySQL的安装与使用: 卸载MySQL: 1.关闭当前MySQL服务:systemctl stop mysql.service 2.查看当前mysql安装状况:rpm -qa | grep -i mysql 3.卸载上述命令查询出的已安装的程序:yum remove mysql-xxx mysql-xxx mysql-xxxx 4.删除mysql相关文件: (1)查找相关文…

解决vscode报错,在赋值前使用了变量“XXX“

问题&#xff1a;如图所示 解决方法&#xff1a; 法一&#xff1a; 补全函数使其完整 法二&#xff1a; 使用断言

c++Qt网络操作

1、基础概念 1.1 TCP/UDP TCP 是一种面向连接的传输层协议&#xff0c;它能提供高可靠性通信(即数据无误、数据无丢失、 数据无失序、数据无重复到达的通信) 适用情况&#xff1a; 1.SN/QQ等即时通讯软件的用户登录账户管理相关的功能通常采用TCP协议 2、适合于对传输质量要求较…

【STM32 CubeMX】串口编程DMA

文章目录 前言一、DMA方式1.1 DMA是什么1.2 CubeMX配置DMA1.3 DMA方式函数使用DMA的发送接收函数 总结 前言 在嵌入式系统中&#xff0c;串口通信是一项至关重要的功能&#xff0c;它允许单片机与外部设备进行数据交换&#xff0c;如传感器、显示器或其他设备。然而&#xff0…

Linux笔记之xhost +和docker的关系以及GDK_SCALE和GDK_DPI_SCALE详解

Linux笔记之xhost 和docker的关系以及GDK_SCALE和GDK_DPI_SCALE详解 ——2024-02-11 code review! 文章目录 Linux笔记之xhost 和docker的关系以及GDK_SCALE和GDK_DPI_SCALE详解xhost 的作用xhost 与 Docker 的关系 -e GDK_SCALE 和 -e GDK_DPI_SCALE详解GDK_SCALEGDK_DPI_SC…

【Linux】进程的初步认识

进程的初步认识 基本概念描述进程task_struct-PCB的一种task_stuct内容分类 查看进程通过系统调用获取进程标识符 基本概念 要了解进程&#xff0c;首先我们要知道两点 我们可以同时启动多个程序&#xff0c;也就意味着我们可以将多个.exe文件加载到内存操作系统如何去管理这些…

036-安全开发-JavaEE应用第三方组件Log4j日志FastJson序列化JNDI注入

036-安全开发-JavaEE应用&第三方组件&Log4j日志&FastJson序列化&JNDI注入 #知识点&#xff1a; 1、JavaEE-组件安全-Log4j 2、JavaEE-组件安全-Fastjson 3、JavaEE-基本了解-JNDI-API 演示案例&#xff1a; ➢Java-三方组件-Log4J&JNDI ➢Java-三方组件-Fa…

OpenAI全新发布文生视频模型Sora - 现实,不存在了

OpenAI&#xff0c;发他们的文生视频大模型&#xff0c;Sora了。。。。。 而且&#xff0c;是强到&#xff0c;能震惊我一万年的程度。。。 https://openai.com/sora 如果非要用三个词来总结Sora&#xff0c;那就是“60s超长长度”、“单视频多角度镜头”和“世界模型” &am…

Codeforces Round 926 (Div. 2)(A,B,C,D,E,F)

这场还是很有含金量的&#xff0c;B题开始就有难度了&#xff0c;B是个推结论的题&#xff0c;C要推结论然后递推&#xff0c;D题是有点难的树上DP&#xff08;主要是状态转移方程不好写&#xff09;&#xff0c;E题是个二进制预处理然后状压DP&#xff0c;F题是个数论&#xf…

写一个程序,输入数量不确定的[0,9]范围内的整数,统计每一种数字出现的次数输入-1表示结束

#include <stdio.h> int main(void) {int x;int count[10];int i;for(i0;i<10;i){//初始化数组 count[i]0;}scanf("%d",&x);while(x!-1){if( x>0 && x<9){count[x];//数组参与运算 }scanf("%d",&x);}for(i0;i<10;i){pr…

车载诊断协议DoIP系列 —— 车辆以太网节点需求汇总

车载诊断协议DoIP系列 —— 车辆以太网节点需求汇总 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师(Wechat:gongkenan2013)。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 本就是小人物,输了就是输了,不要在意别人怎么看自己。江湖一碗茶,…

安装 Windows Server 2003

1.镜像安装 镜像安装:Windows Server 2003 2.安装过程(直接以图的形式呈现) 按Enter(继续),继续后F8继续 直接Enter安装 下一步 秘钥:GM34K-RCRKY-CRY4R-TMCMW-DMDHM 等待安装成功即可

JavaWeb

一、技术栈 【1】 前端部分 HTML CSS JavaScript ES6 Nodejs npm vite vue3 router pinia axios element-plus … 【2】 后端部分 HTTP xml Tomcat Servlet Request Response Cookie Sesssion Filter Listener MySQL JDBC Druid Jackson lombok jwt … 二、JAVAWEB交互模…

【知识整理】产研中心岗位评定标准之大数据岗位

为贯彻执行集团数字化转型的需要,该知识库将公示集团组织内各产研团队不同角色成员的职务“职级”岗位的评定标准; 一、定级定档目的 通过对公司现有岗位及相应岗位员工的工作能力、工作水平进行客观公正评定,确定各岗位的等级及同等级岗位员工对应的档级,从而为员工以后的晋升…

三种输入输出函数

目录 printf函数 scanf函数 getchar函数 putchar函数 gets函数 puts函数 printf函数 当你需要将数据或文本输出到屏幕或其他输出设备时&#xff0c;C语言提供了一个非常有用的函数&#xff0c;即 printf() 函数。它是标准库中定义的函数&#xff0c;用于格式化输出。 pr…

React 的调度系统 Scheduler

原文地址1 原文地址2 其中startTime是任务开始的时间&#xff0c;默认是-1&#xff0c;任务开始时将任务开始时间赋值给了startTime&#xff0c; 这里意思是判断这个任务执行时间是否超过5ms(写死的)。若超过&#xff0c;则要交出。

Linux platform tree下的单总线驱动程序设计(DHT11)

目录 概述 1 认识DHT11 1.1 DHT11特性 1.2 DHT11数据格式 1.3 DHT11与MCU通信 1.4 DHT11信号解析 1.4.1 起始信号 1.4.2 解析信号0 1.4.3 解析信号1 2 驱动开发 2.1 硬件接口 2.2 更新设备树 2.2.1 添加驱动节点 2.2.2 编译.dts 2.2.3 更新板卡中的.dtb 2.3 驱…

【Git】上传本地文件到Git(以Windows环境为例)

Git 的下载参考&#xff1a;Git 安装及配置 一、Git 上传的整体流程 1、工作区 > 本地仓库 将本地文件上传到Git&#xff0c;需要先上传到本地仓库&#xff0c;然后再上传到远程仓库。要上传文件到本地仓库&#xff0c;不是直接拷贝进去的&#xff0c;而是需要通过命令一步…

【Linux网络编程六】服务器守护进程化Daemon

【Linux网络编程六】服务器守护进程化Daemon 一.背景知识&#xff1a;前台与后台二.相关操作三.Linux的进程间关系四.自成会话五.守护进程四步骤六.服务器守护进程化 一.背景知识&#xff1a;前台与后台 核心知识就是一个用户在启动Linux时&#xff0c;都会给一个session会话&a…