Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: GUI и Java FX приложения > Запрещение передачи фокуса


Автор: AndreyF 5.1.2006, 17:30
Правильно ли я мыслю?

Мне нужно запретить передавать фокус из редактора ячейки таблицы в любой другой элемент окна. При этом менять текущую ячейку так же нельзя. Мой вариант решения разбит на два этапа. На первом этапе я запрещаю таблице менять текущую ячейку следующим образом:
наследуя класс JTable переопределяется метод
Код

public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend)

Переопределение заключается в том, что добавляется только одно условие
Код

if (getEditingColumn() != -1 || getEditingRow() != -1) return;        

С этого условия начинается метод. Естественно приходиться перетаскивать в нетронутом виде все private методы класса JTable, которые используются в
Код

public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend)


На втором этапе на редактор ячейки навешивается слушатель изменения фокуса и если фокус теряется, когда это запрещено, слушатель возвращает фокус редактору ячейки насильно ---
Код

grabFocus()



Первый этап для меня более или менее приемлем, но второй вызывает большое недоверие, ведь фокус то на мгновение, но теряется!
Подскажите, пожалуйста, возможные варианты решения.

Автор: Ortega 6.1.2006, 06:03
Если редактор ведет свою родословню от JComponent, можно попробовать использовать InputVerifier. В нем переопределяется метод
Код

public boolean verify(JComponent input)

и компоненту делается
Код

setInputVerifier()
Пока verify не вернет true, фокус с компонента никуда не денется.
Добавлено @ 06:03
Цитата

Переопределение заключается в том, что добавляется только одно условие
...
С этого условия начинается метод. Естественно приходиться перетаскивать в нетронутом виде все private методы класса JTable...

А зачем? ведь можно сделать
Код

public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend)
{
  if (getEditingColumn() != -1 || getEditingRow() != -1) return;  
  super.changeSelection(rowIndex, columnIndex, toggle, extend);
}

Автор: AndreyF 10.1.2006, 11:48
Спасибо! Вариант с вызовом родительского метода выглядит очень изящно!

Но фокус, к сожалению, не получается удержать полностью. Фокус не убежит с одного текстового поля на другое, но если щелкнуть мышкой по кнопке, то кнопка получит событие нажатия и не получая фокуса. Так же можно мышкой открыть ComboBox. Но мне нужно запретить нажатия всех кнопочек, списочков и т.д.

Код

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;

import javax.swing.InputVerifier;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JTextField;

public class InputVerifierTest extends JFrame{

    public InputVerifierTest(){
        super("InputVerifier");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        
        final JTextField txt1 = new JTextField();
        final JButton btn = new JButton("Click here!");
        
        btn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                System.out.println("Button clicked!");
            }
        });
        final InputVerifier iv = new InputVerifier() {
            public boolean verify(JComponent cmp) {
                JTextField txt = (JTextField)cmp;
                try {
                    Integer.parseInt(txt.getText());
                    return true;
                } catch(Exception e) {}
                
                System.out.println("verify: false !!!");
                return false;
            }
        };
        
        txt1.setInputVerifier(iv);
        txt1.setPreferredSize(new Dimension(60, 20));
        txt1.setVerifyInputWhenFocusTarget(false);
        txt1.addFocusListener(new FocusListener() {
            public void focusGained(FocusEvent e){
                System.out.println("Text1 focus gained!");
            }

            public void focusLost(FocusEvent e) {             
             System.out.println("Text1 focus lost!");
             if (!iv.verify(txt1)) txt1.grabFocus();
            }            
        });
        
        final JTextField txt2 = new JTextField();
        txt2.setPreferredSize(new Dimension(60, 20));
        txt2.addFocusListener(new FocusListener() {
            public void focusGained(FocusEvent e){
                System.out.println("Text2 focus gained!");
            }

            public void focusLost(FocusEvent e) {
             System.out.println("Text2 focus lost!");
            }            
        });
        
        getContentPane().setLayout(new FlowLayout());
        getContentPane().add(txt1);
        getContentPane().add(txt2);
        getContentPane().add(new JComboBox((Object[]) new String[]{"abc", "def", "hgi", "jkl"}));
        getContentPane().add(btn);
        
        pack();
        setVisible(true);
    }
    
    public static void main(String[] args) {
        new InputVerifierTest();
    }
}


Автор: 02077461 10.1.2006, 18:21
А setEnabled(false) не подходит??.
Код

JButton button = new JButton("Button 1");
button.setEnabled(false);

или
Код

JPanel manualPanel = new JPanel();
for (int i = 0; i<manualPanel.getComponentCount();i++)
manualPanel.getComponent(i).setEnabled(proxyManual.isSelected());
чтобы всю панель деактивировать...

Автор: AndreyF 11.1.2006, 15:38
setEnabled(false) не подходит по трем причинам. Во-первых, количество компонентов определяется динамически и уследить за каждым довольно сложная задача. Во-вторых, кнопка меняет свой внешний вид, а это не нужно. В-третьих, если в редакторе таблицы введены корректные данные, то фокус и событие можно передать другому компоненту, запрет на любую работу с другими компонентами должен быть только если ячейка таблицы заполнена некорректными данными.


Обсуждение наводит меня на идею --- комбинировать InputVerifier, который запретит передачу фокуса клавиатуры другим компонентам и Использования прозрачной панели поверх всего фрейма. Эта панель быдет появляться только при входе в редактор и исчезать при выходе из него. Прозрачная панель одна примет все события мыши. Те из них, которые будут происходить внутри редактора, будут переданы ему, а остальные будут переданы "под прозрачную панель", только если удасться закрыть редактор ячейки.

Хотелось бы получить какие-нибудь рецензии.

PS
Никак не могу отделаться от мысли, что эта проблема легко решается без всяких изворотов, а только лишь с помощью стандартных средств.

Автор: Hroft 6.2.2006, 13:14
А зачем это все надо? Как я себе это представляю, лично мне было бы неудобно, если бы меня не отпускали, пока я не введу "правильное" с точки зрения программы значение. А пользователю должно быть удобно, это - самое главное.
Или, может, лучше переопределить cellEditor и следить, правильное ли мы значение имеем после каждой нажатой клавиши?

Автор: AndreyF 7.2.2006, 00:47
Дело в том, что правильны ли данные в ячейке, нет ли, определяет не сама программа, а сервер у которого она это спрашивает, так же как и любые другие компоненты большинство своих событий отправляют на сервер, который решает что делать дальше --- создать/изменить/удалить некоторые(й) компонент(ы). Вопрос удобно это или нет не стоит, т.к. львиная доля системы (которая даже не знает что такое Java) требует именно такого поведения от графической оболочки --- это всего лишь "проигрыватель".

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)