JTable move screen/pointer 搜索文本
JTable move screen/pointer to search text
我需要突出显示文本并将整个 screen/view 移动到搜索到的文本。例如:如果视图持有 1 到 1000 个数字(行),如果我输入搜索文本 55 并单击“搜索”按钮,首先它必须将屏幕移动到文本 55(第一次出现)然后应该只突出显示 55,而不是其他出现的 55。当我一直按“搜索”按钮时,搜索应该继续进行并突出显示 155,然后突出显示 255、355、455、555 等。一次只能突出显示一个 55。
它应该具有与记事本相同的搜索体验。
这是一个有效的用例吗?我是 Swings 的新手,正在尝试构建一个小型应用程序作为学习的一部分。已经写了一个示例代码(参考其他post),但是这是一次突出显示所有事件并且不确定如何将视图移动到第一个事件。请提出建议。
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.text.BadLocationException;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Form extends JFrame {
private String textForSearch = "";
private JTable t;
public Form() {
t = new JTable();
String[] headers = new String[]{"first", "second", "third"};
DefaultTableModel model = new DefaultTableModel(0, 0);
model.setColumnIdentifiers(headers);
for(int i =0;i<1000;i++){
model.addRow(new Object[]{i});
model.addRow(new Object[]{i});
}
t.setModel(model);
for(int i =0;i<t.getColumnCount();i++){
t.getColumnModel().getColumn(0).setCellRenderer(getRenderer());
}
JScrollPane jsp = new JScrollPane(t);
final RightPanel right = new RightPanel();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(jsp, BorderLayout.CENTER);
add(right, BorderLayout.EAST);
pack();
setLocationRelativeTo(null);
}
private TableCellRenderer getRenderer() {
return new TableCellRenderer() {
JTextField f = new JTextField(5);
@Override
public Component getTableCellRendererComponent(JTable arg0, Object arg1, boolean arg2, boolean arg3, int arg4, int arg5) {
if(arg1 != null){
f.setText(arg1.toString());
String string = arg1.toString();
if(string.contains(textForSearch)){
int indexOf = string.indexOf(textForSearch);
try {
f.getHighlighter().addHighlight(indexOf,indexOf+textForSearch.length(),new javax.swing.text.DefaultHighlighter.DefaultHighlightPainter(Color.RED));
} catch (BadLocationException e) {
e.printStackTrace();
}
}
} else {
f.setText("");
f.getHighlighter().removeAllHighlights();
}
return f;
}
};
}
class RightPanel extends JPanel{
public RightPanel(){
setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.insets = new Insets(5, 5, 5, 5);
c.gridy = 0;
final JTextField f = new JTextField();
add(f,c);
JButton b = new JButton("search");
b.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
textForSearch = f.getText();
t.repaint();
}
});
c.gridy++;
add(b,c);
}
}
public static void main(String[] args) throws Exception {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Form().setVisible(true);
}
});
}
}
已编辑:
从其他 post 中,找到了将 pointer/screen 移动到特定行的解决方案,但不确定如何获取搜索文本的 rowIndex 值:
public static void scrollToVisible(JTable table, int rowIndex, int vColIndex) {
if (!(table.getParent() instanceof JViewport)) return;
JViewport viewport = (JViewport) table.getParent();
Rectangle rect = table.getCellRect(rowIndex, vColIndex, true);
Point pt = viewport.getViewPosition();
rect.setLocation(rect.x - pt.x, rect.y - pt.y);
viewport.scrollRectToVisible(rect);
}
已添加供其他人参考:
在屏幕中间显示所选行:
http://www.java2s.com/Code/Java/Swing-JFC/ScrollingaCelltotheCenterofaJTableComponent.htm
我想我已经做到了你想要的,就像你说的那样Notepad++ 搜索。不要将 new JTextField()
用于渲染器,只需扩展 JTextField
并实现 TableCellRenderer
。然后在您的动作侦听器中,找到具有此值的单元格的索引,并让渲染器仅突出显示此单元格。
✓ 每次搜索1次(而且只有1次突出显示)。
✓ 滚动找到的值。
✓ 无搜索时提示音
✓ 从头开始时发出蜂鸣声。
✓ 搜索后不会丢失选择(您可以更改)
预览:
代码中的一些额外注释。
package test;
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.text.BadLocationException;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Form extends JFrame {
private String textForSearch = "";
private JTable t;
private static int rowIndex = -1;
public Form() {
t = new JTable();
String[] headers = new String[]{"first", "second", "third"};
DefaultTableModel model = new DefaultTableModel(0, 0);
model.setColumnIdentifiers(headers);
for(int i =0;i<1555;i++){
model.addRow(new Object[]{i});
}
t.setModel(model);
for(int i =0;i<t.getColumnCount();i++){
t.getColumnModel().getColumn(0).setCellRenderer(new MyTextFieldRenderer()); //Add JTextField as renderer
}
JScrollPane jsp = new JScrollPane(t);
final RightPanel right = new RightPanel();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(jsp, BorderLayout.CENTER);
add(right, BorderLayout.EAST);
pack();
setLocationRelativeTo(null);
}
private class MyTextFieldRenderer extends JTextField implements TableCellRenderer{
@Override
public Component getTableCellRendererComponent(JTable arg0, Object arg1, boolean arg2, boolean arg3, int row,
int col) {
String string = String.valueOf(arg1);
this.setText(string);
if(row == rowIndex) //Check if the row of the found text matches this value
{
int indexOf = getText().indexOf(textForSearch);
try {
getHighlighter().addHighlight(indexOf, indexOf + textForSearch.length(),
new javax.swing.text.DefaultHighlighter.DefaultHighlightPainter(Color.RED));
} catch (BadLocationException e) {
e.printStackTrace();
}
}
return this;
}
}
class RightPanel extends JPanel{
public RightPanel(){
setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.insets = new Insets(5, 5, 5, 5);
c.gridy = 0;
final JTextField f = new JTextField(11);
add(f,c);
JButton b = new JButton("search");
b.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
//Start all over again
int tempRow = rowIndex;
if (rowIndex + 1 >= t.getRowCount())
{
rowIndex = -1;
Toolkit.getDefaultToolkit().beep(); //Notepad++ beeps i think
}
for (int row = rowIndex+1; row < t.getRowCount(); row++) { //Start checking all rows
Component cc = t.prepareRenderer(t.getCellRenderer(row, 0), row, 0);
if (cc instanceof MyTextFieldRenderer) {
MyTextFieldRenderer textField = (MyTextFieldRenderer) cc; //Grab the text of the renderer
if (textField.getText().contains(f.getText())) { //We got a match!
textForSearch = f.getText();
rowIndex = row;
int selRow = t.getSelectedRow();
//Selection code taken from here:
//
t.getSelectionModel().setSelectionInterval(row, row); //Scroll to the value
t.scrollRectToVisible(new Rectangle(t.getCellRect(row, 0, true)));
if (selRow!=-1) //Something was selected
t.setRowSelectionInterval(selRow, selRow); //Restore selection
break;
}
}
}
if (rowIndex == tempRow) //Index didn't change, means there is no value for this search
{
Toolkit.getDefaultToolkit().beep();
}
t.repaint();
}
});
c.gridy++;
add(b,c);
}
}
public static void main(String[] args) throws Exception {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Form().setVisible(true);
}
});
}
}
我需要突出显示文本并将整个 screen/view 移动到搜索到的文本。例如:如果视图持有 1 到 1000 个数字(行),如果我输入搜索文本 55 并单击“搜索”按钮,首先它必须将屏幕移动到文本 55(第一次出现)然后应该只突出显示 55,而不是其他出现的 55。当我一直按“搜索”按钮时,搜索应该继续进行并突出显示 155,然后突出显示 255、355、455、555 等。一次只能突出显示一个 55。
它应该具有与记事本相同的搜索体验。
这是一个有效的用例吗?我是 Swings 的新手,正在尝试构建一个小型应用程序作为学习的一部分。已经写了一个示例代码(参考其他post),但是这是一次突出显示所有事件并且不确定如何将视图移动到第一个事件。请提出建议。
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.text.BadLocationException;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Form extends JFrame {
private String textForSearch = "";
private JTable t;
public Form() {
t = new JTable();
String[] headers = new String[]{"first", "second", "third"};
DefaultTableModel model = new DefaultTableModel(0, 0);
model.setColumnIdentifiers(headers);
for(int i =0;i<1000;i++){
model.addRow(new Object[]{i});
model.addRow(new Object[]{i});
}
t.setModel(model);
for(int i =0;i<t.getColumnCount();i++){
t.getColumnModel().getColumn(0).setCellRenderer(getRenderer());
}
JScrollPane jsp = new JScrollPane(t);
final RightPanel right = new RightPanel();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(jsp, BorderLayout.CENTER);
add(right, BorderLayout.EAST);
pack();
setLocationRelativeTo(null);
}
private TableCellRenderer getRenderer() {
return new TableCellRenderer() {
JTextField f = new JTextField(5);
@Override
public Component getTableCellRendererComponent(JTable arg0, Object arg1, boolean arg2, boolean arg3, int arg4, int arg5) {
if(arg1 != null){
f.setText(arg1.toString());
String string = arg1.toString();
if(string.contains(textForSearch)){
int indexOf = string.indexOf(textForSearch);
try {
f.getHighlighter().addHighlight(indexOf,indexOf+textForSearch.length(),new javax.swing.text.DefaultHighlighter.DefaultHighlightPainter(Color.RED));
} catch (BadLocationException e) {
e.printStackTrace();
}
}
} else {
f.setText("");
f.getHighlighter().removeAllHighlights();
}
return f;
}
};
}
class RightPanel extends JPanel{
public RightPanel(){
setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.insets = new Insets(5, 5, 5, 5);
c.gridy = 0;
final JTextField f = new JTextField();
add(f,c);
JButton b = new JButton("search");
b.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
textForSearch = f.getText();
t.repaint();
}
});
c.gridy++;
add(b,c);
}
}
public static void main(String[] args) throws Exception {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Form().setVisible(true);
}
});
}
}
已编辑: 从其他 post 中,找到了将 pointer/screen 移动到特定行的解决方案,但不确定如何获取搜索文本的 rowIndex 值:
public static void scrollToVisible(JTable table, int rowIndex, int vColIndex) {
if (!(table.getParent() instanceof JViewport)) return;
JViewport viewport = (JViewport) table.getParent();
Rectangle rect = table.getCellRect(rowIndex, vColIndex, true);
Point pt = viewport.getViewPosition();
rect.setLocation(rect.x - pt.x, rect.y - pt.y);
viewport.scrollRectToVisible(rect);
}
已添加供其他人参考:
在屏幕中间显示所选行: http://www.java2s.com/Code/Java/Swing-JFC/ScrollingaCelltotheCenterofaJTableComponent.htm
我想我已经做到了你想要的,就像你说的那样Notepad++ 搜索。不要将 new JTextField()
用于渲染器,只需扩展 JTextField
并实现 TableCellRenderer
。然后在您的动作侦听器中,找到具有此值的单元格的索引,并让渲染器仅突出显示此单元格。
✓ 每次搜索1次(而且只有1次突出显示)。
✓ 滚动找到的值。
✓ 无搜索时提示音
✓ 从头开始时发出蜂鸣声。
✓ 搜索后不会丢失选择(您可以更改)
预览:
代码中的一些额外注释。
package test;
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.text.BadLocationException;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Form extends JFrame {
private String textForSearch = "";
private JTable t;
private static int rowIndex = -1;
public Form() {
t = new JTable();
String[] headers = new String[]{"first", "second", "third"};
DefaultTableModel model = new DefaultTableModel(0, 0);
model.setColumnIdentifiers(headers);
for(int i =0;i<1555;i++){
model.addRow(new Object[]{i});
}
t.setModel(model);
for(int i =0;i<t.getColumnCount();i++){
t.getColumnModel().getColumn(0).setCellRenderer(new MyTextFieldRenderer()); //Add JTextField as renderer
}
JScrollPane jsp = new JScrollPane(t);
final RightPanel right = new RightPanel();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(jsp, BorderLayout.CENTER);
add(right, BorderLayout.EAST);
pack();
setLocationRelativeTo(null);
}
private class MyTextFieldRenderer extends JTextField implements TableCellRenderer{
@Override
public Component getTableCellRendererComponent(JTable arg0, Object arg1, boolean arg2, boolean arg3, int row,
int col) {
String string = String.valueOf(arg1);
this.setText(string);
if(row == rowIndex) //Check if the row of the found text matches this value
{
int indexOf = getText().indexOf(textForSearch);
try {
getHighlighter().addHighlight(indexOf, indexOf + textForSearch.length(),
new javax.swing.text.DefaultHighlighter.DefaultHighlightPainter(Color.RED));
} catch (BadLocationException e) {
e.printStackTrace();
}
}
return this;
}
}
class RightPanel extends JPanel{
public RightPanel(){
setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.insets = new Insets(5, 5, 5, 5);
c.gridy = 0;
final JTextField f = new JTextField(11);
add(f,c);
JButton b = new JButton("search");
b.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
//Start all over again
int tempRow = rowIndex;
if (rowIndex + 1 >= t.getRowCount())
{
rowIndex = -1;
Toolkit.getDefaultToolkit().beep(); //Notepad++ beeps i think
}
for (int row = rowIndex+1; row < t.getRowCount(); row++) { //Start checking all rows
Component cc = t.prepareRenderer(t.getCellRenderer(row, 0), row, 0);
if (cc instanceof MyTextFieldRenderer) {
MyTextFieldRenderer textField = (MyTextFieldRenderer) cc; //Grab the text of the renderer
if (textField.getText().contains(f.getText())) { //We got a match!
textForSearch = f.getText();
rowIndex = row;
int selRow = t.getSelectedRow();
//Selection code taken from here:
//
t.getSelectionModel().setSelectionInterval(row, row); //Scroll to the value
t.scrollRectToVisible(new Rectangle(t.getCellRect(row, 0, true)));
if (selRow!=-1) //Something was selected
t.setRowSelectionInterval(selRow, selRow); //Restore selection
break;
}
}
}
if (rowIndex == tempRow) //Index didn't change, means there is no value for this search
{
Toolkit.getDefaultToolkit().beep();
}
t.repaint();
}
});
c.gridy++;
add(b,c);
}
}
public static void main(String[] args) throws Exception {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Form().setVisible(true);
}
});
}
}