Swing框架之Component:续文二

         Swing的事件处理过程为:事件调度线程(Event Dispatch Thread)从事件队列(EventQueue)中获取底层系统捕获的原生事件,如鼠标、键盘、焦点、PAINT事件等。接着调用该事件源组件的 dispachEvent。该方法过滤出特殊事件后,调用processEvent进行处理。processEvent方法根据事件类型调用注册在这个组 件上的相应事件处理器函数。事件处理器函数根据这些事件的特征,判断出用户的期望行为,然后根据期望行为改变组件的状态,然后根据需要刷新组件外观,触发 带有特定语义的高级事件。此事件继续传播下去,直至调用应用程序注册在该组件上的处理器函数。下图是这个过程的示意图:

 

         上图所示意的过程简要说就是:

Pump an Event->Dispatch & Process Event->MouseListener.mousePressed->fireActionPerformed->ActionListener.actionPeformed->Do database query and display result to a table->Return from actionPerformed->Return from fireActionPerformed->Return from MouseListener.mousePressed->Pump another Event.

         事件调度线程在应用程序事件处理函数actionPerformed没有完成之前是不能处理下一个事件的,如果应用程序处理函数是一个时间复杂的任务(比 如查询数据库并将结果显示到表格中),后面包括PAINT事件将在长时间内得不到执行。由于PAINT事件负责将界面更新,所以这就使用户界面失去响应。

          打一个比方,事件处理线程就像进入某城唯一的单行道一样,事件相当于汽车。有种PAINT汽车负责为城市运输非常重要的生活物资。但是有一天,PAINT 前面有一辆汽车突然坏掉了,司机下来修车。但是这车太难修,一修就是几天,结果后面的PAINT汽车无法前进,物资无法按时运到城里。市民急了,市长虽然 不停的打电话催PAINT公司,但即使PAINT公司多添加几辆车也没用。由于进城的唯一条路被那辆车给占着,所以再多的PAINT车也只能堵在路上。

         不了解Swing的这种事件处理模型的人往往将时间复杂的任务放在处理函数中完成,这是造成Swing应用程序速度很慢的原因。用户触发这个动作,用户界 面就失去了响应,于是给用户的感觉就是Swing太慢了。其实这个错误是程序员造成的,并不是Swing的过失。

         说点题外话,所有采用这种事件模型的用户界面工具都会产生这种问题,包括SWT、GTK、MFC等流行的用户界面工具。之所以只有Swing被误解,主要是和Swing的历史、市场时机、商业宣传策略和心理学相关的。

         首先Swing的历史和市场时机极差。Swing出现早期性能也差、错误也多,而Java程序员脱身于传统图形界面工具,对于Swing这种新的事件处理 模型并不太了解,而此时正处于Java第一轮狂热的时期,大家都满怀希望做了大量的Swing应用程序,而这些程序中大量存在这种错误方法。于是市场上涌 现了大批的这种程序。自从那个时代,因为这些程序,Swing被贴上了慢的标签。又由于当时的Swing界面也丑,和一般的Windows程序风格炯异, 更加深人们的这种印象。这种印象一直持续到现在,像烙印一样深深的刻在人们的脑海里。

           其次,Swing还有一个致命的问题,就是没有涌现出一个具有标识性的好程序,这是造成它比SWT印象惨的原因。为什么SWT采用相同的事件处理模型,而 获得了速度快的声誉呢?这是因为人们当时对于Java做桌面应用的期望心理达到了低谷,而SWT的出现恰恰是伴随Eclipse出现的,早期的 Eclipse的确是在速度快、界面漂亮,这一扫当时人们认为Java慢,Java界面丑陋,Java无法做桌面应用的印象,继而这个印象被加在SWT身 上,人们认为Eclipse速度快、漂亮是因为SWT,其实如果你知道Swing/SWT事件处理模型的话,你就明白功劳是Eclipse开发者的, Eclipse界面漂亮其实要归功于Eclipse界面设计专家,他们的高水平造就了这个好的IDE,从而也抬起了SWT的声誉。而Swing的名誉恰恰 就被早期Swing低水平开发者给毁了。

        再次, 这和商业宣传策略有关。IBM和Eclipse很懂得市场宣传,人们不是认为Java慢吗,就宣传SWT使用原生组件,人们不是认为Swing丑陋、风格 炯异吧,就宣传SWT风格一致性,人们不是认为Java不能做桌面应用吗,就宣传基于SWT的Eclipse。其实这一切的背后原因只是“人”的不同, Eclipse的开发者和Swing应用程序的开发者,Swing和SWT技术差异并没有造成那么大的差别,如果是相近能力的人使用他们开发的话,应该能 做出相近的产品。这可以从现在Eclipse和NetBeans、Intellij IDEA、JDeveloper和JBuilder看的出来。

         最后,人类有一个心理学现象,就是一旦形成对某种事物的印象,很难摆脱旧的认识,有时甚至人们不愿意承认摆在眼前的事实。总而言之,Swing和SWT不同遭遇是因为历史、市场时机、商业宣传策略、心理学的种种原因造成的。

          那么如何避免这个问题,编写响应速度快的Swing应用程序呢?在SwingWorker的javadoc中有这样两条原则:

