模态框的学习

假设存在这样场景:我登录lol页面的时候,一区人很多,我连着点登陆,客户端没给我反应。竟然没反应,然后我就疯狂点登陆,假设lol服务器无法处理这种重复命令,那么lol的服务器反应过来的时候,可能我已经点了n次登陆了,那么服务器就要处理很多没有意义的登陆指令。这是一个假设,是为了说明,用户操作的不当,会造成服务器雪上加霜的情况。
所以我们就要设计一个东西,来阻止用户的无理取闹,我的方式就是用模态框,当你进行点击登陆操作后,弹出一个模态框,对于模态框外面的界面,你不能在点了!模态框显示正在帮你处理,你别着急,这就有效的处理了刚才假设的情况。
下面贴一个模态框的代码:
继承自JDialog 类,当创建这个对象时,当传入参数是true时,表示这是一个模态框。

public class MDialog extends JDialog {private static final long serialVersionUID = -3666711423943333589L;public MDialog(Frame owner, boolean modal) {super(owner, modal);}public MDialog(Dialog owner, boolean modal) {super(owner, modal);}public MDialog(Frame owner, String title, boolean modal) {super(owner, title, modal);}public MDialog(Dialog owner, String title, boolean modal) {super(owner, title, modal);}public MDialog setCaption(String context) {Font font = new Font("宋体", Font.BOLD, 16);int width = (context.length() + 4) * font.getSize();int height = 5 * font.getSize();setSize(width, height);setLocationRelativeTo(getOwner());setLayout(null);setUndecorated(true);JPanel jpnlMessage = new JPanel();jpnlMessage.setSize(width, height);jpnlMessage.setLayout(new BorderLayout());jpnlMessage.setBackground(Color.lightGray);jpnlMessage.setBorder(BorderFactory.createLineBorder(Color.gray, 2));add(jpnlMessage);JLabel jlblMessage = new JLabel(context, JLabel.CENTER);jlblMessage.setFont(font);jlblMessage.setSize(width, height);jlblMessage.setForeground(Color.blue);jlblMessage.setHorizontalTextPosition(JLabel.CENTER);jpnlMessage.add(jlblMessage, BorderLayout.CENTER);dealAction();return this;}public void dealAction() {}public void showDialog(){setVisible(true);}public void closeDialog() {dispose();}
}

外面调用的时候就是这样:

MDialog mDialog = new MDialog(mainView, "温馨提示", true);
mDialog.showDialog();
System.out.println("连接成功");

这里有一个坑,这个连接成功不会打印,因为当主线程执行setVisible(true);之后主线程就被阻塞了,jvm会运行模态框中的代码,所以在哪里关闭模态框是一个大问题。这还没完,假如我们要根据主线程中的条件来关闭模态框,而主线程又是被阻塞的,那么就得不到关闭模态框的相关信息,这就矛盾了。有人说用一个新的线程来运行这个模态框,我试过是不行的,但是具体是哪里的问题,我没搞明白。

所以我用了另一种方式:
把主线程要做的事,放到了模态框的事件处理中,当执行完了主线程的代码,他根据事件关闭模态框。

模态框的一个应用

给一个新的应用场景:
现在我需要通过客户端登陆服务器,而这个连接方式采用短连接,短连接的实现方式就是用RMI即客户端调用服务器的远程方法。当客户端输入账号和密码后,点击登陆,服务器反应比较慢。所以我希望用模态框来组织用户继续点击这个登陆按钮,如下图的登陆按钮。

这是登陆界面的代码,当用户点击按钮后,触发事件执行这个方法。

