我认为对话框是一个延迟加载的窗体。并且是有条件加载的。对话框的使用方法和Frame相比基本相同。当然,两者本身就都是容器类。
但是对话框并不是程序运行就存在的,而是出发某些条件后产生的。比如要求输入数字结果输入了其他字符,这时候可能就会弹出一个对话框来。但是awt在这方面做得有点让人用的不方便。Windows编程里面可以比较方便的弹一个MessageBox,但是awt里面只能自己手写了,真痛苦....
1.创建对话框Dialog d=new Dialog(Container);//对话框不能独立存在,创建对话框必须传入一个窗体作为其依赖对象。这是和Frame相比很大的不同。
2.设置对话框
d.setBounds(x,y,w,h);
d.setLayout(null);
3.添加组件
Label lbl=new Label("hello!");
d.add(lbl);
4.注册监听器
d.addWinowListener(new windowAdapter(){
public void windowClosing(WindowEvent e){}
});
5.设置可见
d.setVisible(true);
大致上都和Frame一致。
【补充】Dialog在初始化时可以传入一个Boolean参数表示其模式,如果为true则当对话框存在时不可以操作其他窗体,比如警告信息;为false则可以同时操作对话框和原来的窗体,比如文本文档的搜索。
如何与调用Dialog的invoker互动。
1.当前我是把需要传递的信息封装在整个大类上,在大类初始化时创建一个相应的对象,类似于全局变量,这样大类内所有方法都可以使用。但是总觉得这样有违数据封装的理念。相信后期高级工具里面会有相应的解决办法。
2.利用组件的名字。通过getName(),setName()来传递信息。
在下面的示例代码中,我将搜索结果用Label动态显示在了对话框里。设置显示文字的同时,设置了Label的名字为数据String值。然后给Label注册了双击的监听器,当双击时,监听器方法会通过e.getComponent()方法获取产生事件的组件,也就是被双击的标签,然后再调用getName()就获取到了事先设置好的数据,然后再将数据存入全局的一个集合中。这时候再在监听器中关闭对话框返回原来的主界面,这时候再向主界面上的TextArea添加刚才获取到的数据,完成信息的传递。
InitWrongDlg提示错误信息的对话框
<span style="font-family: Arial, Helvetica, sans-serif;">InitNormalDlg是显示搜索结果的对话框</span>
在主界面的代码中增加一个监听器,当在TextField中按下了回车则调用searchGameByName();搜索输入的关键字。
// TextField增加一个按键监听器。如果按下回车相当于点了“查询”
tfSearch.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
if (KeyEvent.VK_ENTER == e.getKeyCode()) {
keyWords = tfSearch.getText();// 获取TextField中的文本。
searchGameByName();
tfSearch.setText("");
}
}
});
private void searchGameByName() {
if(keyWords.equals(""))//如果输入为空则直接返回,不进行下一步
return;
matchResults.clear();//“全局”的TreeMap<String, Integer> matchResults;//这里清空以存放本次的搜索结果。
//dbMap是加载到内存的“全局”的游戏信息“数据库”TreeMap<String, GameInfo>
//这里使用的GameSearchModule是一个工具类,使用的是单例设计模式。以后再说。
GameSearchModule engine = GameSearchModule.getInstance(dbMap.keySet());
//public int searchGame(String keyWords,TreeMap<String, Integer> matchResults)
//参数是搜索的关键字和用于存放搜索结果的Map,返回值是表示搜索结果状态的整数。为了方便使用我将返回的整数设置为常量。
//判断搜索结果,如果是BAD_KEYWORDS和NO_RESULT则弹出提示错误信息的对话框。如果是NORMAL_RESULTS则弹出列有搜索结果的对话框。
switch (engine.searchGame(keyWords,matchResults)) {
case GameSearchModule.BAD_KEYWORDS:
InitWrongDlg(new String("InValid words with your search:\""
+ keyWords + "\"."));
break;
case GameSearchModule.NO_RESULT:
InitWrongDlg("Could not find the result with your search:\""
+ keyWords + "\".");
break;
case GameSearchModule.NORMAL_RESULTS:
InitNormalDlg(matchResults);
break;
}
}
//显示错误信息,没啥好说的。
private void InitWrongDlg(String info) {
int screenWidth = (int) Toolkit.getDefaultToolkit().getScreenSize().width;
int screenHeight = (int) Toolkit.getDefaultToolkit().getScreenSize().height;
Dialog dlgErr = new Dialog(fBase, "Error", true);
dlgErr.setBounds(screenWidth / 8 * 3, screenHeight / 8 * 3,
screenWidth / 4, screenHeight / 4);
dlgErr.setLayout(new FlowLayout());
Label lblErr = new Label(info);
Button btnConfirm = new Button("Confirm");
btnConfirm.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dlgErr.setVisible(false);
}
});
dlgErr.add(lblErr);
dlgErr.add(btnConfirm);
dlgErr.setVisible(true);
}
private void InitNormalDlg(TreeMap<String, Integer> matchResults) {
int screenWidth = (int) Toolkit.getDefaultToolkit().getScreenSize().width;
int screenHeight = (int) Toolkit.getDefaultToolkit().getScreenSize().height;
dlgSearchResult = new Dialog(fBase, "Search Result", true);
dlgSearchResult.setBounds(screenWidth / 4, screenHeight / 4,
screenWidth / 2, screenHeight / 2);
// setLayout()设置窗体的布局。
dlgSearchResult.setLayout(null);
//提示语标签
Label lblIntro = new Label(
"Here are the results listed by relevance with your search:\""
+ keyWords
+ "\",please double click the label of the game that you are looking for!",
Label.LEFT);
dlgSearchResult.add(lblIntro);
lblIntro.setBounds(screenWidth / 80, screenHeight / 40,
screenWidth / 2, screenHeight / 20);
// 这是之前做的正则表达式(2)中练习的代码。我抽取出来了。
// 将匹配结果按照标记次数排列,已备之后由用户选择匹配出的结果。
// 也就是把MAP按照value降序排列
// 先将map的条目转换成list
List<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>(
matchResults.entrySet());
// 用sort排序,自定义一个比较器
Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
@Override
// 让value大的排在前面。
public int compare(Map.Entry<String, Integer> arg0,
Map.Entry<String, Integer> arg1) {
return arg1.getValue().compareTo(arg0.getValue());
}
});
/*动态加载搜索结果
* 输入:List<Map.Entry<String, Integer>>//String表示数据库中的游戏名称,Integer表示游戏名称与所搜索的关键字中的所有单词的匹配次数。
* 输出:标签Label
* 步骤:
* 1.新建一个标签。同时加上标签所显示的内容
* 2.设置标签的名字为游戏名称,以便之后传递给其他。
* 3.注册双击的监听器
* 4.添加到对话框
* 5.设置标签的位置。
* 双击思路:在mouseClicked(MouseEvent e)中,事件对象中有许多相关信息,其中就有点击次数的信息。- 查找事件的相关信息应当去看Event的API
* 调用e.getClickCount()即可获取。 *
* */
//将将要显示搜索结果限制在10个以内。
int cntResults = 10;
Label[] lblResults = new Label[cntResults+1];
int id=0;
String name=null;
for (Map.Entry<String, Integer> me : list) {
++id;
name=me.getKey();
//1.新建一个标签。同时加上标签所显示的内容
lblResults[id]=new Label(id + ":\t[" + name+ "]......with [" + me.getValue() + "] relevance.");
//2.设置标签的名字为游戏名称
lblResults[id].setName(name);
//3.注册双击的监听器
lblResults[id].addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e)
{
if(2==e.getClickCount())
{
String newKey=e.getComponent().getName();
//System.out.println(e.getComponent().getName());
//dlgSearchResult.setName(e.getComponent().getName());
GameInfo newGame=dbMap.get(newKey);
//将用户选择的搜索结果所包含的信息打印在主界面的TextArea上。
taInfo.append(newGame.toString()+"\r\n");
//将搜索结果添加到统计信息的集合中。ArrayList<GameInfo> bundleContent
bundleContent.add(newGame);
//清空搜索结果的Map,待下次搜索使用。
matchResults.clear();
dlgSearchResult.setVisible(false);
}
}
});
//4.添加到对话框
dlgSearchResult.add(lblResults[id]);
//5.设置标签的位置。
lblResults[id].setBounds(screenWidth / 80,
screenHeight / 200 * (15 + 8 * id - 8), screenWidth / 40 * 19,
screenHeight / 200 * 8);
// 为了控制输出内容的数量,可以做个限制
if (id >= cntResults) { break; }
}
dlgSearchResult.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
dlgSearchResult.setVisible(false);
}
});
dlgSearchResult.setVisible(true);
}