2009-07-24 5 views
2

У меня, похоже, проблемы с моим кодом java gui, и я понятия не имею, почему он не работает.Проблемы с компонентами swing и событиями awt

Что должно произойти, когда мышь нажата на панели или кадр - пока что позволяет просто сказать панель; так как это всего лишь тест, в конце концов этот код будет реализован для другого компонента gui, но я бы хотел, чтобы эта работа начиналась - всплывающее меню должно стать видимым, а фокус должен быть установлен в текстовом поле . Затем, когда пользователь нажимает кнопку ввода или фокус на текстовом поле теряется, всплывающее меню должно скрываться, а текст сбрасывается до нуля или независимо от того, что мне нужно.

Так это то, что я писал:

public class Test { 
    private final JFrame frame = new JFrame(); 
    private final JPanel panel = new JPanel(); 
    private final JPopupMenu menu = new JPopupMenu(); 
    private final JTextField field = new JTextField(); 
    private final Obj obj; 

    //... constructor goes here 

    public void test(){ 
     frame.setSize(new Dimension(200,200)); 
     field.setColumns(10); 
     field.addActionListener(new ActionListener(){ 
      public void actionPerformed(ActionEvent arg0) { 
       obj.method(field.getText()); 
       menu.setVisible(false); 
       field.setText(""); 
      } 
     }); 
     field.addFocusListener(new FocusListener() { 
      public void focusLost(FocusEvent e) { 
       menu.setVisible(false); 
       field.setText(""); 
      } 

      //... focus gained event goes here 
     }); 
     panel.addMouseListener(new MouseListener() { 
      public void mouseClicked(MouseEvent e) { 
       menu.setLocation(e.getX(), e.getY()); 
       menu.setVisible(true); 
       field.requestFocusInWindow(); 
      } 

      //... other mouse events go here 
     }); 

     menu.add(field); 
     frame.getContentPane().add(panel); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.setVisible(true); 
    } 
} 

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

Если я изменю код, чтобы исключить любые вхождения menu.setVisible(false), тогда текстовое поле никогда не будет фокусироваться.

Это из-за неправильного использования JPopupMenu? Где я иду не так?

Также обратите внимание, что я оставил основной или объект. Они находятся в другом файле и, скорее всего, незначительны для этой проблемы. Obj.method() ничего не делает, и основной вызов вызывает только конструктор Test и метод test().

+0

Какова цель всплывающего меню? – user101884

+0

Кажется странным, что у вас есть текстовое поле во всплывающем меню. Какова мотивация такого подхода? Возможно, есть еще один способ сделать это ... – basszero

ответ

2

