JTable: переопределить prepareRenderer при применении стиля Nimbus по умолчанию?

Я использую Нимбус. Чтобы упростить переопределение prepareRenderer в JTable, первое, что я обычно делаю, это получаю компонент из суперметода, поэтому я могу настроить только те свойства, которые мне нужны, оставив все остальное без изменений.

Проблема в том, что когда я изменяю свойство стиля этого компонента, например цвет фона, он выполняет каждый последующий рендеринг с этим цветом, потому что он, по-видимому, повторно использует этот JLabel. Таким образом, каждая новая отображаемая ячейка становится красной, а не только та, которую я хотел.

Я всегда использовал HTML, чтобы избежать этого, но мне нужно манипулировать свойствами переднего плана/фона JLabel. Есть ли у кого-нибудь блок кода, устанавливающий все свойства по умолчанию для средства визуализации, и я могу использовать его в заполнителе метода applyDefaults, приведенном ниже?

Я использую Nimbus, поэтому не знаю, усложняет ли это задачу. Но я хочу, чтобы передний план/фон для выбранных/невыделенных и нечетных/четных строк отображались по умолчанию, и после этого все манипулировалось.

@Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int col) {

        final Component c =super.prepareRenderer(renderer, row, col);
        applyDefaults(c, row, col); //what do I need to restore default styles here? 

        boolean highlightRed condtion == //some boolean condition
        boolean isSelected = //calculate whether row is selected

        if (c instanceof JLabel) { 
            if (isSelected == false && highlightRed) { 
                ((JLabel) c).setBackground(Color.RED);
            }
        }

ОБНОВЛЕНИЕ: согласился с предложением camickr и создал удобный интерфейс по умолчанию для Nimbus JTables. restoreDefaultRenderer сбрасывает все свойства на цвета и выравнивание Nimbus по умолчанию.

public interface JTableCustomRender {
    static final Color foreGround = Color.black;
    static final Color oddBackGround = new Color(255,255,255);
    static final Color evenBackGround = new Color(242,242,242);
    static final Color selectedForeGround = new Color(255,255,255);
    static final Color selectedBackGround = new Color(57,105,138);

    //static final ImmutableList<Class<?>> leftAlignTypes = ImmutableList.of(String.class, Date.class, DateTime.class);
    static final ImmutableList<Class<?>> rightAlignTypes = ImmutableList.of(Integer.class, Double.class, Float.class, BigDecimal.class);

    public Component prepareRenderer(TableCellRenderer renderer, int viewRow, int viewCol);

    public default Component restoreDefaultRenderer(JTable table, Component c, int viewRow, int viewCol) { 

        if (c instanceof JLabel) { 
            final boolean rowSelected = Arrays.stream(table.getSelectedRows()).filter(i -> i == viewRow).findAny().isPresent();

            JLabel label = (JLabel) c;
            if (rowSelected) { 
                label.setForeground(selectedForeGround);
                label.setBackground(selectedBackGround);
            }
            else { 
                if (viewRow % 2 == 0) { 
                    label.setBackground(evenBackGround);
                }
                else { 
                    label.setBackground(oddBackGround);
                }
                label.setForeground(foreGround);
            }
            Object value = table.getValueAt(viewRow, viewCol);

            if(rightAlignTypes.contains(value.getClass())) { 
                label.setHorizontalAlignment(SwingConstants.RIGHT);
            }
            else { 
                label.setHorizontalAlignment(SwingConstants.LEFT);
            }
        }

        return c;
    }

}

person tmn    schedule 20.02.2015    source источник
comment
1. переопределить isSelected, hasFocus и т.д. (методы из XxxTableCellRenderer доступны и для prepareRenderer), 2. преобразовать индекс из представления в модель также для строки и столбца, 3. 1-е. строка кода в prepareRenderer должна быть if (myTable.getRowCount › 0) должна проверить, что 4. model cat возвращает значение, закодированное в rightAlignTypes, не так ли == getColumnClass 5. все условия должны быть подготовлены как значения, потому что средство визуализации довольно интенсивно рисование (мышь. ключ, события, реализованные в API) 6. для лучшей справки, скорее опубликуйте короткий, исполняемый, компилируемый SSCCE/MCVE с жестко запрограммированным значением для JTable/XxxModel   -  person mKorbel    schedule 20.02.2015


Ответы (2)


после этого он выполняет каждый рендеринг с этим цветом, потому что он, по-видимому, повторно использует этот JLabel.

Правильно, поэтому вам нужен оператор else, чтобы сбросить фон обратно к таблице по умолчанию.

Ознакомьтесь с рендерингом строки таблицы, чтобы узнать, как это сделать. это так, чтобы вы также учитывали цвет выбора строки.

У кого-нибудь есть блок кода, который устанавливает все свойства по умолчанию для средства визуализации?

Основной код будет:

c.setBackground( getBackground() );
c.setForeground( getForeground() );

Вы бы сделали это для любого свойства, которое вы вручную переопределяете.

person camickr    schedule 20.02.2015
comment
Да, я немного знаком с этими концепциями, но я думаю, что ищу серебряную пулю, которую я могу вставить в интерфейс по умолчанию и использовать везде. Возможно ли, что я могу клонировать () JLabel и манипулировать этим? Таким образом, оригинал не пострадал? - person tmn; 20.02.2015
comment
Что ж, я не думаю, что вы хотите клонировать метку каждый раз, поскольку цель средства визуализации — быть эффективным, чтобы вам не приходилось создавать компоненты каждый раз, когда визуализируется ячейка. Средство визуализации по умолчанию также имеет некоторые переопределенные методы, чтобы сделать рисование более эффективным. Вы можете создавать свои собственные рендереры, которые сбрасывают все свойства на значения по умолчанию. - person camickr; 20.02.2015
comment
Хорошо, мне нужно поиграть с этим. Моя цель - максимизировать повторное использование, а не создавать больше классов. Но я посмотрю, что я могу сделать здесь... - person tmn; 20.02.2015
comment
Ладно, может быть, я был слишком усерден, это действительно не так уж плохо. Я собрал различные цвета контекста для Nimbus JTable и создал интерфейс, позволяющий легко вызывать сброс свойств компонента по умолчанию. Код выше... - person tmn; 20.02.2015
comment
@Thomas N. 1. плохой код, он вам не нужен, 2. почему есть подсветка нечетных/четных, значения по умолчанию от Nimbus не подходят, 3. Object value = table.getValueAt(viewRow, viewCol); должна быть 1-я строка кода, 2-я. следует преобразовать индекс из представления в модель (действительно в том случае, если/если вы уверены, что количество строк в представлении больше нуля) - person mKorbel; 20.02.2015

Вот пример кода, переопределяющего метод prepareRenderer(), надеюсь, он кому-нибудь поможет:

public class MyJTable extends JTable {
    private final Color lineSelectedBackgroundColor = new Color(153,204,255);
    private final Color cellSelectedBackgroundColor = new Color(51,153,255);
    private final Color cellSelectedForeGroundColor = Color.BLACK;

    private final Color oddRowBackgroundColor = new Color(224,224,224);
    private final Color evenRowBackgroundColor = Color.WHITE;

    private final int lowThreshold = 33;
    private final int highThreshold = 66;

    private final boolean debugEnabled = true;
    private void log(String msg){ if(debugEnabled){ System.out.println(msg); } }

    @Override
    public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
        JComponent component = (JComponent) super.prepareRenderer(renderer, row, column);
        int selectedRow = super.getSelectedRow();
        int selectedColumn = super.getSelectedColumn();

        if(row==selectedRow && column==selectedColumn){
            component.setForeground(cellSelectedForeGroundColor);
            component.setBackground(cellSelectedBackgroundColor);
        }else if (row==selectedRow){
            component.setBackground(lineSelectedBackgroundColor);
        }else{
            if(row % 2 == 0) {
                component.setBackground(evenRowBackgroundColor);
            }else{
                component.setBackground(oddRowBackgroundColor);
            }
        }

        if(column==AppData.hyundaiTableStockIndex) {
            String stockStr = getValueAt(row, AppData.hyundaiTableStockIndex).toString();
            try{
                int stockValue = Integer.valueOf(stockStr);
                if (stockValue < lowThreshold) {
                    component.setBackground(Color.RED);
                } else if (stockValue > lowThreshold && stockValue < highThreshold) {
                    component.setBackground(Color.YELLOW);
                } else if (stockValue > highThreshold) {
                    component.setBackground(Color.GREEN);
                }
            }catch (Exception ex){
                log("parsing failed.");
            }
        }

        return component;
    }
}
person Paulo Silva    schedule 14.09.2017