【发布时间】:2015-02-15 01:51:06
【问题描述】:
使用 JCheckBox 作为 JTable 列中的编辑器,我想忽略 TableCell 中 CheckBox 左右空间中的鼠标点击。
我在 Oracle 论坛上找到了 2011 年的讨论,但问题在那里没有解决:https://community.oracle.com/thread/2183210
这是迄今为止我已经意识到的 hack,有趣的部分开始于class CheckBoxEditor:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.util.EventObject;
import javax.swing.DefaultCellEditor;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
/**
* Trying to set the Checkbox only if clicked directly on the box of the CheckBox. And ignore clicks on the
* remaining space of the TableCell.
*
* @author bobndrew
*/
public class JustCheckOnCheckboxTable extends JPanel
{
private static final int CHECK_COL = 1;
private static final Object[][] DATA = { { "One", Boolean.TRUE }, { "Two", Boolean.FALSE },
{ "Three", Boolean.TRUE }, { "Four", Boolean.FALSE }, { "Five", Boolean.TRUE },
{ "Six", Boolean.FALSE }, { "Seven", Boolean.TRUE }, { "Eight", Boolean.FALSE },
{ "Nine", Boolean.TRUE }, { "Ten", Boolean.FALSE } };
private static final String[] COLUMNS = { "Number", "CheckBox" };
private final DataModel dataModel = new DataModel( DATA, COLUMNS );
private final JTable table = new JTable( dataModel );
public JustCheckOnCheckboxTable()
{
super( new BorderLayout() );
this.add( new JScrollPane( table ) );
table.setRowHeight( table.getRowHeight() * 2 );
table.setPreferredScrollableViewportSize( new Dimension( 250, 400 ) );
TableColumn checkboxColumn = table.getColumnModel().getColumn( 1 );
checkboxColumn.setCellEditor( new CheckBoxEditor() );
}
private class DataModel extends DefaultTableModel
{
public DataModel( Object[][] data, Object[] columnNames )
{
super( data, columnNames );
}
@Override
public Class<?> getColumnClass( int columnIndex )
{
if ( columnIndex == 1 )
{
return getValueAt( 0, CHECK_COL ).getClass();
}
return super.getColumnClass( columnIndex );
}
}
class CheckBoxEditor extends DefaultCellEditor
{
private final JCheckBox checkBox;
public CheckBoxEditor()
{
super( new JCheckBox() );
checkBox = (JCheckBox) getComponent();
checkBox.setHorizontalAlignment( JCheckBox.CENTER );
System.out.println( "the checkbox has no size: " + checkBox.getSize() );
}
@Override
public boolean shouldSelectCell( final EventObject anEvent )
{
System.out.println( "\nthe checkbox fills the TableCell: " + checkBox.getSize() );
//Throws NullPointerException: System.out.println( checkBox.getIcon().getIconWidth() );
System.out.println( "always JTable :-( " + anEvent.getSource() );
MouseEvent ev =
SwingUtilities.convertMouseEvent( ((ComponentEvent) anEvent).getComponent(), (MouseEvent) anEvent,
getComponent() );
System.out.println( "Position clicked in TableCell: " + ev.getPoint() );
System.out.println( "always JCheckBox :-( " + getComponent().getComponentAt( ev.getPoint() ) );
Point middleOfTableCell = new Point( checkBox.getWidth() / 2, checkBox.getHeight() / 2 );
System.out.println( "middleOfTableCell: " + middleOfTableCell );
Dimension preferredSizeOfCheckBox = checkBox.getPreferredSize();
int halfWidthOfClickArea = (int) (preferredSizeOfCheckBox.getWidth() / 2);
int halfHeightOfClickArea = (int) (preferredSizeOfCheckBox.getHeight() / 2);
if ( (middleOfTableCell.getX() - halfWidthOfClickArea > ev.getX() || middleOfTableCell.getX() + halfWidthOfClickArea < ev.getX())
|| (middleOfTableCell.getY() - halfHeightOfClickArea > ev.getY() || middleOfTableCell.getY() + halfHeightOfClickArea < ev.getY()) )
{
stopCellEditing();
}
return super.shouldSelectCell( anEvent );
}
}
private static void createAndShowUI()
{
JFrame frame = new JFrame( "Direct click on CheckBox" );
frame.add( new JustCheckOnCheckboxTable() );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
public static void main( String[] args )
{
java.awt.EventQueue.invokeLater( new Runnable()
{
@Override
public void run()
{
createAndShowUI();
}
} );
}
}
我喜欢这个解决方案的地方:
- 所有 TableCell 行为都是正确的:选择、鼠标悬停、EditModes、...
我不喜欢它的地方:
- JCheckBox 的硬编码大小 (
int halfWidthOfClickArea)- 在哪里可以获得未上漆组件的尺寸?
或者有没有更好的方法来实现这个表和复选框行为?
编辑:
我根据 camickr 的建议更改了源代码,并为具有较高 RowHeights 的表添加了垂直命中区。
但到目前为止,我忘了提及我的问题的主要原因...... ;-)
我在方法shouldSelectCell(..) 中调用stopCellEditing()。
除了单元格选择之外可以决定吗?
【问题讨论】:
-
如果您使用来自 XxxTabeleCellEditor 的 getComponent().getC... 并更改编辑器的 setClickCountToStart 会发生什么
-
@mKorbel 如果您的意思是
getComponent().getComponentAt(ev.getPoint()),它会返回 JCheckBox,因为它填充了整个 TableCell。关于您更改“setClickCountToStart for Editor”的建议,我不知道它对我有什么帮助!? -
我不想变得粗鲁或其他任何事情,但是我的回答对您有用吗?如果没有,你能留下评论为什么吗? (如果你只是想等着看有没有其他答案,那没关系,直接说吧:))只是想知道我是否可以做些什么来让我的回复更好。
-
让我快点没问题。请在您的回答下查看我的评论。
标签: java swing jtable jcheckbox tablecelleditor