用搜索词过滤JTable而不丢失背景颜色

Posted

技术标签:

【中文标题】用搜索词过滤JTable而不丢失背景颜色【英文标题】:Filter JTable with search word without losing background color 【发布时间】:2018-04-19 18:31:46 【问题描述】:

我已按照教程过滤和突出显示 JTable here 中的文本。

我唯一添加的是 LookAndFeel,它设置为 Nimbus。该代码有效,除了当我选择一行时,该行的背景颜色和前景颜色都丢失了。

没有渲染器:

使用渲染器:

在代码中,渲染器创建了一个新标签(LabelHighlighted extends JLabel),它覆盖了 painComponent 方法。我猜想这个方法应该采用表格中行的背景颜色。

@Override
protected void paintComponent(Graphics g) 
    if (rectangles.size() > 0) 
        Graphics2D g2d = (Graphics2D) g;
        Color c = g2d.getColor();
        for (Rectangle2D rectangle : rectangles) 
            g2d.setColor(colorHighlight);
            g2d.fill(rectangle);
            g2d.setColor(Color.LIGHT_GRAY);
            g2d.draw(rectangle);
        
        g2d.setColor(c);
    
    super.paintComponent(g);

注意:我知道 JTable 的 JXTable 变体有更多用于过滤和突出显示行的选项,但我还没有找到解决方案...

渲染器:

public class RendererHighlighted extends DefaultTableCellRenderer 
     private JTextField searchField;

public RendererHighlighted(JTextField searchField) 
    this.searchField = searchField;


@Override
public Component getTableCellRendererComponent(JTable table, Object value,
                                               boolean selected, boolean hasFocus,
                                               int row, int column) 
    Component c = super.getTableCellRendererComponent(table, value, selected, hasFocus, row, column);

    JLabel original = (JLabel) c;
    LabelHighlighted label = new LabelHighlighted();
    label.setFont(original.getFont());
    label.setText(original.getText());
    label.setBackground(original.getForeground());
    label.setForeground(original.getForeground());
    label.setHorizontalTextPosition(original.getHorizontalTextPosition());
    label.highlightText(searchField.getText());
    return label;

标签突出显示:

public class LabelHighlighted extends JLabel 
private List<Rectangle2D> rectangles = new ArrayList<>();
private Color colorHighlight = Color.YELLOW;

public void reset() 
    rectangles.clear();
    repaint();


public void highlightText(String textToHighlight) 
    if (textToHighlight == null) 
        return;
    
    reset();

    final String textToMatch = textToHighlight.toLowerCase().trim();
    if (textToMatch.length() == 0) 
        return;
    
    textToHighlight = textToHighlight.trim();

    final String labelText = getText().toLowerCase();
    if (labelText.contains(textToMatch)) 
        FontMetrics fm = getFontMetrics(getFont());
        float w = -1;
        final float h = fm.getHeight() - 1;
        int i = 0;
        while (true) 
            i = labelText.indexOf(textToMatch, i);
            if (i == -1) 
                break;
            
            if (w == -1) 
                String matchingText = getText().substring(i,
                        i + textToHighlight.length());
                w = fm.stringWidth(matchingText);
            
            String preText = getText().substring(0, i);
            float x = fm.stringWidth(preText);
            rectangles.add(new Rectangle2D.Float(x, 1, w, h));
            i = i + textToMatch.length();
        
        repaint();
    


@Override
protected void paintComponent(Graphics g) 
    if (rectangles.size() > 0) 
        Graphics2D g2d = (Graphics2D) g;
        Color c = g2d.getColor();
        for (Rectangle2D rectangle : rectangles) 
            g2d.setColor(colorHighlight);
            g2d.fill(rectangle);
            g2d.setColor(Color.LIGHT_GRAY);
            g2d.draw(rectangle);
        
        g2d.setColor(c);
    
    super.paintComponent(g);

【问题讨论】:

提供完整的Renderer 课程 我编辑了我的原始帖子并添加了渲染器和标签类。我的问题顶部只有一个链接的副本。 【参考方案1】:

