1)模态框的简单介绍

模态对话框(Modal Dialogue Box,又叫做模式对话框),是指在用户想要对对话框以外的应用程序进行操作时,必须首先对该对话框进行响应。如单击【确定】或【取消】按钮等将该对话框关闭。一般来说,Windows应用程序中,对话框分为模态对话框和非模态对话框两种。二者的区别在于当对话框打开时,是否允许用户进行其他对象的操作。(以上内容来自百度百科)

举例来说,当我们登录某个界面时,输入信息之后点击登录按钮,有时候会出现暂时无响应或者是还没有完成响应的情况下,用户再次或多次点击登录按钮,不断地向服务器发送“请求”。而服务器此时没有办法做到识别出用户正在进行重复操作,进而阻止用户操作,当服务器完成刚开始第一次的“请求”返回响应时,用户可能已经进行了无数次的点击操作,但是服务器此时已经不需要对这些重复的“请求”做出响应。为了阻止用户的类似无效操作,减少服务器的负担,给出一个解决办法,在用户第一次发出登录请求时,弹出一个模态框,上面显示正在等率,请稍后······的提示,以此提醒用户服务器正在对你的操作进行反应,请稍等。这样给出提示之后,用户就不会再进行多次无效的操作。这就是模态框起到的作用。

当我们点击某个事件之后,弹出来一个窗口,而当我们再次对这个窗口之外的位置进行点击或者任何操作时,该窗口会发出“叮叮叮”的声音,并且阻挡其它的任何操作,这个窗口就是模态框了。而模态框又分为模态和非模态,上面的例子表示的是模态,非模态指的是,弹出一个窗口之后,把该窗口挪过去,依然可以继续进行后续的操作,这种说的就是非模态了。

模态框有个专门的类JDialog,为了简单说明模态框,这里给出一个类似适配器的类MDialog:

public class MDialog extends JDialog{private static final long serialVersionUID = -6367411118125656047L;public MDialog(Dialog owner, boolean modal) {super(owner, modal);}public MDialog(Dialog owner, String title, boolean modal) {super(owner, title, modal);}public MDialog(Frame owner, boolean modal) {super(owner, modal);}public MDialog(Frame owner, String title, boolean modal) {super(owner, title, modal);}//对模态框外观显示的初始化设置public ModelDialog 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());//前面界面中用的一般都是参数为null,默认位置;//在这里参数写成getOwner()的意思是将模态框的位置设置成相对于父窗口的中间位置setLayout(null);setUndecorated(true);//给模态框去掉边框,避免出现“x”关闭按钮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 closeDialog() {dispose();}//显示模态框public void showDialog() {setVisible(true);}//给出一个处理事件的方法,可以在之后进行覆盖(重写)public void dealAction() {}
}

说明:第二行的代码意思是序列号,也就是版本号;
简单覆盖了JDialog类中的几个方法,其中有个boolean类型的参数model,取值true和false,代表的就是前面说过的模态和非模态;

以上是对模态框的简单说明,下面接着来介绍有关模态框的应用

2)有关模态框的应用和存在的问题

基于上面的类来完成模态框的简单显示,先给出一个swing普通窗口,

public class MainView implements INormalView,Runnable{private JFrame mainView;private JButton jbtnAction;private JButton jbtnExit;public MainView() {initView();}@Overridepublic void init() {mainView = new JFrame("关于对话框的学习");mainView.setSize(new Dimension(500, 350));mainView.setLayout(new BorderLayout());mainView.setLocationRelativeTo(null);mainView.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);JLabel jlblTopic = new JLabel("关于对话框的学习",JLabel.CENTER);Font font = new Font("微软雅黑", Font.BOLD, 30);jlblTopic.setFont(font);mainView.add(jlblTopic,BorderLayout.NORTH);JPanel jpnlBody = new JPanel();mainView.add(jpnlBody,BorderLayout.CENTER);jbtnAction = new JButton("开始");jbtnAction.setFont(normalFont);jpnlBody.add(jbtnAction);JPanel jpnlFooter = new JPanel();mainView.add(jpnlFooter,BorderLayout.SOUTH);jbtnExit = new JButton("退出");jbtnExit.setFont(normalFont);jpnlFooter.add(jbtnExit);}@Overridepublic void reinit() {}@Overridepublic void dealEvent() {mainView.addWindowListener(new WindowAdapter() {@Overridepublic void windowClosing(WindowEvent e) {closeView();}});jbtnExit.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {closeView();}});}private void closeView() {try {exitWindow();} catch (FrameIsNullException e) {e.printStackTrace();}}@Overridepublic JFrame getFrame() {return mainView;}

显示结果如下:

要达到的目的是,点击“开始”按钮,会弹出一个模态框,显示正在获取信息,请稍后······,需要给开始按钮增加事件响应,

