StockTable 6: Action and Dynamic Display
/*
Swing, Second Edition
by Matthew Robinson, Pavel Vorobiev
*/
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;
import java.text.*;
import java.sql.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class StocksTable6 extends JFrame
{
protected JTable m_table;
protected StockTableData m_data;
protected JLabel m_title;
public StocksTable6() {
super("Stocks Table");
setSize(600, 300);
m_data = new StockTableData();
m_title = new JLabel(m_data.getTitle(),
new ImageIcon("money.gif"), SwingConstants.LEFT);
m_title.setFont(new Font("TimesRoman",Font.BOLD,24));
m_title.setForeground(Color.black);
getContentPane().add(m_title, BorderLayout.NORTH);
m_table = new JTable();
m_table.setAutoCreateColumnsFromModel(false);
m_table.setModel(m_data);
for (int k = 0; k < StockTableData.m_columns.length; k++) {
DefaultTableCellRenderer renderer = new
ColoredTableCellRenderer();
renderer.setHorizontalAlignment(
StockTableData.m_columns[k].m_alignment);
TableColumn column = new TableColumn(k,
StockTableData.m_columns[k].m_width, renderer, null);
m_table.addColumn(column);
}
JTableHeader header = m_table.getTableHeader();
header.setUpdateTableInRealTime(true);
header.addMouseListener(m_data.new ColumnListener(m_table));
header.setReorderingAllowed(true);
m_table.getColumnModel().addColumnModelListener(
m_data.new ColumnMovementListener());
JScrollPane ps = new JScrollPane();
ps.getViewport().add(m_table);
getContentPane().add(ps, BorderLayout.CENTER);
JMenuBar menuBar = createMenuBar();
setJMenuBar(menuBar);
WindowListener wndCloser = new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
};
addWindowListener(wndCloser);
setVisible(true);
}
protected JMenuBar createMenuBar() {
JMenuBar menuBar = new JMenuBar();
JMenu mFile = new JMenu("File");
mFile.setMnemonic('f');
JMenuItem mData = new JMenuItem("Retrieve Data...");
mData.setMnemonic('r');
ActionListener lstData = new ActionListener() {
public void actionPerformed(ActionEvent e) {
retrieveData();
}
};
mData.addActionListener(lstData);
mFile.add(mData);
mFile.addSeparator();
JMenuItem mExit = new JMenuItem("Exit");
mExit.setMnemonic('x');
ActionListener lstExit = new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
};
mExit.addActionListener(lstExit);
mFile.add(mExit);
menuBar.add(mFile);
JMenu mView = new JMenu("View");
mView.setMnemonic('v');
TableColumnModel model = m_table.getColumnModel();
for (int k = 0; k < StockTableData.m_columns.length; k++) {
JCheckBoxMenuItem item = new JCheckBoxMenuItem(
StockTableData.m_columns[k].m_title);
item.setSelected(true);
TableColumn column = model.getColumn(k);
item.addActionListener(new ColumnKeeper(column,
StockTableData.m_columns[k]));
mView.add(item);
}
menuBar.add(mView);
return menuBar;
}
public void retrieveData() {
SimpleDateFormat frm = new SimpleDateFormat("MM/dd/yyyy");
String currentDate = frm.format(m_data.m_date);
String result = (String)JOptionPane.showInputDialog(this,
"Please enter date in form mm/dd/yyyy:", "Input",
JOptionPane.INFORMATION_MESSAGE, null, null,
currentDate);
if (result==null)
return;
java.util.Date date = null;
try {
date = frm.parse(result);
}
catch (java.text.ParseException ex) {
date = null;
}
if (date == null) {
JOptionPane.showMessageDialog(this,
result+" is not a valid date",
"Warning", JOptionPane.WARNING_MESSAGE);
return;
}
setCursor( Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR) );
switch (m_data.retrieveData(date)) {
case 0: // Ok with data
m_title.setText(m_data.getTitle());
m_table.tableChanged(new TableModelEvent(m_data));
m_table.repaint();
break;
case 1: // No data
JOptionPane.showMessageDialog(this,
"No data found for "+result,
"Warning", JOptionPane.WARNING_MESSAGE);
break;
case -1: // Error
JOptionPane.showMessageDialog(this,
"Error retrieving data",
"Warning", JOptionPane.WARNING_MESSAGE);
break;
}
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
class ColumnKeeper implements ActionListener
{
protected TableColumn m_column;
protected ColumnData m_colData;
public ColumnKeeper(TableColumn column, ColumnData colData) {
m_column = column;
m_colData = colData;
}
public void actionPerformed(ActionEvent e) {
JCheckBoxMenuItem item = (JCheckBoxMenuItem)e.getSource();
TableColumnModel model = m_table.getColumnModel();
if (item.isSelected()) {
model.addColumn(m_column);
}
else {
model.removeColumn(m_column);
}
m_table.tableChanged(new TableModelEvent(m_data));
m_table.repaint();
}
}
public static void main(String argv[]) {
new StocksTable6();
}
}
class ColoredTableCellRenderer extends DefaultTableCellRenderer
{
public void setValue(Object value)
{
if (value instanceof ColorData) {
ColorData cvalue = (ColorData)value;
setForeground(cvalue.m_color);
setText(cvalue.m_data.toString());
}
else if (value instanceof IconData) {
IconData ivalue = (IconData)value;
setIcon(ivalue.m_icon);
setText(ivalue.m_data.toString());
}
else
super.setValue(value);
}
}
class Fraction
{
public int m_whole;
public int m_nom;
public int m_den;
public Fraction(double value) {
int sign = value <0 ? -1 : 1;
value = Math.abs(value);
m_whole = (int)value;
m_den = 32;
m_nom = (int)((value-m_whole)*m_den);
while (m_nom!=0 && m_nom%2==0) {
m_nom /= 2;
m_den /= 2;
}
if (m_whole==0)
m_nom *= sign;
else
m_whole *= sign;
}
public double doubleValue() {
return (double)m_whole + (double)m_nom/m_den;
}
public String toString() {
if (m_nom==0)
return ""+m_whole;
else if (m_whole==0)
return ""+m_nom+"/"+m_den;
else
return ""+m_whole+" "+m_nom+"/"+m_den;
}
}
class SmartLong
{
protected static NumberFormat FORMAT;
static {
FORMAT = NumberFormat.getInstance();
FORMAT.setGroupingUsed(true);
}
public long m_value;
public SmartLong(long value) { m_value = value; }
public long longValue() { return m_value; }
public String toString() { return FORMAT.format(m_value); }
}
class ColorData
{
public Color m_color;
public Object m_data;
public static Color GREEN = new Color(0, 128, 0);
public static Color RED = Color.red;
public ColorData(Fraction data) {
m_color = data.doubleValue() >= 0 ? GREEN : RED;
m_data = data;
}
public ColorData(Color color, Object data) {
m_color = color;
m_data = data;
}
public ColorData(Double data) {
m_color = data.doubleValue() >= 0 ? GREEN : RED;
m_data = data;
}
public String toString() {
return m_data.toString();
}
}
class IconData
{
public ImageIcon m_icon;
public Object m_data;
public IconData(ImageIcon icon, Object data) {
m_icon = icon;
m_data = data;
}
public String toString() {
return m_data.toString();
}
}
class StockData
{
public static ImageIcon ICON_UP = new ImageIcon("ArrUp.gif");
public static ImageIcon ICON_DOWN = new ImageIcon("ArrDown.gif");
public static ImageIcon ICON_BLANK = new ImageIcon("blank.gif");
public IconData m_symbol;
public String m_name;
public Fraction m_last;
public Fraction m_open;
public ColorData m_change;
public ColorData m_changePr;
public SmartLong m_volume;
public StockData(String symbol, String name, double last,
double open, double change, double changePr, long volume) {
m_symbol = new IconData(getIcon(change), symbol);
m_name = name;
m_last = new Fraction(last);
m_open = new Fraction(open);
m_change = new ColorData(new Fraction(change));
m_changePr = new ColorData(new Double(changePr));
m_volume = new SmartLong(volume);
}
public static ImageIcon getIcon(double change) {
return (change>0 ? ICON_UP : (change<0 ? ICON_DOWN :
ICON_BLANK));
}
}
class ColumnData
{
public String m_title;
public int m_width;
public int m_alignment;
public ColumnData(String title, int width, int alignment) {
m_title = title;
m_width = width;
m_alignment = alignment;
}
}
class StockTableData extends AbstractTableModel
{
static final public ColumnData m_columns[] = {
new ColumnData( "Symbol", 100, JLabel.LEFT ),
new ColumnData( "Name", 160, JLabel.LEFT ),
new ColumnData( "Last", 100, JLabel.RIGHT ),
new ColumnData( "Open", 100, JLabel.RIGHT ),
new ColumnData( "Change", 100, JLabel.RIGHT ),
new ColumnData( "Change %", 100, JLabel.RIGHT ),
new ColumnData( "Volume", 100, JLabel.RIGHT )
};
protected SimpleDateFormat m_frm;
protected Vector m_vector;
protected java.util.Date m_date;
protected int m_columnsCount = m_columns.length;
protected int m_sortCol = 0;
protected boolean m_sortAsc = true;
protected int m_result = 0;
public StockTableData() {
m_frm = new SimpleDateFormat("MM/dd/yyyy");
m_vector = new Vector();
setDefaultData();
}
public void setDefaultData() {
try {
m_date = m_frm.parse("4/6/1999");
}
catch (java.text.ParseException ex) {
m_date = null;
}
m_vector.removeAllElements();
m_vector.addElement(new StockData("ORCL", "Oracle Corp.",
23.6875, 25.375, -1.6875, -6.42, 24976600));
m_vector.addElement(new StockData("EGGS", "Egghead.com",
17.25, 17.4375, -0.1875, -1.43, 2146400));
m_vector.addElement(new StockData("T", "AT&T",
65.1875, 66, -0.8125, -0.10, 554000));
m_vector.addElement(new StockData("LU", "Lucent Technology",
64.625, 59.9375, 4.6875, 9.65, 29856300));
m_vector.addElement(new StockData("FON", "Sprint",
104.5625, 106.375, -1.8125, -1.82, 1135100));
m_vector.addElement(new StockData("ENML", "Enamelon Inc.",
4.875, 5, -0.125, 0, 35900));
m_vector.addElement(new StockData("CPQ", "Compaq Computers",
30.875, 31.25, -0.375, -2.18, 11853900));
m_vector.addElement(new StockData("MSFT", "Microsoft Corp.",
94.0625, 95.1875, -1.125, -0.92, 19836900));
m_vector.addElement(new StockData("DELL", "Dell Computers",
46.1875, 44.5, 1.6875, 6.24, 47310000));
m_vector.addElement(new StockData("SUNW", "Sun Microsystems",
140.625, 130.9375, 10, 10.625, 17734600));
m_vector.addElement(new StockData("IBM", "Intl. Bus. Machines",
183, 183.125, -0.125, -0.51, 4371400));
m_vector.addElement(new StockData("HWP", "Hewlett-Packard",
70, 71.0625, -1.4375, -2.01, 2410700));
m_vector.addElement(new StockData("UIS", "Unisys Corp.",
28.25, 29, -0.75, -2.59, 2576200));
m_vector.addElement(new StockData("SNE", "Sony Corp.",
96.1875, 95.625, 1.125, 1.18, 330600));
m_vector.addElement(new StockData("NOVL", "Novell Inc.",
24.0625, 24.375, -0.3125, -3.02, 6047900));
m_vector.addElement(new StockData("HIT", "Hitachi, Ltd.",
78.5, 77.625, 0.875, 1.12, 49400));
Collections.sort(m_vector, new
StockComparator(m_sortCol, m_sortAsc));
}
public int getRowCount() {
return m_vector==null ? 0 : m_vector.size();
}
public int getColumnCount() {
return m_columnsCount;
}
public String getColumnName(int column) {
String str = m_columns[column].m_title;
if (column==m_sortCol)
str += m_sortAsc ? ">>" : "<<";
return str;
}
public boolean isCellEditable(int nRow, int nCol) {
return false;
}
public Object getValueAt(int nRow, int nCol) {
if (nRow < 0 || nRow>=getRowCount())
return "";
StockData row = (StockData)m_vector.elementAt(nRow);
switch (nCol) {
case 0: return row.m_symbol;
case 1: return row.m_name;
case 2: return row.m_last;
case 3: return row.m_open;
case 4: return row.m_change;
case 5: return row.m_changePr;
case 6: return row.m_volume;
}
return "";
}
public String getTitle() {
if (m_date==null)
return "Stock Quotes";
return "Stock Quotes at "+m_frm.format(m_date);
}
public int retrieveData(final java.util.Date date) {
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTime(date);
int month = calendar.get(Calendar.MONTH)+1;
int day = calendar.get(Calendar.DAY_OF_MONTH);
int year = calendar.get(Calendar.YEAR);
final String query = "SELECT data.symbol, symbols.name, "+
"data.last, data.open, data.change, data.changeproc, "+
"data.volume FROM DATA INNER JOIN SYMBOLS "+
"ON DATA.symbol = SYMBOLS.symbol WHERE "+
"month(data.date1)="+month+" AND day(data.date1)="+day+
" AND year(data.date1)="+year;
Thread runner = new Thread() {
public void run() {
try {
// Load the JDBC-ODBC bridge driver
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
Connection conn = DriverManager.getConnection(
"jdbc:odbc:Market", "admin", "");
Statement stmt = conn.createStatement();
ResultSet results = stmt.executeQuery(query);
boolean hasData = false;
while (results.next()) {
if (!hasData) {
m_vector.removeAllElements();
hasData = true;
}
String symbol = results.getString(1);
String name = results.getString(2);
double last = results.getDouble(3);
double open = results.getDouble(4);
double change = results.getDouble(5);
double changePr = results.getDouble(6);
long volume = results.getLong(7);
m_vector.addElement(new StockData(symbol, name, last,
open, change, changePr, volume));
}
results.close();
stmt.close();
conn.close();
if (!hasData) // We've got nothing
m_result = 1;
}
catch (Exception e) {
e.printStackTrace();
System.err.println("Load data error: "+e.toString());
m_result = -1;
}
m_date = date;
Collections.sort(m_vector,
new StockComparator(m_sortCol, m_sortAsc));
m_result = 0;
}
};
runner.start();
return m_result;
}
class ColumnListener extends MouseAdapter
{
protected JTable m_table;
public ColumnListener(JTable table) {
m_table = table;
}
public void mouseClicked(MouseEvent e) {
TableColumnModel colModel = m_table.getColumnModel();
int columnModelIndex = colModel.getColumnIndexAtX(e.getX());
int modelIndex = colModel.getColumn(columnModelIndex).getModelIndex();
if (modelIndex < 0)
return;
if (m_sortCol==modelIndex)
m_sortAsc = !m_sortAsc;
else
m_sortCol = modelIndex;
for (int i=0; i < m_columnsCount; i++) { //NEW
TableColumn column = colModel.getColumn(i);
column.setHeaderValue(getColumnName(column.getModelIndex()));
}
m_table.getTableHeader().repaint();
Collections.sort(m_vector, new
StockComparator(modelIndex, m_sortAsc));
m_table.tableChanged(
new TableModelEvent(StockTableData.this));
m_table.repaint();
}
}
class ColumnMovementListener implements TableColumnModelListener
{
public void columnAdded(TableColumnModelEvent e) {
m_columnsCount++;
}
public void columnRemoved(TableColumnModelEvent e) {
m_columnsCount--;
if (m_sortCol >= e.getFromIndex())
m_sortCol = 0;
}
public void columnMarginChanged(ChangeEvent e) {}
public void columnMoved(TableColumnModelEvent e) {}
public void columnSelectionChanged(ListSelectionEvent e) {}
}
}
class StockComparator implements Comparator
{
protected int m_sortCol;
protected boolean m_sortAsc;
public StockComparator(int sortCol, boolean sortAsc) {
m_sortCol = sortCol;
m_sortAsc = sortAsc;
}
public int compare(Object o1, Object o2) {
if(!(o1 instanceof StockData) || !(o2 instanceof StockData))
return 0;
StockData s1 = (StockData)o1;
StockData s2 = (StockData)o2;
int result = 0;
double d1, d2;
switch (m_sortCol) {
case 0: // symbol
String str1 = (String)s1.m_symbol.m_data;
String str2 = (String)s2.m_symbol.m_data;
result = str1.compareTo(str2);
break;
case 1: // name
result = s1.m_name.compareTo(s2.m_name);
break;
case 2: // last
d1 = s1.m_last.doubleValue();
d2 = s2.m_last.doubleValue();
result = d1<d2 ? -1 : (d1>d2 ? 1 : 0);
break;
case 3: // open
d1 = s1.m_open.doubleValue();
d2 = s2.m_open.doubleValue();
result = d1<d2 ? -1 : (d1>d2 ? 1 : 0);
break;
case 4: // change
d1 = ((Fraction)s1.m_change.m_data).doubleValue();
d2 = ((Fraction)s2.m_change.m_data).doubleValue();
result = d1<d2 ? -1 : (d1>d2 ? 1 : 0);
break;
case 5: // change %
d1 = ((Double)s1.m_changePr.m_data).doubleValue();
d2 = ((Double)s2.m_changePr.m_data).doubleValue();
result = d1<d2 ? -1 : (d1>d2 ? 1 : 0);
break;
case 6: // volume
long l1 = s1.m_volume.longValue();
long l2 = s2.m_volume.longValue();
result = l1<l2 ? -1 : (l1>l2 ? 1 : 0);
break;
}
if (!m_sortAsc)
result = -result;
return result;
}
public boolean equals(Object obj) {
if (obj instanceof StockComparator) {
StockComparator compObj = (StockComparator)obj;
return (compObj.m_sortCol==m_sortCol) &&
(compObj.m_sortAsc==m_sortAsc);
}
return false;
}
}
Related examples in the same category
1. | Creating a JTable Component | | |
2. | Creates tables that allow rows and columns to be added or deleted | | |
3. | Build a table from list data and column names | | |
4. | Getting the Number of Rows and Columns in a JTable Component | | |
5. | Appending a Row to a JTable Component | | |
6. | Add columns to a table through DefaultTableModel | | |
7. | Insert a row to a table through DefaultTableModel | | |
8. | Insert a row to a table through DefaultTableModel at specified row | | |
9. | Scroll Table Sample | | |
10. | Simple demonstration of JTable | | |
11. | Create a table with two dimensional array | | |
12. | Create table with Unicode data | | |
13. | Resize Table | | |
14. | Expense Table | | |
15. | JTable selection events | | |
16. | A table with the ability to play with row and column selections | | |
17. | Table Selection mode | | |
18. | Display ResultSet in Table (JTable) | | |
19. | JTable(Table) with JDBC and ResultSet | | |
20. | List UI Properties in a JTable and sortable | | |
21. | Property Table: Use JTable to display and edit properties | | |
22. | Table with tool tips for both cells and column headers | | |
23. | StockTable 4: Table Sorter | | |
24. | JTable sorter:click the table header to sort a column and a table | | |
25. | Creating image out of a JTable | | |
26. | JTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); | | |
27. | JTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); | | |
28. | JTable.setColumnSelectionAllowed(boolean b); | | |
29. | JTable.setRowSelectionAllowed(boolean b); | | |
30. | JTable.setCellSelectionEnabled(boolean b); | | |
31. | Handle selection and model change events for a JTable. | | |
32. | ListSelectionModel rowSelMod = JTable.getSelectionModel(); | | |
33. | ListSelectionModel colSelMod = JTable.getColumnModel().getSelectionModel(); | | |
34. | JTree.getModel().addTreeModelListener(new TreeModelListener()) | | |
35. | Move the last visible column so it becomes the first visible column | | |
36. | the last column is moved to the first position | | |
37. | Allowing the User to Resize a Column in a JTable Component | | |
38. | Retrieve the value in the visible cell (1,2) in a JTable | | |
39. | Retrieve the value in cell (1,2) from the model | | |
40. | Change a cell in the 2nd visible column | | |
41. | Change a cell in the 3rd column in the model | | |
42. | Showing the Table Header in a Non-Scrollable JTable Component | | |
43. | Changing the Name of a Column in a JTable Component | | |
44. | Displaying an Icon in a Column Head of a JTable Component | | |
45. | Implementing Variable-Height Column Headers in a JTable Component | | |
46. | Removing the Column Headers from a Scrollable in a JTable Component | | |
47. | Creating a Custom Column Header Renderer in a JTable Component | | |
48. | Setting Column Header Tool Tips in a JTable Components | | |
49. | Setting Tool Tips on Cells in a JTable Component | | |
50. | Enable row selection (default) in a JTable | | |
51. | Enable column selection in a JTable | | |
52. | Enable cell selection in a JTable | | |
53. | Get default selection mode:MULTIPLE_INTERVAL_SELECTION | | |
54. | Allow only single a selection | | |
55. | Allow selection to span one contiguous set of rows, visible columns, or block of cells | | |
56. | Allow multiple selections of rows, visible columns, or cell blocks (default) | | |
57. | Select a column - column 0 in a JTable | | |
58. | Select an additional range of columns - columns 1 to 2 | | |
59. | Deselect a range of columns - columns 0 to 1 | | |
60. | Select a row - row 0 | | |
61. | Select an additional range of rows - rows 1 to 2 | | |
62. | Deselect a range of rows - rows 0 to 1 | | |
63. | Select a cell: cell (2,1) | | |
64. | Extend the selection to include all cells (5,3) | | |
65. | Deselect a cell: cell (3,2), All cells in the row and column containing (3,2) are deselected. | | |
66. | Toggles the selection state, if it were called again, it exactly reverses the first call. | | |
67. | Select all cells | | |
68. | Deselect all cells | | |
69. | Column selection is enabled, get the indices of the selected columns | | |
70. | Row selection is enabled, Get the indices of the selected rows | | |
71. | Get selected row and selected index | | |
72. | Get the min and max ranges of selected cells | | |
73. | Check each cell in the min and max ranges of selected cells | | |
74. | Disabling Selections in a JTable Component | | |
75. | Getting the Anchor Cell in a JTable Component | | |
76. | Creating a Scrollable JTable Component | | |
77. | Disable auto resizing to make the table horizontal scrollable | | |
78. | Determining If a Cell Is Visible in a JTable Component | | |
79. | Making a Cell Visible in a JTable Component | | |
80. | Scrolling a Cell to the Center of a JTable Component | | |
81. | Show both horizontal and vertical grid lines (the default) | | |
82. | Don't show any grid lines | | |
83. | Show only vertical grid lines | | |
84. | Show only horizontal grid lines | | |
85. | Set the grid color | | |
86. | Getting the Gap Size Between Cells in a JTable Component | | |
87. | Add 5 spaces to the left and right sides of a cell. | | |
88. | Increase the row height | | |
89. | Programmatically Starting Cell Editing in a JTable Component | | |
90. | Save the current value in the cell being edited and stops the editing process | | |
91. | Discard any changes made by the user and stops the editing process | | |
92. | Disabling User Edits in a JTable | | |
93. | Disabling User Edits in a JTable with DefaultTableModel | | |
94. | Sorting the Rows in a JTable Component Based on a Column | | |
95. | Sorting a Column in a JTable Component | | |
96. | Listening for Selection Events in a JTable Component | | |
97. | Listening for Changes to the Rows and Columns of a JTable Component | | |
98. | Listening for Column-Related Changes in a JTable Component | | |
99. | Listening for Clicks on a Column Header in a JTable Component | | |
100. | Sorting and Filtering Tables | | |
101. | Use a regexFilter to filter table content | | |
102. | Creating a JTable with rows of variable height | | |
103. | Scroll JTable To Center | | |