JDialog模态框阻塞线程的妙用

JDialog是swing的一个组件。他有两种用法。

第一种就是使用系统提供的静态方法。在JOptionPane中提供了四种静态方法:

方法名 描述
showMessageDialog消息对话框,向用户展示一个消息,没有返回值。
showConfirmDialog确认对话框,询问一个问题是否执行。
showInputDialog输入对话框,要求用户提供某些输入。
showOptionDialog选项对话框,上述三项的大统一,自定义按钮文本,询问用户需要点击哪个按钮。

 

 

 

 

 

 

这四种方法重载了很多次,有不同的参数。可根据需要选用。

第二种就是继承JDialog,自定义一个模态框。今天,我们就来着重介绍下自定义一个模态框,阻止用户登录的例子。

 

众所周知,用户在登录某个系统的时候,输完账号密码后点击登录,如果没有反应,对服务器方面知识空白的绝大多数用户会认为这是卡住了,可能会多次点击登录。但事实上每一次点击都会向系统发出请求,服务器不能及时处理,就是因为业务繁忙或者网络故障等等,如果用户多次请求,服务器就要多次响应。

 如图是我编写的一个登录界面,当我连续点击三次登录按钮后,会有如下输出:

 如图,客户端连着向服务器发送了三次连接请求,也就意味着服务器需要处理这三次请求。

近些年来,为了减轻服务器的工作压力,推出了不少方案,比如分布式服务器等等。但是如果能从源头上减轻服务器的负担,岂不是美滋滋。如果能有效阻止用户向服务器多次发送没有意义的请求,就能有效地从源头减轻服务器的负担。

JDialog模态框,有一个boolean类型的参数modal,这个参数就是控制模态框显示之后,还能不能对其父窗口进行操作,如果选择为false,则该模态框为非模态的,在弹出模态框后还能继续对其父窗口操作。如果选择为true,弹出模态框后不能对父窗口进行操作。我们要用的就是这种模态的。

首先,自己编写一个继承了JDialog的模态框,然后再编写一个类,该类中产生一个线程,在线程中调用模态框。

package com.mec.server_client.common;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dialog;
import java.awt.Font;
import java.awt.Frame;

import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;

public class MecDialog extends JDialog {
	private static final long serialVersionUID = 2309852253785194778L;
	
	private static final String TITLE = "晨哥温馨提示";
	private static final Color topicColor = new Color(0, 0, 0);
	private static final Font normalFont = new Font("宋体", Font.PLAIN, 16);
	private static final Color backcolor = new Color(0x88, 0x88, 0x88);
	private static final int PADDING = 15;
	
	private Container container;
	
	public MecDialog(Frame owner, boolean modal) {
		super(owner, modal);

		container = getContentPane();
		setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
		setUndecorated(true);
	}
	
	MecDialog(Dialog owner, boolean modal) {
		super(owner, modal);
		
		container = getContentPane();
		setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
		setUndecorated(true);
	}

	public MecDialog initDialog(String message) {
		JPanel jpnlBackground = new JPanel(new BorderLayout());
		container.add(jpnlBackground);
		
		TitledBorder ttbdDialog = new TitledBorder(TITLE);
		ttbdDialog.setTitleColor(topicColor);
		ttbdDialog.setTitleFont(normalFont);
		ttbdDialog.setTitlePosition(TitledBorder.TOP);
		ttbdDialog.setTitleJustification(TitledBorder.CENTER);
		jpnlBackground.setBorder(ttbdDialog);
		jpnlBackground.setBackground(backcolor);
		
		JLabel jlblMessage = new JLabel(message, JLabel.CENTER);
		jlblMessage.setFont(normalFont);
		jlblMessage.setForeground(topicColor);
		jlblMessage.setSize(message.length() * normalFont.getSize(), 
				normalFont.getSize() + 4);
		jpnlBackground.add(jlblMessage, BorderLayout.CENTER);
		
		int height = 5 * PADDING + jlblMessage.getHeight();
		int width = 10 * normalFont.getSize() + jlblMessage.getWidth();
		setSize(width, height);
		jpnlBackground.setSize(width, height);
		setLocationRelativeTo(null);
		
		return this;
	}
	
	public void showDialog() {
		setVisible(true);
	}
	
	public void closeDialog() {
		dispose();
	}

}
package com.mec.server_client.common;

public class WaittingDialog implements Runnable {
	private volatile MecDialog dialog;

	public WaittingDialog(MecDialog dialog, String response) {
		this.dialog = dialog;
		ClientConversation.putDialogLock(response, dialog);
		new Thread(this, "Waitting Dialog").start();
	}
	
	@Override
	public void run() {
			dialog.showDialog();
	}
}

在客户端需要向服务器发送用户的登录请求时,启动该线程,在客户端显示这个不可关闭的模态框,然后在客户端收到服务器的响应后释放客户端的屏幕。以此来保证当用户点击登陆后,服务器未及时响应时,阻止用户多此点击登录按钮的操作。

 说起来挺简单的,但是在实现过程中还遇到了一些麻烦。

在此先说一下关于线程的相关事宜。线程在调用后(start之后),并不是直接启动,而是让线程进入就绪态,竞争cpu,在竞争到cpu之后线程才能运行(run方法运行)。

那么在启动了模态框之后,也就是运行了waittingDialog的构造方法,在线程进入就绪态竞争cpu还没有真正运行的时候,访问服务器的操作已经完成,并且接着执行了关闭模态框的方法,然后run()方法才开始运行,启动模态框,那么启动了之后就无法关闭了。

这个问题的难点就在调用了模态框之后这个线程就阻塞了,无法在执行后续代码。因此无法在服务器返回响应后执行关闭模态框的方法。

在经过多此尝试后,总结出了解决问题的方法。那就是isActive()方法。这个方法可以检测一个线程的run()方法是否运行。因此可以在客户端处理服务器返回响应的时候检测waittingDialog线程的run()方法是否运行,用一个循环持续检测,当检测到该run()方法运行后,再继续执行后续代码,关闭该模态框。

如果出现刚刚的问题,当还未运行run()方法,服务器就返回处理结果时,进入检测, 持续循环,知道模态框被调用后才能继续往下执行。

MecDialog dialog = dialogMap.get(action);
if (dialog != null) {
    while (!dialog.isActive()) {
	    ;
    }
    dialog.closeDialog();
    dialogMap.remove(action);
			
}

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值