JLabel 使用html 标签可能很容易。

<span style='color:#000000; background-color:#FFFF00'>%s</span>

import java.awt.*;
import java.util.Objects;
import java.util.regex.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;

class RendererHighlighted extends DefaultTableCellRenderer 
  private final JTextField searchField;
  public RendererHighlighted(JTextField searchField) 
    this.searchField = searchField;
  
  @Override public Component getTableCellRendererComponent(
      JTable table, Object value, boolean isSelected, boolean hasFocus,
      int row, int column) 
    String txt = Objects.toString(value, "");
    String pattern = searchField.getText();

    if (Objects.nonNull(pattern) && !pattern.isEmpty()) 
      Matcher matcher = Pattern.compile(pattern).matcher(txt);
      int pos = 0;
      StringBuilder buf = new StringBuilder("<html>");
      while (matcher.find(pos)) 
        int start = matcher.start();
        int end   = matcher.end();
        buf.append(String.format(
            "%s<span style='color:#000000; background-color:#FFFF00'>%s</span>",
            txt.substring(pos, start), txt.substring(start, end)));
        pos = end;
      
      buf.append(txt.substring(pos));
      txt = buf.toString();
    
    super.getTableCellRendererComponent(table, txt, isSelected, hasFocus, row, column);
    return this;
  


public class HtmlHighlightCellTest 
  public JComponent makeUI() 
    String[] columnNames = "A", "B";
    Object[][] data = 
      "aaa", "bbaacc", "bbb", "defg",
      "ccccbbbbaaabbbbaaeabee", "xxx", "dddaaabbbbb", "ccbbaa",
      "cc cc bbbb aaa bbbb e", "xxx", "ddd aaa b bbbb", "cc bbaa"
    ;
    TableModel model = new DefaultTableModel(data, columnNames) 
      @Override public boolean isCellEditable(int row, int column) 
        return false;
      
      @Override public Class<?> getColumnClass(int column) 
        return String.class;
      
    ;
    JTable table = new JTable(model);
    table.setFillsViewportHeight(true);
    TableRowSorter<? extends TableModel> sorter = new TableRowSorter<>(model);
    table.setRowSorter(sorter);

    JTextField field = new JTextField();
    RendererHighlighted renderer = new RendererHighlighted(field);
    table.setDefaultRenderer(String.class, renderer);
    field.getDocument().addDocumentListener(new DocumentListener() 
      @Override public void insertUpdate(DocumentEvent e) 
        update();
      
      @Override public void removeUpdate(DocumentEvent e) 
        update();
      
      @Override public void changedUpdate(DocumentEvent e) 
      private void update() 
        String pattern = field.getText().trim();
        if (pattern.isEmpty()) 
          sorter.setRowFilter(null);
         else 
          sorter.setRowFilter(RowFilter.regexFilter("(?i)" + pattern));
        
      
    );

    JPanel sp = new JPanel(new BorderLayout(2, 2));
    sp.add(new JLabel("regex pattern:"), BorderLayout.WEST);
    sp.add(field);
    sp.add(Box.createVerticalStrut(2), BorderLayout.SOUTH);
    sp.setBorder(BorderFactory.createTitledBorder("Search"));
    JPanel p = new JPanel(new BorderLayout(2, 2));
    p.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
    p.add(sp, BorderLayout.NORTH);
    p.add(new JScrollPane(table));
    return p;
  

  public static void main(String[] args) 
    EventQueue.invokeLater(() -> 
      try 
        UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
       catch (Exception ex) 
        ex.printStackTrace();
      
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      f.getContentPane().add(new HtmlHighlightCellTest().makeUI());
      f.pack();
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    );
  

【讨论】:

以上是关于用搜索词过滤JTable而不丢失背景颜色的主要内容,如果未能解决你的问题,请参考以下文章

更改 UITable 部分背景颜色而不丢失部分标题

JTable 表头背景颜色

jTable 单元格背景颜色

更改单元格颜色而不更改其他单元格中的颜色(Jtable)

更改 JTable 中行的背景颜色

JTable设置表格背景颜色——隔行不同