Java Swing:如何停止不需要的shift-tab keystroke动作 [英] Java Swing: how to stop unwanted shift-tab keystroke action

查看:86
本文介绍了Java Swing:如何停止不需要的shift-tab keystroke动作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当JPanel中有一个JTextField并且它有焦点时,按tab不会执行任何操作,但按下shift-tab会导致焦点丢失(FocusEvent.getOppositeComponent()为空)。

如果在JPanel上(或者在焦点循环根下面)有其他可聚焦的组件,则不会发生这种情况:相反,在下面的SSCCE中,我演示了这个...每次在搜索框中按下Return键,你都会在JTable中添加一行,这会导致它变得焦点。您也可以取消注释让JRadioButtons无法对焦的行。



我还查看了InputMaps以查看shift-tab是否以某种方式参与其中...一点也不。

我也试着用FocusTraversalPolicy做实验来看看我能否理解这个问题。我的目标是:当焦点周期中有一个可聚焦组件时,停止shift-tab导致焦点丢失(焦点消失)。根的环境。

稍后



解决方法是添加行

  if(oppComp == null){impl.searchBox.requestFocus(); } 

在搜索框的FocusListener的focusLost方法的结尾处​​,但是对于我来说这是只有一个解决方法... 1)不通过对焦点遍历机制的理解来解决问题; 2)当你需要在搜索框中丢失焦点的时候,可能会出现这种情况...

  import java.awt 。*; 
import java.awt.event。*;
import java.lang。*;
import java.lang.reflect.InvocationTargetException;
import java.util。*;
import javax.swing。*;
import javax.swing.table。*;

class BackTabProb {

JFrame mainFrame;
JTextField searchBox;
JTable resultsTable;

public static void print(String msg){
System.out.println(msg);


public static void main(String [] a_args)throws InvocationTargetException,InterruptedException {
final BackTabProb impl = new BackTabProb();

class显示实现Runnable {
public void run(){
impl.mainFrame = new JFrame(Back Tab problem);
impl.mainFrame.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent windowEvent){
impl.mainFrame.dispose();
}

});

impl.resultsTable = new JTable();
impl.resultsTable.setFocusable(false);
Vector< Object> dataVector = new Vector< Object>();
Vector< Object> colIdentifiers = new Vector< Object>(Arrays.asList(new String [] {ONE,TWO})); $(b)((DefaultTableModel)impl.resultsTable.getModel())。setDataVector(dataVector,colIdentifiers);
JScrollPane jsp = new JScrollPane(impl.resultsTable);
JPanel northPanel = new JPanel();
northPanel.setLayout(new BoxLayout(northPanel,BoxLayout.X_AXIS));
impl.searchBox = new JTextField(Enter search text,10);
JLabel label = new JLabel(Search:);
label.setLabelFor(impl.searchBox);
northPanel.add(label);
northPanel.add(impl.searchBox);
ButtonGroup buttonGroup = new ButtonGroup();
ArrayList< JRadioButton> indexButtons = new ArrayList< JRadioButton>();
for(int i = 0; i< 2; i ++){
JRadioButton indexButton = new JRadioButton(i == 0?Stemmer:Simple);

//注释掉这意味着在搜索框中反标签不会导致
//在焦点中会出现无处
indexButton.setFocusable(false);

buttonGroup.add(indexButton);
northPanel.add(indexButton);

$ b impl.mainFrame.getContentPane()。setLayout(new BorderLayout());
impl.mainFrame.getContentPane()。add(northPanel,BorderLayout.NORTH);
impl.mainFrame.getContentPane()。add(jsp,BorderLayout.CENTER);
impl.mainFrame.pack();
impl.mainFrame.setVisible(true);
print(=== visible);



EventQueue.invokeAndWait(new Show());
$ b $ class AddMore implements Runnable {
public void run(){
impl.mainFrame.setFocusTraversalPolicyProvider(true);
class SearchBoxFocusListener实现了FocusListener {
public void focusGained(FocusEvent focusEvent){
print(=== search box got focus);
impl.searchBox.selectAll();


$ b public void focusLost(FocusEvent focusEvent){
Component oppComp = focusEvent.getOppositeComponent();
print(String.format(=== search box lost focus to%s,
oppComp == null?nowhere:oppComp.getClass()));
}

impl.searchBox.addFocusListener(new SearchBoxFocusListener());
$ b $ class SearchBoxActionListener实现ActionListener {
public void actionPerformed(ActionEvent actionEvent){$ b $ if(actionEvent.getSource()!= null){
((DefaultTableModel)impl .resultsTable.getModel())。insertRow(0,new Object [] {blip,blap});

//只要表格至少有一行,它就会设置为focusable

//注释掉这意味着从搜索框结果中返回tabb
//聚焦在无处
impl.resultsTable.setFocusable(true);



impl.searchBox.addActionListener(new SearchBoxActionListener());

ActionMap am = impl.searchBox.getActionMap();
print(=== ActionMap);
for(Object key:am.allKeys()){
print(String.format(=== action key%s,key));
}
for(int i = 0; i <3; i ++){
print(String.format(=== InputMap type%d,i));
InputMap im = impl.searchBox.getInputMap(i);
KeyStroke [] allKeys = im.allKeys(); (KeyKtroke ks:allKeys){
print(String.format(=== keystroke%s object%s,ks,im。得到(KS)));



$ b //使用FocusTraversalPolicy进行的各种实验NB LayoutTraversalPolicy
//这是默认情况下框架使用的
$ b $ class MainFrameFocusTraversalPolicy extends LayoutTraversalPolicy {
public Component getComponentAfter(Container arg0,Component arg1){
Component comp = super.getComponentAfter(arg0,arg1);
print(String.format(=== comp%s,comp == null?Null:comp.getClass()));
return comp;

$ b $ public Component getComponentBefore(Container arg0,Component arg1){
Component comp = super.getComponentBefore(arg0,arg1);
print(String.format(=== comp before%s,comp == null?Null:comp.getClass()));
return comp;

$ b $ public Component getDefaultComponent(Container arg0){
Component comp = super.getDefaultComponent(arg0);
print(String.format(=== default comp%s,comp == null?Null:comp.getClass()));
return comp;

$ b $公共组件getFirstComponent(Container arg0){
Component comp = super.getFirstComponent(arg0);
print(String.format(=== first comp%s,comp == null?Null:comp.getClass()));

return comp;
//返回impl.searchBox;

$ b $公共组件getLastComponent(Container arg0){
Component comp = super.getLastComponent(arg0);
print(String.format(=== last comp%s,comp == null?Null:comp.getClass()));
return comp;
}

protected boolean accept(Component comp){
boolean accept = super.accept(comp);
print(String.format(=== accept%s?%s,comp == null?Null:comp.getClass(),accept));
返回接受;
}
}
impl.mainFrame.setFocusTraversalPolicy(new MainFrameFocusTraversalPolicy());
}
}
EventQueue.invokeAndWait(new AddMore());




$ b

解决方案



<$ p $

如果(oppComp == null){
final Component srcComp =(Component)focusEvent.getSource();
FocusTraversalPolicy ftp = impl.mainFrame.getFocusTraversalPolicy();
Component lastComp = ftp.getLastComponent(impl.mainFrame);
Component beforeComp = ftp.getComponentBefore(impl.mainFrame,srcComp);

if(lastComp == beforeComp){
EventQueue.invokeLater(new Runnable(){
public void run(){
if(impl.mainFrame.isFocused ()){
srcComp.requestFocus();
};
}});






$ b实际上,这是单一可调焦组件:在Shift-Tab上,焦点遍历策略然后发现beforecomp与lastcomp是相同的。在这些循环中,组件重点(而不是窗口焦点)似乎消失。奇怪的是,在Tab(往前走)中,当后comp与firstcomp相同时,它不会。这是一个错误?

无论如何,已经确定了这一点,你必须检查窗口的焦点异步...所以焦点可以被允许去另一个窗口。在Shift-Tab上产生轻微的闪烁(boo!)。

When I have a JTextField in a JPanel and it has focus, pressing "tab" doesn't do anything... but pressing "shift-tab" causes focus to be lost (FocusEvent.getOppositeComponent() is null).

If there are other focusable components on the JPanel (or rather under the "focus cycle root") this doesn't happen: instead, they get the focus on shift-tab.

In the SSCCE below I demonstrate this... each time you press Return in the search box you add a row to the JTable, which causes it to become focusable. You can also uncomment the line which makes the JRadioButtons unfocusable.

I looked at the InputMaps as well to see whether shift-tab is somehow involved there ... not at all.

I also tried experimenting with FocusTraversalPolicy to see whether I could understand the problem. No joy.

My goal: to stop "shift-tab" causing a loss of focus (focus disappears) when there is a single focusable component in the focus cycle root's ambit.

later

a workaround is to add the line

if( oppComp == null ){ impl.searchBox.requestFocus(); }

at the end of the focusLost method of the search box's FocusListener ... but for me this is only a workaround... 1) it doesn't solve the problem through understanding of the focus traversal mechanism; 2) there might be circs when you would need the focus to be lost from the search box...

import java.awt.*;
import java.awt.event.*;
import java.lang.*;
import java.lang.reflect.InvocationTargetException;
import java.util.*;
import javax.swing.*;
import javax.swing.table.*;

class BackTabProb {

    JFrame mainFrame;
    JTextField searchBox;
    JTable resultsTable;

    public static void print(String msg) {
        System.out.println(msg);
    }

    public static void main(String[] a_args) throws InvocationTargetException, InterruptedException {
        final BackTabProb impl = new BackTabProb();

        class Show implements Runnable {
            public void run() {
                impl.mainFrame = new JFrame("Back Tab problem");
                impl.mainFrame.addWindowListener(new WindowAdapter() {
                    public void windowClosing(WindowEvent windowEvent) {
                        impl.mainFrame.dispose();
                    }

                });

                impl.resultsTable = new JTable();
                impl.resultsTable.setFocusable(false);
                Vector<Object> dataVector = new Vector<Object>();
                Vector<Object> colIdentifiers = new Vector<Object>(Arrays.asList(new String[] { "ONE", "TWO" }));
                ((DefaultTableModel) impl.resultsTable.getModel()).setDataVector(dataVector, colIdentifiers);
                JScrollPane jsp = new JScrollPane(impl.resultsTable);
                JPanel northPanel = new JPanel();
                northPanel.setLayout(new BoxLayout(northPanel, BoxLayout.X_AXIS));
                impl.searchBox = new JTextField("Enter search text", 10);
                JLabel label = new JLabel("Search:");
                label.setLabelFor(impl.searchBox);
                northPanel.add(label);
                northPanel.add(impl.searchBox);
                ButtonGroup buttonGroup = new ButtonGroup();
                ArrayList<JRadioButton> indexButtons = new ArrayList<JRadioButton>();
                for (int i = 0; i < 2; i++) {
                    JRadioButton indexButton = new JRadioButton(i == 0 ? "Stemmer" : "Simple");

                    // commenting this out means back-tabbing from search box does not result
                    // in focus going "nowhere"
                    indexButton.setFocusable(false);

                    buttonGroup.add(indexButton);
                    northPanel.add(indexButton);

                }
                impl.mainFrame.getContentPane().setLayout(new BorderLayout());
                impl.mainFrame.getContentPane().add(northPanel, BorderLayout.NORTH);
                impl.mainFrame.getContentPane().add(jsp, BorderLayout.CENTER);
                impl.mainFrame.pack();
                impl.mainFrame.setVisible(true);
                print("=== visible");
            }
        }

        EventQueue.invokeAndWait(new Show());

        class AddMore implements Runnable {
            public void run() {
                impl.mainFrame.setFocusTraversalPolicyProvider(true);
                class SearchBoxFocusListener implements FocusListener {
                    public void focusGained(FocusEvent focusEvent) {
                        print("=== search box got focus");
                        impl.searchBox.selectAll();

                    }

                    public void focusLost(FocusEvent focusEvent) {
                        Component oppComp = focusEvent.getOppositeComponent();
                        print(String.format("=== search box lost focus to %s",
                                oppComp == null ? "nowhere" : oppComp.getClass()));
                    }
                }
                impl.searchBox.addFocusListener(new SearchBoxFocusListener());

                class SearchBoxActionListener implements ActionListener {
                    public void actionPerformed( ActionEvent actionEvent ){
                        if( actionEvent.getSource() != null ){
                            ((DefaultTableModel)impl.resultsTable.getModel()).insertRow( 0, new Object[]{ "blip", "blap" });

                            // as soon as the table has at least one row it is set to "focusable"

                            // commenting this out means back-tabbing from search box results
                            // in focus going "nowhere"
                            impl.resultsTable.setFocusable( true );
                        }
                    }
                }
                impl.searchBox.addActionListener( new SearchBoxActionListener() );

                ActionMap am = impl.searchBox.getActionMap();
                print("=== ActionMap");
                for (Object key : am.allKeys()) {
                    print(String.format("  === action key %s", key));
                }
                for (int i = 0; i < 3; i++) {
                    print(String.format("=== InputMap type %d", i));
                    InputMap im = impl.searchBox.getInputMap(i);
                    KeyStroke[] allKeys = im.allKeys();
                    if (allKeys != null) {
                        for (KeyStroke ks : allKeys) {
                            print(String.format("  === keystroke %s object %s", ks, im.get(ks)));
                        }
                    }
                }

                // various experiments with FocusTraversalPolicy... NB LayoutTraversalPolicy
                // is what the framework uses here by default

                class MainFrameFocusTraversalPolicy extends LayoutTraversalPolicy {
                    public Component getComponentAfter(Container arg0, Component arg1) {
                        Component comp = super.getComponentAfter(arg0, arg1);
                        print(String.format("=== comp after %s", comp == null ? "Null" : comp.getClass()));
                        return comp;
                    }

                    public Component getComponentBefore(Container arg0, Component arg1) {
                        Component comp = super.getComponentBefore(arg0, arg1);
                        print(String.format("=== comp before %s", comp == null ? "Null" : comp.getClass()));
                        return comp;
                    }

                    public Component getDefaultComponent(Container arg0) {
                        Component comp = super.getDefaultComponent(arg0);
                        print(String.format("=== default comp %s", comp == null ? "Null" : comp.getClass()));
                        return comp;
                    }

                    public Component getFirstComponent(Container arg0) {
                        Component comp = super.getFirstComponent(arg0);
                        print(String.format("=== first comp %s", comp == null ? "Null" : comp.getClass()));

                        return comp;
                        // return impl.searchBox;
                    }

                    public Component getLastComponent(Container arg0) {
                        Component comp = super.getLastComponent(arg0);
                        print(String.format("=== last comp %s", comp == null ? "Null" : comp.getClass()));
                        return comp;
                    }

                    protected boolean accept(Component comp) {
                        boolean accept = super.accept(comp);
                        print(String.format("=== accept %s? %s", comp == null ? "Null" : comp.getClass(), accept));
                        return accept;
                    }
                }
                impl.mainFrame.setFocusTraversalPolicy(new MainFrameFocusTraversalPolicy());
            }
        }
        EventQueue.invokeAndWait(new AddMore());

    }

}

解决方案

this still comes under the workaround heading for me... but it's a bit more useful than the workaround I gave under "later"

if( oppComp == null ){
    final Component srcComp = (Component)focusEvent.getSource();
    FocusTraversalPolicy ftp = impl.mainFrame.getFocusTraversalPolicy();
    Component lastComp = ftp.getLastComponent( impl.mainFrame );
    Component beforeComp = ftp.getComponentBefore( impl.mainFrame, srcComp );

    if( lastComp == beforeComp ){
        EventQueue.invokeLater( new Runnable(){
            public void run() {
                if( impl.mainFrame.isFocused()){
                    srcComp.requestFocus();
                };
            }});
    }
}

Indeed, this is the situation faced by a single focusable component: on Shift-Tab the focus traversal policy then finds that the "before" comp is the same as the "last" comp. Under these circs component focus (as opposed to window focus) appears to vanish. The odd thing is that on Tab (traverse forwards), when the "after" comp is the same as the "first" comp, it doesn't. Is this a bug?

Anyway, having ascertained this you then have to check the focus of the window asynchronously... so that focus can be allowed to go to another window. Results in a slight flicker (boo!) on Shift-Tab.

这篇关于Java Swing:如何停止不需要的shift-tab keystroke动作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