gpt4 book ai didi

java - 当使用 TableCellRenderer 以 dd.mm.yyyy 格式显示本地日期时,我的 JTable 搜索功能无法按预期工作

转载 作者:行者123 更新时间:2023-12-02 15:52:18 24 4
gpt4 key购买 nike

基本上这里的问题如下,我有这个 TableCellRenderer:

public class CellRenderer_LocalDate extends DefaultTableCellRenderer implements TableCellRenderer {
private static final long serialVersionUID = -9184414041940041458L;

String displayFormat;

public CellRenderer_LocalDate(String dateFormat) {
this.displayFormat = dateFormat;
}

@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {

if (value instanceof LocalDate) {
LocalDate date = (LocalDate) value;

value = date.format(DateTimeFormatter.ofPattern(displayFormat));
}
return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
}

还有这个搜索 JTable 的函数:

    /**
* Filters the table to show a specific text
*/
public void searchTable(JTextField searchTextField) {
// Get model & instantiate table sorter
DefaultTableModel tableToFilter = (DefaultTableModel) this.getModel();
TableRowSorter<DefaultTableModel> trSorter = new TableRowSorter<DefaultTableModel>(tableToFilter);

// Get text to search & Set row filter for this table
String search = searchTextField.getText();

// Filter table in correct format
trSorter.setRowFilter(RowFilter.regexFilter("(?i)" + search)); // Insensitive to upper case or lower case

this.setRowSorter(trSorter);
}

我在 JTable 中有一列,其中包含 LocalDate。我让 TableCellRenderer 将 LocalDate 列显示为 dd.mm.yyyy。它按应有的方式工作。

问题是,当我使用 dd.mm.yyyy 格式的搜索功能时,它没有显示任何与 JTable 中显示的 LocalDate 方式相匹配的行。

例如:我有一列包含 LocalDate 2022-05-10。由于 TableCellRenderer,它显示为 10.05.2022。现在,如果我使用搜索并查找 10.05.2022,则不会显示任何内容,就好像没有任何匹配项一样。但是,如果我在搜索字段 2022-05-10 中输入,它会立即显示正确的结果。拜托,我应该更改我的功能以修复此错误吗?

最佳答案

因此,基于 this example ,我深入研究了 Java 源代码并提取了 RowFilter.dateFilter 并对其进行了修改以直接支持 LocalDate。这意味着,您可以获得 RowFilter.dateFilter 的所有特性和功能,但使用 LocalDate 而不是 Date

警告

如果我要为一系列混合值提供可搜索的解决方案,我会设计一个专用的“过滤器组件”,它提供了允许用户自行配置过滤器的机制。在这种情况下,这意味着允许用户独立地为日期值配置过滤参数(即,包括/排除给定范围,按月或年过滤或直接过滤,仅在这一天)

这将根据用户偏好相应地构建RowSorter

可运行的例子

以下示例过于简单,仅用于演示如何自定义 RowSorter 以处理不同的数据类型。

要按日期值搜索,您必须提供格式为 dd/MM/yyyy 的有效日期。

该示例使用了 RowFilter.orFilter,因此它将匹配 LocalDateFilterRowFilter.regexFilter

再次重申,这仅作为演示。

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.RowFilter;
import javax.swing.RowFilter.ComparisonType;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableRowSorter;

public class Main {
public static void main(String[] args) {
new Main();
}

public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}

public class TestPane extends JPanel {
private JTable table;

private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");

public TestPane() {
setLayout(new BorderLayout());
table = new JTable();
DefaultTableModel model = new DefaultTableModel(
new Object[][]{
{"A", 1, LocalDate.parse("12/05/2000", formatter)},
{"B", 2, LocalDate.parse("12/06/2000", formatter)},
{"C", 3, LocalDate.parse("12/07/2000", formatter)},
{"D", 4, LocalDate.parse("12/08/2000", formatter)},
{"E", 5, LocalDate.parse("12/09/2000", formatter)},
{"F", 1, LocalDate.parse("12/10/2000", formatter)},
{"G", 2, LocalDate.parse("12/11/2000", formatter)},
{"H", 3, LocalDate.parse("12/12/2000", formatter)},
{"I", 4, LocalDate.parse("12/01/1990", formatter)},
{"J", 5, LocalDate.parse("12/02/1990", formatter)},
{"K", 1, LocalDate.parse("12/03/1990", formatter)},
{"L", 2, LocalDate.parse("12/04/1995", formatter)},
{"M", 3, LocalDate.parse("12/05/1995", formatter)},
{"N", 4, LocalDate.parse("12/06/1995", formatter)},
{"O", 5, LocalDate.parse("12/07/1995", formatter)},
{"P", 1, LocalDate.parse("12/08/1980", formatter)},
{"Q", 2, LocalDate.parse("12/09/1980", formatter)},
{"R", 3, LocalDate.parse("12/10/1980", formatter)},
{"S", 4, LocalDate.parse("12/11/1980", formatter)},
{"T", 5, LocalDate.parse("12/12/1980", formatter)},
{"U", 1, LocalDate.parse("12/01/1985", formatter)},
{"V", 2, LocalDate.parse("12/02/1985", formatter)},
{"W", 3, LocalDate.parse("12/03/1985", formatter)},
{"X", 4, LocalDate.parse("12/04/1985", formatter)},
{"Y", 5, LocalDate.parse("12/05/1985", formatter)},
{"Z", 1, LocalDate.parse("12/06/1985", formatter)},},
new Object[]{"Name", "Number", "Date"}) {
@Override
public Class<?> getColumnClass(int columnIndex) {
switch (columnIndex) {
case 0:
return String.class;
case 1:
return Integer.class;
case 2:
return LocalDate.class;
}
return Object.class;
}

};

table.setModel(model);
table.setAutoCreateRowSorter(true);
table.setDefaultRenderer(LocalDate.class, new LocalDateTableCellRenderer(formatter));
add(new JScrollPane(table));

JTextField textField = new JTextField(10);
add(textField, BorderLayout.SOUTH);
textField.addActionListener(new ActionListener() {

protected LocalDate toLocalDate(String text) {
try {
return LocalDate.parse(textField.getText(), formatter);
} catch (DateTimeParseException exp) {
return null;
}
}

@Override
public void actionPerformed(ActionEvent e) {
String text = textField.getText();
if (text.isEmpty()) {
table.setRowSorter(null);
return;
}
List<RowFilter<Object, Object>> filters = new ArrayList<>(2);
// Include the date only if we can parse the text
LocalDate searchDate = toLocalDate(text);
if (searchDate != null) {
filters.add(new LocalDateFilter(ComparisonType.EQUAL, searchDate, 2));
// You can also support date rangers if you want
//filters.add(new LocalDateFilter(ComparisonType.BEFORE, searchDate, 2));
//filters.add(new LocalDateFilter(ComparisonType.AFTER, searchDate, 2));
}
// OR filter every thing else...
filters.add(RowFilter.regexFilter("(?i)" + text, new int[]{0, 1}));
TableRowSorter<DefaultTableModel> sorter = new TableRowSorter<>((DefaultTableModel) table.getModel());
sorter.setRowFilter(RowFilter.orFilter(filters));

table.setRowSorter(sorter);
}
});
}
}

public class LocalDateTableCellRenderer extends DefaultTableCellRenderer {

private DateTimeFormatter formatter;

public LocalDateTableCellRenderer(DateTimeFormatter formatter) {
this.formatter = formatter;
}

public DateTimeFormatter getFormatter() {
return formatter;
}

@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (value instanceof LocalDate) {
setText(getFormatter().format((LocalDate) value));
}
return this;
}
}

