JavaGUI(二)——组件
有无示例代码取决于作者想不想练
AWT中常用组件
基本组件
组件名 | 功能 |
---|---|
Button | 按钮 |
Canvas | 用于绘图的画布 |
Checkbox | 复选框组件(也可当做单选框组件使用) |
CheckboxGroup | 用于将多个Checkbox组件组合成一组,一组Checkbox组件将只有一个可以被选中,即全部变成单选框组件 |
Choice | 下拉选择框 |
Frame | 窗口,在GUI程序里通过该类创建窗口 |
Label | 标签类,用于放置提示性文本 |
List | 列表框组件,可以添加多条目 |
Panel | 不能单独存在基本容器类,必须放到其他容器中 |
Scrollbar | 滑动条组件,如果需要用户输入谓语某个范围的值,就可以使用滑动条组件,比如调色板中设置RGB的三个值所用的滑动条。当创建一个滑动条时,必须指定它的方向,初始值、滑块大小,最小值和最大值。 |
ScrollPane | 带水平以及垂直滚动条的容器组件 |
TextArea | 多行文本域 |
TextField | 单行文本框 |
示例代码:
public class Demo01 { static TextArea text = new TextArea(5,50); static Choice choice = new Choice(); static CheckboxGroup cg = new CheckboxGroup(); static Checkbox male = new Checkbox("male",true,cg); static Checkbox female = new Checkbox("female",false,cg); static Checkbox married = new Checkbox("married?"); static List list = new List(); static TextField textField = new TextField(); static Button btn = new Button("confirm"); public static void main(String[] args){ initComponent(); showView(); } static void initComponent(){ list.add("red"); list.add("green"); list.add("blue"); choice.add("red"); choice.add("green"); choice.add("blue"); } static void showView(){ Box box1 = Box.createVerticalBox(); Box box1_box1 = Box.createHorizontalBox(); Box box1_box2 = Box.createHorizontalBox(); box1.add(box1_box1); box1.add(box1_box2); Box box1_box1_box1 =Box.createVerticalBox(); box1_box1.add(box1_box1_box1); box1_box1_box1.add(text); Box box1_box1_box1_box = Box.createHorizontalBox(); box1_box1_box1.add(box1_box1_box1_box); box1_box1_box1_box.add(male); box1_box1_box1_box.add(female); box1_box1_box1_box.add(married); box1_box1_box1_box.add(choice); box1_box1.add(list); Box box1_box2_box = Box.createHorizontalBox(); box1_box2.add(box1_box2_box); box1_box2_box.add(textField); box1_box2_box.add(btn); Frame frame = new Frame("测试窗口"); frame.add(box1); frame.pack(); frame.setVisible(true); } }
对话框Dialog
Dialog
Dialog是Window类的子类,是一个容器类,属于特殊组件。对话框是可以独立存在的顶级窗口,因此用法与普通窗口的用法几乎完全一样,但是使用对话框需要注意下面两点:
- 对话框通常依赖于其他窗口,就是通常需要有一个父窗口;
- 对话框有非模式(non-modal)和模式(modal)两种,当某个模式对话框被打开后,该模式对话框总是位于它的父窗口之上,在模式对话框被关闭之前,父窗口无法获得焦点。
方法名称 | 方法功能 |
---|---|
Dialog(Frame owner,String title,boolean modal) | 创建一个对话框对象: owner:当前对话框的父窗口 title:当前对话框的标题 modal:当前对话框是否是模式对话框,true/false |
FileDialog
Dialog类还有一个子类:FileDialog,它代表一个文件对话框,用于打开或者保存文件,需要注意的是Filedialog无法指定模态或者非模态,这是因为FileDIalog依赖于运行平台的实现,如果运行平台的文件对话框都是模态的,那么FileDialog也是模态的;否则就是非模态的。
方法名称 | 方法功能 |
---|---|
FileDialog(Frame parent,String title,int mode) | 创建一个文件对话框: parent:指定父窗口 title:对话框标题 mode:文件对话框类型,如果指定为FileDialog.LOAD,用于打开文件,如果指定为FileDialog.SAVE,用于保存文件 |
String getDirectory() | 获取被打开或保存文件的绝对路径 |
String getFile() | 获取被打开或保存文件的文件名 |
事件处理
前面学习了如何防止各种组件,从而得到了丰富多彩的图形界面,但这些界面还不能响应用户的任何操作。比如单击前面所有窗口右上角的“X”按钮,但窗口依然不会关闭。因为在AWT编程中,所有用户的操作,都必须经过一套事件处理机制来完成,而Frame和组件本身并没有事件处理能力。
GUI事件处理机制
定义:当在某个组件上发生某些操作的时候,会自动触发一段代码的执行。
在GUI事件处理机制中设计到4个重要的概念需要理解:
事件源(Event Source):操作发生的场所,通常指某个组件,例如按钮、窗口等;
事件(Event):在事件源上发生的操作可以叫做对象,GUI会把事件都封装到一个Event对象中,如果需要知道该事件的详细信息,就可以通过Event对象来获取。
事件监听器(Event Listener):当某个事件源上发生了某个事件,事件监听器就可以对这个事件进行处理。
注册监听:把某个事件监听器(A)通过某个事件(B)绑定到某个事件源(C)上,当在事件源C上发生了实践B之后,那么事件监听器A的代码就会自动执行。
使用步骤:
- 创建事件源组对象;
- 自定义类,实现XXXListener接口,重写方法;
- 创建事件监听器对象(自定义类对象)
- 调用事件源组件对象的addXXXListener方法完成注册监听
GUI中常见事件和事件监听器
事件监听器必须实现事件监听接口,AWT提供了大量的时间监听器用于实现不同类型的事件监听器,用于监听不同类型的事件。AWT中提供了丰富的事件类,用于封装不同组件上所有发生的特点操作,AWT的事件类都是AWTEvent类的子类,AWTEvent是EventObject的子类。
事件
AWT把事件分为了两大类:
- 低级事件:这类事件是基于某个特定动作的事件。比如进入、点击、拖放等动作的鼠标事件。比如进入、点击拖放等动作的鼠标事件,再比如得到焦点和失去焦点等焦点事件。
事件 | 触发时机 |
---|---|
ComponentEvent | 组件事件,当组件尺寸发生变化、位置发生移动、显示/隐藏状态发生改变时触发该事件。 |
Container | 容器事件,当容器里发生添加组件、删除组件时触发该事件。 |
WindowEvent | 窗口事件,当窗口状态发生改变(如打开、关闭、最大化、最小化)时触发该事件。 |
FocusEvent | 焦点事件,当组件得到焦点或失去焦点时触发该事件。 |
KeyEvent | 键盘事件,当按键被按下、松开、单击时触发该事件。 |
MouseEvent | 鼠标事件,当进行点击、按下、松开、移动鼠标等动作时触发该事件。 |
PaintEvent | 组件绘制事件,该事件是一个特殊的事件类型 |
- 高级事件:这类事件并不会基于某个特定动作,而是根据功能含义定义的事件。
事件 | 触发时机 |
---|---|
ActionEvent | 动作时间,当按钮、菜单项被单击,在TextField中安Enter键时触发 |
AjustmentEvent | 条件事件,在滑动条上移动滑块以调节数值时触发该事件。 |
ItemEvent | 选项事件,当用户选中某项,或取消选中某项时触发该事件。 |
TextEvent | 文本事件,当文本框、文本域的文本发生变化时触发该事件。 |
事件监听器
不同的事件需要使用不同的监听器监听,不同的监听器需要实现不同的监听器接口,当指定事件发生后,事件监听器就会调用所包含的事件处理器(实例方法)来处理事件。
事件类别 | 描述信息 | 监听器接口名 |
---|---|---|
ActionEvent | 激活组件 | ActionListener |
ItemEvent | 选择了某些项目 | ItemListener |
MouseEvent | 鼠标移动 | MouseMotionListener |
MouseEvent | 鼠标点击等 | MouseListener |
KeyEvent | 键盘输入 | KeyListener |
FocusEvent | 组件收到或失去焦点 | FocusListener |
AdjustmentEvent | 移动了滚动条等组件 | AdjustmentListener |
ComponentEvent | 对象移动缩放显示隐藏等 | ComponentListener |
WindowEvent | 窗口收到窗口级事件 | WindowListener |
TextEvent | 文本字段或文本区发生改变 | TextListener |
菜单组件
构建GUI界面,其实就是把一些GUI组件,按照一定的布局放入到容器中展示就可以了。在实际开发中,除了主界面,还有一类比较重要的内容就是菜单相关组件,可以通过菜单相关组件很方便地使用特定的功能,在AWT中,菜单相关组件的使用和之前学习的组件时一模一样的,只需要把菜单条、菜单、菜单项组合到一起,按照一定的布局,放入容器中即可。
菜单组件名称 | 功能 |
---|---|
MenuBar | 菜单条,菜单的容器 |
menu | 菜单组件,菜单项的容器。它是MenuItem的子类,所以可作为菜单项使用 |
PopupMenu | 上下文菜单组件(右键菜单组件) |
MenuItem | 菜单项组件 |
CheckboxMenuItem | 复选框菜单项组件 |
菜单相关组件使用:
- 准备菜单项组件,这些组件可以是MenuItem及其子类对象
- 准备菜单组件Menu或者PopupMenu(右击弹出子菜单),把第一步中准备好的菜单项组件添加进来;
- 准备菜单条组件MenuBar,把第二步中准备好的菜单组件Menu添加进来;
- 把第三步中准备好的菜单条组件添加到窗口对象中显示。
小技巧:
- 如果要在某个菜单的菜单项之间添加分割线,那么只需要调用Menu的
add(new MenuItem("-"))
即可。 - 如果要给某个菜单项关联快捷键功能,那么只需要在创建菜单项对象时设置即可,例如给菜单项关联Ctrl+shift+Q快捷键,只需要:
new MenuItem("菜单项名字",new MenuShortcut(KeyEvent.VK Q,true));
示例代码如下:
public class Demo05 { public static void main(String[] args){ new Demo05().init(); } public void init(){ Frame frame = new Frame(); frame.setBounds(300,300,500,300); MenuBar menuBar = new MenuBar(); Menu file = new Menu("File"); Menu edit = new Menu("Edit"); Menu format = new Menu("Format"); MenuItem autoWrap = new MenuItem("Auto Wrap"); MenuItem copy = new MenuItem("Copy"); MenuItem paste = new MenuItem("Paste"); MenuItem comment = new MenuItem("Comment ",new MenuShortcut(KeyEvent.VK_Q,true)); MenuItem cancelComment = new MenuItem("Cancel Comment" ); frame.setMenuBar(menuBar); menuBar.add(file); menuBar.add(edit); edit.add(autoWrap); edit.add(copy); edit.add(paste); edit.add(new MenuItem("-")); edit.add(format); format.add(comment); format.add(cancelComment); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.setVisible(true); } }
绘图
很多程序如各种游戏都需要在窗口中绘制各种图形,除此之外,即使在开发JavaEE项目时,有时候也必须“动态”地向客户端生成各种图形、图标,比如 图形验证码、统计图形等,这些都需要利用AWT的绘图功能。
组件绘图原理
之前我们所学的组件,例如Button、Frame等等,这些组件展示出来的图形,其本质就是用AWT的绘图来完成的。
在AWT中,真正提供绘图功能的是Graphics对象,那么Component组件和Graphics对象存在什么关系,才能让Component绘制自身图形呢?在Component类中,提供了下列三个方法来完成组件图形的绘制与刷新;
paint(Graphics g): 绘制组件的外观;
update(Graphics g):内部调用paint方法,刷新组件外观;
repain():调用update方法,刷新组件外观;
一般情况下,update和paint方法时由AWT系统负责调用,如果程序要希望系统重新绘制组件,可以调用repaint方法完成。
Graphics对象的使用
AWT中提供了Canvas类充当画布,提供了Graphics类来充当画笔,通过调用Graphics对象的setColor()方法可以给画笔设置颜色。
画图的步骤:
- 自定义类,继承Canvas类,重写paint(Graphics g)方法完成画图;
- 在paint方法内部,真正开始画图之前调用Graphics对象的setColor()、setFont()等方法设置画笔颜色、字体等属性;
- 调用Graphics画笔的drawXxx()方法开始画图。
其实画图的核心在于使用Graphics画笔在Canvas画布上画出什么颜色、什么样式的图形,所以核心在画笔上,下表中列出了Graphics类中常用的一些方法:
方法名称 | 方法功能 |
---|---|
setColor(Color c) | 设置颜色 |
setFont(Font font) | 设置字体 |
drawLine() | 绘制直线 |
drawRect() | 绘制矩形 |
drawRoundRect() | 绘制圆角矩形 |
drawOval() | 绘制椭圆形 |
drawPolygon() | 绘制多边形 |
drawArc() | 绘制圆弧 |
drawPolyline() | 绘制折线 |
fillRect() | 填充矩形区域 |
fillOval() | 填充椭圆区域 |
fillPolygon() | 填充多边形区域 |
fillArc() | 填充圆弧对应的扇形区域 |
drawImage() | 绘制位图 |
绘图示例代码:
public class Demo01 { private static Graphics gra = null; public static void main(String[] args){ init(); } static class MyCanvas extends Canvas { @Override public void paint(Graphics g) { gra = g; g.drawOval(200 ,200,200,100); g.setColor(Color.red); } } static void init(){ Frame frame = new Frame(); MyCanvas mc = new MyCanvas(); Panel p = new Panel(); mc.setPreferredSize(new Dimension(500,500)); frame.add(p); p.add(mc); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.pack(); frame.setVisible(true); } }
Java也可以用于开发一些动画。所谓的动画,就是间隔一定事件(通常小于0.1秒)重新绘制新的图像,两次绘制的图像之间差异较小,肉眼看起来就成了所谓的动画。
为了实现间隔一定的时间就重新调用组件的repaint()方法,可以借助与Swing提供的TImer类,Timer类时一个定时器,它由如下一个构造器:
Timer(int delay,ActionListener listener):每隔delay毫秒,系统就会自动触发ActionListener监听器里的事件处理器方法,在方法内部我们就可以调用组件的repaint方法,完成组件重绘。
处理位图
如果仅仅绘制一些简单的几何图形,程序的图形效果依然比较单调。AWT也允许在组件上绘制位图,Graphics提供了drawImage(Image image)方法用于绘制位图,该方法需要一个Image参数——代表位图,通过该方法就可以绘制出指定的位图。
位图使用步骤:
- 创建Image的子类对象BufferedImage(int width,int height,int ImageType),创建时需要指定位图的宽高及类型属性;此时相当于在内存中生成了一张图片;
- 调用BufferedImage对象的getGraphics()方法获取画笔,此时就可以往内存中的这张图片上绘图了,绘图的方法和之前学习的一模一样;
- 调用组件paint方法中提供的Graphics对象的drawImage()方法,一次性的内存中的图片BufferedImage绘制到特定的组件上。
使用位图绘制组件的好处:
使用位图阿里绘制组件,相当于实现了图的缓冲区,此时绘图时没有直接把图形绘制到组件上,而是先绘制到内存中的BufferedImage上,等全部绘制完毕,再一次的图像显示到组件上即可,这样用户的体验会好一些。
示例代码:
public class Demo02 { Frame frame = new Frame("画布"); // 设置绘图区的宽高 private final int AREA_WIDTH = 500; private final int AREA_HEIGHT = 400; // 定义一个右键菜单,用于更改颜色 private PopupMenu contextMenu = new PopupMenu(); private MenuItem redItem = new MenuItem("RED"); private MenuItem greenItem = new MenuItem("GREEN"); private MenuItem blueItem = new MenuItem("BLUE"); private MenuItem Clean = new MenuItem("CLEAN"); // 定义一个用于记录画笔颜色的变量 private Color forceColor = Color.black; // 创建一个BufferedImage位图对象 BufferedImage image = new BufferedImage(AREA_WIDTH,AREA_HEIGHT,BufferedImage.TYPE_INT_RGB); // 通过位图,获取关联的Graphics对象 Graphics g = image.createGraphics(); // 自定义一个类,继承Canvas private class MyCanvas extends Canvas{ @Override public 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() { @Override public void actionPerformed(ActionEvent e) { switch (e.getActionCommand()){ case "RED": forceColor = Color.red; break; case "GREEN": forceColor = Color.green; break; case "BLUE": forceColor = Color.BLUE; break; case "CLEAN": g.setColor(Color.white); g.fillRect(0,0,AREA_WIDTH,AREA_HEIGHT); drawArea.repaint(); break; default: break; } if(!e.getActionCommand().equals("CLEAN")){ System.out.println("当前颜色是:"+e.getActionCommand()); } } }; redItem.addActionListener(listener); greenItem.addActionListener(listener); blueItem.addActionListener(listener); Clean.addActionListener(listener); contextMenu.add(redItem); contextMenu.add(greenItem); contextMenu.add(blueItem); contextMenu.add(Clean); // 把colorMenu设置给区域 drawArea.add(contextMenu); drawArea.addMouseListener(new MouseAdapter() { @Override // 鼠标点击释放事件 public void mouseReleased(MouseEvent e) { // PopupTrigger代表点击了弹出菜单键,也就是右键 boolean popupTrigger = e.isPopupTrigger(); if(popupTrigger){ contextMenu.show(drawArea,e.getX(),e.getY()); } preX = -1; preY = -1; } }); g.setColor(Color.white); g.fillRect(0,0,AREA_WIDTH,AREA_HEIGHT); drawArea.addMouseMotionListener(new MouseMotionAdapter() { // 鼠标拖拽(滑动) @Override public void mouseDragged(MouseEvent e) { // 鼠标拖拽使触发 if(preX>=0&&preY>=0){ g.setColor(forceColor); g.drawLine(preX,preY,e.getX(),e.getY()); } preY = e.getY(); preX = e.getX(); drawArea.repaint(); } }); // 设置画布大小 drawArea.setPreferredSize(new Dimension(AREA_WIDTH,AREA_HEIGHT)); frame.add(drawArea); frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.exit(0); } }); frame.pack(); frame.setVisible(true); } public static void main(String[] args){ new Demo02().init(); } }
ImageIO的使用
在实际生活中,很多软件偶支持打开本地磁盘已经存在的图片,然后进行编辑,编辑完毕,在重新保存到本地磁盘。如果使用AWT要完成这样的功能,那么需要使用到ImageIO这个类,可以操作本地磁盘的图片文件。
方法名称 | 方法功能 |
---|---|
static BufferedImage read(File input) | 读取本地磁盘图片文件 |
static BufferedImage read(InputStream input) | 读取本地磁盘图片文件 |
static boolean write(RenderedImage im, String formatName,File output) | 往本地磁盘中输出图片文件 |
本文来自博客园,作者:maplerain,转载请注明原文链接:https://www.cnblogs.com/maplerain/p/16667744.html 博主B站
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通