前几篇文章介绍了JTable的基本用法,本文实现一个简单的JTable,算是前文的一个总结,并造福供拷贝党们。

Swing-JTable用法-入门

Swing-JTable的渲染器与编辑器使用demo

Swing-JTable检测单元格数据变更事件

一、主要功能

1.数据的增删改;

2.渲染器:“Vegetarian”列存放布尔值,以checkBox形式显示;“Sport”列存放字符串,以comboBox形式显示;

3.编辑器:“Name”的编辑器实现一个按钮,按下时弹出对话框;

4.ToolTip:各列和各单元格均具有自己的ToolTip,且单元格ToolTip与其值相关;

5.事件:检测单元格值的变更,并输出旧值、新值和单元格坐标。

二、程序设计

本程序根据功能可分为6部分,以6个类来实现,分别是:

Gui.java:实现GUI,成员有:1个JTable,2个按钮;

MyJTable.java:继承自JTable,重载2个方法:getToolTipText和createDefaultTableHeader,分别实现单元格和表头的toolTip;

MyTableModel.java:继承自DefaultTableModel,重载1个方法:getColumnClass,实现布尔值的checkBox形式显示。表格的基本功能均已被DefaultTableModel类实现,直接使用就好。如果你还需要对单元格可访问性等细节进行精确控制,可以重载相关方法。

TableCellListener.java:实现对单元格数据变更的检测。这是通过表格的addPropertyChangeListener方法实现的,而不是基于tableModel的addTableModelListener方法。后者的不足之处在前文中已经分析。

ButtonEditor.java:实现一个基于按钮的编辑器,被按下时弹出对话框;

ButtonRenderer.java:实现一个渲染器,可定制单元格的配色。

三、程序代码

Gui.java

package DefaultTableModelDemo;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn;
import JButtonTableExample.ButtonEditor;
import JButtonTableExample.ButtonRenderer; public class Gui extends JPanel { private Object[] tmpRow = {"tmpName", "tmpDescription"};
private MyJTable table;
private JButton addBtn;
private JButton delBtn;
private MyTableModel model ; public Gui() {
table = new MyJTable();
table.setPreferredScrollableViewportSize(new Dimension(500, 300));
table.setFillsViewportHeight(true); //Create the scroll pane and add the table to it.
JScrollPane scrollPane = new JScrollPane(table);
//scrollPane.setPreferredSize(new Dimension(500, 600));
//scrollPane.set
//Add the scroll pane to this panel.
add(scrollPane);
//set tableModel and data
model = new MyTableModel();
String[] columnNames = {"Name",
"Description",
"Sport",
"# of Years",
"Vegetarian"};
Object[][] data = {
{"Kathy", "Smith",
"Snowboarding", new Integer(5), new Boolean(false)},
{"John", "Doe",
"Rowing", new Integer(3), new Boolean(true)},
{"Sue", "Black",
"Knitting", new Integer(2), new Boolean(false)},
{"Jane", "White",
"Speed reading", new Integer(20), new Boolean(true)},
{"Joe", "Brown",
"Pool", new Integer(10), new Boolean(false)}
};
model.setDataVector(data, columnNames);
table.setModel(model);
//添加渲染器
table.getColumn("Name").setCellRenderer(new ButtonRenderer());
//添加编辑器
table.getColumn("Name").setCellEditor( new ButtonEditor());
//添加按钮
addBtn = new JButton("增加");
addBtn.addActionListener(new ActionListener() { @Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
model.addRow(tmpRow);
}
}); delBtn = new JButton("删除");
delBtn.addActionListener(new ActionListener() { @Override
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
int rowIndex = table.getSelectedRow();
if(rowIndex != -1)
model.removeRow(rowIndex);
}
}); add(addBtn);
add(delBtn); addDataChangeListener(); //设置列
setSportsColumn();
} private void setSportsColumn(){
String [] itmes = {"Snowboarding", "Rowing", "Knitting", "Speed reading", "Pool"};
JComboBox<String> comboBox = new JComboBox<String>(itmes);
DefaultTableCellRenderer renderer =
new DefaultTableCellRenderer();
renderer.setToolTipText("Click for combo box");
setColumn("Sport", comboBox, renderer);
TableColumn col = table.getColumn("Sport");
//setToolTipText("favorit sport is " + );
} public void setColumn(String colName, Object editor, Object renderer) {
int index = table.getColumnModel().getColumnIndex(colName);
TableColumn modeColumn = table.getColumnModel().getColumn(index);
if (editor instanceof JComponent) {
setEditor(modeColumn, (JComponent)editor);
}
else if (editor instanceof DefaultCellEditor) {
modeColumn.setCellEditor((DefaultCellEditor)editor);
} if (renderer instanceof DefaultTableCellRenderer) {
modeColumn.setCellRenderer((DefaultTableCellRenderer)renderer);
}
else if (renderer instanceof ButtonRenderer) {
modeColumn.setCellRenderer((ButtonRenderer)renderer);
}
} protected void setEditor(TableColumn column, JComponent component){
if(component instanceof JTextField )
column.setCellEditor(new DefaultCellEditor((JTextField) component));
else if(component instanceof JComboBox )
column.setCellEditor(new DefaultCellEditor((JComboBox<String>) component));
else if(component instanceof JCheckBox )
column.setCellEditor(new DefaultCellEditor((JCheckBox) component));
} private void addDataChangeListener(){
//检测单元格数据变更
Action action = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
TableCellListener tcl = (TableCellListener)e.getSource();
int row = tcl.getRow();
int col = tcl.getColumn();
Object oldValue = tcl.getOldValue();
//if(oldValue == null)
//oldValue = "";
Object newValue = tcl.getNewValue();
//if(newValue == null)
//newValue = "";
System.out.printf("cell changed at [%d,%d] : %s -> %s%n",row, col, oldValue, newValue);
}
};
@SuppressWarnings("unused")
TableCellListener tcl1 = new TableCellListener(table, action);
System.out.printf("cell changed%n");
} private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("Gui");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Create and set up the content pane.
Gui newContentPane = new Gui();
newContentPane.setOpaque(true); //content panes must be opaque
frame.setContentPane(newContentPane); //Display the window.
frame.pack();
frame.setVisible(true);
} public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}

