Java 中文官方教程 2022 版(二十)(3)

简介: Java 中文官方教程 2022 版(二十)

Java 中文官方教程 2022 版(二十)(2)https://developer.aliyun.com/article/1486750

使用LayerUI

LayerUI类大部分行为都继承自ComponentUI类。以下是最常重写的方法:

  • 当目标组件需要绘制时,会调用paint(Graphics g, JComponent c)方法。为了以与 Swing 相同的方式呈现组件,调用super.paint(g, c)方法。
  • 当你的LayerUI子类与一个组件关联时,会调用installUI(JComponent c)方法。在这里执行任何必要的初始化。传入的组件是相应的JLayer对象。使用JLayer类的getView()方法检索目标组件。
  • 当你的LayerUI子类不再与给定组件关联时,会调用uninstallUI(JComponent c)方法。如果需要,进行清理。

在组件上绘制

要使用JLayer类,你需要一个良好的LayerUI子类。最简单的LayerUI类改变了组件的绘制方式。例如,这里有一个在组件上绘制透明颜色渐变的示例。

class WallpaperLayerUI extends LayerUI<JComponent> {
  @Override
  public void paint(Graphics g, JComponent c) {
    super.paint(g, c);
    Graphics2D g2 = (Graphics2D) g.create();
    int w = c.getWidth();
    int h = c.getHeight();
    g2.setComposite(AlphaComposite.getInstance(
            AlphaComposite.SRC_OVER, .5f));
    g2.setPaint(new GradientPaint(0, 0, Color.yellow, 0, h, Color.red));
    g2.fillRect(0, 0, w, h);
    g2.dispose();
  }
}

paint()方法是自定义绘制发生的地方。调用super.paint()方法会绘制JPanel对象的内容。在设置了 50%透明度的合成后,绘制颜色渐变。

定义了LayerUI子类之后,使用它很简单。这里是一些使用WallpaperLayerUI类的源代码:

import java.awt.*;
import javax.swing.*;
import javax.swing.plaf.LayerUI;
public class Wallpaper {
  public static void main(String[] args) {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        createUI();
      }
    });
  }
  public static void createUI() {
    JFrame f = new JFrame("Wallpaper");
    JPanel panel = createPanel();
    LayerUI<JComponent> layerUI = new WallpaperLayerUI();
    JLayer<JComponent> jlayer = new JLayer<JComponent>(panel, layerUI);
    f.add (jlayer);
    f.setSize(300, 200);
    f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
    f.setLocationRelativeTo (null);
    f.setVisible (true);
  }
  private static JPanel createPanel() {
    JPanel p = new JPanel();
    ButtonGroup entreeGroup = new ButtonGroup();
    JRadioButton radioButton;
    p.add(radioButton = new JRadioButton("Beef", true));
    entreeGroup.add(radioButton);
    p.add(radioButton = new JRadioButton("Chicken"));
    entreeGroup.add(radioButton);
    p.add(radioButton = new JRadioButton("Vegetable"));
    entreeGroup.add(radioButton);
    p.add(new JCheckBox("Ketchup"));
    p.add(new JCheckBox("Mustard"));
    p.add(new JCheckBox("Pickles"));
    p.add(new JLabel("Special requests:"));
    p.add(new JTextField(20));
    JButton orderButton = new JButton("Place Order");
    p.add(orderButton);
    return p;
  }
}

这是结果:


源代码:

Wallpaper NetBeans 项目

Wallpaper.java

使用Java Web Start运行:


LayerUI类的paint()方法让你完全控制组件的绘制方式。这里是另一个LayerUI子类,展示了如何使用 Java 2D 图像处理修改面板的整个内容:

class BlurLayerUI extends LayerUI<JComponent> {
  private BufferedImage mOffscreenImage;
  private BufferedImageOp mOperation;
  public BlurLayerUI() {
    float ninth = 1.0f / 9.0f;
    float[] blurKernel = {
      ninth, ninth, ninth,
      ninth, ninth, ninth,
      ninth, ninth, ninth
    };
    mOperation = new ConvolveOp(
            new Kernel(3, 3, blurKernel),
            ConvolveOp.EDGE_NO_OP, null);
  }
  @Override
  public void paint (Graphics g, JComponent c) {
    int w = c.getWidth();
    int h = c.getHeight();
    if (w == 0 || h == 0) {
      return;
    }
    // Only create the off-screen image if the one we have
    // is the wrong size.
    if (mOffscreenImage == null ||
            mOffscreenImage.getWidth() != w ||
            mOffscreenImage.getHeight() != h) {
      mOffscreenImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
    }
    Graphics2D ig2 = mOffscreenImage.createGraphics();
    ig2.setClip(g.getClip());
    super.paint(ig2, c);
    ig2.dispose();
    Graphics2D g2 = (Graphics2D)g;
    g2.drawImage(mOffscreenImage, mOperation, 0, 0);
  }
}

