Problem mit einer JComboBox, Event temporär deaktivieren

Dieses Thema Problem mit einer JComboBox, Event temporär deaktivieren im Forum "Allgemeine Java-Themen" wurde erstellt von FrittenFritze, 5. Dez. 2016.

Thema: Problem mit einer JComboBox, Event temporär deaktivieren Hallo zusammen, ich habe da ein kleines Problem und zwar habe ich folgende Konstellation: 1. eine JComboBox wird...

  1. Hallo zusammen,

    ich habe da ein kleines Problem und zwar habe ich folgende Konstellation:

    1. eine JComboBox wird "von aussen" befüllt, diese hat einen ActionListener registriert.
    2. dieser ActionListener feuert, wenn ein Eintrag ausgewählt wird und befüllt die zweite JComboBox
    3. die wiederrum auch einen ActionListener registriert hat
    4. der dann feuert wenn in der zweiten JComboBox ein Eintrag ausgewählt wird.

    Das ganze funktioniert auch einwandfrei, beim ersten Mal. Wenn man die erste JComboBox dann verändert, fliegt das Ganze mit einer NPE raus. Es ist so, dass die erste JComboBox die Einträge aus der zweiten rauswirft und beim ChangeEvent der ActionListener der zweiten JComboBox feurt.

    Gibt es eine Möglichkeit zu sagen "jetzt deaktiviere ich kurzzeitig die Events" und sie dann wieder einschalten?

    Hier der Code:

    Code (Text):

        JComboBox<Object> cbxLang = new JComboBox<Object>();
         Iterator<String> iterator = languageList.iterator();
         
         JComboBox<Object> cbxModel = new JComboBox<Object>();
         
         while (iterator.hasNext()) {
           String next = iterator.next();
           cbxLang.addItem(makeObj(next));
         }
         
         cbxLang.addActionListener(new ActionListener() {
           
           @Override
           public void actionPerformed(ActionEvent e) {
             _wds_dvd.setDVDLanguage(((JComboBox<Object>)e.getSource()).getSelectedItem().toString());
             _logger.info("Selected language: " +((JComboBox<Object>)e.getSource()).getSelectedItem().toString());
             
             List<String> modelList = _wds_dvd.getModelList();
             Iterator<String> iterator = modelList.iterator();
             
             cbxModel.removeAllItems();
             
             
             while (iterator.hasNext()) {
               String next = iterator.next();
               cbxModel.addItem(makeObj(next));
             }
             
             cbxModel.addActionListener(new ActionListener() {
               
               @Override
               public void actionPerformed(ActionEvent e) {
                 _logger.info("Selected modelline: " + ((JComboBox<Object>)e.getSource()).getSelectedItem().toString());
                 _wds_dvd.setModel(((JComboBox<Object>)e.getSource()).getSelectedItem().toString());
                 try {
                   String navigationXML = _wds_dvd.getNavigationXML();
                   _navTree.setIconLocation(_wds_dvd.getIconLocation());
                   _navTree.setCellRenderer(new WDSCellRenderer());
                   _navTree.buildNavigationTree(navigationXML);
                   open_wds ();
                 } catch (IOException e1) {
                   e1.printStackTrace();
                 }
               }
             });
           }
         });
     
    Danke Euch schon mal. :)
     
  2. Vielleicht hilft dir das Grundlagen Training weiter --> *Klick*
  3. Du könntest auch einfach mal ein paar sicherheitsabfragen in deinen actionlistener machen. Wenn du natürlich einfach auf getsource.getselecteditem zugreifst obwohl vielleicht gar keine items drin sind, dann kann das nicht klappen
     
  4. Naja, das beseitigt ja nicht das eigentliche Problem, dass der ActionListener feuert, obwohl es gar nicht notwendig ist. Das Sauberste wäre den ActionListener rauszuhängen...
     
  5. Lösung gefunden:

    Code (Text):

         JComboBox<Object> cbxLang = new JComboBox<Object>();
         Iterator<String> iterator = languageList.iterator();
         
         JComboBox<Object> cbxModel = new JComboBox<Object>();
         
         while (iterator.hasNext()) {
           String next = iterator.next();
           cbxLang.addItem(makeObj(next));
         }
         
         cbxLang.addActionListener(new ActionListener() {
           
           @Override
           public void actionPerformed(ActionEvent e) {
             _wds_dvd.setDVDLanguage(((JComboBox<Object>)e.getSource()).getSelectedItem().toString());
             _logger.info("Selected language: " +((JComboBox<Object>)e.getSource()).getSelectedItem().toString());
             
             List<String> modelList = _wds_dvd.getModelList();
             Iterator<String> iterator = modelList.iterator();
             
             final ActionListener[] actionListeners = cbxModel.getActionListeners();
             
             for (final ActionListener listener : actionListeners) {
               cbxModel.removeActionListener(listener);
             }
             
             try {
               cbxModel.removeAllItems();
               while (iterator.hasNext()) {
                 String next = iterator.next();
                 cbxModel.addItem(makeObj(next));
               }
             } finally {
               for (final ActionListener listener : actionListeners) {
                 cbxModel.addActionListener(listener);
               }
             }
             
             cbxModel.addActionListener(new ActionListener() {
               
               @Override
               public void actionPerformed(ActionEvent e) {
                 _logger.info("Selected modelline: " + ((JComboBox<Object>)e.getSource()).getSelectedItem().toString());
                 _wds_dvd.setModel(((JComboBox<Object>)e.getSource()).getSelectedItem().toString());
                 try {
                   String navigationXML = _wds_dvd.getNavigationXML();
                   _navTree.setIconLocation(_wds_dvd.getIconLocation());
                   _navTree.setCellRenderer(new WDSCellRenderer());
                   _navTree.buildNavigationTree(navigationXML);
                   open_wds ();
                 } catch (IOException e1) {
                   e1.printStackTrace();
                 }
               }
             });
           }
         });
     
    Mit getActionListeners holt man sich alle registrierten Listener raus, läuft die Liste durch und löscht sie (.remove(listener)), macht was auch immer man machen will und hängt sie wieder rein (.addActionListener(listener)).

    Fertig...
     
  6. Oh Mann....

    Klar viel besser so....
     
  7. Ist irgendwas "falsch" oder warum so viele ....?
     
  8. Joose
    Joose Mitarbeiter
    Falsch ist es nicht, aber unnötig die Listener zu entfernen um sie dann wieder hinzuzufügen.
    Eine einfache Abfrage in der actionPerformed wie Thallius schon gesagt hat würde reichen.
     
  9. Mehrere Lösungen führen zum Ziel.

    Ich vermeide lieber, dass der Listener feuert statt per Abfrage rauszuhüpfen.
     
  10. Was meinst du wohl was mehr Performance kostet? Eine If-Abfrage oder das Hinzufügen und Entfernen der Listener?

    Das ist einfach typisch für die heutige Zeit. Speicher und CPU Power haben wir ja genug und wenn nicht soll sich der User gefälligst einen besseren Rechner kaufen.

    In diesem Fall ist es sogar weniger Code die Performance zu steigern als Deine merkwürdige Lösung. Aber hey es funktioniert ja warum sollte ich also weiter drüber nachdenken....
     
  11. Hast Du schlecht gegessen??? Typisch für heutige Zeit, so ein Schwachsinn.

    Diese Abfrage läuft genau ein mal beim Start... jetzt bleib mal auf dem Teppich. Und der einzige User bin ich selbst....
     
    Zuletzt bearbeitet: 6. Dez. 2016
  12. Ich würde das nicht gerade als "merkwürdige" Lösung bezeichnen. Bei uns handhaben wir das genau so. Warum? Weil mit organischem wachsen der Software handelt man sich so immer mehr und mehr solcher if/elses ein. Diese haben dann mit der eigentlichen Aufgabe der Listener nichts mehr zu tun und dienen nur noch der Steuerung: "Darf ich nun oder darf ich nicht". Der Code wird dadurch mitunter schwerer lesbar. Darum wurde bei uns diese Guideline des Entfernens/wieder hinzufügens eingeführt.

    Meiner Meinung nach kann man heutzutage gut und gerne auf Performance Optimierung verzichten, wenn dadurch besser wartbarer/lesbarer Code entsteht. Das kann natürlich jeder so machen wie er will. Letztenendes ist es wohl eine Design Entscheidung.
     
  13. Genau diese Guideline gab es bei uns auch. Gab weil ich nicht mehr bei dem Arbeitgeber bin. Ich bin nicht dafür etwas unnötig feuern zu lassen um dann abzufragen "brauche ich oder nicht". Das ist ein schlechtes Design, so meine Meinung, auch wenn "Herr Softwareentwickler" es anders sehen mag. Vor allem, wenn Tausende von diesen Event fliegen... was da wohl mehr Performance kostet????

    Egal, Problem gelöst, Diskussion zu Ende.
     
  14. Kostenloses Java-Grundlagen Training im Wert von 39 €
    Schau dir jetzt hier das Tutorial an und starte richtig durch!