Time-consuming tasks should not be run on the Event Dispatch Thread. Otherwise the application becomes unresponsive. 耗时任务不要放到事件调度线程上执行,否则程序就会失去响应。

Swing components should be accessed on the Event Dispatch Thread only. Swing组件只能在事件调度线程上访问。

         因此处理耗时任务时,首先要启动一个专门线程,将当前任务交给这个线程处理,而当前处理函数立即返回,继续处理后面未决的事件。这就像前面塞车的例子似的,那个司机只要简单的把车开到路边或者人行道上修理,整个公路系统就会恢复运转。

         其次,在为耗时任务启动的线程访问Swing组件时,要使用SwingUtilties. invokeLater或者SwingUtilities.invokeAndWait来访问,invokeLater和invokeAndWait的参 数都是一个Runnable对象,这个Runnable对象将被像普通事件处理函数一样在事件调度线程上执行。这两个函数的区别是, invokeLater不阻塞当前任务线程,invokeAndWait阻塞当前线程,直到Runnable对象被执行返回才继续。在前面塞车的例子中, 司机在路边修车解决了塞车问题,但是他突然想起来要家里办些事情,这时他就可以打个电话让家里开车来。假如修车不受这件事情的影响,比如叫家人送他朋友一 本书,他可以继续修车,这时就相当于invokeLater;假如修车受影响,比如缺少某个汽车零件,叫家人给他送过来,那么在家人来之前,他就没法继续 修车,这时就相当于invokeAndWait。

         下面举一个例子说明这两点,比如按下查询按钮,查询数据量很大的数据库,并显示在一个表中,这个过程需要给用户一个进度提示,并且能动态显示表格数据动态增加的过程。假设按钮的处理函数是myButton_actionPerformed,则:

void myButton_actionPerformed(ActionEvent evt){
     new MyQueryTask().start();
}
public class MyQueryTask extends Thread{
    public void run(){
        //查询数据库
        final ResultSet result=...;
       / /显示记录
      for(;result.next();){
          //往表的Model中添加一行数据,并更新进度条,注意这都是访问组件
         SwingUtilities.invokeLater(new Runnable(){
              public void run(){
                    addRecord(result);
              }
         });
      }
   ....
   }
   void addRecord(ResultSet result){
       //往表格中添加数据
       jTable.add....
      //更新进度条
      jProgress.setValue(....);
    }
}

         JDK1.6以后,Swing提供了一个专门的类SwingWorker能帮你解决这个编程范式,你所需要做的就是继承这个类,重载 doInBackground,然后在actionPeformed中调用它的execute方法,并通过publish/process方法来更新界 面。SwingWorker的主要方法和它们的作用在下面的示意图:

          从上面示意图可以看出,SwingWorker实际上不过是封装了前面我所说的例子中的MyQueryTask,并做了更详尽的考虑。execute方法 相当于MyQueryTask线程start,它启动这个后台线程并立刻返回。SwingWorker可以注册 PropertyChangeListener,这些listener都被在事件调度线程上执行,相当于MyQueryTask中的那些访问组件的 Runnable对象。另外,publish、setProgress只不过是特殊的property事件吧,process和done不过是响应 publish和PropertyChangeEvent.DONE这个事件的方法罢了。因此我们很容易将上面的例子改成SwingWorker的版本:

void myButton_actionPerformed(ActionEvent evt){
    new MyQueryTask().execute();
}

public class MyQueryTask extends SwingWorker{
    public void doInBackground(){
        //查询数据库
        final ResultSet result=...;
        //显示记录
        for(;result.next();){
            //往表的Model中添加一行数据,并更新进度条,注意这都是访问组件
            publish(result);
        }
        ....
    }
    public void process(Object ... result){
        //往表格中添加数据
        jTable.add....
        //更新进度条
        jProgress.setValue(....);
    }
}

         对于一般的耗时任务这样做是比较普遍的,但是有一些任务是一旦触发之后,会周期性的触发,如何做处理这种任务呢?JDK中提供了两个Timer类帮你完成 定时任务,一个是javax.swing.Timer,一个java.util.Timer。使用它们的方法很简单,对于Swing的timer,使用方 法如下:

public void myActionPerformed(){
    //假设点击了某个按钮开始记时
    Action myAction=new AbstractAction(){
        public void actionPerformed(ActionEvent e){
            //做周期性的活动,比如显示当前时间
            Date date=new Date();
            jMyDate.setDate(date);//jMyDate是个假想的组件,能显示日期时间
        }
    };
    new Timer(1000, myAction).start();
}

         java.util.Timer类似,只不过使用TimerTask完成动作封装。注意这两个Timer有一个关键的区别:Swing的Timer的事件 处理都是在事件调度线程上进行的,因而它里面的操作可以直接访问Swing组件。而java.util.Timer则可能在其他线程上,因而访问组件时要 使用SwingUtilities.invokeLater和invokeAndWait来进行。这一点要记住。

         如果要了解更详细的信息,可以查阅SwingWorker、Swing Timer和util Timer这些类javadoc文档和其他网上资料。最重要的是要记住了那两条原则。

Java Swing大神必经之路17:Component 请求此 Component 获取输入焦点,并且此 Component 的顶层祖先成为获得焦点的 Window。此 Component 对于所要许可的请求而言必须是不可显示的、可聚焦的和可见的并且其所有祖先(除了顶层 Window 以外)必须是可见的。此方法会尽力完成该请求;但是在某些情况下可能无法完成。在此 Component 接收 FOCUS_GAINED 事件前,开发人员永远不能假定此 Component 是焦点所有者。如果由于此 Component 的顶层 Window 没有成为获得焦点的窗口而拒.. 阅读详情

相关推荐

UE5导入MetaHuman虚拟头像后,连接live link face,面部表情捕捉出错修正

UE5 利用live link face 驱动meta human面部表情捕捉

m0_53122690的博客 6595

Swing框架之Component:续文一

Swing框架之Component:续文一 (2007-01-09 21:30:56) 转载▼   分类: Swing          昨晚回去后还是觉得Component对象本身说的太简单,想来想去,觉得内容实在是太多,有必要补充两个续文说明Component的其它概念。今天介绍Swing组件paint方法的处理流程,这个流程能使我们理解许

。。。。。。。 1555

机器学习-02 模型的评估与选择

2.1 误差与过拟合 我们将学习器对样本的实际预测结果与样本的真实值之间的差异成为:误差(error)。定义: 在训练集上的误差称为训练误差(training error)或经验误差(empirical error)。 在测试集上的误差称为测试误差(test error)。 学习器在所有新样本上的误差称为泛化误差(generalization error)。 显然,我们希望得到的是在新样本上表现得很好的学习器,即泛化误差小的学习器。因此,我们应该让学习器尽可能地从训练集中学出普适性的“一般特征”,这

一个小白 1703

Swing框架之Component:续文三

Swing框架之Component:续文三 Swing事件与事件处理器模型          Component在Swing模型中是事件触发源。前一篇文章在描述Swing的事件处理模型时就已经提到了这个事件处理过程。简单来说,Swing组 件在侦听到原生事件并处理后,往往产生新的逻辑事件。逻辑事件是某些组件所特有的、具有特定语义的事件,比如JButton按下时产生 ActionEvent...

topinking的专栏 202

保姆级教程:在Ubuntu 22.04上搞定PX4 V1.14 + ROS2 Humble的HITL仿真(避坑实录)

本文提供在Ubuntu 22.04上配置PX4 V1.14与ROS2 Humble的HITL仿真环境的详细教程,涵盖环境准备、固件编译、QGroundControl配置、ROS2通信设置及联调测试。特别针对版本兼容性、Gazebo插件构建和MicroDDS配置等常见问题提供避坑指南,帮助开发者高效搭建无人机仿真系统。

weixin_30836759的博客 1001

特征提取 Features Extraction

介绍了特征提取的基本概念,从分类变量,文本信息和图片信息中进行特征提取的方法,以及实现特征提取的类库

JasonH2021的博客 1万+

Swing框架之Component

Component在Swing的MVC模型中担任Controller的角色,同时它也是SwingAPI中代表具体组件的对象。Component在Swing中对外负责提供API接口,对内负责协调控制Model和UIDelegate(有时可能还包括Renderer)的操作,可以说是整个Swing结构的中心角色。为了方便你回忆Swing的MVC模型,将Swing模型示意图引了过来:

expleeve 3608

从扇束到平行束:等角重排算法在CT重建中的核心原理与MATLAB实践

