最近,我创建了两个非常简单但非常有用的组件,名为 AttributesEditableView 和 AttributesEditor 。 AttributesEditableView旨在显示任意数量的属性,而AttributesEditor则可以编辑属性。
那么,假设我们有三个属性可以取值'Y','N'和'?' (在哪里'?'我们的意思是“未指明”)。该视图类似于[[Y][N][?]]
:
在编辑器中,用户可以使用箭头键在属性之间左右跳转,并通过按 SPACE 键切换特定(当前选定)属性的值。
(我想那些熟悉JTable
及其特点的人已经明白我什么时候才能到达目的地。)
一切都在表单中运行良好,但是当我想从这个AttributesEditor中创建一个TableCellEditor
时,我会卡住,因为JTable
要么“吃掉”所有事件,要么就是我做错了所以我的AttributesEditor根本没有得到事件...... :(
我的逻辑如下:当编辑器组件DefaultCellEditor
获取这些事件时,JTextField
怎么来( left -key或 right - 按键,例如),而我的单元格编辑器没有?
我知道我不是在这里给所有课程,但我相信下面的两个课程应该给那些已经遇到过这个问题的人提供足够的信息,告诉我如何使这个单元格编辑器按预期工作?
UPDATE :我设法通过重构AttributesEditor类来解决问题。现在它使用键绑定而不是KeyListener
,一切都按预期工作。获得的经验......
你可以在下面的屏幕截图中看到AttributesEditableView,AttributesEditor和AttributesCellEditor(我也有渲染器,但是无论如何都打不开它,它看起来像是AttributesEditableView):
在上面的屏幕截图中,第一个属性可能包含'Y','N'和'?'值,第二个'A','B','C'和'D',第三个属性可能有'T'和'F'作为值。
以下是课程:
AttributesCellEditor
/**
* Authors: Dejan Lekic , http://dejan.lekic.org
* License: MIT
*/
public class AttributesCellEditor extends AbstractCellEditor
implements TableCellEditor, TreeCellEditor {
private AttributesEditor attributesEditor;
private AttributesColumnModel attrColModel;
private AttributesModel model;
private int clickCountToStart = 2;
DefaultCellEditor dfe;
public AttributesCellEditor(AttributesColumnModel argModel) {
super();
attrColModel = argModel;
model = new AttributesModel(attrColModel.getAllowedValues());
model.setDefaultValues(attrColModel.getDefaultValues());
attributesEditor = new AttributesEditor(model);
attributesEditor.setBorder(new BevelBorder(BevelBorder.LOWERED));
}
// ::::: CellEditor method implementations :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
@Override
public Object getCellEditorValue() {
System.out.println("getCellEditorValue()");
// before we return the value, we should also modify the attributes column model and set the
// selected attribute index to the index of what we last edited.
attrColModel.setSelectedAttributeIndex(model.getSelectedAttributeIndex());
return model.getAttributes();
}
// ::::: TableCellEditor method implementations ::::::::::::::::::::::::::::::::::::::::::::::::::::::::
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row,
int column) {
String val = (value == null) ? "" : value.toString();
model.setAttributes(val);
model.setSelectedAttributeIndex(attrColModel.getSelectedAttributeIndex());
attributesEditor.setModel(model);
return attributesEditor;
}
// ::::: TreeCellEditor method implementations ::::::::::::::::::::::::::::::::::::::::::::::::::::::::
// TODO: implement these
@Override
public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected,
boolean expanded, boolean leaf, int row) {
//To change body of generated methods, choose Tools | Templates.
throw new UnsupportedOperationException("Not supported yet.");
}
// ::::: AbstractCellEditor method overrides ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
@Override
public boolean isCellEditable(EventObject e) {
if (e instanceof MouseEvent) {
return ((MouseEvent) e).getClickCount() >= clickCountToStart;
}
return true;
}
/**
* {@inheritDoc}
* @return
*/
@Override
public boolean stopCellEditing() {
boolean ret = super.stopCellEditing();
return ret;
}
} // AttributesCellEditor class
AttributesEditor
/**
* Authors: Dejan Lekic , http://dejan.lekic.org
* License: MIT
*/
public class AttributesEditor
extends AttributesEditableView
implements PropertyChangeListener, FocusListener, KeyListener {
public AttributesEditor() {
super();
editorComponent = true;
setFocusable(true);
setBackground(Color.white);
// Let's copy the border from the TextField
Border b = (Border) UIManager.getLookAndFeelDefaults().get("TextField.border");
setBorder(b);
// Let's copy the insets from the TextField
Insets insets = (Insets) UIManager.getLookAndFeelDefaults().get("TextField.margin");
getInsets().set(insets.top, insets.left, insets.bottom, insets.right);
addKeyListener(this);
// listeners...
addFocusListener(this);
}
public AttributesEditor(AttributesModel argModel) {
this();
setOpaque(true);
setFocusable(true);
setBackground(Color.white);
repaint();
setModel(argModel);
}
// :::: PropertyChangeListener method implementations :::::::::::::::::::::::::::::::::::::::::::::::::
@Override
public void propertyChange(PropertyChangeEvent evt) {
String str = (String) evt.getNewValue();
System.out.println("CALL: AttributesEditor.propertyChange() : " + str);
updateView();
}
// :::: FocusListener method implementations ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
@Override
public void focusGained(FocusEvent e) {
int sel = model.getSelectedAttributeIndex();
if (sel < 0) {
model.setSelectedAttributeIndex(0);
}
sel = model.getSelectedAttributeIndex();
labels[sel].setBackground(model.getSelectedBackgroundColor());
}
@Override
public void focusLost(FocusEvent e) {
model.setSelectedAttributeIndex(-1);
updateView();
}
// :::: KeyListener method implementations ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
@Override
public void keyTyped(KeyEvent e) {
// Weird thing is, arrow keys do not trigger keyTyped() to be called,
// so we have to use keyPressed here, or keyReleased
}
/**
* Weird thing is, arrow keys do not trigger keyTyped() to be called, so we have to use keyPressed/keyReleased here.
* @param e
*/
@Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
switch (key) {
case KeyEvent.VK_UP:
model.previous(model.getSelectedAttributeIndex());
break;
case KeyEvent.VK_DOWN:
case KeyEvent.VK_SPACE:
model.next(model.getSelectedAttributeIndex());
break;
case KeyEvent.VK_LEFT:
model.previousAttribute();
updateView();
break;
case KeyEvent.VK_RIGHT:
model.nextAttribute();
updateView();
break;
default:
int idx = model.getSelectedAttributeIndex();
char chr = Character.toUpperCase(e.getKeyChar());
if (model.isValid(idx, chr)) {
model.setValue(idx, chr);
}
} // switch
} // keyPressed() method
@Override
public void keyReleased(KeyEvent e) {
// nothing
}
} // AttributesEditor class
AttributesEditableView
/**
* Authors: Dejan Lekic , http://dejan.lekic.org
* License: MIT
*/
public class AttributesEditableView
extends JComponent
implements PropertyChangeListener, MouseListener {
protected AttributesModel model;
protected JLabel[] labels;
protected boolean editorComponent;
protected boolean inTable;
public AttributesEditableView() {
super();
FlowLayout fl = new FlowLayout(FlowLayout.LEFT);
fl.setVgap(0);
setLayout(fl);
editorComponent = false;
inTable = false;
}
public AttributesEditableView(AttributesModel argModel) {
this();
setModel(argModel);
}
// :::: JComponent method overrides :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
/**
* I had to do this because it is a common problem with JComponent subclasses.
* More about it: http://docs.oracle.com/javase/tutorial/uiswing/painting/problems.html
*
* @param g
*/
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(getBackground());
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(getForeground());
}
// :::: PropertyChangeListener mthod implementations ::::::::::::::::::::::::::::::::::::::::::::::::::
@Override
public void propertyChange(PropertyChangeEvent evt) {
String str = (String) evt.getNewValue();
updateView();
}
// :::: <Interface> method implementations ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
@Override
public void mouseClicked(MouseEvent e) {
// labels have names in form of "attributelbl-3", we need to extract the ID from the name
String num = e.getComponent().getName().split("-")[1];
int idx = Integer.parseInt(num);
if (editorComponent) {
model.setSelectedAttributeIndex(idx);
}
model.next(idx);
} // mouseClicked() method
@Override
public void mousePressed(MouseEvent e) {
// do nothing
}
@Override
public void mouseReleased(MouseEvent e) {
// do nothing
}
@Override
public void mouseEntered(MouseEvent e) {
// labels have names in form of "attributelbl-3", we need to extract the ID from the name
String num = e.getComponent().getName().split("-")[1];
int idx = Integer.parseInt(num);
model.setSelectedAttributeIndex(idx);
updateView();
}
@Override
public void mouseExited(MouseEvent e) {
// labels have names in form of "attributelbl-3", we need to extract the ID from the name
String num = e.getComponent().getName().split("-")[1];
int idx = Integer.parseInt(num);
if (!editorComponent) {
model.setSelectedAttributeIndex(-1);
}
updateView();
}
/**
* Use this method to forcefully highlight specific attribute.
* @param argIndex
*/
public final void highlight(int argIndex) {
for (int i = 0; i < model.getNumberOfAttributes(); i++) {
if (i == argIndex) {
labels[i].setBackground(model.getSelectedBackgroundColor());
} else {
labels[i].setBackground(model.getBackgroundColor());
}
} // for
} // highlight() method
/**
* Extremely important method. Here we set the model, and generate JLabel objects for the attributes.
* We also set the values, and initialise the listeners.
* @param argModel
*/
public final void setModel(AttributesModel argModel) {
if (model != null) {
model.removePropertyChangeListener(this);
}
labels = null;
removeAll();
labels = new JLabel[argModel.getNumberOfAttributes()];
int w = 0;
int h = 0;
for (int i = 0; i < argModel.getNumberOfAttributes(); i++) {
String txt = "" + argModel.getValue(i);
System.out.println(txt);
JLabel lbl = new JLabel(txt);
labels[i] = lbl;
lbl.setName("attributelbl-" + i); // very important, because we will use the name to get the idx
lbl.setHorizontalAlignment(SwingConstants.CENTER);
lbl.setOpaque(true);
lbl.setBackground(argModel.getBackgroundColor());
if (isInTable()) {
lbl.setBorder(BorderFactory.createMatteBorder(0, 0, 0, 1, Color.GRAY));
}
int nh = lbl.getPreferredSize().height;
int nw = nh; // make the width to be equal to the height
lbl.setPreferredSize(new Dimension(nw, nh));
lbl.addMouseListener(this);
h = Math.max(h, lbl.getPreferredSize().height);
w = w + lbl.getPreferredSize().width;
add(lbl);
} // for
Dimension ps = new Dimension(w, h);
model = argModel;
model.addPropertyChangeListener(this);
} // setModel() method
public final AttributesModel getModel() {
return model;
}
public boolean isInTable() {
return inTable;
}
public void setInTable(boolean inTable) {
this.inTable = inTable;
}
/**
* Updates the view
*/
protected void updateView() {
String attrs = model.getAttributes();
for (int i = 0; i < model.getNumberOfAttributes(); i++) {
labels[i].setText("" + model.getValue(i));
if (model.getSelectedAttributeIndex() == i) {
labels[i].setBackground(model.getSelectedBackgroundColor());
} else {
labels[i].setBackground(model.getBackgroundColor());
}
}
}
} // AttributesEditableView class