- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试实现一种优雅的树表示,其中某些类型的节点显示为包含文本、单选按钮和复选框的面板。下面是我当前拥有的图片以及生成它的代码。然而,有一些问题只会让人感觉很脏,而且我不确定解决这些问题的最佳方法。
public class DatasetTree extends JTree {
public DatasetTree(String name) {
super(new DatasetTreeModel(name));
getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
DatasetTreeCellRenderer renderer = new DatasetTreeCellRenderer();
renderer.setOpenIcon(null);
renderer.setClosedIcon(null);
renderer.setLeafIcon(null);
setCellRenderer(renderer);
setEditable(true);
PanelCellEditor editor = new PanelCellEditor(this, renderer);
setCellEditor(editor);
setShowsRootHandles(true);
setRootVisible(false);
}
public DatasetTreeModel getDatasetModel() {
return (DatasetTreeModel) treeModel;
}
public static class DatasetTreeCellRenderer extends DefaultTreeCellRenderer {
public DatasetTreeCellRenderer() {
}
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel,
boolean expanded, boolean leaf, int row, boolean hasFocus) {
if ((value != null) && (value instanceof DatasetHandle)) {
DatasetHandle h = (DatasetHandle) value;
DatasetCellPanel line = new DatasetCellPanel(h);
if (sel) {
line.setBackground(getBackgroundSelectionColor());
line.setForeground(getTextSelectionColor());
} else {
line.setBackground(getBackgroundNonSelectionColor());
line.setForeground(getTextNonSelectionColor());
}
return line;
}
return super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
}
}
public static class DatasetCellPanel extends JPanel {
private final JLabel lblName, lblType, lblom, lbldata, lblimages, lblspectra;
private boolean observable;
private boolean orientable;
private JRadioButton omButton;
private JCheckBox dataSelectBox;
/**
* Create the panel.
*/
public DatasetCellPanel(DatasetHandle h) {
super();
setBackground(Color.WHITE);
FileData fd = h.getFileData();
String name = fd.getFileName();
boolean observable = (fd instanceof ObservableData);
boolean orientable = (fd instanceof Orientable);
String typeName = fd.getClass().getSimpleName();
lblName = new JLabel("");
lblType = new JLabel("");
lblom = new JLabel("[om]");
lbldata = new JLabel("[data]");
lblimages = new JLabel("[images]");
lblspectra = new JLabel("[spectra]");
JRadioButton omButton = new JRadioButton("");
JCheckBox dataSelectBox = new JCheckBox("");
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
lblName.setText(name);
lblName.setMinimumSize(new Dimension(100, 8));
lblName.setPreferredSize(new Dimension(100, 16));
lblName.setMaximumSize(new Dimension(100, 64));
add(lblName);
add(Box.createRigidArea(new Dimension(5, 0)));
lblType.setText(typeName);
lblType.setMinimumSize(new Dimension(100, 8));
lblType.setPreferredSize(new Dimension(100, 16));
lblType.setMaximumSize(new Dimension(100, 64));
add(lblType);
add(Box.createRigidArea(new Dimension(5, 0)));
if (orientable) {
omButton = h.getLatticeButton();
} else {
lblom.setForeground(UIManager.getColor("Label.disabledForeground"));
omButton.setEnabled(false);
}
add(lblom);
add(omButton);
add(Box.createRigidArea(new Dimension(5, 0)));
if (observable) {
dataSelectBox = h.getDataButton();
} else {
lbldata.setForeground(UIManager.getColor("Label.disabledForeground"));
dataSelectBox.setEnabled(false);
}
add(lbldata);
add(dataSelectBox);
add(Box.createRigidArea(new Dimension(5, 0)));
add(lblimages);
add(Box.createRigidArea(new Dimension(5, 0)));
add(lblspectra);
}
public void addListeners(EventListener l) {
}
@Override
public void setForeground(Color fg) {
if (lblName != null) {
lblName.setForeground(fg);
}
if (lblType != null) {
lblType.setForeground(fg);
}
if (observable && (lbldata != null)) {
lbldata.setForeground(fg);
}
if (orientable && (lblom != null)) {
lblom.setForeground(fg);
}
if (lblimages != null) {
lblimages.setForeground(fg);
}
if (lblspectra != null) {
lblspectra.setForeground(fg);
}
super.setForeground(fg);
}
@Override
public void setBackground(Color bg) {
if (omButton != null) {
omButton.setBackground(bg);
}
if (dataSelectBox != null) {
dataSelectBox.setBackground(bg);
}
super.setBackground(bg);
}
}
public static class PanelCellEditor extends AbstractCellEditor implements TreeCellEditor {
Object value;
private JTree tree;
private DefaultTreeCellRenderer renderer;
public PanelCellEditor(JTree tree, DefaultTreeCellRenderer renderer) {
this.tree = tree;
this.renderer = renderer;
}
@Override
public Object getCellEditorValue() {
return value;
}
// FIXME: Redraw all in group when one is edited
@Override
public Component getTreeCellEditorComponent(JTree tree, Object value, boolean sel,
boolean expanded, boolean leaf, int row) {
this.value = value;
if ((value != null) && (value instanceof DatasetHandle)) {
DatasetHandle h = (DatasetHandle) value;
DatasetCellPanel line = new DatasetCellPanel(h);
if (sel) {
line.setBackground(renderer.getBackgroundSelectionColor());
line.setForeground(renderer.getTextSelectionColor());
} else {
line.setBackground(renderer.getBackgroundNonSelectionColor());
line.setForeground(renderer.getTextNonSelectionColor());
}
return line;
}
return renderer.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, false);
}
}
}
(1) 仅在单击节点一次启用编辑后,按钮/框才会响应。在此之前,按钮/框在鼠标悬停时不会发光。
(2) 父级下每组节点的单选按钮位于单个按钮组中。但是,当我选择其中一个时,另一个的视觉表示不会更新以反射(reflect)它已被取消选择,直到我单击其中的某个位置来“编辑”它。
(3) 一般来说,这种标准类型的树(其中节点只是虚拟对象,而不是实际组件)似乎不适合于此,但我想不出更好的替代方案来允许我对这些对象进行分组,选择单个节点(叶节点或父节点),并让每个叶节点包含正常工作的复选框/按钮。
我愿意接受替代解决方案的建议。
编辑:
尝试使用 Outline,这似乎更接近我想要的,但存在技术问题。我按照例子here 。这是我得到的:
如您所见,按钮未正确显示。这是我的 RowModel:
public class DatasetOutlineRowModel implements RowModel {
@Override
public Class getColumnClass(int column) {
switch (column) {
case 0:
return JRadioButton.class;
case 1:
return JCheckBox.class;
case 2:
return String.class;
case 3:
return String.class;
default:
assert false;
}
return null;
}
@Override
public int getColumnCount() {
return 4;
}
@Override
public String getColumnName(int column) {
switch (column) {
case 0:
return "OM";
case 1:
return "Data";
case 2:
return "Images";
case 3:
return "Spectra";
default:
assert false;
}
return null;
}
@Override
public Object getValueFor(Object node, int column) {
if (!(node instanceof DatasetHandle))
return null;
DatasetHandle handle = (DatasetHandle) node;
switch (column) {
case 0:
return handle.getLatticeButton();
case 1:
return handle.getDataButton();
case 2:
return "";
case 3:
return "";
default:
assert false;
}
return null;
}
@Override
public boolean isCellEditable(Object arg0, int arg1) {
return false;
}
@Override
public void setValueFor(Object arg0, int arg1, Object arg2) {
// TODO Auto-generated method stub
}
}
最佳答案
好的,我终于根据 JTable 处理 boolean 单元格的方式弄清楚了如何实现这一点。我创建了一个独占 boolean 选择渲染器来绘制 JRadioButton 并设置树节点以确保维持独占选择。如果其中一个单元格被编辑,我还覆盖了 editStopped 来更新列中的所有单元格。可能有一些方法可以改进这一点,但它适合我的需要。感谢您的指导。
这是我的代码:
DatasetOutline 类
public class DatasetOutline extends Outline {
public DatasetOutline(DatasetTreeModel mdl) {
setRenderDataProvider(new DatasetRenderProvider());
setRootVisible(false);
setShowGrid(false);
setIntercellSpacing(new Dimension(0, 0));
setModel(DefaultOutlineModel.createOutlineModel(mdl, new DatasetOutlineRowModel(), true,
"Dataset"));
getColumnModel().getColumn(1).setCellRenderer(new ExclusiveBooleanRenderer());
getColumnModel().getColumn(1).setCellEditor(new ExclusiveBooleanEditor());
// [snip]
getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
// Update the entire column of the conditional boolean if one is changed
@Override
public void editingStopped(ChangeEvent e) {
super.editingStopped(e);
if (e.getSource() instanceof ExclusiveBooleanEditor) {
tableChanged(new TableModelEvent(getModel(), 0, getRowCount(), 1, TableModelEvent.UPDATE));
}
}
}
DatasetOutlineRowModel 类
public class DatasetOutlineRowModel implements RowModel {
@Override
public Class getColumnClass(int column) {
switch (column) {
case 0:
return Boolean.class;
case 1:
return Boolean.class;
case 2:
return String.class;
case 3:
return String.class;
default:
assert false;
}
return null;
}
// [snip]
@Override
public Object getValueFor(Object node, int column) {
if (!(node instanceof DatasetHandle))
return null;
DatasetHandle handle = (DatasetHandle) node;
switch (column) {
case 0:
return handle.isLatticeSelected();
case 1:
return handle.isSelected();
case 2:
return "";
case 3:
return "";
default:
assert false;
}
return null;
}
@Override
public boolean isCellEditable(Object node, int column) {
if (column > 1)
return false;
if (node instanceof DatasetHandle)
return true;
return false;
}
@Override
public void setValueFor(Object node, int column, Object value) {
if (!(node instanceof DatasetHandle))
return;
DatasetHandle handle = (DatasetHandle) node;
if (column == 0) {
handle.setLatticeSelected((Boolean) value);
}
if (column == 1) {
handle.setSelected((Boolean) value);
}
}
}
ExclusiveBooleanEditor 类(DefaultCellRenderer 的修改副本)
public class ExclusiveBooleanEditor extends AbstractCellEditor implements TableCellEditor,
TreeCellEditor {
//
// Instance Variables
//
/** The Swing component being edited. */
protected JComponent editorComponent;
/**
* The delegate class which handles all methods sent from the <code>CellEditor</code>.
*/
protected EditorDelegate delegate;
/**
* An integer specifying the number of clicks needed to start editing. Even if
* <code>clickCountToStart</code> is defined as zero, it will not initiate until a click occurs.
*/
protected int clickCountToStart = 1;
//
// Constructors
//
public ExclusiveBooleanEditor() {
this(new JRadioButton());
JRadioButton radioButton = (JRadioButton) getComponent();
radioButton.setHorizontalAlignment(JRadioButton.CENTER);
}
public ExclusiveBooleanEditor(final JRadioButton radioButton) {
editorComponent = radioButton;
delegate = new EditorDelegate() {
// FIXME replace
@Override
public void setValue(Object value) {
boolean selected = false;
if (value instanceof Boolean) {
selected = ((Boolean) value).booleanValue();
} else if (value instanceof String) {
selected = value.equals("true");
}
radioButton.setSelected(selected);
}
@Override
public Object getCellEditorValue() {
return Boolean.valueOf(radioButton.isSelected());
}
};
radioButton.addActionListener(delegate);
radioButton.setRequestFocusEnabled(false);
}
/**
* Returns a reference to the editor component.
*
* @return the editor <code>Component</code>
*/
public Component getComponent() {
return editorComponent;
}
//
// Modifying
//
/**
* Specifies the number of clicks needed to start editing.
*
* @param count an int specifying the number of clicks needed to start editing
* @see #getClickCountToStart
*/
public void setClickCountToStart(int count) {
clickCountToStart = count;
}
/**
* Returns the number of clicks needed to start editing.
*
* @return the number of clicks needed to start editing
*/
public int getClickCountToStart() {
return clickCountToStart;
}
//
// Override the implementations of the superclass, forwarding all methods
// from the CellEditor interface to our delegate.
//
/**
* Forwards the message from the <code>CellEditor</code> to the <code>delegate</code>.
*
* @see EditorDelegate#getCellEditorValue
*/
@Override
public Object getCellEditorValue() {
return delegate.getCellEditorValue();
}
/**
* Forwards the message from the <code>CellEditor</code> to the <code>delegate</code>.
*
* @see EditorDelegate#isCellEditable(EventObject)
*/
@Override
public boolean isCellEditable(EventObject anEvent) {
return delegate.isCellEditable(anEvent);
}
/**
* Forwards the message from the <code>CellEditor</code> to the <code>delegate</code>.
*
* @see EditorDelegate#shouldSelectCell(EventObject)
*/
@Override
public boolean shouldSelectCell(EventObject anEvent) {
return delegate.shouldSelectCell(anEvent);
}
/**
* Forwards the message from the <code>CellEditor</code> to the <code>delegate</code>.
*
* @see EditorDelegate#stopCellEditing
*/
@Override
public boolean stopCellEditing() {
return delegate.stopCellEditing();
}
/**
* Forwards the message from the <code>CellEditor</code> to the <code>delegate</code>.
*
* @see EditorDelegate#cancelCellEditing
*/
@Override
public void cancelCellEditing() {
delegate.cancelCellEditing();
}
//
// Implementing the TreeCellEditor Interface
//
/** Implements the <code>TreeCellEditor</code> interface. */
@Override
public Component getTreeCellEditorComponent(JTree tree, Object value, boolean isSelected,
boolean expanded, boolean leaf, int row) {
String stringValue = tree.convertValueToText(value, isSelected, expanded, leaf, row, false);
delegate.setValue(stringValue);
return editorComponent;
}
//
// Implementing the CellEditor Interface
//
/** Implements the <code>TableCellEditor</code> interface. */
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
int row, int column) {
delegate.setValue(value);
if ((editorComponent instanceof JCheckBox) || (editorComponent instanceof JRadioButton)) {
// in order to avoid a "flashing" effect when clicking a checkbox
// in a table, it is important for the editor to have as a border
// the same border that the renderer has, and have as the background
// the same color as the renderer has. This is primarily only
// needed for JCheckBox since this editor doesn't fill all the
// visual space of the table cell, unlike a text field.
TableCellRenderer renderer = table.getCellRenderer(row, column);
Component c =
renderer.getTableCellRendererComponent(table, value, isSelected, true, row, column);
if (c != null) {
editorComponent.setOpaque(true);
editorComponent.setBackground(c.getBackground());
if (c instanceof JComponent) {
editorComponent.setBorder(((JComponent) c).getBorder());
}
} else {
editorComponent.setOpaque(false);
}
}
return editorComponent;
}
//
// Protected EditorDelegate class
//
/**
* The protected <code>EditorDelegate</code> class.
*/
protected class EditorDelegate implements ActionListener, ItemListener, Serializable {
/** The value of this cell. */
protected Object value;
/**
* Returns the value of this cell.
*
* @return the value of this cell
*/
public Object getCellEditorValue() {
return value;
}
/**
* Sets the value of this cell.
*
* @param value the new value of this cell
*/
public void setValue(Object value) {
this.value = value;
}
/**
* Returns true if <code>anEvent</code> is <b>not</b> a <code>MouseEvent</code>. Otherwise, it
* returns true if the necessary number of clicks have occurred, and returns false otherwise.
*
* @param anEvent the event
* @return true if cell is ready for editing, false otherwise
* @see #setClickCountToStart
* @see #shouldSelectCell
*/
public boolean isCellEditable(EventObject anEvent) {
if (anEvent instanceof MouseEvent) {
return ((MouseEvent) anEvent).getClickCount() >= clickCountToStart;
}
return true;
}
/**
* Returns true to indicate that the editing cell may be selected.
*
* @param anEvent the event
* @return true
* @see #isCellEditable
*/
public boolean shouldSelectCell(EventObject anEvent) {
return true;
}
/**
* Returns true to indicate that editing has begun.
*
* @param anEvent the event
*/
public boolean startCellEditing(EventObject anEvent) {
return true;
}
/**
* Stops editing and returns true to indicate that editing has stopped. This method calls
* <code>fireEditingStopped</code>.
*
* @return true
*/
public boolean stopCellEditing() {
fireEditingStopped();
return true;
}
/**
* Cancels editing. This method calls <code>fireEditingCanceled</code>.
*/
public void cancelCellEditing() {
fireEditingCanceled();
}
/**
* When an action is performed, editing is ended.
*
* @param e the action event
* @see #stopCellEditing
*/
@Override
public void actionPerformed(ActionEvent e) {
ExclusiveBooleanEditor.this.stopCellEditing();
}
/**
* When an item's state changes, editing is ended.
*
* @param e the action event
* @see #stopCellEditing
*/
@Override
public void itemStateChanged(ItemEvent e) {
ExclusiveBooleanEditor.this.stopCellEditing();
}
}
public static class ExclusiveBooleanRenderer extends JRadioButton implements TableCellRenderer,
UIResource {
private static final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
private static final JLabel emptyLabel = new JLabel("");
public ExclusiveBooleanRenderer() {
super();
setHorizontalAlignment(JRadioButton.CENTER);
setBorderPainted(true);
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
// Don't draw if it is not changeable
if (value == null) {
if (isSelected) {
emptyLabel.setForeground(table.getSelectionForeground());
emptyLabel.setBackground(table.getSelectionBackground());
} else {
emptyLabel.setForeground(table.getForeground());
emptyLabel.setBackground(table.getBackground());
}
return emptyLabel;
}
if (isSelected) {
setForeground(table.getSelectionForeground());
super.setBackground(table.getSelectionBackground());
} else {
setForeground(table.getForeground());
setBackground(table.getBackground());
}
setSelected((value != null && ((Boolean) value).booleanValue()));
if (hasFocus) {
setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
} else {
setBorder(noFocusBorder);
}
return this;
}
}
} // End of class JCellEditor
关于java - 使用单选框/复选框实现 JTree 节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28612110/
我正在编写一个具有以下签名的 Java 方法。 void Logger(Method method, Object[] args); 如果一个方法(例如 ABC() )调用此方法 Logger,它应该
我是 Java 新手。 我的问题是我的 Java 程序找不到我试图用作的图像文件一个 JButton。 (目前这段代码什么也没做,因为我只是得到了想要的外观第一的)。这是我的主课 代码: packag
好的,今天我在接受采访,我已经编写 Java 代码多年了。采访中说“Java 垃圾收集是一个棘手的问题,我有几个 friend 一直在努力弄清楚。你在这方面做得怎么样?”。她是想骗我吗?还是我的一生都
我的 friend 给了我一个谜语让我解开。它是这样的: There are 100 people. Each one of them, in his turn, does the following
如果我将使用 Java 5 代码的应用程序编译成字节码,生成的 .class 文件是否能够在 Java 1.4 下运行? 如果后者可以工作并且我正在尝试在我的 Java 1.4 应用程序中使用 Jav
有关于why Java doesn't support unsigned types的问题以及一些关于处理无符号类型的问题。我做了一些搜索,似乎 Scala 也不支持无符号数据类型。限制是Java和S
我只是想知道在一个 java 版本中生成的字节码是否可以在其他 java 版本上运行 最佳答案 通常,字节码无需修改即可在 较新 版本的 Java 上运行。它不会在旧版本上运行,除非您使用特殊参数 (
我有一个关于在命令提示符下执行 java 程序的基本问题。 在某些机器上我们需要指定 -cp 。 (类路径)同时执行java程序 (test为java文件名与.class文件存在于同一目录下) jav
我已经阅读 StackOverflow 有一段时间了,现在我才鼓起勇气提出问题。我今年 20 岁,目前在我的家乡(罗马尼亚克卢日-纳波卡)就读 IT 大学。足以介绍:D。 基本上,我有一家提供簿记应用
我有 public JSONObject parseXML(String xml) { JSONObject jsonObject = XML.toJSONObject(xml); r
我已经在 Java 中实现了带有动态类型的简单解释语言。不幸的是我遇到了以下问题。测试时如下代码: def main() { def ks = Map[[1, 2]].keySet()
一直提示输入 1 到 10 的数字 - 结果应将 st、rd、th 和 nd 添加到数字中。编写一个程序,提示用户输入 1 到 10 之间的任意整数,然后以序数形式显示该整数并附加后缀。 public
我有这个 DownloadFile.java 并按预期下载该文件: import java.io.*; import java.net.URL; public class DownloadFile {
我想在 GUI 上添加延迟。我放置了 2 个 for 循环,然后重新绘制了一个标签,但这 2 个 for 循环一个接一个地执行,并且标签被重新绘制到最后一个。 我能做什么? for(int i=0;
我正在对对象 Student 的列表项进行一些测试,但是我更喜欢在 java 类对象中创建硬编码列表,然后从那里提取数据,而不是连接到数据库并在结果集中选择记录。然而,自从我这样做以来已经很长时间了,
我知道对象创建分为三个部分: 声明 实例化 初始化 classA{} classB extends classA{} classA obj = new classB(1,1); 实例化 它必须使用
我有兴趣使用 GPRS 构建车辆跟踪系统。但是,我有一些问题要问以前做过此操作的人: GPRS 是最好的技术吗?人们意识到任何问题吗? 我计划使用 Java/Java EE - 有更好的技术吗? 如果
我可以通过递归方法反转数组,例如:数组={1,2,3,4,5} 数组结果={5,4,3,2,1}但我的结果是相同的数组,我不知道为什么,请帮助我。 public class Recursion { p
有这样的标准方式吗? 包括 Java源代码-测试代码- Ant 或 Maven联合单元持续集成(可能是巡航控制)ClearCase 版本控制工具部署到应用服务器 最后我希望有一个自动构建和集成环境。
我什至不知道这是否可能,我非常怀疑它是否可能,但如果可以,您能告诉我怎么做吗?我只是想知道如何从打印机打印一些文本。 有什么想法吗? 最佳答案 这里有更简单的事情。 import javax.swin
我是一名优秀的程序员,十分优秀!