本文深入解析了CT图像重建中等角扇束重排算法的核心原理与MATLAB实现。通过将实际采集的扇束投影数据,利用几何映射和两次关键插值,转换为适用于经典滤波反投影算法的平行束数据,打通了高效重建的关键路径。文章结合Shepp-Logan模型仿真,提供了完整的MATLAB代码实践,并分析了源-物距、采样率等关键参数对重建质量的影响。

cnn8visionary的博客 647

java Swing Component

所有 Swing 组件(如按钮、窗口、面板)的“老祖宗”都是。都能作为对话框的父组件参数!所有 Swing 组件都是。

wu_android的博客 220

数字化车间智能排产调度挑战赛(一)—— 数学模型

科大讯飞——数字化车间智能排产调度挑战赛。

Lyyyp的博客 5649

从大疆智图到Cesium:3D Tiles模型加载与Web三维场景构建实战

本文详细介绍了如何利用大疆智图生成3D Tiles数据,并通过Cesium在Web端实现高效加载与三维场景构建。从大疆智图参数设置到Cesium环境配置,再到3D Tiles性能调优与高级功能实现,提供了一套完整的实战指南,帮助开发者快速掌握3D Tiles模型加载与Web三维场景构建技术。

weixin_30520015的博客 1285

How to Write a Custom Swing Component

How to Write a Custom Swing Component February 22, 2007 Kirill Grouchnikov     Contents Basic Building Blocks The Component Class: UI Delegate Plumbing The Model I...

myNameAbian的专栏 367

解决群晖NAS无法拉取docker镜像问题

在2024-06-01日以前,使用SSH登录后是可以直接拉取docker镜像的;但是之后当我们使用SSH登录上群晖NAS,使用【sudo -i】切换到超管拉取镜像会提示报错【error pulling image configuration: Get "https://production.cloudflare.docker.com/registry-v2/docker/registry/v2/blobs/sha256/cf/cff6b68a194a672fd337d8728bfb252071012cce6

提供C#相关开发 、云计算、运维测试、网络安全相关技术分享与服务,有意向可联系。 2万+

java component类_Swing Component类

boolean action(Event evt, Object what) - Deprecated. As of JDK version 1.1, should register this component as ActionListener on the component which fires action events.void add(PopupMenu popup) - Adds...

weixin_42497762的博客 512

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

java getcomponents()_Java Swing - 如何创建getComponentAt()从JFrame获取Component

import java.awt.BorderLayout;import java.awt.Color;import java.awt.Component;import java.awt.Container;import java.awt.Point;import javax.swing.BorderFactory;import javax.swing.JFrame;import javax.swi...

weixin_33050129的博客 664

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Swing component使用方式

<br />在使用Swing中JFrame、JPanel及其他Composite组件时有两种方式。<br /> <br />1, 新建一个类并继承此类组件,然后在新的类中向其中添其他组件。<br />      例如 <br />      Class AKindJFrame extends JFrame {<br />             AKindJFrame(){<br />                 Container contents = getContentPane();<br /> 

Jinuxwu的专栏 1483

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Swing简单边框(Border)设置

最近重温了下Swing ,写个Border记录下,Border在Swing界面美化这块比较好用,界面的美化还真离不开Border。 快速开发简单Border 步骤: 1、创建Component设置Border 2、创建simpleJpane 添加Component 3、创建JFrame  添加 simpleJpane 代码如下:package border; packag

it小虾米的专栏 2万+

什么是Swing,什么又是lightweight component

 什么是Swing,什么又是lightweight component          ---》Swing是JFC中的一部分,现在已被列入JAVA标准类库里面!JFC是Java Foundation Classes的缩写,其功能是提供程序设计者设计图形用户界面用的,JFC主要包括下面的5个部分:            1,AWT组件:旧有的窗口组件包            2,Swing组件,...

开发笔记 482

Swing框架学习

Swing是JFC的一部分 Swing提供窗口,按钮,表格等一系列控件; Swing是纯JAVA写的。 例如:JButton,JCheckBox,JScrollbar等都是JComponent的子类; 可以理解为JComponent是控件的超类; 上代码初学,可能还有理解不到位的地方: import java.awt.*; import java.awt.event.*; import...

大风起兮云飞扬 474

[原创]Swing技巧.6:Component中设置光标

 [原创]Swing技巧.6:Component中设置光标//java.awt.Component中设置光标,Component,Window,Frame,JWindow,JFrame,Dialog,JDialogjava.awt.Toolkit toolkit=Toolkit.getDefaultToolkit();java.awt.Image image=toolkit.g

病菌集中营 2278
上一篇: Swing框架之Component
下一篇: Swing框架之Component:续文三
topinking
博客等级 码龄20年 15粉丝 242原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值