MyTableModel.java

package DefaultTableModelDemo;

import javax.swing.table.DefaultTableModel;

public class MyTableModel extends DefaultTableModel{

    @Override
public Class<?> getColumnClass(int columnIndex) {
if (columnIndex == 4)
return Boolean.class;
return super.getColumnClass(columnIndex);
}
}

MyJTable.java

package DefaultTableModelDemo;

import java.awt.event.MouseEvent;

import javax.swing.JTable;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableModel; public class MyJTable extends JTable{ protected String[] columnToolTips = {null,
null,
"The person's favorite sport to participate in is : ",
"The number of years the person has played the sportis : ",
"If checked, the person eats no meat"}; //Implement table cell tool tips.
public String getToolTipText(MouseEvent e) {
String tip = null;
java.awt.Point p = e.getPoint();
int rowIndex = rowAtPoint(p);
int colIndex = columnAtPoint(p);
int realColumnIndex = convertColumnIndexToModel(colIndex);
if(rowIndex < 0)
{
//System.out.printf("abnormal rowIndex: %n", rowIndex);
return null;
} if (realColumnIndex == 2) { //Sport column
tip = columnToolTips[2]
+ getValueAt(rowIndex, colIndex);
}
else if (realColumnIndex == 3) { //Years column
tip = columnToolTips[3] + getValueAt(rowIndex, colIndex); }else if (realColumnIndex == 4) { //Veggie column
TableModel model = getModel();
String firstName = (String)model.getValueAt(rowIndex,0);
String lastName = (String)model.getValueAt(rowIndex,1);
Boolean veggie = (Boolean)model.getValueAt(rowIndex,4);
if (Boolean.TRUE.equals(veggie)) {
tip = firstName + " " + lastName
+ " is a vegetarian";
} else {
tip = firstName + " " + lastName
+ " is not a vegetarian";
}
} else {
//You can omit this part if you know you don't
//have any renderers that supply their own tool
//tips.
tip = super.getToolTipText(e);
}
return tip;
} //Implement table header tool tips.
protected JTableHeader createDefaultTableHeader() {
return new JTableHeader(columnModel) {
public String getToolTipText(MouseEvent e) {
String tip = null;
java.awt.Point p = e.getPoint();
int index = columnModel.getColumnIndexAtX(p.x);
int realIndex =
columnModel.getColumn(index).getModelIndex();
return columnToolTips[realIndex];
}
};
} }

TableCellListener.java

