You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JTable使用setDefaultRenderer动态修改多行背景色问题求解

我几乎搜遍了全网也没能找到适配我需求的可行方案。我现有一个JTable组件,需要动态修改选中的多行的背景色,同时不能影响其他已经被修改过背景色的行。

颜色修改的触发逻辑绑定在右键ContextMenu的JMenuItem的actionListener上,如下方截图所示:
上下文菜单截图

目前我尝试过的代码如下:

JMenu highlightMenu = new JMenu("Highlight");

// Add null
for (Color color : Arrays.asList(Color.RED, Color.ORANGE, Color.YELLOW, Color.GREEN, Color.BLUE, Color.MAGENTA,
    Color.PINK, Color.GRAY)) {
  JMenuItem x = new JMenuItem();
  x.setOpaque(true);
  x.setBackground(color);

  highlightMenu.add(x);

  x.addHierarchyListener(e -> x.setText(tab.getTable()
      .getValueAt(tab.getTable().getSelectedRow(), tab.getTable().getColumn("Server").getModelIndex()).toString()));

  x.addActionListener(e -> IntStream.of(tab.getTable().getSelectedRows())
      .forEach(row -> ((Component) tab.getTable().getModel().getValueAt(row, 0)).setBackground(color)));

  // x.addActionListener(e -> {
  // IntStream.of(tab.getTable().getSelectedRows())
  // .forEach(r -> tab.getTable().setDefaultRenderer(Object.class, new
  // DefaultTableCellRenderer() {
  // @Override
  // public Component getTableCellRendererComponent(JTable table, Object value,
  // boolean isSelected,
  // boolean hasFocus, int row, int column) {
  // Component comp = super.getTableCellRendererComponent(table, value,
  // isSelected, hasFocus, row, column);

  // if (r == row) {
  // comp.setBackground(color);
  // } else {
  // comp.setBackground(null);
  // }

  // return comp;
  // }
  // }));

  // tab.getTable().repaint();
  // });
}

如果大家有可行的解决方案,恳请分享,万分感谢!😁


编辑0

我清理了过多的历史编辑内容,添加调试日志后发现表格运行表现完全不符合预期,调试输出截图如下:
调试输出截图

说明:我暂未找到表格被重复迭代5次的原因,理论上每个JMenuItem都绑定了独立的事件监听器,选中对应颜色的菜单项时应该仅触发一次事件。

修改后的表格效果截图如下:
表格效果截图

对应实现代码如下:

for (Color color : Arrays.asList(Color.RED, Color.ORANGE, Color.YELLOW, Color.GREEN, Color.BLUE, Color.MAGENTA,
    Color.PINK, Color.GRAY)) {
  JMenuItem x = new JMenuItem();
  x.setOpaque(true);
  x.setBackground(color);
  x.setForeground(Color.BLACK);

  highlightMenu.add(x);

  x.addHierarchyListener(e -> x.setText(tab.getTable()
      .getValueAt(tab.getTable().getSelectedRow(), tab.getTable().getColumn("Server").getModelIndex()).toString()));

  x.addActionListener(e -> {
    IntStream.of(tab.getTable().getSelectedRows()).forEach(row -> this.highlightedRows.put(row, color)
    // this.highlightedRows.put(row, Arrays.asList(Color.BLACK, color)
    );

    tab.getTable().setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
      @Override
      public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
          boolean hasFocus, int row, int column) {
        Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

        stdOut.println(String.format("%s -> %s", row, highlightedRows.get(row)));

        if (highlightedRows.get(row) != null) {
          stdOut.println("XXXXXXX");
          component.setBackground(highlightedRows.get(row));
        }

        // if (!isSelected && highlightedRows.containsKey(row)) {
        // component.setForeground(highlightedRows.get(row).get(0));
        // component.setBackground(highlightedRows.get(row).get(1));
        // }

        return component;
      }
    });
  });
}

显然该实现存在问题。


第N次编辑

我通过以下代码几乎解决了该问题:

for (Color color : Arrays.asList(Color.RED, Color.ORANGE, Color.YELLOW, Color.GREEN, Color.BLUE, Color.MAGENTA,
    Color.PINK, Color.GRAY)) {
  final JMenuItem x = new JMenuItem();
  x.setOpaque(true);
  x.setBackground(color);
  x.setForeground(Color.BLACK);

  highlightMenu.add(x);

  x.addHierarchyListener(e -> x.setText(tab.getTable()
      .getValueAt(tab.getTable().getSelectedRow(), tab.getTable().getColumn("Server").getModelIndex()).toString()));

  x.addActionListener(e -> {
    IntStream.of(tab.getTable().getSelectedRows())
        .forEach(row -> this.highlightedRows.put(row, Arrays.asList(Color.BLACK, color)));
    // row -> this.highlightedRows.put(row, color)

    tab.getTable().setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
      @Override
      public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
          boolean hasFocus, int row, int column) {
        final Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row,
            column);

        stdOut.println(String.format("%s -> %s", row, highlightedRows.get(row)));

        if (highlightedRows.containsKey(row)) {
          component.setForeground(highlightedRows.get(row).get(0));
          component.setBackground(highlightedRows.get(row).get(1));
        } else {
          if (row % 2 == 0) {
            component.setBackground(javax.swing.UIManager.getLookAndFeelDefaults().getColor("Table.background"));
          } else {
            component
                .setBackground(javax.swing.UIManager.getLookAndFeelDefaults().getColor("Table.alternateRowColor"));
          }

          component.setForeground(javax.swing.UIManager.getLookAndFeelDefaults().getColor("Table.foreground"));
        }

        if (isSelected) {
          component
              .setForeground(javax.swing.UIManager.getLookAndFeelDefaults().getColor("Table.selectionForeground"));
          component
              .setBackground(javax.swing.UIManager.getLookAndFeelDefaults().getColor("Table.selectionBackground"));
        }

        return component;
      }
    });
  });
}

目前仅存的问题是事件监听器会被多次触发,解决该问题就能完全实现需求,感谢大家的帮助!😁


内容的提问来源于stack exchange,提问作者aress31

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 09:45:04