jbtnAction.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {mDialog = new MDialog(mainView, "模态框", true);mDialog.setCaption("正在获取信息,请稍后···");mDialog.setVisible(true);System.out.println("模态框自动关闭!");}});

点击开始按钮之后,显示模态框:

但是现在存在一个问题,就是模态框显示之后,没办法关闭,即,就是在执行mDialog.setVisible(true)之后的操作会阻塞,模态框没有关闭之前,根本无法继续进行后面的操作,不会输出模态框自动关闭的语句。

为了看得更清楚,在模态框显示之前给出一个线程,在模态框显示5秒之后,完成模态框的关闭操作,

jbtnAction.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {new Thread(MainView.this,"模态框控制线程").start();mDialog = new MDialog(mainView, "模态框", true);mDialog.setCaption("正在获取信息,请稍后···");mDialog.setVisible(true);System.out.println("模态框自动关闭!");}});
@Overridepublic void run() {System.out.println("开始显示模态框:");try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}mDialog.closeDialog();}

这样虽然完成了模态框的关闭,可以正常执行setVisible(true)之后的操作,但这样做绝对存在很大的弊端,比如,如果某次事件响应随之显示的是两个或多个不同的模态框,但是关闭操作又写在一个线程中,这是很不合理的。于是给出一种更为巧妙的处理方法,继续向下来看:

3)巧妙处理setVisible(true)的阻塞问题

经过上面的说明,了解到,在某个事件中增加模态框的相关内容,会在遇到setVisible(true)之后造成线程阻塞,无法继续进行后续的操作,那换个角度来看,可以把原本事件响应要做的事放到模态框的事件处理当中,这样做就不需要在主线程中显示完模态框再去做其他的操作。

简单来说,在原本要执行事件响应的地方,先不做具体的操作,只是完成模态框的显示,而在模态框获取焦点之后执行原本事件响应需要做的事,执行完该操作之后关闭模态框就好。

下面给出模态框的一个应用场景,用户登录界面:

用户点击登录按钮之后,触发某个事件响应操作

jbtnLogin.addKeyListener(new KeyAdapter() {@Overridepublic void keyTyped(KeyEvent e) {dealUserLogin();}});
private void dealUserLogin() {String id = jtxtUserName.getText();String password = new String(jpswPassword.getPassword());password = String.valueOf(password.hashCode());IUserAction userAction = rmiClient.getProxy(IUserAction.class, jfrmLogin, "正在登录,请稍后……");UserInfo user = userAction.userLogin(id, password);if (user.getId().equalsIgnoreCase("ERROR")) {ViewTool.showError(jfrmLogin, user.getNick());jpswPassword.setText("");jtxtUserName.selectAll();jtxtUserName.requestFocus();return;}jbtnLogin.setEnabled(true);}

有关 rmiClient.getProxy(IUserAction.class, jfrmLogin, “正在登录,请稍后……”)方法如下,这里用代理机制执行相关方法(有关代理机制可以查看java的两种动态代理机制

@SuppressWarnings("unchecked")public <T> T getProxy(Class<?> interfacer, JFrame frame, 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 {RMIModelDialog dialog = new RMIModelDialog(frame, true).setMethodInvoker(methodInvoker).setMethod(method).setArgs(args);dialog.setCaption(caption);dialog.showDialog();return dialog.getResult();}});}

像上面所说的,在代理执行相关方法的地方不做相关操作,只完成模态框的显示,在这里对于代理机制的应用也有了很大的突破,在代理中并没有做什么实质性的操作,而把真正的执行方法的具体操作放在了处理模态框的地方:

@Overridepublic <T> T methodInvoke(Object object, Method method, Object[] args) {Socket socket = null;DataOutputStream dos = null;DataInputStream dis = null;try {socket = new Socket(rmiServerIp, rmiServerPort);dos = new DataOutputStream(socket.getOutputStream());dos.writeUTF(method.toString());dos.writeUTF(getArgs(args));dis = new DataInputStream(socket.getInputStream());String resultString = dis.readUTF();Type returnType = method.getGenericReturnType();@SuppressWarnings("unchecked")T result = (T) ArgumentMaker.gson.fromJson(resultString, returnType);return result;} 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;}

该操作真正执行的地方在模态框处理事件的方法中,执行完之后关闭模态框;

@Overridepublic void dealAction() {addFocusListener(new FocusAdapter() {@Overridepublic void focusGained(FocusEvent e) {result = methodInvoker.methodInvoke(null, method, args);closeDialog();}});}

以上操作就基本处理了有关模态框的阻塞问题,总之,在使用模态框的时候,要特别注意模态框的关闭操作到底应该放在哪里,才会避开setVisible(true)之后的线程阻塞问题,这里我们用了一种可以说很取巧的方法来处理。

