2 votes

Rendu de TableCell avec JComboBox et fond de sélection

J'ai besoin d'afficher les cellules sélectionnées/focalisées dans un tableau de bord. JTable avec un JComboBox si la colonne en question utilise le combo comme éditeur. L'objectif est d'indiquer aux utilisateurs que les cellules de la colonne sont éditées à l'aide d'une combinaison plutôt qu'à l'aide de la fonction JTextField .

Mon problème est que pour d'autres LookAndFeels que Metal il est impossible de définir la sélection de fond du tableau à la combobox. Si l'on clique ou navigue avec le clavier vers une "colonne combo", la cellule sélectionnée est rendue par la combo avec le fond par défaut.

Metal L&F fonctionne comme je le souhaite, mais ce n'est pas une option car nos clients utilisent soit Substance/Nimbus/Windows L&F et cela ne fonctionne pour aucun d'entre eux.

J'espère avoir été assez clair, toute aide est appréciée !

Sélectionnez les cellules de la "colonne Combo" de ce SSCCE pour voir ce que je veux dire :

import java.awt.Component;

import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;

import com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel;

public class RenderSelectedCellWithComboSSCCE extends JFrame
{   
    RenderSelectedCellWithComboSSCCE()
    {
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        add(new JScrollPane(createTable()));
        pack();
    }

    private JTable createTable()
    {
        TableModel model = new DefaultTableModel(
                new Object [][] {{"A", "Item 0"},
                                 {"B", "Item 1"},
                                 {"C", "Item 2"},
                                 {"D", "Item 3"},
                                 {"E", "Item 4"}},
                new String [] {"TextField", "Combo"});
        JTable table = new JTable(model);
        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        DefaultCellEditor editor = new DefaultCellEditor(new JComboBox(new Object[]{"Item 0", "Item 1", "Item 2", "Item 3", "Item 4"}));
        editor.setClickCountToStart(2);
        table.getColumnModel().getColumn(1).setCellEditor(editor);
        table.getColumnModel().getColumn(1).setCellRenderer(new ComboCellRenderer());
        return table;
    }

    /**
     * Renderer that demonstrates problem rendering selected cells with a combo with selection background.
     */
    private static class ComboCellRenderer implements TableCellRenderer
    {
        final TableCellRenderer defaultRenderer;
        final JComboBox combo;

        ComboCellRenderer()
        {
            defaultRenderer = new DefaultTableCellRenderer();
            combo = new JComboBox();
        }

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
        {
            if (hasFocus && table != null && table.isCellEditable(row, column))
            {
                combo.setModel(new DefaultComboBoxModel(new Object[]{value}));
                combo.setSelectedItem(value);
                combo.setBackground(table.getSelectionBackground());    // This only have desired effect for Metal L&F
                return combo;
            }
            else
            {
                return defaultRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            }
        }
    }

    public static void main(String[] args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                setLookAndFeel();
                new RenderSelectedCellWithComboSSCCE().setVisible(true);
            }

            private void setLookAndFeel()
            {
                try
                {
                    //UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());       // Metal works fine
                    UIManager.setLookAndFeel(new NimbusLookAndFeel());
                    //UIManager.setLookAndFeel(new WindowsLookAndFeel());
                    //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    //UIManager.setLookAndFeel("org.jvnet.substance.SubstanceLookAndFeel");
                }
                catch (Exception e)
                {
                    throw new RuntimeException("Failed to set LookAndFeel", e);
                }
            }
        });
    }
}

3voto

kleopatra Points 31585

Le rendu des ComboBox pose des problèmes, typiquement le LAF a des idées très spéciales sur la façon dont ils veulent montrer le combo lui-même, beaucoup sont stylisés, ont des coins arrondis ... c'est improbable de le faire correctement pour tous. En jouant un peu avec la suggestion de Stani, je me suis heurté à tous les détails désagréables (et vite oubliés :-), tels que

  • Windows désactive l'opacité lors du rendu du combo, il serait donc utile ici d'intégrer le moteur de rendu du combo dans un moteur qui définit l'opacité à true après avoir appelé super
  • Nimbus ignore l'arrière-plan du composant qui a été défini lui-même, quelle que soit l'opacité : votre moteur de rendu fonctionnerait comme prévu (ok, presque, modulo les changements de couleur inattendus :-) si vous définissez une couleur de sélection (sur la table) qui diffère de la couleur par défaut.
  • ...

D'autre part, vous n'avez pas besoin d'une JComboBox entièrement fonctionnelle, tout ce dont vous avez besoin est un indice visuel qu'il y a quelque chose à ouvrir. Vous pouvez donc vous en sortir avec un composant personnalisé - au plus simple, un JLabel avec quelques flèches - qui simule une JComboBox, quelque chose comme ça :

public static class MockCombo extends JLabel {

    private JButton arrow;

    public MockCombo() {
        JComboBox box = new JComboBox();
        box.setEditable(true);
        arrow = (JButton) box.getComponent(0);
        setLayout(new BorderLayout());
        add(arrow, BorderLayout.LINE_END);
        setOpaque(true);
    }

}

Elle doit encore être affinée par LAF, mais c'est une tâche bien plus facile que de modifier une JComboBox.

2voto

StanislavL Points 31343

Vous pouvez spécifier le moteur de rendu combiné et y utiliser la couleur souhaitée. Type de moteur de rendu pour le composant rendu.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X