`
pkjava
  • 浏览: 778 次
  • 性别: Icon_minigender_1
  • 来自: 北京
最近访客 更多访客>>
社区版块
存档分类
最新评论

【转载】Fully Interactive JTables (aka Mouseover Editing)

阅读更多

 

在学Swing的时候,因为想写一个表格里面镶嵌其他组建的功能。找到老外一片文章,如下:

原文:http://blog.palantirtech.com/2007/05/17/jtable-mouseover-editing/

 

-------------------------------------------------------------------------------------------------

 

May 17th, 2007 | Kevin

What sucks about JTables ? Everything, of course—but that’s a developer’s perspective. To the user, cell editing is rough around the edges: when and where to click, and how many times—it’s never perfectly clear. Cells in a table just don’t provide the mouseover feedback that regular components do. If only a JTable behaved like a bunch of components thrown into a giant GridBag or TableLayout

mouseover-screenshot.png

Mouseover Editing simulates just that. The idea is to attach a MouseListener to the JTable and call editCellAt(row, col) whenever the cursor moves over a new cell. In other words, even though only one cell in a table can be fully interactive (the editing cell) at any given time, as long as we keep moving that cell to stay underneath the user’s cursor, the whole table will appear to be fully interactive. If done correctly, this will appear to the user as though he’s interacting with a bunch of real components (rather than rendered stamps) inside a giant Grid/GridBag/TableLayout.

Most importantly, the user will get mouseover feedback about which cells are editable, and how to edit them. Checkboxes, buttons, and comboboxes (if the L&F supports it) will highlight to indicate press-ability and the cursor will turn to a text caret when hovering over cells that contain textfields. When done correctly, the effect is nearly seamless and very satisfying.

Here’s a webstart demo . Read on for the solution in code.

 

There are three parts to the Mouseover Editing solution (over and above what’s needed for typical JTable editing).

Part 1: Identical Editors and Renderers

This is important. Typically, a table will use a JLabel to render a cell and a JTextField to edit the cell. When the editor is swapped in to replace the renderer, there’s a slight flicker—the textfield might have a different background color, the text mayb be in a slightly different location, etc. This is all well and good when the user has to click or double-click to engage the editor, because the click can be perceived as granting permission to the program to do something on its own. However, a simple mouseover is a different story. Here, the look, feel, and placement of the editor should exactly match up with the look, feel, and placement of the renderer; otherwise, there will be a flicker trail every time the cursor passes through the JTable.

In order to make editors and renderers look and behave identically, (a) we need them to start out identical and (b) we need to apply the same transformations to them.

The easiest way to make an identical editor and renderer is to produce two objects from a combined EditorRenderer class. Here’s how that might work for a checkbox:

public class CheckBoxEditorRenderer extends AbstractCellEditor implements TableCellRenderer
{
	private JCheckBox checkbox = new JCheckBox();
	public CheckBoxEditorRenderer() {
		super();
		checkbox.setFocusable(false);
	}
	public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
		if (value instanceof Boolean) {
			checkbox.setSelected((Boolean) value);
		}
		return checkbox;
	}
	public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
		if (value instanceof Boolean) {
			checkbox.setSelected((Boolean) value);
		}
		return checkbox;
	}
	public Object getCellEditorValue() {
		return checkbox.isSelected();
	}
}

 

Notice how CheckBoxEditorRenderer implements both the TableCellRenderer and TableCellEditor interfaces (the latter via AbstractCellEditor ).

Editors and renderers must also be subjected to the same transformations. In a subclass of JTable, say one called MouseoverJTable, use the following format for your prepareEditor() and prepareRenderer() methods:

public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
	Component c = super.prepareRenderer(renderer, row, column);
	return prepareEditorRenderer(c, row, column);
	}
	public Component prepareEditor(TableCellEditor editor, int row, int column) {
	Component c = super.prepareEditor(editor, row, column);
	return prepareEditorRenderer(c, row, column);
	}
	private Component prepareEditorRenderer(Component stamp, int row, int column) {
//	 ...  All sorts of shenanigans can go on here.
	}
}
 

 

This ensures that both the editor and the renderer will go through the same decoration path.

Part 2: Two-stage editing

What we’ve presented thus far works really well for buttons and checkboxes, which are minimally interactive. With comboboxes and textfields, there’s a problem. Suppose you mouse over a cell with a combobox. First the combobox will become highlighted (if the L&F supports it) to indicate that it’s clickable; this is expected and reasonable behavior. If you click on it, the combobox flyout will appear; this is also expected and reasonable behavior. Now move your mouse just a little bit…. oh no! You accidentally moused over another cell, and the table decided to swap out the editor you were using (the combobox) and swap in a new editor. Goodbye flyout.

To make sure this doesn’t happen, we need editors with two states: temporarily engaged and fully engaged. When the cursor first moves over a cell, we call editCellAt(r, c), and plop the editor into place, temporarily engaged. This means it’s an interactive JComponent that responds to mouse events, but that it’s okay to swap it out and replace it with a new editor if the cursor changes location. Then, if the user starts interacting with the Editor in a way that requires the editor to keep around a bit of state (like the visibility of a flyout for a combobox), we say that the editor is fully engaged, and that the table isn’t allowed to swap it out until the user disengages it.

What this looks like in code:

public interface TwoStageTableCellEditor extends TableCellEditor
{
    public boolean isFullyEngaged();
}
 
public class ComboBoxEditorRenderer extends AbstractCellEditor implements TwoStageTableCellEditor, TableCellRenderer
{
    private JComboBox combobox;
    ...
    public Object getCellEditorValue() {
        return combobox.getSelectedItem();
    }
    public boolean isFullyEngaged() {
        return combobox.isPopupVisible();
    }
}

 

Part 3: Mouseover swapping

Here’s where it all comes together. Mouseover swapping is what your (subclass of) JTable does in order to keep track of which cell is being edited, where the cursor is, and whether to swap the editor from one cell to another. This is kind of boring, and only really makes sense in code, so here you go:

 

// In the constructor...
// listeners for two-stage editing
this.addMouseListener(twoStageEditingListener);
this.addMouseMotionListener(twoStageEditingListener);

 

// In the body of your JTable subclass...
private final FullMouseAdapter twoStageEditingListener = new FullMouseAdapter() {
    public void mouseMoved(MouseEvent e) {
        possiblySwitchEditors(e);
    }
    public void mouseEntered(MouseEvent e) {
        possiblySwitchEditors(e);
    }
    public void mouseExited(MouseEvent e) {
        possiblySwitchEditors(e);
    }
    public void mouseClicked(MouseEvent e) {
        possiblySwitchEditors(e);
    }
};
private void possiblySwitchEditors(MouseEvent e) {
    Point p = e.getPoint();
    if (p != null) {
        int row = rowAtPoint(p);
        int col = columnAtPoint(p);
        if (row != getEditingRow() || col != getEditingColumn()) {
            if (isEditing()) {
                TableCellEditor editor = getCellEditor();
                if (editor instanceof TwoStageTableCellEditor && !((TwoStageTableCellEditor)editor).isInStageTwo()) {
                    if (!editor.stopCellEditing()) {
                        editor.cancelCellEditing();
                    }
                }
            }

            if (!isEditing()) {
                if (row != -1 && isCellEditable(row, col)) {
                    editCellAt(row, col);
                }
            }
        }
    }
}

 

Conclusion

This solution works pretty well. There are a couple flaws (e.g. start editing a textfield and then mouseover a button—no feedback, because the text field is fully engaged), but overall it is much better than an unadorned JTable, and not too much of a burden on the developer. Be warned, though: it may wreak havoc on the focus system.

Extra credit: Is it possible to achieve a similar effect by forwarding MouseEvents through to the renderers/stamps?

分享到:
评论

相关推荐

    实现Swing的JTables和Excel间的复制和粘贴功能.docx

    标题中的“实现Swing的JTables和Excel间的复制和粘贴功能”指的是在Java Swing应用中,使用JTable组件与Microsoft Excel之间进行数据复制和粘贴的交互操作。描述部分未给出具体信息,但我们可以根据标题和标签推断,...

    实现Swing的JTables和Excel间的复制和粘贴功能.pdf

    【Swing的JTables与Excel间复制粘贴功能实现】 Swing的JTable组件是Java GUI编程中用于显示和编辑表格数据的重要工具,它在许多业务应用中扮演着电子表格的角色。然而,用户往往需要在JTable和Microsoft Excel之间...

    CSDN.rar_简繁体_股票 java

    实现 Swing 的 JTables 和 Excel 间的复制和粘贴功能 实 现JAVA 的 动 态 类 载 入 机 制 使用Java实现数据报通讯过程 使用Java制作多点发送程序 提高Java代码可重用性的三个措施 用 Java 保存位图文件 用JAVA...

    JPEG源码非常简单的源码

    接下来,"JTABLES.H"、"JTYPES.H"和"JGLOBALS.H"是头文件,它们可能包含了JPEG解码过程中所需的常量、数据类型定义和全局变量声明。"JTABLES.H"可能包含了JPEG的标准量化表和Huffman表定义,这些都是JPEG编码的关键...

    Swing下滚动条实现仿分页

    两个JTables可以放在同一个JScrollPane中,但是各自的可见性和布局需要进行精确的设置和同步。 文件“DynamicTb”很可能包含了实现这个功能的代码,包括但不限于以下部分: 1. 自定义的TableModel,它可能根据滚动...

    Jtable导出到excel

    使用这一 Java 技巧中提供的适配器类,只需一行代码即可添加在 JTables 和 Excel 间复制和粘贴信息的功能。请注意,由于未签名的 applet 不能使用系统剪贴板,此功能不适用于这些 Java 程序。 当今很多业务应用...

    100多个非常有用的java功能代码

    这里的代码可能包含创建窗口、添加控件、响应用户事件、实现复杂的布局设计,甚至涉及Swing的高级特性,如JTables、JTrees以及模型-视图-控制器(MVC)架构的应用。 在"有用的Java代码"这个文件名中,我们可以期待...

    University-Automation-System

    使用JTables和JLists实时从数据库中获取数据。 以原始格式(在本例中为PDF格式)获取存储在数据库中的文件。 在excel中创建的电子表格将导入MySql本地服务器,并在应用程序的JTable中获取。 使用GUI组件的集成...

    eclipse swing/SWT插件

    jigloo支持Swing JFrames、JSplitPanes、JTables等组件,同时也支持SWT的Composite、Shell、Table等元素。使用jigloo,开发者可以快速预览UI设计,进行实时调整,并自动生成对应的Java源代码。 在Eclipse中安装...

    Quarterback Java Classes Collection-开源

    提供了许多有用的 Java 内容:CSV 文件处理、线程交互、新的 Swing 数据模型,例如用于 JTables 中的地图列表、JTable 单元格大小调整类和用于网络应用程序的完整强大的客户端-服务器框架。

    XPTableXPTableXPTableXPTableXPTableXPTable

    因此,在现代开发环境中,开发者可能需要考虑其他替代方案,如JTables、Apache POI、JFreeTable等,它们提供了更现代的特性和持续的维护。 在提供的压缩包文件"aa2.xls"中,很可能是包含了使用XPTable创建的示例...

    如何在Java中从mysql“订单表”和“付款表”显示客户分类帐

    我正在创建简单的Inventory java应用程序,因此该如何显示java中MySQL表中的客户完成订单和付款。 我想在Java Jtables中显示客户分类帐。 我无法显示所需的表,因为它仅显示在一行中。 但是我想要的数据在...

    gui.zip_Java-GUI

    7. **Swing增强(JTables, JTrees, JLists)**: Swing提供了一些高级组件,如JTable用于显示和编辑表格数据,JTree用于展示树状结构,JList用于列出可选择的项。这些组件常用于数据展示和导航。 8. **国际化...

    JFreeChart1.0.9 lib

    JFreeChart 可以很好地与 JavaFX、Swing 等图形库集成,同时也可配合 JTables 和 JTrees 使用,实现数据可视化。在企业级应用中,它经常与 JDBC、Hibernate 等数据库访问技术结合,展示数据库查询结果。 **总结** ...

    jXyner - Java GUI Component Designer-开源

    这款工具特别适用于那些需要频繁使用诸如JTables、JMenus、JTrees、状态栏以及选项卡式窗格等组件的项目。通过jXyner,开发者可以直观地设计和布局这些组件,从而提升开发效率和代码质量。 **GUI组件设计**: 在...

Global site tag (gtag.js) - Google Analytics