paint()方法中,面板被渲染到一个离屏图像中。离屏图像使用卷积运算符进行处理,然后绘制到屏幕上。

整个用户界面仍然活跃,只是模糊了:


源代码:

Myopia NetBeans 项目

Myopia.java

使用Java Web Start运行:


响应事件

你的LayerUI子类也可以接收其对应组件的所有事件。然而,JLayer实例必须注册对特定类型事件的兴趣。这是通过JLayer类的setLayerEventMask()方法实现的。通常情况下,这个调用是在LayerUI类的installUI()方法中进行初始化时进行的。

例如,以下摘录显示了一个LayerUI子类的部分内容,该子类注册接收鼠标和鼠标移动事件。

public void installUI(JComponent c) {
  super.installUI(c);
  JLayer jlayer = (JLayer)c;
  jlayer.setLayerEventMask(
    AWTEvent.MOUSE_EVENT_MASK |
    AWTEvent.MOUSE_MOTION_EVENT_MASK
  );
}

所有发送到你的JLayer子类的事件都会路由到一个事件处理方法,其名称与事件类型匹配。例如,你可以通过重写相应的方法来响应鼠标和鼠标移动事件:

protected void processMouseEvent(MouseEvent e, JLayer l) {
  // ...
}
protected void processMouseMotionEvent(MouseEvent e, JLayer l) {
  // ...
}

以下是一个LayerUI子类,它在面板内鼠标移动时绘制一个半透明的圆圈。

class SpotlightLayerUI extends LayerUI<JPanel> {
  private boolean mActive;
  private int mX, mY;
  @Override
  public void installUI(JComponent c) {
    super.installUI(c);
    JLayer jlayer = (JLayer)c;
    jlayer.setLayerEventMask(
      AWTEvent.MOUSE_EVENT_MASK |
      AWTEvent.MOUSE_MOTION_EVENT_MASK
    );
  }
  @Override
  public void uninstallUI(JComponent c) {
    JLayer jlayer = (JLayer)c;
    jlayer.setLayerEventMask(0);
    super.uninstallUI(c);
  }
  @Override
  public void paint (Graphics g, JComponent c) {
    Graphics2D g2 = (Graphics2D)g.create();
    // Paint the view.
    super.paint (g2, c);
    if (mActive) {
      // Create a radial gradient, transparent in the middle.
      java.awt.geom.Point2D center = new java.awt.geom.Point2D.Float(mX, mY);
      float radius = 72;
      float[] dist = {0.0f, 1.0f};
      Color[] colors = {new Color(0.0f, 0.0f, 0.0f, 0.0f), Color.BLACK};
      RadialGradientPaint p =
          new RadialGradientPaint(center, radius, dist, colors);
      g2.setPaint(p);
      g2.setComposite(AlphaComposite.getInstance(
          AlphaComposite.SRC_OVER, .6f));
      g2.fillRect(0, 0, c.getWidth(), c.getHeight());
    }
    g2.dispose();
  }
  @Override
  protected void processMouseEvent(MouseEvent e, JLayer l) {
    if (e.getID() == MouseEvent.MOUSE_ENTERED) mActive = true;
    if (e.getID() == MouseEvent.MOUSE_EXITED) mActive = false;
    l.repaint();
  }
  @Override
  protected void processMouseMotionEvent(MouseEvent e, JLayer l) {
    Point p = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), l);
    mX = p.x;
    mY = p.y;
    l.repaint();
  }
}

mActive变量指示鼠标是否在面板坐标内。在installUI()方法中,调用setLayerEventMask()方法来指示LayerUI子类对接收鼠标和鼠标移动事件的兴趣。

