Java Swing,100 个 TextField 都有类似的任务,所以我想写一个函数来完成
Java Swing, 100 TextFields have similar task, So I want to write the one function to do so
我正在开发一个小项目(使用 NetBeans 的 Java GUI Builder),其中我有 100 个文本字段,它们对不同的数据执行完全相同的操作。它们排列在 10 行 和 10 列 中,(变量)名称如下:
txt11, txt12, ... txt110
txt21, txt22, ... txt210
. . ... .
txt101, txt102, ... txt1010
因此,可以很容易地通过行号和列号生成名称,并且我可以很容易地提取它所属的 TextField 的行和列(但我不能)。
因为他们执行类似的任务我可以写一个方法,它需要行和列 作为参数并在用户在任何 TextField 中写入内容时执行。为了完成任务,我必须找出它们所属的行和列。
我尝试在事件侦听器中使用以下代码(我为所有 JTextField 添加了 相同的事件侦听器):
private void TextFieldAnswerTyped(java.awt.event.KeyEvent evt) {
String name = ((JTextField)evt.getSource()).getName();
int row,col;
if(name.endsWith("10"))
{
col=10;
name=name.substring(0, name.length()-2);
}
else
{
col=Integer.parseInt(name.substring(name.length()-1,name.length()));
name=name.substring(0, name.length()-1);
}
if(name.endsWith("10"))
row=10;
else
row=Integer.parseInt(name.substring(name.length()-1,name.length()));
checkForCell(row, col); //Performs the task
}
每次事件发生时,它都会给我 null
作为 name
。
我是不是做错了或者有什么好的选择。
您的问题是您将变量名称与 JTextField 的名称字段混淆了。在 JTextField returns 上调用 getName()
后者,它的名称字段,如您所见,默认设置为 null。有几种解决方案:
- 您可以尝试使用反射来获取您感兴趣的变量所引用的对象——这是一个糟糕、脆弱且笨拙的想法——只是不要这样做。
- 您实际上可以将名称字段设置为与变量名称相同,方法是在创建 JTextField 后调用
setName(...)
-- 另一个糟糕的组合
- 更好的办法是将所有 JTextField 对象放入一维或二维数组或集合中。通过这样做,可以很容易地找出您的字段所在的行和列。
- 也许最好的解决方案(在不知道更多要求的情况下很难说)是使用一个 JTable,它有 10 行和 10 列。
你的问题听起来可能实际上是 XY Problem 你问 "how do I fix this code" 而真正的解决方案是完全使用不同的方法。请告诉我们更多关于您的 "problem space" -- 您要解决的总体问题,因为我再次认为可能有更好的解决方案。
另一个问题:您似乎在尝试将 KeyListener 与 JTextFields 一起使用,我也不推荐这样做,因为这会干扰文本字段的本机键处理。相反,使用 DocumentListener 或 DocumentFilter 几乎总是更好。
另一个选项是设置 Swing 组件方法,putClientProperty(...)
,让你的 JTextFields "know" 它们在哪一行和哪一列。一个使用上述方法的例子加上它是getter等价,其中使用JTextField中的ActionListener获取数据如下:
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
@SuppressWarnings("serial")
public class ManyFields extends JPanel {
private static final int ROWS = 10;
private static final int COLS = ROWS;
private static final int GAP = 2;
private static final int TF_COLS = 5;
public static final String ROW = "row";
public static final String COL = "col";
private JTextField[][] fieldGrid = new JTextField[ROWS][COLS];
public ManyFields() {
setLayout(new GridLayout(ROWS, COLS, GAP, GAP));
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
TFieldListener tFieldListener = new TFieldListener();
for (int row = 0; row < fieldGrid.length; row++) {
for (int col = 0; col < fieldGrid[row].length; col++) {
JTextField tField = new JTextField(TF_COLS);
tField.putClientProperty(ROW, row);
tField.putClientProperty(COL, col);
tField.addActionListener(tFieldListener);
add(tField);
fieldGrid[row][col] = tField;
}
}
}
private class TFieldListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
JTextField field = (JTextField) e.getSource();
int row = (int) field.getClientProperty(ROW);
int col = (int) field.getClientProperty(COL);
// or another way to get row and column using the array:
int row2 = -1;
int col2 = -1;
for (int r = 0; r < fieldGrid.length; r++) {
for (int c = 0; c < fieldGrid[r].length; c++) {
if (field == fieldGrid[r][c]) {
row2 = r;
col2 = c;
}
}
}
// now here row2 and col2 are set
String text = field.getText();
String title = String.format("Text for Cell [%d, %d]", col, row);
String message = "text: " + text;
int messageType = JOptionPane.INFORMATION_MESSAGE;
JOptionPane.showMessageDialog(ManyFields.this, message, title, messageType);
field.transferFocus(); // move to next component
}
}
private static void createAndShowGui() {
ManyFields mainPanel = new ManyFields();
JFrame frame = new JFrame("Many Fields");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
但同样,JTable 可能会提供更好的解决方案,但是如果没有更多需求信息,很难确切地知道如何创建它。
我正在开发一个小项目(使用 NetBeans 的 Java GUI Builder),其中我有 100 个文本字段,它们对不同的数据执行完全相同的操作。它们排列在 10 行 和 10 列 中,(变量)名称如下:
txt11, txt12, ... txt110
txt21, txt22, ... txt210
. . ... .
txt101, txt102, ... txt1010
因此,可以很容易地通过行号和列号生成名称,并且我可以很容易地提取它所属的 TextField 的行和列(但我不能)。
因为他们执行类似的任务我可以写一个方法,它需要行和列 作为参数并在用户在任何 TextField 中写入内容时执行。为了完成任务,我必须找出它们所属的行和列。
我尝试在事件侦听器中使用以下代码(我为所有 JTextField 添加了 相同的事件侦听器):
private void TextFieldAnswerTyped(java.awt.event.KeyEvent evt) {
String name = ((JTextField)evt.getSource()).getName();
int row,col;
if(name.endsWith("10"))
{
col=10;
name=name.substring(0, name.length()-2);
}
else
{
col=Integer.parseInt(name.substring(name.length()-1,name.length()));
name=name.substring(0, name.length()-1);
}
if(name.endsWith("10"))
row=10;
else
row=Integer.parseInt(name.substring(name.length()-1,name.length()));
checkForCell(row, col); //Performs the task
}
每次事件发生时,它都会给我 null
作为 name
。
我是不是做错了或者有什么好的选择。
您的问题是您将变量名称与 JTextField 的名称字段混淆了。在 JTextField returns 上调用 getName()
后者,它的名称字段,如您所见,默认设置为 null。有几种解决方案:
- 您可以尝试使用反射来获取您感兴趣的变量所引用的对象——这是一个糟糕、脆弱且笨拙的想法——只是不要这样做。
- 您实际上可以将名称字段设置为与变量名称相同,方法是在创建 JTextField 后调用
setName(...)
-- 另一个糟糕的组合 - 更好的办法是将所有 JTextField 对象放入一维或二维数组或集合中。通过这样做,可以很容易地找出您的字段所在的行和列。
- 也许最好的解决方案(在不知道更多要求的情况下很难说)是使用一个 JTable,它有 10 行和 10 列。
你的问题听起来可能实际上是 XY Problem 你问 "how do I fix this code" 而真正的解决方案是完全使用不同的方法。请告诉我们更多关于您的 "problem space" -- 您要解决的总体问题,因为我再次认为可能有更好的解决方案。
另一个问题:您似乎在尝试将 KeyListener 与 JTextFields 一起使用,我也不推荐这样做,因为这会干扰文本字段的本机键处理。相反,使用 DocumentListener 或 DocumentFilter 几乎总是更好。
另一个选项是设置 Swing 组件方法,putClientProperty(...)
,让你的 JTextFields "know" 它们在哪一行和哪一列。一个使用上述方法的例子加上它是getter等价,其中使用JTextField中的ActionListener获取数据如下:
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
@SuppressWarnings("serial")
public class ManyFields extends JPanel {
private static final int ROWS = 10;
private static final int COLS = ROWS;
private static final int GAP = 2;
private static final int TF_COLS = 5;
public static final String ROW = "row";
public static final String COL = "col";
private JTextField[][] fieldGrid = new JTextField[ROWS][COLS];
public ManyFields() {
setLayout(new GridLayout(ROWS, COLS, GAP, GAP));
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
TFieldListener tFieldListener = new TFieldListener();
for (int row = 0; row < fieldGrid.length; row++) {
for (int col = 0; col < fieldGrid[row].length; col++) {
JTextField tField = new JTextField(TF_COLS);
tField.putClientProperty(ROW, row);
tField.putClientProperty(COL, col);
tField.addActionListener(tFieldListener);
add(tField);
fieldGrid[row][col] = tField;
}
}
}
private class TFieldListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
JTextField field = (JTextField) e.getSource();
int row = (int) field.getClientProperty(ROW);
int col = (int) field.getClientProperty(COL);
// or another way to get row and column using the array:
int row2 = -1;
int col2 = -1;
for (int r = 0; r < fieldGrid.length; r++) {
for (int c = 0; c < fieldGrid[r].length; c++) {
if (field == fieldGrid[r][c]) {
row2 = r;
col2 = c;
}
}
}
// now here row2 and col2 are set
String text = field.getText();
String title = String.format("Text for Cell [%d, %d]", col, row);
String message = "text: " + text;
int messageType = JOptionPane.INFORMATION_MESSAGE;
JOptionPane.showMessageDialog(ManyFields.this, message, title, messageType);
field.transferFocus(); // move to next component
}
}
private static void createAndShowGui() {
ManyFields mainPanel = new ManyFields();
JFrame frame = new JFrame("Many Fields");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
但同样,JTable 可能会提供更好的解决方案,但是如果没有更多需求信息,很难确切地知道如何创建它。