- 浏览: 57980 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
zeyuphoenix:
问题14:
对于emp中同一部门低于自己工资至少3人的员工,列 ...
SQL面试题(十) -
zeyuphoenix:
问题13:
对于emp中低于自己工资至少5人的员工,列出其部门 ...
SQL面试题(十) -
zeyuphoenix:
问题12:
对于emp中工资高于本部门平均水平,人数多与1人的 ...
SQL面试题(十) -
zeyuphoenix:
问题11:
对于emp,列出各个部门中平均工资高于本部门平均水 ...
SQL面试题(十) -
zeyuphoenix:
问题10:
对于工资高于本部门平均水平的员工,列出部门号,姓名 ...
SQL面试题(十)
表格(单元格放置组件)
对于JTable单元格的渲染主要是通过两个接口来实现的,一个是TableCellRenderer另一个是TableCellEditor,JTable默认是用的是DefaultCellRenderer和DefaultCellEditor,这两个都是在类似JTextfield的一个JComponent的基础上来实现的,如果我们需要在JTable的单元格内放置特殊的控件或者绘制出特殊的效果,就要实现TableCellRenderer和TableCellEditor接口,在其上绘制出自己需要的样式,再通过JTable的setCellRenderer和setCellEditor方法设置新的外观呈现.
首先我们先看看TableCellRenderer和TableCellEditor接口的区别, TableCellRenderer接口就是用来绘制和展示当前单元格的内容的,可以用文字、图片、组件、甚至Java2D来绘制效果; TableCellEditor主要是用来当用户点击具体的某个单元格进行编辑的时候来展现的,除了绘制之外,在点击时还会有更加复杂的效果出现.
先看Sun官方给的简单的例子,首先是TableCellRenderer的
运行图示如下:
<!--[if gte vml 1]> <![endif]-->
我们只需要实现TableCellRenderer就可以了,
/**
* This interface defines the method required by any object * that would like to be a renderer for cells in a JTable
* in there, I put button in it.
*/
publicclass MyButtonRenderer extends JButton implements TableCellRenderer {
实现接口的方法:
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
然后设置属性:
setForeground(table.getSelectionForeground());
setBackground(table.getSelectionBackground());
setText((value == null) ? "" : value.toString());
使用也很简单,假如我们希望第一列是JButton,则
table.getColumnModel().getColumn(0).setCellRenderer(new MyButtonRenderer());
接着是TableCellEditor的实现,还是Sun给的例子:
运行图示如下
<!--[if gte vml 1]> <![endif]-->
Sun公司在DefaultCellEditor类里提供了JComboBox参数的构造函数,直接使用就可以了.
//Set up the editor for the sport cells.
JComboBox comboBox = new JComboBox();
comboBox.addItem("Snowboarding");
comboBox.addItem("Rowing");
comboBox.addItem("Knitting");
comboBox.addItem("Speed reading");
comboBox.addItem("Pool");
comboBox.addItem("None of the above");
table.getColumnModel().getColumn(2).setCellEditor(new DefaultCellEditor(comboBox));
在这里看来,这个例子就可以了,但是它还是有问题的,什么问题呢,看下截图:
<!--[if gte vml 1]> <![endif]-->
当JTable的单元格比较短时,下拉框显示的内容会出现不全的情况,需要修改一下:
问题在哪儿呢,在于JCombobox的UI,需要设置一下JCombobox的下拉菜单的宽度,具体实现在JCombobox那篇文章里已经实现了,这里我们直接使用,
String[] str = new String[] { "Snowboarding", "Rowing", "Knitting", "Speed reading", "None of the above" };
MyComboBox combo = new MyComboBox(str);
Dimension d = combo.getPreferredSize();
combo.setPopupWidth(d.width);
table.getColumnModel().getColumn(2).setCellEditor(newDefaultCellEditor(combo));
运行如下图:
<!--[if gte vml 1]> <![endif]-->
到此为止,Renderer和Editor的简单实用就完成了,这些例子都是Sun官方给的,我大概
修改了一下,其实还有问题.
让我们回头看第一个例子:
当鼠标在JButton按下时,如下图:
<!--[if gte vml 1]> <![endif]-->
JButton的效果消失了,因为Renderer只是处理表示的样式,对于可编辑的单元格就不可
以了,编辑状态下呈现的还是默认的JTextField组件,所以对于可编辑的单元格,我们需
要设置它的Editor.
我们需要写一个自己的Editor,为了简单就不实现TableCellEditor接口了,只需要继
承DefaultCellEditor.
/**
* The default editor for table and tree cells.
*/
publicclass MyButtonCellEditor extends DefaultCellEditor {
定义两个属性:
//editor show
private JButton button = null;
//text
private String label = null;
分别代表编辑状态下显示的组件和显示的值.
然后重写getTableCellEditorComponent方法,在编辑状态表示我们自己的组件.
/**
* Sets an initial <code>value</code> for the editor.
*/
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
设置组件样式:
button.setForeground(table.getSelectionForeground());
button.setBackground(table.getSelectionBackground());
label = (value == null) ? "" : value.toString();
button.setText(label);
returnbutton;
然后还需要重写getCellEditorValue方法,返回编辑完成后的值,
@Override
public Object getCellEditorValue() {
returnnew String(label);
}
使用和以前设置Renderer和Editor一样,设置2个就可以了.
table.getColumnModel().getColumn(0).setCellRenderer(new MyButtonRenderer());
table.getColumnModel().getColumn(0).setCellEditor(new MyButtonCellEditor());
最后按下效果正常了:
<!--[if gte vml 1]> <![endif]-->
到此为止,简单的Renderer和Editor就差不多了,但是我们在JTable放置的都是基本的Swing组件,可不可以放置复杂的呢,当然是可以的,下面我们放置一个选择组:
如下图:
<!--[if gte vml 1]> <![endif]-->
它也需要实现自己的Renderer和Editor,我们可以把这个显示选择按钮组的单元格看做一个组件,当然首先就是把这个组件作出来:
/**
* create the pane that some radio pane in it.
*/
publicclass MyRadioPanel extends JPanel {
它只有一个属性,根据给定数组长度构建Radio数组,
/** radio button group. */
private JRadioButton[] buttons = null;
再看它的构造函数:
public MyRadioPanel(String[] strButtonText) {
我们在这里构造JRadioButton:
buttons[i] = new JRadioButton(strButtonText[i]);
加入到面板:
add(buttons[i]);
再添加取得和设置JRadioButton选择的方法:
/**
* get button groups.
*/
public JRadioButton[] getButtons() {
returnbuttons;
}
/**
* set which index select.
*/
publicvoid setSelectedIndex(int index) {
for (int i = 0; i < buttons.length; i++) {
buttons[i].setSelected(i == index);
}
}
然后就是写Renderer了,我们继承MyRadioPanel并且实现TableCellRenderer接口就可以了.
publicclass MyRadioCellRenderer extends MyRadioPanel implements
TableCellRenderer {
构造函数直接使用MyRadioCellRenderer的
public MyRadioCellRenderer(String[] strButtonTexts) {
super(strButtonTexts);
}
然后是实现接口的getTableCellRendererComponent方法:
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
if (value instanceof Integer) {
setSelectedIndex(((Integer) value).intValue());
}
returnthis;
}
最后就是Editor了,
/**
* create cell editor that radio in it.
*/
publicclass MyRadioCellEditor extends DefaultCellEditor implements
ItemListener {
在它的构造函数里我们为JRadioButton添加监听:
JRadioButton[] buttons = panel.getButtons();
buttons[i].addItemListener(this);
在监听处理中我们停止编辑,
@Override
publicvoid itemStateChanged(ItemEvent e) {
super.fireEditingStopped();
}
然后我们需要覆盖DefaultCellEditor的getTableCellEditorComponent,返回我们需要显示的MyRadioPanel.
@Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
if (value instanceof Integer) {
panel.setSelectedIndex(((Integer) value).intValue());
}
returnpanel;
}
最后我们重写getCellEditorValue,返回编辑完成后我们显示的值:
@Override
public Object getCellEditorValue() {
returnnew Integer(panel.getSelectedIndex());
}
使用也很简单,和前面设置Renderer和Editor一样:
String[] answer = { "A", "B", "C" };
table.getColumnModel().getColumn(1).setCellRenderer(
new MyRadioCellRenderer(answer));
table.getColumnModel().getColumn(1).setCellEditor(
new MyRadioCellEditor(newMyRadioCellRenderer(answer)));
接下来我们看一个比较综合的例子,首先还是从画面开始:
<!--[if gte vml 1]> <![endif]-->
先从简单的开始做起,首先使JTable的第三列显示成进度条,这个和前面的设置Renderer一样,实现TableCellRenderer就可以了.
/**
* This interface defines the method required by any object * that would like to be a renderer for cells in a JTable
* in there, I put progress bar in it.
*/
publicclass MyProgressCellRenderer extends JProgressBar implements
TableCellRenderer {
它提供一个属性放置各个颜色区间需要设置的颜色:
/** the progress bar's color. */
private Hashtable<Integer, Color> limitColors = null;
在构造函数里我们设置显示的最大和最小值:
/**
* Creates a progress bar using the specified orientation, * minimum, and maximum.
*/
public MyProgressCellRenderer(int min, int max) {
super(JProgressBar.HORIZONTAL, min, max);
setBorderPainted(false);
}
然后实现TableCellRenderer接口的getTableCellRendererComponent方法,设置显示组件和颜色:
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
先根据单元格的值取得颜色:
Color color = getColor(n);
if (color != null) {
setForeground(color);
}
同时设置JProcessBar的值并返回它.
setValue(n);
returnthis;
最后还提供一个设置颜色的方法:
publicvoid setLimits(Hashtable<Integer, Color> limitColors) {
它把传入的颜色表按照大小先排序,然后设置好.
这样一个简单的显示进度条的TabelCellRenderer就完成了.然后通过setRenderer来使用它.
//create renderer.
MyProgressCellRenderer renderer = new MyProgressCellRenderer(
MyProgressTableModel.MIN, MyProgressTableModel.MAX);
renderer.setStringPainted(true);
renderer.setBackground(table.getBackground());
// set limit value and fill color
Hashtable<Integer, Color> limitColors = new Hashtable<Integer, Color>();
limitColors.put(new Integer(0), Color.green);
limitColors.put(new Integer(20), Color.GRAY);
limitColors.put(new Integer(40), Color.blue);
limitColors.put(new Integer(60), Color.yellow);
limitColors.put(new Integer(80), Color.red);
renderer.setLimits(limitColors);
//set renderer table.getColumnModel().getColumn(2).setCellRenderer(renderer);
然后我们需要考虑的是这个Renderer的值无法变化,只能根据初始化的时候的数值显示,这明显是不行的,所以我们考虑给JTable加上改变,改变第二列的数字,第三列进度条随之改变,如图示:
<!--[if gte vml 1]> <![endif]-->
<!--[if gte vml 1]> <![endif]-->
这时我们需要修改我们的TableModel,默认的已经无法满足我们的需要了,我们需要自己写一个:
publicclass MyProgressTableModel extends DefaultTableModel {
在它的构造函数里面,我们增加一个监听:
this.addTableModelListener(new TableModelListener() {
@Override
publicvoid tableChanged(TableModelEvent e) {
当引起TableModel改变的事件是UPDATE时并且是第二列时候:
//when table action is update.
if (e.getType() == TableModelEvent.UPDATE) {
int col = e.getColumn();
if (col == 1) {
我们取得新设立的value,赋予第三列:
//get the new set value.
Integer value = (Integer) model.getValueAt(row, col);
model.setValueAt(checkMinMax(value), row, ++col);
重写isCellEditable方法,设置可编辑的列:
@Override
publicboolean isCellEditable(int row, int col) {
switch (col) {
case 1:
returntrue;
default:
returnfalse;
}
}
重写setValueAt方法,设置可赋予的值:
@Override
publicvoid setValueAt(Object obj, int row, int col) {
这样一个我们需要的TableModel就完成了,修改第二列的值,第三列进度条也随之改变,使用也很简单:
// set the table model.
table.setModel(dm);
就可以了.
到这里,这个进度条JTable基本完成了,但是在实际运用中可能会出现这样的问题:
<!--[if gte vml 1]> <![endif]-->
我们编辑JTable的时候给它的单元格赋予了一个不正常的值,导致显示不正常,但是却无法返回旧有的状态,这样我们就需要再次改进它:
当输入错误的值时:
<!--[if gte vml 1]> <![endif]-->
然后可以返回以前的状态:
<!--[if gte vml 1]> <![endif]-->
这时候我们需要设置的是第二列的Editor,使它编辑状态时可以验证我们的输入,并触发:
/**
* Implements a cell editor that uses a formatted text
* field to edit Integer values.
*/
publicclass MyIntegerEditor extends DefaultCellEditor {
它有一个参数,用来处理编辑值的:
//show component when cell edit
private JFormattedTextField ftf;
然后重写DefaultCellEditor的getTableCellEditorComponent方法,返回我们定义的JFormattedTextField.
JFormattedTextField ftf = (JFormattedTextField) super
.getTableCellEditorComponent(table, value, isSelected, row, column); ftf.setValue(value);
return ftf;
重写getCellEditorValue方法,保证我们返回值正确:
getCellEditorValue
@Override
public Object getCellEditorValue() {
取得编辑完成的值:
Object o = ftf.getValue();
判断然后返回.
然后重写stopCellEditing方法,判断编辑的值是否正确,不正确的情况下提示用户,询问用户是返回还是重新设置.
// Override to check whether the edit is valid,
// setting the value if it is and complaining if it isn't.
@Override
publicboolean stopCellEditing() {
JFormattedTextField ftf = (JFormattedTextField) getComponent();
if (ftf.isEditValid()) {
try {
ftf.commitEdit();
} catch (java.text.ParseException exc) {
}
} else { // text is invalid
if (!userSaysRevert()) {
// user wants to edit don't let the editor go away
returnfalse;
}
}
returnsuper.stopCellEditing();
}
到目前为止,这个类基本完成了,但是只有焦点离开单元格才触发验证事件,比较不和逻辑,我们加入一个键盘监听,回车也可以触发.
ftf.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "check");
ftf.getActionMap().put("check", new AbstractAction() {
@Override
publicvoid actionPerformed(ActionEvent e) {
// The text is invalid.
if (!ftf.isEditValid()) {
if (userSaysRevert()) {
// reverted inform the editor
ftf.postActionEvent();
}
} else
try {
// The text is valid, so use it.
ftf.commitEdit();
// stop editing
ftf.postActionEvent();
} catch (java.text.ParseException exc) {
}
}
然后就可以使用它了,和前面设置一个Editor一样:
table.getColumnModel().getColumn(1).setCellEditor(
new MyIntegerEditor(MyProgressTableModel.MIN,
MyProgressTableModel.MAX));
到目前为止,JTable的Renderer和Editor就完成了,实际使用中也就这样了,但是还有一种特殊情况需要说一下,虽然这样变态需求一般现实中很难碰到.上面我们所有的例子都是对某一个列来说的,但是如果有人需要第一行显示正常单元格,第二行显示JCombobox,第三行显示JButton怎么处理呢.其实也相差不大,自己写个Renderer和Editor,里面实现一个Renderer和Editor的序列,依次展现就可以了.
先看图:
<!--[if gte vml 1]> <![endif]-->
<!--[if gte vml 1]> <![endif]-->
首先要做的写一个类实现TableCellEditor接口,
publicclass MyCellEditor implements TableCellEditor {
它有两个属性:
/** save all editor to it. */
private Hashtable<Integer, TableCellEditor> editors = null;
/** each cell editor. */
private TableCellEditor editor = null;
分别存储了此Editor上所有的Editor队列和当前需要使用的Editor.
再看它的构造函数,
/**
* Constructs a EachRowEditor. create default editor
*/
public MyCellEditor(JTable table) {
它初始化了Editor队列
editors = new Hashtable<Integer, TableCellEditor>();
然后实现TableCellEditor接口的getTableCellEditorComponent方法
@Override
public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
根据行号取得当前单元格的Editor:
editor = (TableCellEditor) editors.get(new Integer(row));
没有的话,使用默认的:
if (editor == null) {
editor = new DefaultCellEditor(new JTextField());
}
然后返回当前Renderer下的单元格:
returneditor.getTableCellEditorComponent(table, value, isSelected, row, column);
接着实现stopCellEditing、cancelCellEditing、addCellEditorListener、
removeCellEditorListener、isCellEditable、shouldSelectCell方法,
在这些方法里取得当前那个单元格被编辑,取得正编辑的单元格的Editor,再调用Editor
同样的方法就可以了.
if (e == null) {
row = table.getSelectionModel().getAnchorSelectionIndex();
} else {
row = table.rowAtPoint(e.getPoint());
}
editor = (TableCellEditor) editors.get(new Integer(row));
if (editor == null) {
editor = new DefaultCellEditor(new JTextField());
}
最后提供一个设置单元格Editor的方法,
/**
* add cell editor to it.
*/
publicvoid setEditorAt(int row, TableCellEditor editor) {
editors.put(new Integer(row), editor);
}
这样可以实现单元格级别的Editor就实现了,同样的Renderer也一样,同样实现TableCellRenderer接口和它里面的方法就可以了,同样用对列存储每个单元格的Renderer,这里就不写了.
最后是使用:
先创建JTable需要用到的Editor,再创建单一Cell用到的Editor,
//create all cell editor
MyCellEditor rowEditor = new MyCellEditor(table);
//create cell editors
MyButtonCellEditor buttonEditor = new MyButtonCellEditor();
DefaultCellEditor comboBoxEditor = new
DefaultCellEditor(comboBox);
然后为需要的单元格设置Editor,
//put cell editor in all cell editors
rowEditor.setEditorAt(0, comboBoxEditor);
rowEditor.setEditorAt(1, comboBoxEditor);
rowEditor.setEditorAt(2, buttonEditor);
rowEditor.setEditorAt(3, buttonEditor);
最后设置JTable的Editor,
//set table editor
table.getColumnModel().getColumn(0).setCellEditor(rowEditor);
同样的,Renderer和Editor完全一样.这样一个可以为具体单元格设置Renderer和Editor的例子就完成了.
到此为止,关于在JTable的单元格放置组件的例子就全部完成了,总结起来也很简单,就是设置Renderer和Editor,至于更复杂的效果,比如合并单元格之类的,就需要重写JTable的TableUI了,这就在以后说了
相关推荐
- 合并后的单元格无法再放置新的子控件,因为它仅作为一个大的单元格存在。 - 重新调整表格的行或列数量可能会改变已设置的合并状态,因此在进行这类操作时要谨慎处理。 - 通过`itemAt`或`item`方法访问合并单元格时...
该表格组件的HTML结构包括一个用于输入搜索条件的表单、一个用于显示表格的div以及一个放置分页控件的div。`#search`元素是搜索按钮,它的祖先级中需要有class为`form`的节点,以便使用`query`库来处理搜索参数。...
"Ext的用户扩展控件-----可以在表格的单元格上弹出提示层信息"是一个专门为EXT的Grid组件设计的功能增强插件,它使得用户在鼠标悬停于表格的特定单元格时,能够显示更详细的信息提示,极大地提升了数据展示的交互性...
同时,为每个表格单元格添加拖放事件监听器。 2. **数据结构** 设计一个合适的数据结构来表示树形表格是非常关键的。每个节点应该包含自身的属性(如ID、值等),以及子节点数组。对于拖拽功能,可能需要额外的...
在.NET框架中,`DataGridView`控件是一种常用的用于显示和编辑数据表格的组件。它提供了丰富的功能,包括列类型自定义,使得我们可以根据需求在单元格中插入各种类型的控件,比如时间选择器。本教程将详细介绍如何在...
标题“listview实现表格效果,带表格线”表明我们要讨论的是如何利用ListView来模拟表格布局,并添加分割线以清晰地展示每个单元格的边界。 首先,我们要理解ListView的基本结构。ListView由多个ListView项...
在一些特定的业务场景中,例如展示省市区等层级数据,我们常常需要将同一省份、城市、区域下的数据合并展示在同一个表格单元格中,以提高数据的可读性和整洁性。为此,组件提供了一个属性,允许开发者自定义合并...
这样的组件可以使用户在表格中直接编辑数据,而无需打开新的窗口或对话框,极大地提高了交互性和用户体验。 Swing的扩展组件包括但不限于以下几种: 1. **JTree**:展示层次结构数据的组件,用户可以展开和折叠...
Toolbar组件提供了一种放置按钮、菜单和其他工具的地方。它可以被配置为固定位置,以便在页面滚动时仍然可见。 #### 三、表单组件详解 Ext的表单组件为创建复杂的数据输入界面提供了强大的支持。 ##### 1. **...
`JToolBar`是一种专门用于放置工具按钮、快捷键或其他小部件的组件。在AsWing中,它被广泛用于创建工具栏。工具栏通常位于应用的顶部或侧边,提供对常用功能的快速访问。通过组合不同的按钮和其他元素,开发者可以...
2. TableRow:每个TableRow代表表格的一行,其中可以包含多个View,如TextView或ImageView,这些View代表表格的单元格。例如: ```xml android:layout_width="wrap_content" android:layout_height="wrap_...
1. **单元格内嵌入控件**:在每个表格单元格内放置一个选项框,这样用户可以直接在表格中勾选或取消勾选,而无需打开单独的设置窗口。这需要开发者对表格控件有深入理解,知道如何自定义单元格模板,以容纳额外的...
在Web前端开发中,表格元素是构建数据展示和交互的核心组件之一。本练习主要关注HTML中的`<table>`元素及其相关标记,如`<tr>`, `<th>`, `<td>`等,它们共同构建了一个标准的表格结构。下面将详细讨论这些元素的使用...
在本实例中,我们使用了表格的模板引擎(templet)功能,这是一种非常便捷的方式,可以在表格单元格中插入自定义内容,比如按钮、图片等。通过定义特定字段的templet函数,可以返回HTML结构,插入到表格单元格中。 ...
首先,`JTable`默认的渲染器和编辑器无法直接支持在单元格内放置多个组件,如按钮。因此,我们需要创建一个自定义的`TableCellRenderer`来实现这个功能。一个简单的实现方式是创建一个`JPanel`,并在其中添加多个`...
而Grid组件则用于展示二维表格数据,支持排序、筛选和编辑等功能。拖拽功能允许用户通过鼠标操作将数据从一个位置移动到另一个位置,增强了用户体验并简化了数据操作。 实现拖拽功能,我们需要使用ExtJS提供的DD...
首先,让我们来讨论如何实现表格单元格的拖拽功能。这通常需要结合HTML5的`dragstart`、`drag`、`dragover`和`drop`事件。在`dragstart`事件中,我们需要标记被拖动的单元格,并存储其原始位置信息。`drag`事件用于...
`TableLayout`可以在其上方直接放置单独的控件,这些控件不会被包含在表格中。 2. **TableLayout的属性**: - `android:collapseColumns`:此属性用于隐藏指定的列。列号从0开始计数,例如`android:...
在VB6.0中集成这样的表格控件,首先需要将其导入到工程中,这可能通过“组件”菜单的“添加部件”选项完成。接着,可以在设计界面中放置控件并调整大小。通过代码设置控件属性,如数据源、列宽等,实现数据的显示和...