Domanda

Ora ho un JMenu e alcuni JMenuItem al suo interno.Voglio che il mio programma esegua alcune azioni quando lo stato di JMenu e JMenuItem viene modificato in "selezionato".Non utilizzo MouseOver di MouseLitener, perché voglio che l'utente possa navigare nel menu anche utilizzando le tastiere.Ora, ho scritto questo ascoltatore:

class MenuItemListener implements ChangeListener {
    @Override
    public void stateChanged(ChangeEvent arg0) {
        JMenuItem item = (JMenuItem) arg0.getSource();
        if(item.isSelected())
            System.out.println(item.getText()+" pressed!");
    }
}

Quando aggiungo questo ascoltatore a JMenu, funziona correttamente, ma quando lo aggiungo a JMenuItem, non succede nulla...Quando elimino l'istruzione if in modo che l'ascoltatore reagisca entrambi, quando il menu è selezionato e deselezionato, funziona bene sia per JMenu che per JMenuItem.Quindi, come vedo, JMenuItem non può "superare" il test isSelected()...Ma cosa può essere un problema?:S

È stato utile?

Soluzione

Senza offesa, questa è solo una di quelle domande con una storia

  • requisito iniziale:fare qualcosa quando il mouse si trova su JMenuItem
  • iniziale, tutti cari:MouseListener
  • suggerimento iniziale deviante (complimenti a @mKorbel!):ChangeListener sul buttonModel, controllando la proprietà rollover

  • requisito raffinato:fai qualcosa quando JMenuItem è appena evidenziato, sia con la tastiera che con il passaggio del mouse.

  • raffinato tesoro:ChangeListener sul buttonModel, proprietà non specificata
  • deviazione raffinata:ActionListener

  • requisito attuale:faiSomething quando la proprietà "selezionata" JMenu o JMenuItem è cambiata.

  • tesoro attuale:non può essere fatto con un ascoltatore, override ...
  • deviazioni attuali:Azione, MenuListener...

La risposta corretta e completa (col senno di poi, dato che la tastiera non era ancora stata menzionata) era già disponibile al primo turno:alcuni ascoltatori semantici che sono "abbastanza di basso livello" per catturare i cambiamenti di stato (i candidati vengono ribaltati, armati, selezionati, premuti a livello di buttonModel) che fanno cambiare il loro menuItems evidenziato stato.Sfortunatamente, la relazione esatta non è ben nota (almeno a me), non documentata (leggi:io che sono pigro non sono riuscito a trovare nulla con una rapida occhiata) e persino confuso (di nuovo, per me) poiché il rollover è sempre falso (?) per menuItems

La reazione dello sperimentalista è quella di...Tentativo:di seguito è riportato uno snippet di codice che ascolta e registra le modifiche di stato su alcuni menu ad albero (basta lanciarlo in una menuBar arbitraria e spostare il mouse e navigare tramite tastiera).

E il vincitore è:- usa un ChangeListener e controlla se la sorgente è selezionata o armata.

    ChangeListener ch = new ChangeListener() {

        @Override
        public void stateChanged(ChangeEvent e) {
            if (e.getSource() instanceof JMenuItem) {
                JMenuItem item = (JMenuItem) e.getSource();
                if (item.isSelected() || item.isArmed()) {
                    System.out.println("Highlighted: " + item.getActionCommand());
                }
            }
        }
    };

funziona sia per tastiera che per mouse, sia JMenu che JMenuItem

//----------- code snippet to track property changes in menuItem/buttonModel

    // test menu
    JMenu menu = new JMenu("Sample menu");
    menu.setMnemonic('s');
    installListeners(menu);

    // first menuitem
    JMenuItem other = menu.add("content1");
    installListeners(other);
    // second menuitem
    other = menu.add("again + ");
    installListeners(other);

    // sub
    JMenu sub = new JMenu("subMenu");
    installListeners(sub);
    menu.add(sub);

    // menus in sub
    other = sub.add("first in sub");
    installListeners(other);
    other = sub.add("second in sub");
    installListeners(other);

    getJMenuBar().add(menu);

private void installListeners(JMenuItem menu) {
    menu.getModel().addChangeListener(getChangeListener());
    menu.addChangeListener(getChangeListener());
}

private ChangeListener getChangeListener() {
    ChangeListener ch = new ChangeListener() {

        @Override
        public void stateChanged(ChangeEvent e) {
            if (e.getSource() instanceof ButtonModel) {
                ButtonModel model = (ButtonModel) e.getSource();
                System.out.println("from model: " + createStateText(model));
            } else if (e.getSource() instanceof JMenuItem) {
                JMenuItem item = (JMenuItem) e.getSource();
                System.out.println("  from item: " + createStateText(item));
            }
        }

        private String createStateText(ButtonModel model) {
            String text = model.getActionCommand() + " armed: " + model.isArmed();
            text += " selected: " + model.isSelected();
            text += " rollover " + model.isRollover();
            text += " pressed: " + model.isPressed();
            return text;
        }

        private String createStateText(JMenuItem model) {
            String text = model.getActionCommand() + " armed: " + model.isArmed();
            text += " selected: " + model.isSelected();
            // not supported on JMenuItem nor on AbstractButton
           // text += " rollover " + model.isRollover();
           // text += " pressed: " + model.isPressed();
            return text;
        }
    };
    return ch;
}

Altri suggerimenti

Questo è il comportamento polimorfico previsto.Il metodo isSelected() di JMenuItem è ereditata da AbstractButton, mentre lo stesso metodo in Jmenu è sovrascrittocosì che "restituisce true se il menu è attualmente selezionato (evidenziato)."

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top