package DefaultTableModelDemo;
import java.awt.event.*;
import javax.swing.*;
import java.beans.*; /*
* This class listens for changes made to the data in the table via the
* TableCellEditor. When editing is started, the value of the cell is saved
* When editing is stopped the new value is saved. When the oold and new
* values are different, then the provided Action is invoked.
*
* The source of the Action is a TableCellListener instance.
*/
public class TableCellListener implements PropertyChangeListener, Runnable
{
private JTable table;
private Action action; private int row;
private int column;
private Object oldValue;
private Object newValue; /**
* Create a TableCellListener.
*
* @param table the table to be monitored for data changes
* @param action the Action to invoke when cell data is changed
*/ public TableCellListener(JTable table, Action action)
{
this.table = table;
this.action = action;
this.table.addPropertyChangeListener( this );
} /**
* Create a TableCellListener with a copy of all the data relevant to
* the change of data for a given cell.
*
* @param row the row of the changed cell
* @param column the column of the changed cell
* @param oldValue the old data of the changed cell
* @param newValue the new data of the changed cell
*/
private TableCellListener(JTable table, int row, int column, Object oldValue, Object newValue)
{
this.table = table;
this.row = row;
this.column = column;
this.oldValue = oldValue;
this.newValue = newValue;
} /**
* Get the column that was last edited
*
* @return the column that was edited
*/
public int getColumn()
{
return column;
} /**
* Get the new value in the cell
*
* @return the new value in the cell
*/
public Object getNewValue()
{
return newValue;
} /**
* Get the old value of the cell
*
* @return the old value of the cell
*/
public Object getOldValue()
{
return oldValue;
} /**
* Get the row that was last edited
*
* @return the row that was edited
*/
public int getRow()
{
return row;
} /**
* Get the table of the cell that was changed
*
* @return the table of the cell that was changed
*/
public JTable getTable()
{
return table;
}
//
// Implement the PropertyChangeListener interface
//
@Override
public void propertyChange(PropertyChangeEvent e)
{
// A cell has started/stopped editing if ("tableCellEditor".equals(e.getPropertyName()))
{
if (table.isEditing()){
//System.out.printf("tableCellEditor is editing..%n");
processEditingStarted();
}
else{
//System.out.printf("tableCellEditor editing stopped..%n");
processEditingStopped();
} }
} /*
* Save information of the cell about to be edited
*/
private void processEditingStarted()
{
// The invokeLater is necessary because the editing row and editing
// column of the table have not been set when the "tableCellEditor"
// PropertyChangeEvent is fired.
// This results in the "run" method being invoked SwingUtilities.invokeLater( this );
}
/*
* See above.
*/
@Override
public void run()
{
row = table.convertRowIndexToModel( table.getEditingRow() );
column = table.convertColumnIndexToModel( table.getEditingColumn() );
oldValue = table.getModel().getValueAt(row, column);
//这里应对oldValue为null的情况做处理,否则将导致原值与新值均为空时仍被视为值改变
if(oldValue == null)
oldValue = "";
newValue = null;
} /*
* Update the Cell history when necessary
*/
private void processEditingStopped()
{
newValue = table.getModel().getValueAt(row, column);
//这里应对newValue为null的情况做处理,否则后面会抛出异常
if(newValue == null)
newValue = "";
// The data has changed, invoke the supplied Action
if (! newValue.equals(oldValue))
{
// Make a copy of the data in case another cell starts editing
// while processing this change TableCellListener tcl = new TableCellListener(
getTable(), getRow(), getColumn(), getOldValue(), getNewValue()); ActionEvent event = new ActionEvent(
tcl,
ActionEvent.ACTION_PERFORMED,
"");
action.actionPerformed(event);
}
}
}

ButtonEditor.java

package JButtonTableExample;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JOptionPane;
import javax.swing.JTable; public class ButtonEditor extends DefaultCellEditor {
protected JButton button;//represent the cellEditorComponent
private String cellValue;//保存cellEditorValue public ButtonEditor() {
super(new JCheckBox());
button = new JButton();
button.setOpaque(true);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(button, cellValue + ": Ouch!");
//刷新渲染器
fireEditingStopped();
}
});
} public JComponent getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
//value 源于单元格数值
cellValue = (value == null) ? "" : value.toString();
return button;
} public Object getCellEditorValue() {
return new String(cellValue);
}
}

ButtonRenderer.java

package JButtonTableExample;

import java.awt.Color;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer; public class ButtonRenderer extends JButton implements TableCellRenderer { public JComponent getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
//value 源于editor
String text = (value == null) ? "" : value.toString();
//按钮文字
setText(text);
//单元格提示
setToolTipText(text);
//背景色
setBackground(Color.BLACK);
//前景色
setForeground(Color.green);
return this;
}
}

运行效果如下:

