Cześć,
od kilku dni męczę się z interfejsem do mojego programu w Java SE. Ciągle mam problem z JComboBox.
Zadawałem już pytania na innych forach jednak chyba nie rozumieją mnie o co chodzi, a ja po eng. nie potrafię tego jasno wytłumaczyć.

Używając metod JComboBox'a nie zdefiniujemy takich rzeczy jak wygląda buttona po prawej stronie (tego ze strzałką po kliknięciu, którego lista się rozwija) oraz renderów. Składniki te są prywatne/protected. Ten button, to javax.swing.plaf.basic.BasicArrowButton. Jest to zwykły JButton, trochę rozbudowany, z rysowaniem tego trójkącika.
Dziedziczenie w Java też więc odpada. Jedyna metoda która mi zadziałała jest niepoprawna i w ogóle szalona.

Ogólne pytanie: Jak najlepiej przedefiniować całkowicie wygląd komponentów Swing'a, mając na uwagę, że dziedziczenia się nie użyje z powodu masy metod prywatnych, w których dzieje się kolorowanie etc. Jakiego wzroca/metody użyć? Są to z góry zdefiniowane klasy biblioteki bazowej, w której kodu źródłowego zmieniać przecież nie chcę. Jak żyć, Panowie programiści?

  1. Chciałbym stworzyć własnego JCombobox i BasicArrowButton - jednak z powodu braku możliwości nadpisywania metod prywatnych nie da się.
  2. Utworzyłem klasę z metodą statyczną, która zwracała mi JComboBox pokolorowanego jak chciałem oraz ze zmienionym BaseArrowButton na mój własny - nie działa, nie wiem dlaczego, ani button się nie podmienia, ani kolory tła itp.
  3. Działa jedynie zlepek rozwiązań z różnych forów.

Na początek klasa DefaultArrowButton, która jest rozszerzeniem oryginalnego BasicArrowButton (użyte w 1,2,3):

package gui;

import helpers.HFColors;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Polygon;
import javax.swing.BorderFactory;
import javax.swing.plaf.basic.BasicArrowButton;

/**
 *
 * @author Szymon Strzałka
 */
public class DefaultArrowButton extends BasicArrowButton {
    
    public DefaultArrowButton(int direction) {
        super(direction);
        setBackground(HFColors.BLUE);
        setBorder(BorderFactory.createEmptyBorder(0,0,0,0));
        
    }
    
    public DefaultArrowButton(int direction, Color background, Color shadow, 
            Color darkShadow, Color highlight) {
        super(direction, background, shadow, darkShadow, highlight);
    }
    
    public void paintTriangle(Graphics g, int x, int y, int size, int direction,
                          boolean isEnabled)
    {
        Color savedColor = g.getColor();

        paintTriangleSouth(g, x, y, size, isEnabled);

        g.setColor(savedColor);
    }
    
    private void paintTriangleSouth(Graphics g, int x, int y, int size, 
            boolean isEnabled) {
        int tipX = x + (size - 2) / 2;
        int tipY = y + (size - 1) + 1;
        int baseX1 = tipX - (size - 1) - 1;
        int baseX2 = tipX + (size - 1 + 1);
        int baseY = y - 1;
        Polygon triangle = new Polygon();
        triangle.addPoint(tipX, tipY);
        triangle.addPoint(baseX1, baseY);
        triangle.addPoint(baseX2, baseY);
        
        if (isEnabled)
        {
            g.setColor(HFColors.DARK_BLUE);
            g.fillPolygon(triangle);
            g.drawPolygon(triangle);
        } else
        {
            g.setColor(HFColors.DARK_BLUE);
            g.fillPolygon(triangle);
            g.drawPolygon(triangle);
        }
    }
}

