前几篇文章介绍了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. Unity Editor 检查工程Prefab(预设)中的空组件

    在我们做项目的过程中 经常会有预设中出现空的脚本 例如: 导致的原因是因为 脚本的丢失 现在我们来做一个检查工程中有空脚本的预设工具 老规矩直接上代码 放到工程就能用 using UnityEngin ...

  2. Mysql 基于日志点的主从复制(实操)

    实现环境: Master 主:192.168.100.165 (Mysql 5.6.36) Slave 从 :192.168.100.156 (Mysql 5.6.36) 步骤1.在主DB服务器上建立 ...

  3. iOS tableview group时头尾视图间隔大小

    解决: 一,当使用tableview的格式为group时 1.先设置 tableview.sectionHeaderHeight = 0.00001; tableview.sectionFooterH ...

  4. python实战===输入密码以******的形式在cmd中展示

    #设置密码输入,显示为****** import msvcrt,sys def pwd_input(): chars = [] while True: try: newChar = msvcrt.ge ...

  5. Gitlab CI 自动部署 asp.net core web api 到Docker容器

    为什么要写这个? 在一个系统长大的过程中会经历不断重构升级来满足商业的需求,而一个严谨的商业系统需要高效.稳定.可扩展,有时候还不得不考虑成本的问题.我希望能找到比较完整的开源解决方案来解决持续集成. ...

  6. 王佩丰第一讲 认识excel笔记

    改变工作表表浅颜色 批量插入工作表 选择多张工作表然后插入 找到表格边界区域快捷键(找到表格的最后一行):快速到达最上下左右端 点击边框上下左右双击 从指定的位置开始冻结窗格 输入今天的日期 快捷键c ...

  7. oracle启动 init.ora spfile pfile[转]

    昨天晚上快下班的时候,公司数据库突然堵住了,一个buf表中累计了20多W的数据提取不出来,改了程序,效果不明显.因为之前有一次也重启过oracle,所以这次还是想把oracle重启一下,因为那些数据都 ...

  8. C++跨平台使用(安卓,iso等)

    1 C#调用C++接口总结 http://www.cnblogs.com/xtblog/p/5729541.html 2 java调用C++接口 http://www.cnblogs.com/liul ...

  9. C#调用C++数据类型对照

    类型对照: BSTR --------- StringBuilder LPCTSTR --------- StringBuilder LPCWSTR --------- IntPtr handle-- ...

  10. ionic3 app 退出应用程序

    在ionic3 打包的app,如果要实现代码来控制应用程序的推出. 在android以下代码是可以的,但是在ios是不支持的.因为这不适用于ios app,因为苹果apple 不允许应用程序以编程的方 ...