Swing Focus von JComboBox entfernen, ohne einem anderen Feld den Focus zuzuweisen

Nachtschicht

Mitglied
Hallo zusammen,

ich stehe gerade wieder vor einem kleinen Problem.
Für eine JComboBox habe ich einen ItemListener gebaut, der bei Auswahl eines Items anhand dessen die Hintergrundfarbe der JComboBox ändert.
Das funktioniert nach einigem Hin- und Herprobieren auch soweit gut, nur ein Problem bleibt:
Nach der Auswahl hat die JComboBox den Focus und statt der neu zugewiesenen Hintergrundfarbe hat das Feld die blau-graue Farbe eines ausgewählten Items.

Das ist nur ein kleiner Schönheitsfehler, mit dem ich notfalls auch leben kann, aber wenn es eine unkomplizierte Lösung dafür gibt, wäre es nett, das Problem loszuwerden.
Ich möchte nicht unbedingt irgendeinem anderen Feld den Focus geben, das fände ich irgendwie unsauber und auch etwas verwirrend.
Ich habe auch überlegt, ob ich den Focus an irgendein Dummy-Element loswerden kann, das nicht sichtbar darauf reagiert, wenn da jemand einen Tip hat, was man dafür nehmen kann, her damit.
 
Du hast da noch ein anders beziehungsweises zusaetzliches Problem: Das Look and Feel. Je nach LaF kann das setzen einer Hintergrundfarbe funktionieren oder nicht. Das GTK-LaF zum Beispiel ignoriert sehr gerne gesetzte Hintergrundfarben weil sowas in GTK einfach nicht vorgesehen ist. Und ob und wann die gesetzte Hintergrundfarbe gezeichnet wird ist auch wieder vom LaF abhaengig.

Eine Alternative die ueberall funktioniert waere zum Beispiel die Farbe in einem eigenen Feld neben dem Auswahlfeld anzuzeigen, also von einer JComponent ableiten und dann die Hintergrundfarbe auf sich selbst fuellend zeichnen sollte reichen. Eine andere Moeglichkeit waere das LaF fix vorzugeben und dann eine darauf angepasste Loesung zu machen. Viele LaFs erlauben es Farben zu ueberschreiben oder umzusetzen zur Laufzeit, aber das haengt vom LaF ab.
 
Du hast da noch ein anders beziehungsweises zusaetzliches Problem: Das Look and Feel. Je nach LaF kann das setzen einer Hintergrundfarbe funktionieren oder nicht. Das GTK-LaF zum Beispiel ignoriert sehr gerne gesetzte Hintergrundfarben weil sowas in GTK einfach nicht vorgesehen ist. Und ob und wann die gesetzte Hintergrundfarbe gezeichnet wird ist auch wieder vom LaF abhaengig.

Eine Alternative die ueberall funktioniert waere zum Beispiel die Farbe in einem eigenen Feld neben dem Auswahlfeld anzuzeigen, also von einer JComponent ableiten und dann die Hintergrundfarbe auf sich selbst fuellend zeichnen sollte reichen. Eine andere Moeglichkeit waere das LaF fix vorzugeben und dann eine darauf angepasste Loesung zu machen. Viele LaFs erlauben es Farben zu ueberschreiben oder umzusetzen zur Laufzeit, aber das haengt vom LaF ab.

Das ist eine interessante Info... das hieße, auch wenn es jetzt funktioniert, tut es das evtl. nicht mehr, wenn Microsoft da mal wieder was ändert?

Über andere Betriebssysteme muß ich mir im Moment noch keine Gedanken machen, mein Tool wird nur Firmenintern eingesetzt werden und da ändert sich nicht so leicht das benutzte System. Gibt es irgendwo sowas wie eine Übersicht gängiger LaF und der Unterschiede in deren Verhalten?

So sieht das ganze im Moment aus, der Hintergrund für das Textfeld der ComboBox war ein bischen tricky:

JComboBox_Farbe.jpg

Ohne Auswahl -> direkt nach Auswahl -> ohne Focus -> ohne Focus geöffnet

Daß der Hintergrund der gesamten Auswahlliste auch grün ist, ist eigentlich nicht nötig, stört aber auch nicht.

Und hier noch der Code dazu:
Java:
cbSegment = new JComboBox<Shop>(Shop.values());
        cbSegment.setBounds(10, 75, 80, 20);
        cbSegment.setEditable(false);