Klasa zwracająca w metodzie statycznej pokolorowanego JComboBoxa - kod kopiowany z metody (3) poniżej. Niestety tutaj jakby kompiler go ignorował. Combobox jest bez zmian. Nawet BaseArrowButton się nie podmienia

    public static JComboBox getDefaultComboBox() {
        JComboBox<String> comboBox = new JComboBox<>();
        comboBox.setUI(new BasicComboBoxUI() {
            @SuppressWarnings({"serial"})
            @Override
            protected ComboPopup createPopup() {
                return new BasicComboPopup(comboBox) {
                    {
                        //---style popup anyway you like
                        //this.setBorder(BorderFactory.createLineBorder(Color.green, 2));//---popup's border color
                    }
                };
            }            
            @Override
            protected JButton createArrowButton() {
                JButton button;
                
                button = new DefaultArrowButton(BasicArrowButton.SOUTH, HFColors.BLUE, HFColors.BLUE, HFColors.BLUE, HFColors.BLUE);
                button.setBackground(HFColors.BLUE);
                button.setForeground(Color.CYAN);
                button.repaint();
                
                
                JButton result = new JButton();
                result.setForeground(Color.WHITE);
                result.setBackground(HFColors.BLUE);//---button's color
                //return result;
                
                return button;
            }
        });
        
        comboBox.setRenderer(new ListCellRenderer<String>() {
            @Override
            public Component getListCellRendererComponent(JList<? extends String> list, String value, int index,
                    boolean isSelected, boolean cellHasFocus) {
                JLabel result = new JLabel(value);
                result.setOpaque(true);
                result.setBackground(isSelected ? HFColors.BLUE : HFColors.ROYAL_BLUE); //---item background color
                return result;
            }
        });

        comboBox.setBorder(BorderFactory.createLineBorder(HFColors.BLUE));
        comboBox.setBackground(HFColors.ROYAL_BLUE);
        comboBox.setForeground(Color.WHITE);
        comboBox.revalidate();
        comboBox.repaint();

        //this.component = comboBox;
        
        return comboBox;
    }

Poniższy kod działa. To jest "rozwiązanie" z puktu (3). Nie wiem dlaczego tą metodą "magicznie" działą @Override nawet metod protected! To jakieś głupie i szalone, nie wiem jakim cudem to działa. Rozwiazaniem to jednak nie jest, pomimo, że rozwiązuje problem.
Jest, to kod z konstruktora JPanel. Nie zamieszczam całego kodu ponieważ jest długi. Docelowy JComboBox, to categoryList. Jest on generowany automatycznie przez Netbeans.

        // to jest metoda nadająca JComboBoxowi bacground, foreground i font'a. To samo co w kodzie powyżej
        GUIHelper.setComboBoxToDefaultNoResize(categoryList);
        
        categoryList.setUI(new BasicComboBoxUI() {
            @SuppressWarnings({"serial"})
            @Override
            protected ComboPopup createPopup() {
                return new BasicComboPopup(categoryList) {
                    {
                        //---style popup anyway you like
                        //this.setBorder(BorderFactory.createLineBorder(Color.green, 2));//---popup's border color
                    }
                };
            }
            @Override
            protected JButton createArrowButton() {
                //---style arrow button anyway you like
                JButton test;
                //test = new DefaultArrowButton(BasicArrowButton.SOUTH);
                test = new DefaultArrowButton(BasicArrowButton.SOUTH, HFColors.BLUE, HFColors.BLUE, HFColors.BLUE, HFColors.BLUE);
                test.setBackground(HFColors.BLUE);
                test.setForeground(Color.CYAN);
                test.repaint();
                
                
                JButton result = new JButton();
                result.setForeground(Color.WHITE);
                result.setBackground(HFColors.BLUE);//---button's color
                //return result;
                
                return test;
            }
        });
        
        categoryList.setBackground(Color.red);
        categoryList.setRenderer(new ListCellRenderer<String>() {
            @Override
            public Component getListCellRendererComponent(JList<? extends String> list, String value, int index,
                    boolean isSelected, boolean cellHasFocus) {
                JLabel result = new JLabel(value);
                result.setOpaque(true);
                result.setBackground(isSelected ? HFColors.BLUE : HFColors.ROYAL_BLUE); //---item background color
                return result;
            }
        });

Jeszcze trochę będę się zajmować tym JComboBox, to do wariatkowa trafię :-)

Co mam robić aby kompletnie zmienić komponenty Swinga? Jest na to jakiś wzorzec, wzorce, które mógłbym użyć? Na jednym forum polecili mi Strategy lecz tutaj się nie da tego użyć przecież. Nie mogę zmieniać w kodzie JDK kodu źródłowego.