在 JTable 中检测鼠标单击时出现问题
Trouble detecting mouse click in JTable
我有一个 JTable,其中第 3 列和第 4 列使用 JComboBox 作为单元格编辑器。第 3 列指定类型,第 4 列指定子类型。第 4 列中可用的子类型列表取决于用户为该类型选择的值。此外,类型和子类型列表由用户编辑table(细节在这里并不重要,只是类型和子类型列表都可以在运行时更改)。
因为子类型组合框的内容是动态的,我的目的是检测用户何时点击进入子类型单元格,并在此时根据内容设置列表模型(设置可用的子类型项目列表)该行中的类型。
但是,我无法检测到所需单元格中的鼠标单击。我在下面发布了我的代码和输出。
问题是鼠标侦听器未检测到组合框中的单击。据推测,该事件是由组合框触发的,而不是 table。我可以将 ListSelectionListener 与 TableColumnModelListener 结合使用,但我不得不想象有更好的方法。我尝试使用与组合框相关的事件,但我无法获得有关选择了哪个组合框的信息(所以我不知道我在 table 中的什么位置)。我试图获取组合框的容器并以这种方式定位点击,但是组合框的 getParent() 方法 returns null.
编辑:在 ComboBox ActionListener 中,我还尝试使用 JTable 的 getSelectedRow() 和 getSelectedColumn() 方法,但它们 return 旧单元格的值,而不是新单元格的值。
如有任何关于如何更简洁地执行此操作的建议,我们将不胜感激。
以下是相关的代码片段(事件处理程序还没有做太多,只是试图获取信息):
// Setup table and table model
tableTypeDataModel = new TypeAssignmentTableModel();
JTable typeTable = new JTable(tableTypeDataModel);
// Add a mouse listener to the table.
typeTable.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e)
{
Point pnt = e.getPoint();
int row = typeTable.rowAtPoint(pnt);
int col = typeTable.columnAtPoint(pnt);
System.out.println(Integer.toString(row) + ", " + Integer.toString(col));
}
});
typeTable.getSelectionModel().addListSelectionListener(new myListSelectionListener());
typeTable.setFillsViewportHeight(true);
JScrollPane scpnTypeTable = new JScrollPane(typeTable);
// Set columns and model listener
TableColumnModel cm = typeTable.getColumnModel();
cm.addColumnModelListener(new myColumnListSelectionListener());
// Setup type column
JComboBox<String> cmbTableTypes = new JComboBox<>(arrOfTypes);
cmbTableTypes.addActionListener(new myCBOActionListener());
cm.getColumn(TYPECOL_TYPE).setCellEditor(new DefaultCellEditor(cmbTableTypes));
// This just adds left padding to the cell
IndentedTableCellRenderer tableTypeRenderer = new IndentedTableCellRenderer(5, 0);
cm.getColumn(TYPECOL_TYPE).setCellRenderer(tableTypeRenderer);
// Setup subtype column
tableSubtypeCboModel = new DefaultComboBoxModel<>();
JComboBox<String> cmbTableSubtypes = new JComboBox<>(tableSubtypeCboModel);
cm.getColumn(TYPECOL_SUBTYPE).setCellEditor(new DefaultCellEditor(cmbTableSubtypes));
IndentedTableCellRenderer tableSubtypeRenderer = new IndentedTableCellRenderer(5, 0);
cm.getColumn(TYPECOL_SUBTYPE).setCellRenderer(tableSubtypeRenderer);
还有...
class myListSelectionListener implements ListSelectionListener {
@Override
public void valueChanged(ListSelectionEvent e) {
System.out.println("Table List selection listener = " + e.getSource().toString());
}
}
class myColumnListSelectionListener implements TableColumnModelListener {
// other methods empty and not shown...
@Override
public void columnSelectionChanged(ListSelectionEvent e) {
// TODO Auto-generated method stub
System.out.println("Table column model listener Source = " +
e.getSource().toString());
}
}
class myCBOActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
JComboBox item = (JComboBox) e.getSource();
System.out.println("CBO Action Listener = " + item.getClass().toString());
String msg = item.getParent() == null ? "null" : item.getParent().toString();
System.out.println("CBO Action Listener item parent is " + msg);
}
}
这是单击以下单元格后的控制台输出:
Row 1, Col 0 (just a regular cell)
Row 2, Col 1 (just a regular cell)
Row 3, Col 2 (just a regular cell)
Row 4, Col 3 (this is the Type column with a combo box editor)
Console Output:
Table column model listener Source = javax.swing.DefaultListSelectionModel 724380095 ~{0}
Table List selection listener = javax.swing.DefaultListSelectionModel 1902920301 ~{1}
Table List selection listener = javax.swing.DefaultListSelectionModel 1902920301 ={1}
Table column model listener Source = javax.swing.DefaultListSelectionModel 724380095 ={0}
1, 0
Table column model listener Source = javax.swing.DefaultListSelectionModel 724380095 ~{1}
Table List selection listener = javax.swing.DefaultListSelectionModel 1902920301 ~{2}
Table List selection listener = javax.swing.DefaultListSelectionModel 1902920301 ={2}
Table column model listener Source = javax.swing.DefaultListSelectionModel 724380095 ={1}
2, 1
Table column model listener Source = javax.swing.DefaultListSelectionModel 724380095 ~{2}
Table List selection listener = javax.swing.DefaultListSelectionModel 1902920301 ~{3}
Table List selection listener = javax.swing.DefaultListSelectionModel 1902920301 ={3}
Table column model listener Source = javax.swing.DefaultListSelectionModel 724380095 ={2}
3, 2
CBO Action Listener = class javax.swing.JComboBox
CBO Action Listener item parent is null
Table column model listener Source = javax.swing.DefaultListSelectionModel 724380095 ~{3}
Table List selection listener = javax.swing.DefaultListSelectionModel 1902920301 ~{4}
Table List selection listener = javax.swing.DefaultListSelectionModel 1902920301 ={4}
Table column model listener Source = javax.swing.DefaultListSelectionModel 724380095 ={3}
谢谢。
您可以将您的子类型 JCombobox
作为全局管理,然后添加一个 ActionListener
,当在 [=16] 中“选择”子类型 JCombobox
组件时更新子类型值=].
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import javax.swing.*;
public class whatev{
JComboBox types = new JComboBox();
JComboBox subtypes = new JComboBox();
Map<String,int[]> m = new HashMap<String,int[]>(); //example source mapping types to sub-types
int[] t1 = {1,3};
int[] t2 = {4, 5};
public static void main(String[] args){ new whatev(); }
whatev(){
//Add example data to types
types.addItem("Type 1");
types.addItem("Type 2");
types.setSelectedIndex(0);
//init map data for example
m.put("Type 1", t1);
m.put("Type 2", t2);
//initialize subtype JCombobox
updateSubtypes();
//add appropriate listener to subtype box
subtypes.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
updateSubtypes();
}
});
}
private void updateSubtypes() {
int[] x = m.get(types.getSelectedItem()); //pull appropriate subtypes from type/subtype mapping source
subtypes.removeAllItems(); //purge old objects in subtype
for(int v : x) { subtypes.addItem(v); } //Add appropriate subtypes
}
}
@camickr - 谢谢你的回答。我按照建议覆盖了 prepareEditor 方法,该方法根据需要更新组合框中的 ListModel。
JTable typeTable = new JTable() {
@Override
public Component prepareEditor(TableCellEditor editor, int row, int column) {
if (column == SUBTYPE_COLUMN) {
// User has entered a subtype cell
// Get value of the adjacent type cell
updateCBOSubtypeDataModel(myTableModel.getValueAt(row, TYPE_COLUMN);
}
return super.prepareEditor(editor, row, column);
}
};
和
private void updateCBOSubtypeDataModel(TypeObject newType) {
myComboBoxListModel.removeAllElements();
myComboBoxListModel.addAll(getListOfSubtypesForThisType(newType));
}
工作顺利。谢谢
我有一个 JTable,其中第 3 列和第 4 列使用 JComboBox 作为单元格编辑器。第 3 列指定类型,第 4 列指定子类型。第 4 列中可用的子类型列表取决于用户为该类型选择的值。此外,类型和子类型列表由用户编辑table(细节在这里并不重要,只是类型和子类型列表都可以在运行时更改)。
因为子类型组合框的内容是动态的,我的目的是检测用户何时点击进入子类型单元格,并在此时根据内容设置列表模型(设置可用的子类型项目列表)该行中的类型。
但是,我无法检测到所需单元格中的鼠标单击。我在下面发布了我的代码和输出。
问题是鼠标侦听器未检测到组合框中的单击。据推测,该事件是由组合框触发的,而不是 table。我可以将 ListSelectionListener 与 TableColumnModelListener 结合使用,但我不得不想象有更好的方法。我尝试使用与组合框相关的事件,但我无法获得有关选择了哪个组合框的信息(所以我不知道我在 table 中的什么位置)。我试图获取组合框的容器并以这种方式定位点击,但是组合框的 getParent() 方法 returns null.
编辑:在 ComboBox ActionListener 中,我还尝试使用 JTable 的 getSelectedRow() 和 getSelectedColumn() 方法,但它们 return 旧单元格的值,而不是新单元格的值。
如有任何关于如何更简洁地执行此操作的建议,我们将不胜感激。
以下是相关的代码片段(事件处理程序还没有做太多,只是试图获取信息):
// Setup table and table model
tableTypeDataModel = new TypeAssignmentTableModel();
JTable typeTable = new JTable(tableTypeDataModel);
// Add a mouse listener to the table.
typeTable.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e)
{
Point pnt = e.getPoint();
int row = typeTable.rowAtPoint(pnt);
int col = typeTable.columnAtPoint(pnt);
System.out.println(Integer.toString(row) + ", " + Integer.toString(col));
}
});
typeTable.getSelectionModel().addListSelectionListener(new myListSelectionListener());
typeTable.setFillsViewportHeight(true);
JScrollPane scpnTypeTable = new JScrollPane(typeTable);
// Set columns and model listener
TableColumnModel cm = typeTable.getColumnModel();
cm.addColumnModelListener(new myColumnListSelectionListener());
// Setup type column
JComboBox<String> cmbTableTypes = new JComboBox<>(arrOfTypes);
cmbTableTypes.addActionListener(new myCBOActionListener());
cm.getColumn(TYPECOL_TYPE).setCellEditor(new DefaultCellEditor(cmbTableTypes));
// This just adds left padding to the cell
IndentedTableCellRenderer tableTypeRenderer = new IndentedTableCellRenderer(5, 0);
cm.getColumn(TYPECOL_TYPE).setCellRenderer(tableTypeRenderer);
// Setup subtype column
tableSubtypeCboModel = new DefaultComboBoxModel<>();
JComboBox<String> cmbTableSubtypes = new JComboBox<>(tableSubtypeCboModel);
cm.getColumn(TYPECOL_SUBTYPE).setCellEditor(new DefaultCellEditor(cmbTableSubtypes));
IndentedTableCellRenderer tableSubtypeRenderer = new IndentedTableCellRenderer(5, 0);
cm.getColumn(TYPECOL_SUBTYPE).setCellRenderer(tableSubtypeRenderer);
还有...
class myListSelectionListener implements ListSelectionListener {
@Override
public void valueChanged(ListSelectionEvent e) {
System.out.println("Table List selection listener = " + e.getSource().toString());
}
}
class myColumnListSelectionListener implements TableColumnModelListener {
// other methods empty and not shown...
@Override
public void columnSelectionChanged(ListSelectionEvent e) {
// TODO Auto-generated method stub
System.out.println("Table column model listener Source = " +
e.getSource().toString());
}
}
class myCBOActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
JComboBox item = (JComboBox) e.getSource();
System.out.println("CBO Action Listener = " + item.getClass().toString());
String msg = item.getParent() == null ? "null" : item.getParent().toString();
System.out.println("CBO Action Listener item parent is " + msg);
}
}
这是单击以下单元格后的控制台输出:
Row 1, Col 0 (just a regular cell)
Row 2, Col 1 (just a regular cell)
Row 3, Col 2 (just a regular cell)
Row 4, Col 3 (this is the Type column with a combo box editor)
Console Output:
Table column model listener Source = javax.swing.DefaultListSelectionModel 724380095 ~{0}
Table List selection listener = javax.swing.DefaultListSelectionModel 1902920301 ~{1}
Table List selection listener = javax.swing.DefaultListSelectionModel 1902920301 ={1}
Table column model listener Source = javax.swing.DefaultListSelectionModel 724380095 ={0}
1, 0
Table column model listener Source = javax.swing.DefaultListSelectionModel 724380095 ~{1}
Table List selection listener = javax.swing.DefaultListSelectionModel 1902920301 ~{2}
Table List selection listener = javax.swing.DefaultListSelectionModel 1902920301 ={2}
Table column model listener Source = javax.swing.DefaultListSelectionModel 724380095 ={1}
2, 1
Table column model listener Source = javax.swing.DefaultListSelectionModel 724380095 ~{2}
Table List selection listener = javax.swing.DefaultListSelectionModel 1902920301 ~{3}
Table List selection listener = javax.swing.DefaultListSelectionModel 1902920301 ={3}
Table column model listener Source = javax.swing.DefaultListSelectionModel 724380095 ={2}
3, 2
CBO Action Listener = class javax.swing.JComboBox
CBO Action Listener item parent is null
Table column model listener Source = javax.swing.DefaultListSelectionModel 724380095 ~{3}
Table List selection listener = javax.swing.DefaultListSelectionModel 1902920301 ~{4}
Table List selection listener = javax.swing.DefaultListSelectionModel 1902920301 ={4}
Table column model listener Source = javax.swing.DefaultListSelectionModel 724380095 ={3}
谢谢。
您可以将您的子类型 JCombobox
作为全局管理,然后添加一个 ActionListener
,当在 [=16] 中“选择”子类型 JCombobox
组件时更新子类型值=].
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import javax.swing.*;
public class whatev{
JComboBox types = new JComboBox();
JComboBox subtypes = new JComboBox();
Map<String,int[]> m = new HashMap<String,int[]>(); //example source mapping types to sub-types
int[] t1 = {1,3};
int[] t2 = {4, 5};
public static void main(String[] args){ new whatev(); }
whatev(){
//Add example data to types
types.addItem("Type 1");
types.addItem("Type 2");
types.setSelectedIndex(0);
//init map data for example
m.put("Type 1", t1);
m.put("Type 2", t2);
//initialize subtype JCombobox
updateSubtypes();
//add appropriate listener to subtype box
subtypes.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
updateSubtypes();
}
});
}
private void updateSubtypes() {
int[] x = m.get(types.getSelectedItem()); //pull appropriate subtypes from type/subtype mapping source
subtypes.removeAllItems(); //purge old objects in subtype
for(int v : x) { subtypes.addItem(v); } //Add appropriate subtypes
}
}
@camickr - 谢谢你的回答。我按照建议覆盖了 prepareEditor 方法,该方法根据需要更新组合框中的 ListModel。
JTable typeTable = new JTable() {
@Override
public Component prepareEditor(TableCellEditor editor, int row, int column) {
if (column == SUBTYPE_COLUMN) {
// User has entered a subtype cell
// Get value of the adjacent type cell
updateCBOSubtypeDataModel(myTableModel.getValueAt(row, TYPE_COLUMN);
}
return super.prepareEditor(editor, row, column);
}
};
和
private void updateCBOSubtypeDataModel(TypeObject newType) {
myComboBoxListModel.removeAllElements();
myComboBoxListModel.addAll(getListOfSubtypesForThisType(newType));
}
工作顺利。谢谢