processMouseEvent()方法中,根据鼠标位置设置mActive标志。在processMouseMotionEvent()方法中,鼠标移动的坐标存储在mXmY成员变量中,以便稍后在paint()方法中使用。

paint()方法显示了面板的默认外观,然后叠加了一个径向渐变以实现聚光灯效果:


源代码:

Diva NetBeans Project

Diva.java

使用Java Web Start运行:


动画繁忙指示器

这个示例是一个动画繁忙指示器。它展示了在LayerUI子类中的动画,并具有淡入和淡出效果。它比之前的示例更复杂,但基于相同的原则定义了一个用于自定义绘制的paint()方法。

点击下订单按钮,查看 4 秒钟的繁忙指示器。注意面板变灰并且指示器旋转。指示器的元素具有不同程度的透明度。

LayerUI子类WaitLayerUI类展示了如何触发属性更改事件以更新组件。WaitLayerUI类使用Timer对象以每秒 24 次的速度更新其状态。这是在计时器的目标方法actionPerformed()中完成的。

actionPerformed()方法使用firePropertyChange()方法指示内部状态已更新。这会触发对applyPropertyChange()方法的调用,该方法重新绘制JLayer对象:


源代码:

TapTapTap NetBeans 项目

TapTapTap.java

使用 Java Web Start 运行:


验证文本字段

本文档中的最后一个示例展示了如何使用 JLayer 类装饰文本字段,以显示它们是否包含有效数据。虽然其他示例使用 JLayer 类来包装面板或一般组件,但此示例显示了如何专门包装 JFormattedTextField 组件。它还演示了单个 LayerUI 子类实现可以用于多个 JLayer 实例。

JLayer 类用于为具有无效数据的字段提供视觉指示。当 ValidationLayerUI 类绘制文本字段时,如果字段内容无法解析,它会绘制一个红色的 X。以下是一个示例:


源代码:

FieldValidator NetBeans 项目

FieldValidator.java

使用 Java Web Start 运行:


如何使用动作

原文:docs.oracle.com/javase/tutorial/uiswing/misc/action.html

Action可用于将功能和状态与组件分离。例如,如果有两个或更多执行相同功能的组件,请考虑使用Action对象来实现该功能。Action对象是一个 action listener,不仅提供动作事件处理,还提供对动作事件触发组件的状态的集中处理,例如工具栏按钮、菜单项、常用按钮和文本字段。动作可以处理的状态包括文本、图标、助记键、启用和选定状态。

通常使用setAction方法将动作附加到组件。当在组件上调用setAction时会发生什么:

  • 组件的状态会更新以匹配Action的状态。例如,如果Action的文本和图标值已设置,则组件的文本和图标将设置为这些值。
  • Action对象在组件上注册为动作监听器。
  • 如果Action的状态发生变化,组件的状态将更新以匹配Action。例如,如果更改动作的启用状态,则所有附加到它的组件将更改其启用状态以匹配动作。

这里有一个示例,创建一个工具栏按钮和菜单项,执行相同的功能:

Action leftAction = new LeftAction(); *//LeftAction code is shown later*
...
button = new JButton(leftAction)
...
menuItem = new JMenuItem(leftAction);

要创建一个Action对象,通常创建AbstractAction的子类,然后实例化它。在子类中,必须实现actionPerformed方法,在动作事件发生时做出适当反应。这里有一个创建和实例化AbstractAction子类的示例:

leftAction = new LeftAction("Go left", anIcon,
             "This is the left button.",
             new Integer(KeyEvent.VK_L));
...
class LeftAction extends AbstractAction {
    public LeftAction(String text, ImageIcon icon,
                      String desc, Integer mnemonic) {
        super(text, icon);
        putValue(SHORT_DESCRIPTION, desc);
        putValue(MNEMONIC_KEY, mnemonic);
    }
    public void actionPerformed(ActionEvent e) {
        displayResult("Action for first button/menu item", e);
    }
}

当前面的代码创建的动作附加到按钮和菜单项时,按钮和菜单项将显示与动作关联的文本和图标。按钮和菜单项上使用L字符作为助记键,并且它们的工具提示文本设置为SHORT_DESCRIPTION字符串,后跟助记键的表示。

