swing KeyStroke在JTextFile与JButton中的效果为何不同?

sweetBug 2009-05-14 09:13:08
我想在按下esc时关闭窗口,当窗体中的JTextField未得到焦点时还能正常工作,但JTextField一旦得到焦点就无法按esc时关闭窗体了,这是为什么?

import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

public class MyFrame extends JFrame {

public MyFrame() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(new Dimension(400, 300));
setContentPane(new MyPanel());
}

public static void main(String... args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
createAndShowGUI();
}
});
}

private static void createAndShowGUI() {
new MyFrame().setVisible(true);
}
}

class MyPanel extends JPanel {

public MyPanel() {
super(new FlowLayout());

initDetector();
add(button);
add(new JButton("do nothing"));
JTextField textField = new JTextField();
textField.setColumns(10);
add(textField);
}

private void initDetector() {
button = new JButton("OK");
button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
KeyStroke.getKeyStroke((char) KeyEvent.VK_ESCAPE), "close the outter window");

button.getActionMap().put("close the outter window", new AbstractAction() {

private static final long serialVersionUID = 1L;

public void actionPerformed(ActionEvent e) {
JComponent source = (JComponent) e.getSource();

JFrame frame = (JFrame) getMostOutterComponent(source);
frame.dispose();
}
});
}

private Component getMostOutterComponent(Component c) {
if(c.getParent() == null) {
return c;
}

return getMostOutterComponent(c.getParent());
}

private JButton button;
}
...全文
108 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
sweetBug 2009-05-15
  • 打赏
  • 举报
回复
看起来是找不到更好的解决方案啦,谢谢gentalguo,有好方法的时候告我一声!
sweetBug 2009-05-14
  • 打赏
  • 举报
回复
gentalguo太谦虚啦,我也工作一年了都。
最近公司的项目用的PB,那上面就有这种效果,没有想到移植到JAVA上还不易啊!
gentalguo 2009-05-14
  • 打赏
  • 举报
回复
的确,这样不是非常好。
呵呵,那么我想可以改写一下JTextField的一个方法
JTextField textField = new JTextField() {
@Override
protected void processKeyEvent(KeyEvent e) {
// TODO Auto-generated method stub
super.processKeyEvent(e);
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
…………//你的处理代码
}
}
};
或者创建一个类,继承自JTextField,然后改写这个processKeyEvent方法。这个地方所有用到的文本框都用你定义的这个。

可是这样也不是很好。虽然,也许在这个地方也许可以,但是其范围也就被限定住了,不利于扩展。换个地方,你就要重新定义一下。
呵呵,工作几年,水平还是这样。见笑了。
sweetBug 2009-05-14
  • 打赏
  • 举报
回复
谢谢gentalguo,不过这样的话每个Input都要加一个侦听了,这样也不好啊,有没有可能,当Input接收到esc时,将这个事件发送给自己的父级容器?
gentalguo 2009-05-14
  • 打赏
  • 举报
回复

import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

public class MyFrame extends JFrame {

public MyFrame() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(new Dimension(400, 300));
setContentPane(new MyPanel());
}

public static void main(String... args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
createAndShowGUI();
}
});
}

private static void createAndShowGUI() {
new MyFrame().setVisible(true);
}
}

class MyPanel extends JPanel {

public MyPanel() {
super(new FlowLayout());

initDetector();
add(button);
add(new JButton("do nothing"));
JTextField textField = new JTextField();
textField.setColumns(10);
textField.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
super.keyPressed(e);
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
close(button);
}
}
});
add(textField);
}

private void initDetector() {
button = new JButton("OK");
button.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
KeyStroke.getKeyStroke((char) KeyEvent.VK_ESCAPE),
"close the outter window");

button.getActionMap().put("close the outter window",
new AbstractAction() {

private static final long serialVersionUID = 1L;

public void actionPerformed(ActionEvent e) {
JComponent source = (JComponent) e.getSource();
close(source);
}
});
}

private void close(JComponent source) {

JFrame frame = (JFrame) getMostOutterComponent(source);
frame.dispose();
}

private Component getMostOutterComponent(Component c) {
if (c.getParent() == null) {
return c;
}

return getMostOutterComponent(c.getParent());
}

private JButton button;
}

呵呵,信手拈来。效果是有了,但是代码也乱了。刚才我本想尝试使用一些控件的方法,如processKeyEvent什么的,但是这些都是protected方法,现在的这个结构不可见。我这算是一个临时的替代品吧。
希望抛砖引玉,有更好的方法出现。
sweetBug 2009-05-14
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 gentalguo 的回复:]
事件的问题。
当焦点定位在文本框中的时候,文本框截获键盘事件,并不会继续向上传递。因此,这个输入事件不会到达上面。所以,这个按钮无法得到键盘事件,自然就不会有任何相应。
[/Quote]
谢谢,那如何在这种情况下达到关闭窗体的目的呢?
gentalguo 2009-05-14
  • 打赏
  • 举报
回复
事件的问题。
当焦点定位在文本框中的时候,文本框截获键盘事件,并不会继续向上传递。因此,这个输入事件不会到达上面。所以,这个按钮无法得到键盘事件,自然就不会有任何相应。
sweetBug 2009-05-14
  • 打赏
  • 举报
回复
呵呵,感觉swing太强大了,我最开始学Swing的时候就用netbeans,布局倒方便了,不过感觉有很多东西还没有直接写代码来的直接呀。特别是JTable,我基本上就不知道在netbeans里面如何用它。。。
这个问题先挂一挂,希望找到更好的解决办法
gentalguo 2009-05-14
  • 打赏
  • 举报
回复
是啊,Swing里面的零碎事情特别多。经常一个小问题就让人痛不欲生。而且许多内部的结构和层次也不是那么简单,毕竟都要通过代码控制,布局也是一个挺烦人的事情,呵呵。我感受阿,两个问题是最令人头疼的。一是焦点。二就是滚动条。呵呵。其实最近我也遇到了你提出的问题,不过我没有太多纠缠,就按照第一种方式去做了。虽然可能乱一些,但至少耦合不是那么高,结构层次没有被破坏,可读性也没有损失太多,更何况时间紧迫。
唉,世上本来就没什么完美的,寻求一个折中的吧。找不到最优的,次优的也行啊,着急了,就什么乱七八糟的都有了。若是你找到了什么好的方法,就告诉我。呵呵。学习确实是没有止境的啊。
GeekZFZ 2009-05-14
  • 打赏
  • 举报
回复
学习

62,615

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