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

标签 java swing filter jtable highlight

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

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

没有渲染器: Selected row has a blue background color

使用渲染器: Selected row loses back and foreground

在代码中,渲染器创建一个新标签(LabelHighlighted 扩展 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);
}

}

最佳答案

HTML 标签用于 JLabel 可能很容易。

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

enter image description here

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);
    });
  }
}

关于java - 使用搜索词过滤 JTable 而不丢失背景颜色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47156529/

相关文章:

c# - 有什么解决方案可以在程序中使用不可猜测的链接吗?

java - 一个 JFrame 中的两个面板

java - 对数组中的偶数和奇数进行排序

java - 使用 JButton 增加/减少 textArea 内的字体大小

java - 在允许可见光标移动的同时禁用 JTextPane 中的编辑

java - 通过按钮调用时不显示用户输入。使用 Java 数组列表

python - 根据条件删除 Pandas 组

java - 多个数据绑定(bind)错误

android - 如何限制numberdecimal EditText中点之前和之后的数字

batch-file - 使用批处理文件删除重复的文本行