public abstract class AbstractFilter<M, I> extends RowFilter<M, I> {
private int[] columns;

public AbstractFilter(int[] columns) {
this.columns = columns;
}

@Override
public boolean include(RowFilter.Entry<? extends M, ? extends I> value) {
int count = value.getValueCount();
if (columns.length > 0) {
for (int i = columns.length - 1; i >= 0; i--) {
int index = columns[i];
if (index < count) {
if (include(value, index)) {
return true;
}
}
}
} else {
while (--count >= 0) {
if (include(value, count)) {
return true;
}
}
}
return false;
}

protected abstract boolean include(RowFilter.Entry<? extends M, ? extends I> value, int index);
}

public class LocalDateFilter<M, I> extends AbstractFilter<M, I> {
private LocalDate date;
private RowFilter.ComparisonType type;

public LocalDateFilter(RowFilter.ComparisonType type, LocalDate date, int column) {
this(type, date, new int[]{column});
}

public LocalDateFilter(RowFilter.ComparisonType type, LocalDate date, int[] columns) {
super(columns);
if (type == null) {
throw new IllegalArgumentException("type must be non-null");
}
this.type = type;
this.date = date;
}

@Override
protected boolean include(RowFilter.Entry<? extends M, ? extends I> value, int index) {
Object v = value.getValue(index);

if (v instanceof LocalDate) {
LocalDate vDate = (LocalDate) v;
switch (type) {
case BEFORE:
return (vDate.isBefore(date));
case AFTER:
return (vDate.isAfter(date));
case EQUAL:
return (vDate.equals(date));
case NOT_EQUAL:
return !(vDate.equals(date));
default:
break;
}
}
return false;
}
}

}

您“可以”修改 LocalDateFilter 以通过提供的 DateTimeFormatter 将日期值转换为 String,但我担心您不恰本地混合了表示和数据概念,因为它们应该彼此不可知 - 但我就是这样。


关于是否应该使用渲染器来“更改数据项的文本”存在一些讨论。老实说,我不认为这是非黑即白的。有时你,主人,不想要那种功能,但对我来说, View 是“数据的可视化表示”,你不应该“需要”按摩数据以通过 View ,这不是模型的工作,而是 View 的工作。

例如,我可以在 JList 中表示相同的数据,根据应用程序的需要以及应用程序试图向用户呈现的内容,使用短日期格式或长日期格式- 甚至更多,它可能是需要应用的用户提供的配置 - 这些是渲染器/ View 的域,数据应该需要更改(恕我直言)。

所以,复制粘贴。当我复制一行 (Command+C) 时,它复制了 A 1 2000-05-12,因此,这里无需执行任何操作。如果您需要更改其复制的“方式”(即,您希望将其显示为 ddd MMM yyyy,您可以执行类似 this for example 的操作 - 这里重要的是,您我已经控制了)

至于可访问性,如果你通读了 How to Support Assistive Technologies您会注意到,可访问性是通过 toolTipTextJComponent#getAccessibleContext 等功能提供的,它们是单元格渲染的方法,因此,再次强调,这不是驱动的问题我“按摩”我的数据。

再次重申,上下文为王。有时包装器/代理对象值得付出努力,但我总是问自己,“我失去了什么?”和“我得到了什么?”通过这样做以及我需要创建多少这些,所以我在 JTableJComboBoxJList 或其他一些中呈现相同的数据组件 - 但是,那就是我。

关于java - 当使用 TableCellRenderer 以 dd.mm.yyyy 格式显示本地日期时,我的 JTable 搜索功能无法按预期工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/72179266/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com