private void dealUserLogin() {jbtnLogin.setEnabled(false);//获得框框中账号和密码String id = jtxtUserName.getText();String password = new String(jpswPassword.getPassword());//获得接口的代理对象IUserAction proxyClass = rmiClient.JDKProxy(IUserAction.class,jfrmLogin,"正在登陆中...请稍后");//调用代理对象的方法UserInfo user = proxyClass.userLogin(id, password);//user是服务器返回的结果,根据这个结果判断这个用户符不符合登陆要求。if (user.getId().equalsIgnoreCase("ERROR")) {ViewTool.showError(jfrmLogin, user.getNick());jpswPassword.setText("");jtxtUserName.selectAll();jtxtUserName.requestFocus();return;}jbtnLogin.setEnabled(true);}

获得接口代理对象的代码,仔细看能发现,这个代理对象中都没有对方法的拦截和对方法参数的改变,和以往我们对代理的认知完全不同,在这个仅仅是把方法的参数传给模态框,并且显示这个模态框的操作。而代理真正对于方法的调用确实在这个模态框的事件中

@SuppressWarnings({ "unchecked", "unused" })        //这是一种特殊情况下的获得代理的操作public <T> T JDKProxy(Class<?> interfacer,JFrame jFrame,String caption) {ClassLoader classLoader = interfacer.getClassLoader();Class<?>[] interfaces = new Class<?>[] { interfacer };return (T) Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {RMIDialog rmiDialog = new RMIDialog(jFrame, caption, true);rmiDialog.setMethodInvoke(methodInvoke).setArgs(args).setCaption(caption).setMethod(method);rmiDialog.showDialog();return rmiDialog.getResult();}});}

看模态框事件中,调用方法的代码,这里是真正执行的rmi操作,即把方法名和方法所需要的参数传递到了服务器,服务器解析然后调用对应方法返回结果。这个result就是服务器返回的结果。

public void dealAction() {addFocusListener(new FocusAdapter() {@Overridepublic void focusGained(FocusEvent e) {//这里真正执行rmi的操作result = methodInvoke.methodInvoke(object, method, args);closeDialog();}});}

可以看一下RMI调用方法的过程,服务器的解析代码就不贴了。

public class DialogMethodInvoke implements IMethodInvoke{private String rmiIp;private int rmiPort;public DialogMethodInvoke() {}void setRmiIp(String rmiIp) {this.rmiIp = rmiIp;}void setRmiPort(int rmiPort) {this.rmiPort = rmiPort;}public <T> T methodInvoke(Object object, Method method, Object[] args) {Socket socket = null;DataInputStream dis = null;DataOutputStream dos = null;try {socket = new Socket(rmiIp,rmiPort);dis = new DataInputStream(socket.getInputStream());dos = new DataOutputStream(socket.getOutputStream());dos.writeUTF(method.toString());dos.writeUTF(getArgs(args));//远程调用服务器端方法的返回值String str = dis.readUTF();Type type = method.getGenericReturnType();@SuppressWarnings("unchecked")T res = (T)ArgumentMaker.gson.fromJson(str, type);return res;} catch (UnknownHostException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}finally {if(dis != null) {try {dis.close();} catch (IOException e) {e.printStackTrace();}}if(dos != null) {try {dos.close();} catch (IOException e) {e.printStackTrace();}}if(socket != null && !socket.isClosed()) {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}return null;}private String getArgs(Object[] args) {if(args == null) {return "";}ArgumentMaker argumentMaker = new ArgumentMaker();for(int i = 0; i< args.length; i++) {argumentMaker.add("args"+i, args[i]);}return argumentMaker.toString();}
}

总结一下,模态框的线程问题还是很棘手的。把真正执行代码放到模态框的事件中,有一种取巧的感觉,还是有必要写个博客记录一下。
再一个就是,对于代理模式思路的开辟,代理模式下,不一定就要把对于方法的拦截和参数修改都写在获得代理对象中,我们还可以更加灵活地操作,比如我只是在里面显示了一个模态框。

巧妙处理Swing模态框setVisible(true)线程阻塞的问题相关推荐

  1. 模态框的学习——巧妙处理setVisible(true)的阻塞问题

    1)模态框的简单介绍 模态对话框(Modal Dialogue Box,又叫做模式对话框),是指在用户想要对对话框以外的应用程序进行操作时,必须首先对该对话框进行响应.如单击[确定]或[取消]按钮等将 ...

  2. bootstrap——模态框

    目录 模态框  类似js中alert(); 1.模态框的主样式:modal 2.模态框的代码最好是直接作为body的子元素,而不是后代元素 3.模态框的区域: 4.与Bootstrap.js中的相关属 ...

  3. Silverlight+WCF 实战-网络象棋最终篇之非线程阻塞倒计时窗口(四)

    前言: 在前面的系列中,我们虽然完成了其大部分功能,但是,离正真运行,还是有一大段距离 当你F5运行时,在弹出对话框之后,如果你不即时点确定,或者上个WC回来之后,你会发现已经提示出错了 这节开始,我 ...

  4. swing中模态对话框(setModal(true))和显示对话框(setVisible(true))的编写顺序

    今天给大家分享一个鄙人在编程中总结出的一个易错点和最容易让人感到困惑的一个知识点: 当你要从一个窗体跳转到另一个窗体,你把跳转目标的窗体设成模态对话框,设计成模态对话框就是禁止父窗体与子窗体之间操作, ...

  5. java swing中setVisible(true)方法的真正作用

    setVisible(true);方法的意思是说数据模型已经构造好了,允许JVM可以根据数据模型执行paint方法开始画图并显示到屏幕上了,并不是显示图形,而是可以运行开始画图了.这个方法和java多 ...

  6. html弹窗赋值给查询框,bootstrap模态框动态赋值, ajax异步请求数据后给id为queryInfo的模态框赋值并弹出模态框(JS)...

    /查询单个 function query(id) { $.ajax({ url : "/small/productServlet", async : true, type : &q ...

  7. java gui 单选_java GUI编程(swing)之三swing单选框复选框组件

    swing复选框(JCheckBox) 单选框(JRadioButton) 特别说明:同一组单选按钮,必须先创建一个ButtonGroup,然后把单选按钮放到ButtonGroup 中 package ...

  8. java swing 列表框_如何在Swing中使用列表框?

    下面的示例展示了如何在Java Swing应用程序中使用标准列表框. 使用以下API - JList - 创建标准列表. JList.setSelectedIndex(index); - 选择项目. ...

  9. java swing做输入框,java Swing 文本框的使用

    /** * Java Swing 文本框控件 * @author gao */ package com.gao; import java.awt.GridLayout; import javax.sw ...

最新文章

  1. sql当等INSERT之后获取主键值
  2. 先进pid控制matlab仿真程序,先进PID控制Matlab仿真第4版-仿真程序-上交
  3. nyoj 12(区间覆盖)
  4. 基于@Bean声明lazy-queue
  5. Spring中的Events
  6. 转载:DataTable使用技巧总结
  7. 【开发者成长】每个人都在编写草率代码
  8. 使用 jQuery Mobile 与 HTML5 开发 Web App (四) —— jQuery Mobile 表单上
  9. 红橙Darren视频笔记 界面优化与屏幕适配(上)
  10. vscode 注释插件
  11. java内存管理(适合初学者)
  12. equals()重写之后为什么要重写hashCode()方法
  13. GoFrame带你从0-1快速入门
  14. 计算机二级office试题构成,2016年计算机二级office题库及答案
  15. 音:Android音频系统之音频框架
  16. 【HAT】 Activating More Pixels in Image Super-Resolution Transformer
  17. Nginx是什么??
  18. 十款开源在线视频播放器
  19. 手机屏幕常见故障_手机触摸屏常见问题及解决方法
  20. 关于openCV安装配置最为详尽的一篇文章

热门文章

  1. 海洋seacms漏洞利用
  2. 只要打气,没有飞不起来的汽球
  3. 中文 NLP(11) -- stanfordNLP 生成文法之 PCFG 模型
  4. 【笔记】AngularJs学习笔记[02]【实践回顾与知识点归纳】
  5. jQuery 子元素选择器 find() 和 children()
  6. java 子类调用静态方法吗_Java子父类中静态方法
  7. Android 配置忽略文件正确的写法
  8. U盘安装ubuntu22.04 Linux系统分区
  9. java的Arrays.fill()方法对二维数组赋值boolean类型
  10. 计算机毕业设计(附源码)python综合众筹网站