模态框的学习——巧妙处理setVisible(true)的阻塞问题相关推荐

  1. 巧妙处理Swing模态框setVisible(true)线程阻塞的问题

    模态框的学习 假设存在这样场景:我登录lol页面的时候,一区人很多,我连着点登陆,客户端没给我反应.竟然没反应,然后我就疯狂点登陆,假设lol服务器无法处理这种重复命令,那么lol的服务器反应过来的时 ...

  2. python测试开发django-122.bootstrap模态框(modal)学习

    前言 模态框(Modal)是覆盖在父窗体上的子窗体,使用场景比如:在页面上编辑内容的时候经常需要弹出一个框框,可以编辑字段提交. 点删除按钮的时候,需要弹出二次确认框,这种现页面上的框框就是模态框 模 ...

  3. BootStrap学习(6)_模态框

    一.模态框 模态框(Modal)是覆盖在父窗体上的子窗体.通常,目的是显示来自一个单独的源的内容,可以在不离开父窗体的情况下有一些互动.子窗体可提供信息.交互等. 如果只使用该功能,只引入BootSt ...

  4. Bootstrap插件(一)——模态框(modal.js)

    前言:这一片文章我们将对bootstrap的modal模态框进行学习,学习他是如何绑定到一个按钮上去点击显示,学习模态框的简单数据配置,学习模态框的使用方式,事件,方法.参数等:下面是modal的内容 ...

  5. 前端之bootstrap模态框

    简介:模态框(Modal)是覆盖在父窗体上的子窗体.通常,目的是显示来自一个单独的源的内容,可以在不离开父窗体的情况下有一些互动.子窗体可提供信息.交互等. Modal简介 Modal实现弹出表单 M ...

  6. Bootstrap中过渡效果(Transition)模态框插件的使用案例

    通过使用模态框效果实现弹出框的登录效果: 效果图: <form id="formmodal" action="#"><h3>过渡效果(T ...

  7. bootstrap 模态窗口按钮位置_Bootstrap 模态框(Modal)插件的使用

    Bootstrap模态框(modal)不知道谁起的名字,反正就这么回事.经常使用在网站的 登陆/注册 按钮,弹出模态框,来提醒用户输入的同时,网站有一个遮罩层来屏蔽其他的操作. 一. 使用方法:1.通 ...

  8. Bootstrap 模态框(Modal)

    #Bootstrap 模态框(Modal)插件 详细讲解 #####第一步: 加载框架: https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jque ...

  9. 模态框间相互传输数据

    A界面中打开B模态框,如果需要引用到A界面里面的某个数据,就是需要把A界面里面的某个值传给B模态框. 在A界面中调用模态框: modalInstance=$modal.open({backdropCl ...

最新文章

  1. php中如何想时间转为时间戳,php中怎么将时间转换为时间戳
  2. 生产环境LNMP (果图片)
  3. 【干货】工作邮件高段位写法
  4. 如何用ABAP代码的方式弹出SPRO里的customizing activity
  5. js正则表达exec和match的区别(转)
  6. 洛谷P2678 跳石头
  7. 回溯策略的汉诺塔问题
  8. Android反编译:使用dex2jar查看dex文件
  9. java多线程编程synchronized关键字
  10. python简单爬虫代码
  11. 企业CIS 系统的收集方法分析
  12. python 文件处理软件_Python如何处理文件的?
  13. OpenHarmony学习笔记——编辑器访问Linux服务器进行编译
  14. 报刊订阅管理系统(数据库课程设计)
  15. 因果分析:原理、方法论、应用
  16. 7-1 设计一个风扇Fan类 (20 分)JAVA PTA
  17. 社会心理学(第8版)
  18. linux海报制作软件,春节海报制作素材平台-春节海报一键制作app下载v1.0.0-Linux公社...
  19. 大学计算机系三年论文6000字,计算机论文6000字范文_计算机论文_计算机应用论文...
  20. Zynq入门——PS和PL接口技术详解

热门文章

  1. Node.js 全网最详细教程 (第一章:Node学习入门必看教程)
  2. Retrofit忽略Https安全验证
  3. html如实现留言板功能,JS实现留言板功能[楼层效果展示]
  4. 星系局部战争(结构struct,sort排序)
  5. python新手入门笔记_2020最新Python入门笔记
  6. 100个最权威的招聘面试题及回答解析 (五)
  7. 在虚幻引擎5中构建你的首款游戏 - 09 - 压力板和开关门
  8. 如何给Linux系统安装中文字体
  9. AC68U梅林固件,从ipv6设置到写脚本手动绑定ddns,通过单ipv6实现公网访问
  10. 临沂三中高考2021成绩查询,临沂2021中考考生10万人参加 6月30前查成绩