例如,我们提供了一个简单的示例,ActionDemo.java,定义了三个操作。每个操作都附加到一个按钮和一个菜单项。由于为每个按钮的操作设置了助记符值,按键序列Alt-L激活左按钮,Alt-M激活中间按钮,Alt-R激活右按钮。左按钮的工具提示显示这是左按钮。Alt-L. 所有这些配置都是自动完成的,程序不需要显式调用设置助记符或工具提示文本。正如我们稍后将展示的,程序确实调用设置按钮文本,但只是为了避免使用操作已设置的值。



试试这个:

  1. 点击“启动”按钮以使用Java™ Web Start运行 ActionDemo(下载 JDK 7 或更高版本)。或者,要自行编译和运行示例,请参考示例索引。

  2. 从左侧菜单中选择顶部项目(菜单 > 向左)。
    文本区域显示一些文本,标识事件源和接收事件的操作监听器。
  3. 点击工具栏中最左边的按钮。
    文本区域再次显示有关事件的信息。请注意,尽管事件的来源不同,但两个事件都是由相同的操作监听器检测到的:附加到组件的Action对象。
  4. 操作状态菜单中选择顶部项目。
    这将禁用“向左”Action对象,进而禁用其关联的菜单项和按钮。

当“向左”操作被禁用时,用户看到的情况如下:

这是禁用“向左”操作的代码:

boolean selected = ...//*true if the action should be enabled;*
                      //*false, otherwise*
leftAction.setEnabled(selected);

在使用Action创建组件后,您可能需要自定义它们。例如,您可能希望通过添加或删除图标或文本来自定义其中一个组件的外观。例如,ActionDemo.java的菜单中没有图标,按钮中也没有文本。以下是实现此目的的代码:

menuItem = new JMenuItem();
menuItem.setAction(leftAction);
menuItem.setIcon(null); //arbitrarily chose not to use icon in menu
...
button = new JButton();
button.setAction(leftAction);
button.setText(""); //an icon-only button

我们选择通过将图标属性设置为null,将文本设置为空字符串,从同一个操作中创建一个仅图标的按钮和一个仅文本的菜单项。然而,如果Action的属性发生变化,小部件可能会尝试再次从Action中重置图标和文本。

Java 中文官方教程 2022 版(二十)(4)https://developer.aliyun.com/article/1486752