Этот код должен работать так, как вы хотите, чтобы работать (надеюсь, вы будете следовать использование анонимных классов:

public class Test { 

public static void main(String[] args) { 
    Test test = new Test(); 
    test.test(); 
} 

private JFrame frame; 
private JPanel panel; 
private JPopupMenu menu; 
private JTextField field; 

public Test() { 
    frame = new JFrame(); 
    frame.setSize(new Dimension(200, 200)); 
    frame.getContentPane().add(getPanel()); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
} 

private JPanel getPanel() { 
    if (panel == null) { 
     panel = new JPanel(); 
     panel.setComponentPopupMenu(getMenu()); 
     panel.addMouseListener(new MouseAdapter() { 

      @Override 
      public void mouseClicked(MouseEvent e) { 
       menu.show(panel, e.getX(), e.getY()); 
      } 
     }); 
    } 
    return panel; 
} 

private JPopupMenu getMenu() { 
    if (menu == null) { 
     menu = new JPopupMenu() { 

      @Override 
      public void setVisible(boolean visible) { 
       super.setVisible(visible); 
       if (visible) { 
        getField().requestFocus(); 
       } 
      } 
     }; 
     menu.add(getField()); 
    } 
    return menu; 
} 

private JTextField getField() { 
    if (field == null) { 
     field = new JTextField(); 
     field.setColumns(10); 
     field.addActionListener(new ActionListener() { 

      @Override 
      public void actionPerformed(ActionEvent e) { 
       getMenu().setVisible(false); 
      } 
     }); 
    } 
    return field; 
} 

public void test() { 
    frame.setVisible(true); 
} 
} 

Ключевые вещи, чтобы заметить это, когда мы настроить всплывающее меню:

panel.setComponentPopupMenu(getMenu()); 
panel.addMouseListener(new MouseAdapter() { 
    @Override 
    public void mouseClicked(MouseEvent event) { 
     getMenu().show(getPanel(), event.getX(), event.getY()); 
    } 
}); 

И как вы запрашиваете фокус для текстового поля, когда отображается всплывающее меню, которое выполняется через текстовое поле с запросом фокуса, но не фокусируется в окне, так как оно не существует в окне, только в меню :

menu = new JPopupMenu() { 
    @Override 
    public void setVisible(boolean visible) { 
     super.setVisible(visible); 
     if (visible) { 
      getField().requestFocus(); 
     } 
    } 
}; 

И, наконец, как текстовое поле отклоняет всплывающее меню:

field.addActionListener(new ActionListener() { 
    @Override 
    public void actionPerformed(ActionEvent e) { 
     getMenu().setVisible(false); 
    } 
}); 
1

Вы должны быть в состоянии сделать это, переопределив getComponentPopupMenu, чтобы вернуть JPopupMenu. Это должно работать точно так, как вы хотите. Это позволит сосредоточиться и т. Д.

EDIT: Это не является строго необходимым, хотя это и позволяет лучше наследовать.

Public JPopupMenu getComponentPopupMenu() { 
    return getMenu(); 
} 

Да, и если вы хотите, чтобы показать на любой мыши, добавить слушатель мыши, и вызов шоу на PopupMenu:

public void processMouseEvent(MouseEvent e) { 
    popup.show(this, e.getX(), e.getY()); 
} 

Это покажет его на любой мыши.

или, другой вариант, если у вас есть слушатель мыши (вызов processMouseEvent), и вы хотите только позвонить на правой кнопкой мыши:

public void processMouseEvent(MouseEvent e) { 
    if (e.isPopupTrigger()) { 
     popup.show(this, e.getX(), e.getY()); 
    } 
} 

Слушатель мыши будет выглядеть следующим образом:

panel.addMouseListener(new MouseAdapter() { 
    mouseClicked(MouseEvent e) { 
     processMouseEvent(e); 
    } 
} 
+0

Я обновлю свой вопрос, но все, что я сделал, это change setVisible, чтобы показать, и он работает, за исключением того, что фокус не переключается автоматически в текстовое поле. Он больше не скрывает ... спасибо. – Victor

+0

Правильно, и если вы используете getPopupMenu или создаете popup.show (...), фокус затем обрабатывается Swing, и вы получаете это поведение бесплатно. – aperkins

+0

Я добавил несколько частей, чтобы попытаться сделать это более понятным - слушатель мыши вызывает методы mouseEvent. Опять же, с popup.show вы позволяете фокусу основного фреймворка фокусироваться на вас. – aperkins

0

Когда вы показываете всплывающее окно, у него должен быть фокус (и он, вероятно, захватывает его), все остальное действительно не имеет большого смысла.

Так что, вероятно, происходит следующее: Меню показывает и захватывает фокус.

со следующей командой вы перемещаете фокус на текстовое поле. Поскольку всплывающее окно не имеет фокуса, а всплывающее окно без фокуса бесполезно, оно снова скрывается.

+0

, что на самом деле не имеет смысла, потому что он скрывается только тогда, когда у меня есть код menu.setVisible (false) в моем коде, даже если у меня есть field.requestFocusInWindow() - он не скрывает. – Victor

1

Я хотел бы отметить, что я обнаружить с помощью использования предложенных методов, которые setComponentPopupMenu() автоматически добавляет MouseListener для отображения данный PopupMenu, который затем потребляет событие щелчка правой кнопкой мыши.
Так что все, что находится внутри структуры if(e.isPopupTrigger()), никогда не запускается по правому клику, потому что событие расходуется.

По существу, я задаю вопрос, указанный в моем вопросе, просто добавив panel.setComponentPopupMenu(getMenu()), но тот факт, что он потребляет все мои щелчки правой кнопкой мыши, а не только mouseClicked, чрезвычайно ограничивает.