//Dieser Teil prüft, ob überhaupt ein Datensatz im Dialog zu sehen ist und ermittelt und setzt die Farbe, wenn das der Fall ist
        if(UP==null)
            cbSegment.setSelectedIndex(-1);
        else
            cbSegment.setSelectedItem(UP.getUnterabteilung());
        Shop selectedShop = (Shop)cbSegment.getSelectedItem();
        JComponent comp = (JComponent)cbSegment.getEditor().getEditorComponent();
        comp.setBackground(selectedShop==null?Color.WHITE:Color.decode(TSM_Kapazitaetsplanung.hmFarben.get(selectedShop.Kurzname())));      

        cbSegment.addItemListener(new ItemListener() {
            @Override
            public void itemStateChanged(ItemEvent e) {
                if(e.getStateChange() == ItemEvent.SELECTED){
                    JComboBox localCombo = (JComboBox)e.getSource();
                    setCBBackground(localCombo);                    
                }              
            }
        });



    private void setCBBackground(JComboBox argCombo) {  
        // die Farbe wird aus einer HashMap anhand eines Wertes im enum Shop ermittelt
        Shop selectedShop = (Shop)argCombo.getSelectedItem();
        argCombo.setBackground(Color.decode(TSM_Kapazitaetsplanung.hmFarben.get(selectedShop.Kurzname())));
        JComponent comp = (JComponent)argCombo.getEditor().getEditorComponent();
        comp.setBackground(Color.decode(TSM_Kapazitaetsplanung.hmFarben.get(selectedShop.Kurzname())));
    }

    private void setCBBackground(JComboBox argCombo) {  
        // zur Übersichtlichkeit nochmal der wesentliche Teil ohne die Ermittlung der Farbe
       
        argCombo.setBackground(Color.MeineFarbe); //wird trotz des comp.setBacground(...) gebraucht, sonst wird keine Hintergrundfarbe sichtbar
        JComponent comp = (JComponent)argCombo.getEditor().getEditorComponent();
        comp.setBackground(Color.MeineFarbe); //wird für die Hintergrundfarbe des Textfeldes gebraucht
    }
 
Also du verwendest das Metal LaF, was so ziemlich der Standard ist. Das kannst du auch in deiner Applikation setzen unabhaengig davon wie das System konfiguriert ist.

Das gesagt, die einfachste Variante wird vermutlich werden die LaF Klasse selbst zu erweitern, in dem Fall waere es die MetalComboBoxUI, beim zeichnen der Komponente zieht diese die Farbe fuer den selektierten Hintergrund aus einer JList-Klasse.

Ein ganz, ganz, ganz kruder Beweis dass man das umsetzen kann waere dies:

Java:
comboBox.setUI(new MetalComboBoxUI() {
    @Override
    public void paint(Graphics g, JComponent c) {
        listBox.setSelectionBackground(Color.RED);
        
        super.paint(g, c);
    }
});

Muesste man natuerlich aufarbeiten und schoener gestalten. Am besten in den Faellen ist immer wenn man direkt den Quellcoder der LaF-Klassen liest und schaut wo die sich die Eigenschaften herholen.
 
Also du verwendest das Metal LaF, was so ziemlich der Standard ist. Das kannst du auch in deiner Applikation setzen unabhaengig davon wie das System konfiguriert ist.

Das gesagt, die einfachste Variante wird vermutlich werden die LaF Klasse selbst zu erweitern, in dem Fall waere es die MetalComboBoxUI, beim zeichnen der Komponente zieht diese die Farbe fuer den selektierten Hintergrund aus einer JList-Klasse.

Ein ganz, ganz, ganz kruder Beweis dass man das umsetzen kann waere dies:

Java:
comboBox.setUI(new MetalComboBoxUI() {
    @Override
    public void paint(Graphics g, JComponent c) {
        listBox.setSelectionBackground(Color.RED);
       
        super.paint(g, c);
    }
});

Muesste man natuerlich aufarbeiten und schoener gestalten. Am besten in den Faellen ist immer wenn man direkt den Quellcoder der LaF-Klassen liest und schaut wo die sich die Eigenschaften herholen.
Danke, das hört sich gut an, dann wäre ich zumindest größtenteils sicher, daß mein UI weiterhin so aussieht, wie ich es programmiert habe, wenn auch vielleicht etwas "altbacken".
Vielleicht bekomme ich ja so auch meine Farbwünsche erfüllt 😅

P.S.: Habs direkt mal getestet und als Versuch mal das System LaF eingestellt. Die Unterschiede sind gar nicht mal so verheerend, wie ich befürchtet habe, bis auf ein paar Kleinigkeiten paßt alles.
Eine der Kleinigkeiten, die nicht funktioniert, ist genau diese JComboBox-Hintergrundfarbe, da bleibt alles grau.
 

Zurück
Oben