java - 在 JList 中过滤和突出显示时出现问题
问题描述
我一直在寻找如何用 a 过滤JTextField
并JList
突出显示相同的表达式写在文本字段和列表的每个元素中,我一直在网上冲浪,我在此页面中找到了一个示例。
https://www.logicbig.com/tutorials/java-swing/list-filter-highlighting.html
即使我尝试制作相同的代码,但我的版本过滤正常,但它没有突出任何内容,我在这里发布我的代码,它或多或少与页面相同,但改变了我的类。
标签突出显示
package ui.admin.citas.filtering;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
public class LabelHighlighted extends JLabel {
/**
*
*/
private static final long serialVersionUID = 1L;
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 (isOpaque()) {
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
}
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);
}
}
这里是装饰器。
package ui.admin.citas.filtering;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiPredicate;
import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
public class JListFilterDecorator {
private JTextField filterField;
public static <T> JListFilterDecorator decorate(JList<T> list, BiPredicate<T, String> userFilter) {
if (!(list.getModel() instanceof DefaultListModel)) {
throw new IllegalArgumentException("List model must be an instance of DefaultListModel");
}
DefaultListModel<T> model = (DefaultListModel<T>) list.getModel();
List<T> items = getItems(model);
JTextField textField = new JTextField();
textField.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
filter();
}
@Override
public void removeUpdate(DocumentEvent e) {
filter();
}
@Override
public void changedUpdate(DocumentEvent e) {
filter();
}
private void filter() {
model.clear();
String s = textField.getText();
for (T item : items) {
if(userFilter.test(item, s)){
model.addElement(item);
}
}
}
});
JListFilterDecorator decorator = new JListFilterDecorator();
decorator.filterField = textField;
return decorator;
}
private static <T> List<T> getItems(DefaultListModel<T> model) {
List<T> list = new ArrayList<>();
for (int i = 0; i < model.size(); i++) {
list.add(model.elementAt(i));
}
return list;
}
public JTextField getFilterField() {
return filterField;
}
}
这里我在窗口的构造函数中创建文本字段
JListFilterDecorator decoratorPacientes = JListFilterDecorator.decorate(listPacientes, VentanaCitasBase::filterPaciente);
JTextField toAddPac = decoratorPacientes.getFilterField();
toAddPac.setText("Busque aquí...");
toAddPac.setForeground(Color.LIGHT_GRAY);
toAddPac.addFocusListener(new FocusAdapter() {
@Override
public void focusGained(FocusEvent e) {
toAddPac.setText("");
toAddPac.setForeground(Color.BLACK);
}
@Override
public void focusLost(FocusEvent e) {
toAddPac.setText("Busque aquí...");
toAddPac.setForeground(Color.LIGHT_GRAY);
}
});
getPanelSearch().add(toAddPac);
listPacientes.setCellRenderer(createListPacientesRenderer(toAddPac));
最后也是在窗口中创建渲染器的方法
private ListCellRenderer<? super PacienteDTO> createListPacientesRenderer(JTextField filterField) {
return new DefaultListCellRenderer() {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected,
boolean cellHasFocus) {
Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (c instanceof JLabel) {
PacienteDTO emp = (PacienteDTO) value;
JLabel original = (JLabel) c;
LabelHighlighted label = new LabelHighlighted();
label.setText(emp.toString());
label.setBackground(original.getBackground());
label.setForeground(original.getForeground());
label.setOpaque(original.isOpaque());
label.setHorizontalTextPosition(original.getHorizontalTextPosition());
label.highlightText(filterField.getText());
return label;
}
return c;
}
};
}