模态对话框(Modal Dialogue Box,又叫做模式对话框),是指在用户想要对对话框以外的应用程序进行操作时,必须首先对该对话框进行响应。如单击【确定】或【取消】按钮等将该对话框关闭。一般来说,在应用程序中,对话框分为模态对话框和非模态对话框两种。二者的区别在于当对话框打开时,是否允许用户进行其他对象的操作。
比如类似这种:
这种就相当于是模态框,即此对话框打开时不允许对其他对象进行操作。
模态框怎么做出来的呢,接下来我们一起来看看代码吧!
首先自己的模态框继承java给的JDialog,然后根据我们的需要在模态框中写入我们想要的界面布局。
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 java.awt.GraphicsConfiguration;
import java.awt.Window;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import javax.swing.BorderFactory;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class MyDialog extends JDialog {
private static final long serialVersionUID = -2954008338150734838L;
private RMIClient rmiClient;
private Object result;
private Container container;
private JLabel jlblMessage;
private JPanel jpnlMessage;
public MyDialog setCaption(String message) {
Font font = new Font("宋体", Font.BOLD, 16);
//得到父窗口以及父窗口的左右坐标以及宽高
Container parent = getParent();
int parentLeft = parent.getX();
int parentTop = parent.getY();
int parentWidth = parent.getWidth();
int parentHeight = parent.getHeight();
//设置自己的模态框的宽高(自己设置的是消息的长度+4的宽度)
int width = (message.length() + 4) * font.getSize();
int height = 5 * font.getSize();
setSize(width, height);
//将其放在父窗口中间
setLocation(parentLeft + (parentWidth - width) / 2,
parentTop + (parentHeight - height) / 2);
container = getContentPane();
container.setLayout(null);
//模套狂形式为true,非模态框为false.
setUndecorated(true);
//放入信息
jpnlMessage = new JPanel();
jpnlMessage.setSize(width, height);
jpnlMessage.setLayout(new BorderLayout());
jpnlMessage.setBackground(Color.lightGray);
jpnlMessage.setBorder(BorderFactory.createLineBorder(Color.gray, 2));
container.add(jpnlMessage);
jlblMessage = new JLabel(message, JLabel.CENTER);
jlblMessage.setFont(font);
jlblMessage.setSize(width, height);
jlblMessage.setForeground(Color.blue);
jlblMessage.setHorizontalTextPosition(JLabel.CENTER);
jpnlMessage.add(jlblMessage, BorderLayout.CENTER);
}
public void showDialog() {
setVisible(true);
}
public void exitDialog() {
this.dispose();
}
public MyDialog() {
}
public MyDialog(Frame owner) {
super(owner);
}
public MyDialog(Dialog owner) {
super(owner);
}
public MyDialog(Window owner) {
super(owner);
}
public MyDialog(Frame owner, boolean modal) {
super(owner, modal);
}
public MyDialog(Frame owner, String title) {
super(owner, title);
}
public MyDialog(Dialog owner, boolean modal) {
super(owner, modal);
}
public MyDialog(Dialog owner, String title) {
super(owner, title);
}
public MyDialog(Window owner, ModalityType modalityType) {
super(owner, modalityType);
}
public MyDialog(Window owner, String title) {
super(owner, title);
}
public MyDialog(Frame owner, String title, boolean modal) {
super(owner, title, modal);
}
public MyDialog(Dialog owner, String title, boolean modal) {
super(owner, title, modal);
}
public MyDialog(Window owner, String title, ModalityType modalityType) {
super(owner, title, modalityType);
}
public MyDialog(Frame owner, String title, boolean modal, GraphicsConfiguration gc) {
super(owner, title, modal, gc);
}
public MyDialog(Dialog owner, String title, boolean modal, GraphicsConfiguration gc) {
super(owner, title, modal, gc);
}
public MyDialog(Window owner, String title, ModalityType modalityType, GraphicsConfiguration gc) {
super(owner, title, modalityType, gc);
}
}
这个使我们要显示的模态框,此时,我们要找一个给他的应用场合,此时小编将它和之前学习的RMI结合起来(RMI点这里),即就是当我们利用短连接去调用一个在服务器上的方法时客户端显示出一个模态框(它的存在使用户在此时不允许有其它操作),当服务器将执行结果返回时模态框关闭,这样可以让用户在方法执行时不能去操作其他对象。
几个基本问题可以确定:
1、建立服务器;
2、客户端连接服务器;
3、在客户端执行一个方法,而该方法应该在服务器上执行;此时在客户端发送方法执行请求时应该显示模态框
4、为了保证其工具性质,可以通过接口完成方法的确定。(我们服务器和客户端都有相同的某个接口类,而客户端执行的方法实则是服务器端执行的,则在服务器端需要实现这个接口类,并在这个实现类上写上注释,以便和接口类一一对应。)
进一步分析:
客户端在执行一个方法的时候,需要在执行过程中,连接服务器,并在连接成功后,将这个方法的名字、
参数都传递给服务器,然后显示出一个Dialog模态框;继而等待服务器返回方法的返回值;
服务器在接到客户端连接请求后,立刻接收方法名称和参数,并反射调用该方法;
最后,将这个方法的执行结果返回给客户端。此时客户端收到返回结果立刻关闭模态框。
客户端只要将这些接口通过代理模式得到代理(用到接口的话就用JDKProxy),那么,就可以完成上述动作。
较小编写的RMI相比,上述的分析加了红色字体的内容,这样我们就把模态框和远程方法调用联合起来了。
下面将基于RMI重新组织代码:
1.首先我们给出一个注解类用来表明我们那些方法在调用时需要显示出一个模态框,以及模态框中要显示的内容。
package com.smy.rmi.annotation;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target(METHOD)
public @interface ModelDialog {
String caption();
}
此时我们的接口中的方法上应加上注释
package com.smy.rmi.service;
import com.smy.rmi.annotation.ModelDialog;
public interface IStudentService {
@ModelDialog(caption = "显示模态框")
StudentInfo fixStudentInfo(StudentInfo student);
StudentInfo fixStudentInfo(StudentInfo student, int a);
}
2.这时我们的客户端应该去使用dialog,我们可以从RMI中知道客户端执行实际上是交给代理执行的此时我们的代理在调用方法之前显示模态框,然后再去将参数和接口
@SuppressWarnings("unchecked")
public <T> T getProxy(Class<?> interfaces, final JFrame parent) {
return (T) Proxy.newProxyInstance(
interfaces.getClassLoader(),
new Class<?>[] {interfaces},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
rmiClient.setMethod(method);
rmiClient.setArgus(args);
if (method.isAnnotationPresent(ModelDialog.class)) { //若此时接口上的method有dialog注释应该showdialog
ModelDialog modelDialog = method.getAnnotation(ModelDialog.class);
String caption = modelDialog.caption();
MyDialog dialog = new MyDialog(parent, true); //此时将RMIClient传过去是为了在处理模态框开启后发送参数给服务器端
dialog.setRmiClient(rmiClient);
dialog.setCaption(caption);
dialog.showDialog();
//得到返回的结果
result = dialog.getResult();
} else {
//若此时接口上的method没有dialog注释应该直接发送参数.
result = rmiClient.invokeMethod();
}
return result;
}
});
}
此时我们的Dialog类应该加上一个方法:
private void dealAction() {
//这个方法能保证模态框开启之后才去发送参数,在收到服务器端的结果后关闭模态框。
addFocusListener(new FocusAdapter() {
@Override
public void focusGained(FocusEvent e) {
result = rmiClient.invokeMethod();
exitDialog();
}
});
}
public Object getResult() {
return result;
}
public void setRmiClient(RMIClient rmiClient) {
this.rmiClient = rmiClient;
}
public void showDialog() {
setVisible(true);
}
这样我们就可以去正真显示模态框了。
结果如此图: