Java tutorial
/* 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 StocksTable5 extends JFrame { protected JTable m_table; protected StockTableData m_data; protected JLabel m_title; public StocksTable5() { 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); 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); 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)); } public static void main(String argv[]) { new StocksTable5(); } } 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_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_columns.length; } 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_columns.length; i++) { 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 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; } }