JTable用法-实例的更多相关文章

  1. php中的curl使用入门教程和常见用法实例

    摘要: [目录] php中的curl使用入门教程和常见用法实例 一.curl的优势 二.curl的简单使用步骤 三.错误处理 四.获取curl请求的具体信息 五.使用curl发送post请求 六.文件 ...

  2. 上传文件及$_FILES的用法实例

    Session变量($_SESSION):�php的SESSION函数产生的数据,都以超全局变量的方式,存放在$_SESSION变量中.1.Session简介SESSION也称为会话期,其是存储在服务 ...

  3. C++语言中cin cin.getline cin.get getline gets getchar 的用法实例

    #include <iostream> #include <string> using namespace std; //关于cin cin.getline cin.get g ...

  4. Union all的用法实例sql

    ---Union all的用法实例sqlSELECT TOP (100) PERCENT ID, bid_user_id, UserName, amount, createtime, borrowTy ...

  5. 【转】javascript入门系列演示·三种弹出对话框的用法实例

    对话框有三种 1:只是提醒,不能对脚本产生任何改变: 2:一般用于确认,返回 true 或者 false ,所以可以轻松用于 if...else...判断 3: 一个带输入的对话框,可以返回用户填入的 ...

  6. php strpos 用法实例教程

    定义和用法该strpos ( )函数返回的立场,首次出现了一系列内部其他字串. 如果字符串是没有发现,此功能返回FALSE . 语法 strpos(string,find,start) Paramet ...

  7. 【JSP】三种弹出对话框的用法实例

    对话框有三种 1:只是提醒,不能对脚本产生任何改变: 2:一般用于确认,返回 true 或者 false ,所以可以轻松用于 if...else...判断 3: 一个带输入的对话框,可以返回用户填入的 ...

  8. python多线程threading.Lock锁用法实例

    本文实例讲述了python多线程threading.Lock锁的用法实例,分享给大家供大家参考.具体分析如下: python的锁可以独立提取出来 mutex = threading.Lock() #锁 ...

  9. jQuery中on()方法用法实例详解

    这篇文章主要介绍了jQuery中on()方法用法,实例分析了on()方法的功能及各种常见的使用技巧,并对比分析了与bind(),live(),delegate()等方法的区别,需要的朋友可以参考下 本 ...

随机推荐

  1. 配置AIX系统互信关系

    解释: 信任关系指一台远程服务器的用户以相同的用户名接入到另外一台服务器,而无需提供口令. 双机之间建立信任关系后,可以使用“rcp”和“rlogin”等命令. 操作步骤: 1.以root用户登录双机 ...

  2. 一次和matplotlib和numpy的初识及简单的异常值清理

    1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 ...

  3. [BZOJ 1058][ZJOI 2007]报表统计 平衡树+线段树

    考试的时候看见这道题,感觉自己能AC掉,然后就冲着正解去了.然后想了想数据结构,应该是平衡树.然而蒟蒻的我忘了平衡树怎么打了..然后就根据自己的记忆和理解打了出来.然后我简单的以为相邻的用个链表就能解 ...

  4. MySQL Flush导致的等待问题

    --MySQL Flush导致的等待问题 -------------------------------2014/07/13 前言 在实际生产环境中有时会发现大量的sql语句处于waiting for ...

  5. 腾讯SNG电面

    第一次电面. 前半段基本闲聊,问题也记得不太清楚了. 自我介绍. 为什么想去上海工作?除了职业方面有其他原因吗?我猜出来面试官想问私人问题了,你真的可以直接问的,拐弯抹角了好久...有什么爱好.特长. ...

  6. 为什么C++中声明和定义要分开写

    现在开始写项目了,你会发现我们一般都要写一个cpp,对应的还得有一个h文件,那么为什么在C++中我们要这么做? .h就是声明,.cpp就是实现,而所谓分离式实现就是指"声明"和&q ...

  7. Fiddler过滤会话

    Fiddler每次打开的时候都会打开十多个会话,期望只想抓取自己想要的请求.   1)User Filters:启用过滤器 2)在Filers面板中勾选"Use Filters", ...

  8. Nginx也应用场景小结

    Nginx简介    Nginx一是一款轻量级的.高性能的HTTP和反向代理服务器, 具有很高的稳定性和支持热部署.模块扩展也很容易.当遇到访问的峰值,或者有人恶意发起慢速连接时,也很可能会导致服务器 ...

  9. Linux桌面环境GNOME实用技巧

    GNOME是Linux桌面上主流的集成桌面环境之一,GNOME桌面以其风格简洁.操作便捷而受到Linux用户的欢迎.这里将介绍Linux桌面环境GNOME的操作技巧,在这里拿出来和大家分享一下. 下面 ...

  10. python 打印三级菜单

    要求: 1.用户选择城市菜单编号显示对应的下级菜单 2.可以返回上级菜单,只有在用户确定正常退出时才退出 #!/usr/bin/env python3 # -*- coding: utf-8 -*- ...