相关文章
|
9天前
|
Java 测试技术 Python
《手把手教你》系列技巧篇(二十九)-java+ selenium自动化测试- Actions的相关操作上篇(详解教程)
【4月更文挑战第21天】本文介绍了Selenium中处理特殊测试场景的方法,如鼠标悬停。Selenium的Actions类提供了鼠标悬停功能,用于模拟用户在网页元素上的悬停行为。文中通过实例展示了如何使用Actions悬停并展开下拉菜单,以及在搜索时选择自动补全的字段。代码示例包括了打开百度首页,悬停在“更多”元素上显示下拉菜单并点击“音乐”,以及在搜索框输入关键词并自动补全的过程。
33 0
|
2天前
|
Java 测试技术 Python
《手把手教你》系列技巧篇(三十六)-java+ selenium自动化测试-单选和多选按钮操作-番外篇(详解教程)
【4月更文挑战第28天】本文简要介绍了自动化测试的实战应用,通过一个在线问卷调查(&lt;https://www.sojump.com/m/2792226.aspx/&gt;)为例,展示了如何遍历并点击问卷中的选项。测试思路包括找到单选和多选按钮的共性以定位元素,然后使用for循环进行点击操作。代码设计方面,提供了Java+Selenium的示例代码,通过WebDriver实现自动答题。运行代码后,可以看到控制台输出和浏览器的相应动作。文章最后做了简单的小结,强调了本次实践是对之前单选多选操作的巩固。
10 0
|
2天前
|
Java 测试技术 项目管理
Java基础教程(22)-构建工具Maven的基本使用
【4月更文挑战第22天】Maven是Java项目管理及构建工具,简化构建、测试、打包和部署等任务。遵循约定优于配置原则,核心是`pom.xml`配置文件,用于管理依赖和项目信息。安装涉及下载、解压、配置环境变量。在IDEA中使用Maven创建项目,通过`pom.xml`添加依赖和管理版本。常用命令包括`clean`、`compile`、`test`、`package`、`install`和`deploy`。IDEA支持直接执行这些命令。
|
2天前
|
NoSQL Java 关系型数据库
Java基础教程(21)-Java连接MongoDB
【4月更文挑战第21天】MongoDB是开源的NoSQL数据库,强调高性能和灵活性。Java应用通过MongoDB Java驱动与之交互,涉及MongoClient、MongoDatabase、MongoCollection和Document等组件。连接MongoDB的步骤包括:配置连接字符串、创建MongoClient、选择数据库和集合。伪代码示例展示了如何建立连接、插入和查询数据。
|
3天前
|
存储 前端开发 测试技术
《手把手教你》系列技巧篇(三十五)-java+ selenium自动化测试-单选和多选按钮操作-下篇(详解教程)
【4月更文挑战第27天】本文介绍了使用Java+Selenium进行Web自动化测试时,如何遍历和操作多选按钮的方法。文章分为两个部分,首先是一个本地HTML页面的示例,展示了多选按钮的HTML代码和页面效果,并详细解释了遍历多选按钮的思路:找到所有多选按钮的共同点,通过定位这些元素并放入list容器中,然后使用for循环遍历并操作。 第二部分介绍了在JQueryUI网站上的实战,给出了被测网址,展示了代码设计,同样使用了findElements()方法获取所有多选按钮并存储到list中,然后遍历并进行点击操作。最后,文章对整个过程进行了小结,并推荐了作者的其他自动化测试教程资源。
11 0
|
3天前
|
Java 关系型数据库 MySQL
Java基础教程(20)-Java连接mysql数据库CURD
【4月更文挑战第19天】MySQL是流行的关系型数据库管理系统,支持SQL语法。在IDEA中加载jar包到项目类路径:右击项目,选择“Open Module Settings”,添加库文件。使用JDBC连接MySQL,首先下载JDBC驱动,然后通过`Class.forName()`加载驱动,`DriverManager.getConnection()`建立连接。执行CRUD操作,例如创建表、插入数据和查询,使用`Statement`或`PreparedStatement`,并确保正确关闭数据库资源。
|
4天前
|
设计模式 算法 Java
Java基础教程(19)-设计模式简述
【4月更文挑战第19天】设计模式是软件设计中反复使用的代码设计经验,旨在提升代码的可重用性、可扩展性和可维护性。23种模式分为创建型、结构型和行为型三类。创建型模式如工厂方法、抽象工厂、建造者、原型和单例,关注对象创建与使用的分离。结构型模式涉及对象组合,如适配器、装饰器、外观等,增强结构灵活性。行为型模式专注于对象间职责分配和算法合作,包括责任链、命令、观察者等。设计模式提供标准化解决方案,促进代码交流和复用。
|
4天前
|
前端开发 测试技术 Python
《手把手教你》系列技巧篇(三十三)-java+ selenium自动化测试-单选和多选按钮操作-上篇(详解教程)
【4月更文挑战第25天】本文介绍了自动化测试中如何处理单选和多选按钮的操作,包括它们的定义、HTML代码示例以及如何判断和操作这些元素。文章通过一个简单的HTML页面展示了单选和多选框的示例,并提供了Java+Selenium实现的代码示例,演示了如何检查单选框是否选中以及如何进行全选操作。
11 0
|
5天前
|
网络协议 Java 网络架构
Java基础教程(18)-Java中的网络编程
【4月更文挑战第18天】Java网络编程简化了底层协议处理,利用Java标准库接口进行TCP/IP通信。TCP协议提供可靠传输,常用于HTTP、SMTP等协议;UDP协议则更高效但不保证可靠性。在TCP编程中,ServerSocket用于监听客户端连接,Socket实现双进程间通信。UDP编程中,DatagramSocket处理无连接的数据报文。HTTP编程可以通过HttpURLConnection发送请求并接收响应。
|
6天前
|
前端开发 Java 测试技术
《手把手教你》系列技巧篇(三十二)-java+ selenium自动化测试-select 下拉框(详解教程)
【4月更文挑战第24天】本文介绍了在自动化测试中处理HTML下拉选择(select)的方法。使用Selenium的Select类,可以通过index、value或visible text三种方式选择选项,并提供了相应的取消选择的方法。此外,文章还提供了一个示例HTML页面(select.html)和相关代码实战,演示了如何使用Selenium进行选择和取消选择操作。最后,文章提到了现代网页中类似下拉框的新设计,如12306网站的出发地选择,并给出了相应的代码示例,展示了如何定位并选择特定选项。
16 0