Java tutorial
/* Swing, Second Edition by Matthew Robinson, Pavel Vorobiev */ import java.awt.*; import java.awt.event.*; import java.io.*; import java.beans.*; import java.lang.reflect.*; import java.util.*; import javax.swing.*; import javax.swing.table.*; import javax.swing.event.*; public class BeanContainer extends JFrame implements FocusListener{ protected File m_currentDir = new File("."); protected Component m_activeBean; protected String m_className = "clock.Clock"; protected JFileChooser m_chooser = new JFileChooser(); protected Hashtable m_editors = new Hashtable(); public BeanContainer() { super("Simple Bean Container"); getContentPane().setLayout(new FlowLayout()); setSize(300, 300); JPopupMenu.setDefaultLightWeightPopupEnabled(false); 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"); JMenuItem mItem = new JMenuItem("New..."); ActionListener lst = new ActionListener() { public void actionPerformed(ActionEvent e) { Thread newthread = new Thread() { public void run() { String result = (String)JOptionPane.showInputDialog( BeanContainer.this, "Please enter class name to create a new bean", "Input", JOptionPane.INFORMATION_MESSAGE, null, null, m_className); repaint(); if (result==null) return; try { m_className = result; Class cls = Class.forName(result); Object obj = cls.newInstance(); if (obj instanceof Component) { m_activeBean = (Component)obj; m_activeBean.addFocusListener( BeanContainer.this); m_activeBean.requestFocus(); getContentPane().add(m_activeBean); } validate(); } catch (Exception ex) { ex.printStackTrace(); JOptionPane.showMessageDialog( BeanContainer.this, "Error: "+ex.toString(), "Warning", JOptionPane.WARNING_MESSAGE); } } }; newthread.start(); } }; mItem.addActionListener(lst); mFile.add(mItem); mItem = new JMenuItem("Load..."); lst = new ActionListener() { public void actionPerformed(ActionEvent e) { Thread newthread = new Thread() { public void run() { m_chooser.setCurrentDirectory(m_currentDir); m_chooser.setDialogTitle( "Please select file with serialized bean"); int result = m_chooser.showOpenDialog( BeanContainer.this); repaint(); if (result != JFileChooser.APPROVE_OPTION) return; m_currentDir = m_chooser.getCurrentDirectory(); File fChoosen = m_chooser.getSelectedFile(); try { FileInputStream fStream = new FileInputStream(fChoosen); ObjectInput stream = new ObjectInputStream(fStream); Object obj = stream.readObject(); if (obj instanceof Component) { m_activeBean = (Component)obj; m_activeBean.addFocusListener( BeanContainer.this); m_activeBean.requestFocus(); getContentPane().add(m_activeBean); } stream.close(); fStream.close(); validate(); } catch (Exception ex) { ex.printStackTrace(); JOptionPane.showMessageDialog( BeanContainer.this, "Error: "+ex.toString(), "Warning", JOptionPane.WARNING_MESSAGE); } repaint(); } }; newthread.start(); } }; mItem.addActionListener(lst); mFile.add(mItem); mItem = new JMenuItem("Save..."); lst = new ActionListener() { public void actionPerformed(ActionEvent e) { Thread newthread = new Thread() { public void run() { if (m_activeBean == null) return; m_chooser.setDialogTitle( "Please choose file to serialize bean"); m_chooser.setCurrentDirectory(m_currentDir); int result = m_chooser.showSaveDialog( BeanContainer.this); repaint(); if (result != JFileChooser.APPROVE_OPTION) return; m_currentDir = m_chooser.getCurrentDirectory(); File fChoosen = m_chooser.getSelectedFile(); try { FileOutputStream fStream = new FileOutputStream(fChoosen); ObjectOutput stream = new ObjectOutputStream(fStream); stream.writeObject(m_activeBean); stream.close(); fStream.close(); } catch (Exception ex) { ex.printStackTrace(); JOptionPane.showMessageDialog( BeanContainer.this, "Error: "+ex.toString(), "Warning", JOptionPane.WARNING_MESSAGE); } } }; newthread.start(); } }; mItem.addActionListener(lst); mFile.add(mItem); mFile.addSeparator(); mItem = new JMenuItem("Exit"); lst = new ActionListener() { public void actionPerformed(ActionEvent e) { System.exit(0); } }; mItem.addActionListener(lst); mFile.add(mItem); menuBar.add(mFile); JMenu mEdit = new JMenu("Edit"); mItem = new JMenuItem("Delete"); lst = new ActionListener() { public void actionPerformed(ActionEvent e) { if (m_activeBean == null) return; Object obj = m_editors.get(m_activeBean); if (obj != null) { BeanEditor editor = (BeanEditor)obj; editor.dispose(); m_editors.remove(m_activeBean); } getContentPane().remove(m_activeBean); m_activeBean = null; validate(); repaint(); } }; mItem.addActionListener(lst); mEdit.add(mItem); mItem = new JMenuItem("Properties..."); lst = new ActionListener() { public void actionPerformed(ActionEvent e) { if (m_activeBean == null) return; Object obj = m_editors.get(m_activeBean); if (obj != null) { BeanEditor editor = (BeanEditor)obj; editor.setVisible(true); editor.toFront(); } else { BeanEditor editor = new BeanEditor(m_activeBean); m_editors.put(m_activeBean, editor); } } }; mItem.addActionListener(lst); mEdit.add(mItem); menuBar.add(mEdit); JMenu mLayout = new JMenu("Layout"); ButtonGroup group = new ButtonGroup(); mItem = new JRadioButtonMenuItem("FlowLayout"); mItem.setSelected(true); lst = new ActionListener() { public void actionPerformed(ActionEvent e){ getContentPane().setLayout(new FlowLayout()); validate(); repaint(); } }; mItem.addActionListener(lst); group.add(mItem); mLayout.add(mItem); mItem = new JRadioButtonMenuItem("GridLayout"); lst = new ActionListener() { public void actionPerformed(ActionEvent e){ int col = 3; int row = (int)Math.ceil(getContentPane(). getComponentCount()/(double)col); getContentPane().setLayout(new GridLayout(row, col, 10, 10)); validate(); repaint(); } }; mItem.addActionListener(lst); group.add(mItem); mLayout.add(mItem); mItem = new JRadioButtonMenuItem("BoxLayout - X"); lst = new ActionListener() { public void actionPerformed(ActionEvent e) { getContentPane().setLayout(new BoxLayout( getContentPane(), BoxLayout.X_AXIS)); validate(); repaint(); } }; mItem.addActionListener(lst); group.add(mItem); mLayout.add(mItem); mItem = new JRadioButtonMenuItem("BoxLayout - Y"); lst = new ActionListener() { public void actionPerformed(ActionEvent e) { getContentPane().setLayout(new BoxLayout( getContentPane(), BoxLayout.Y_AXIS)); validate(); repaint(); } }; mItem.addActionListener(lst); group.add(mItem); mLayout.add(mItem); mItem = new JRadioButtonMenuItem("DialogLayout"); lst = new ActionListener() { public void actionPerformed(ActionEvent e) { getContentPane().setLayout(new DialogLayout()); validate(); repaint(); } }; mItem.addActionListener(lst); group.add(mItem); mLayout.add(mItem); menuBar.add(mLayout); return menuBar; } public void focusGained(FocusEvent e) { m_activeBean = e.getComponent(); repaint(); } public void focusLost(FocusEvent e) {} // This is a heavyweight component so we override paint // instead of paintComponent. super.paint(g) will // paint all child components first, and then we // simply draw over top of them. public void paint(Graphics g) { super.paint(g); if (m_activeBean == null) return; Point pt = getLocationOnScreen(); Point pt1 = m_activeBean.getLocationOnScreen(); int x = pt1.x - pt.x - 2; int y = pt1.y - pt.y - 2; int w = m_activeBean.getWidth() + 2; int h = m_activeBean.getHeight() + 2; g.setColor(Color.black); g.drawRect(x, y, w, h); } public static void main(String argv[]) { new BeanContainer(); } } class BeanEditor extends JFrame implements PropertyChangeListener { protected Component m_bean; protected JTable m_table; protected PropertyTableData m_data; public BeanEditor(Component bean) { m_bean = bean; m_bean.addPropertyChangeListener(this); Point pt = m_bean.getLocationOnScreen(); setBounds(pt.x + 50, pt.y + 10, 400, 300); getContentPane().setLayout(new BorderLayout()); m_data = new PropertyTableData(m_bean); m_table = new JTable(m_data); JScrollPane ps = new JScrollPane(); ps.getViewport().add(m_table); getContentPane().add(ps, BorderLayout.CENTER); setDefaultCloseOperation(HIDE_ON_CLOSE); setVisible(true); } public void propertyChange(PropertyChangeEvent evt) { m_data.setProperty(evt.getPropertyName(), evt.getNewValue()); } class PropertyTableData extends AbstractTableModel { protected String[][] m_properties; protected int m_numProps = 0; protected Vector m_v; public PropertyTableData(Component bean) { try { BeanInfo info = Introspector.getBeanInfo(m_bean.getClass()); BeanDescriptor descr = info.getBeanDescriptor(); setTitle("Editing " + descr.getName()); PropertyDescriptor[] props = info.getPropertyDescriptors(); m_numProps = props.length; m_v = new Vector(m_numProps); for (int k = 0; k < m_numProps; k++) { String name = props[k].getDisplayName(); boolean added = false; for (int i = 0; i < m_v.size(); i++) { String str = ((PropertyDescriptor) m_v.elementAt(i)).getDisplayName(); if (name.compareToIgnoreCase(str) < 0) { m_v.insertElementAt(props[k], i); added = true; break; } } if (!added) m_v.addElement(props[k]); } m_properties = new String[m_numProps][2]; for (int k = 0; k < m_numProps; k++) { PropertyDescriptor prop = (PropertyDescriptor) m_v.elementAt(k); m_properties[k][0] = prop.getDisplayName(); Method mRead = prop.getReadMethod(); if (mRead != null && mRead.getParameterTypes().length == 0) { Object value = mRead.invoke(m_bean, null); m_properties[k][1] = objToString(value); } else m_properties[k][1] = "error"; } } catch (Exception ex) { ex.printStackTrace(); JOptionPane.showMessageDialog(BeanEditor.this, "Error: " + ex.toString(), "Warning", JOptionPane.WARNING_MESSAGE); } } public void setProperty(String name, Object value) { for (int k = 0; k < m_numProps; k++) if (name.equals(m_properties[k][0])) { m_properties[k][1] = objToString(value); m_table.tableChanged(new TableModelEvent(this, k)); m_table.repaint(); break; } } public int getRowCount() { return m_numProps; } public int getColumnCount() { return 2; } public String getColumnName(int nCol) { return nCol == 0 ? "Property" : "Value"; } public boolean isCellEditable(int nRow, int nCol) { return (nCol == 1); } public Object getValueAt(int nRow, int nCol) { if (nRow < 0 || nRow >= getRowCount()) return ""; switch (nCol) { case 0: return m_properties[nRow][0]; case 1: return m_properties[nRow][1]; } return ""; } public void setValueAt(Object value, int nRow, int nCol) { if (nRow < 0 || nRow >= getRowCount()) return; String str = value.toString(); PropertyDescriptor prop = (PropertyDescriptor) m_v.elementAt(nRow); Class cls = prop.getPropertyType(); Object obj = stringToObj(str, cls); if (obj == null) return; // can't process Method mWrite = prop.getWriteMethod(); if (mWrite == null || mWrite.getParameterTypes().length != 1) return; try { mWrite.invoke(m_bean, new Object[] { obj }); m_bean.getParent().doLayout(); m_bean.getParent().repaint(); m_bean.repaint(); } catch (Exception ex) { ex.printStackTrace(); JOptionPane.showMessageDialog(BeanEditor.this, "Error: " + ex.toString(), "Warning", JOptionPane.WARNING_MESSAGE); } m_properties[nRow][1] = str; } public String objToString(Object value) { if (value == null) return "null"; if (value instanceof Dimension) { Dimension dim = (Dimension) value; return "" + dim.width + "," + dim.height; } else if (value instanceof Insets) { Insets ins = (Insets) value; return "" + ins.left + "," + ins.top + "," + ins.right + "," + ins.bottom; } else if (value instanceof Rectangle) { Rectangle rc = (Rectangle) value; return "" + rc.x + "," + rc.y + "," + rc.width + "," + rc.height; } else if (value instanceof Color) { Color col = (Color) value; return "" + col.getRed() + "," + col.getGreen() + "," + col.getBlue(); } return value.toString(); } public Object stringToObj(String str, Class cls) { try { if (str == null) return null; String name = cls.getName(); if (name.equals("java.lang.String")) return str; else if (name.equals("int")) return new Integer(str); else if (name.equals("long")) return new Long(str); else if (name.equals("float")) return new Float(str); else if (name.equals("double")) return new Double(str); else if (name.equals("boolean")) return new Boolean(str); else if (name.equals("java.awt.Dimension")) { int[] i = strToInts(str); return new Dimension(i[0], i[1]); } else if (name.equals("java.awt.Insets")) { int[] i = strToInts(str); return new Insets(i[0], i[1], i[2], i[3]); } else if (name.equals("java.awt.Rectangle")) { int[] i = strToInts(str); return new Rectangle(i[0], i[1], i[2], i[3]); } else if (name.equals("java.awt.Color")) { int[] i = strToInts(str); return new Color(i[0], i[1], i[2]); } return null; // not supported } catch (Exception ex) { return null; } } public int[] strToInts(String str) throws Exception { int[] i = new int[4]; StringTokenizer tokenizer = new StringTokenizer(str, ","); for (int k = 0; k < i.length && tokenizer.hasMoreTokens(); k++) i[k] = Integer.parseInt(tokenizer.nextToken()); return i; } } } /** DialogLayout */ class DialogLayout implements LayoutManager { protected int m_divider = -1; protected int m_hGap = 10; protected int m_vGap = 5; public DialogLayout() { } public DialogLayout(int hGap, int vGap) { m_hGap = hGap; m_vGap = vGap; } public void addLayoutComponent(String name, Component comp) { } public void removeLayoutComponent(Component comp) { } public Dimension preferredLayoutSize(Container parent) { int divider = getDivider(parent); int w = 0; int h = 0; for (int k = 1; k < parent.getComponentCount(); k += 2) { Component comp = parent.getComponent(k); Dimension d = comp.getPreferredSize(); w = Math.max(w, d.width); h += d.height + m_vGap; } h -= m_vGap; Insets insets = parent.getInsets(); return new Dimension(divider + w + insets.left + insets.right, h + insets.top + insets.bottom); } public Dimension minimumLayoutSize(Container parent) { return preferredLayoutSize(parent); } public void layoutContainer(Container parent) { int divider = getDivider(parent); Insets insets = parent.getInsets(); int w = parent.getWidth() - insets.left - insets.right - divider; int x = insets.left; int y = insets.top; for (int k = 1; k < parent.getComponentCount(); k += 2) { Component comp1 = parent.getComponent(k - 1); Component comp2 = parent.getComponent(k); Dimension d = comp2.getPreferredSize(); comp1.setBounds(x, y, divider - m_hGap, d.height); comp2.setBounds(x + divider, y, w, d.height); y += d.height + m_vGap; } } public int getHGap() { return m_hGap; } public int getVGap() { return m_vGap; } public void setDivider(int divider) { if (divider > 0) m_divider = divider; } public int getDivider() { return m_divider; } protected int getDivider(Container parent) { if (m_divider > 0) return m_divider; int divider = 0; for (int k = 0; k < parent.getComponentCount(); k += 2) { Component comp = parent.getComponent(k); Dimension d = comp.getPreferredSize(); divider = Math.max(divider, d.width); } divider += m_hGap; return divider; } public String toString() { return getClass().getName() + "[hgap=" + m_hGap + ",vgap=" + m_vGap + ",divider=" + m_divider + "]"; } } ///////////File: Clock.java import java.applet.*; import java.awt.*; import java.awt.event.*; import java.beans.*; import java.io.*; import java.util.*; import javax.swing.*; import javax.swing.border.*; public class Clock extends JButton implements Customizer, Externalizable, Runnable { protected PropertyChangeSupport m_helper; protected boolean m_digital = false; protected Calendar m_calendar; protected Dimension m_preffSize; public Clock() { m_calendar = Calendar.getInstance(); m_helper = new PropertyChangeSupport(this); Border br1 = new EtchedBorder(EtchedBorder.RAISED, Color.white, new Color(128, 0, 0)); Border br2 = new MatteBorder(4, 4, 4, 4, Color.red); setBorder(new CompoundBorder(br1, br2)); setBackground(Color.white); setForeground(Color.black); (new Thread(this)).start(); } public void writeExternal(ObjectOutput out) throws IOException { out.writeBoolean(m_digital); out.writeObject(getBackground()); out.writeObject(getForeground()); out.writeObject(getPreferredSize()); } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { setDigital(in.readBoolean()); setBackground((Color) in.readObject()); setForeground((Color) in.readObject()); setPreferredSize((Dimension) in.readObject()); } public Dimension getPreferredSize() { if (m_preffSize != null) return m_preffSize; else return new Dimension(50, 50); } public void setPreferredSize(Dimension preffSize) { m_preffSize = preffSize; } public Dimension getMinimumSize() { return getPreferredSize(); } public Dimension getMaximumSize() { return getPreferredSize(); } public void setDigital(boolean digital) { m_helper.firePropertyChange("digital", new Boolean(m_digital), new Boolean(digital)); m_digital = digital; repaint(); } public boolean getDigital() { return m_digital; } public void addPropertyChangeListener(PropertyChangeListener lst) { if (m_helper != null) m_helper.addPropertyChangeListener(lst); } public void removePropertyChangeListener(PropertyChangeListener lst) { if (m_helper != null) m_helper.removePropertyChangeListener(lst); } public void setObject(Object bean) { } public void paintComponent(Graphics g) { super.paintComponent(g); Color colorRetainer = g.getColor(); g.setColor(getBackground()); g.fillRect(0, 0, getWidth(), getHeight()); getBorder().paintBorder(this, g, 0, 0, getWidth(), getHeight()); m_calendar.setTime(new Date()); // get current time int hrs = m_calendar.get(Calendar.HOUR_OF_DAY); int min = m_calendar.get(Calendar.MINUTE); g.setColor(getForeground()); if (m_digital) { String time = "" + hrs + ":" + min; g.setFont(getFont()); FontMetrics fm = g.getFontMetrics(); int y = (getHeight() + fm.getAscent()) / 2; int x = (getWidth() - fm.stringWidth(time)) / 2; g.drawString(time, x, y); } else { int x = getWidth() / 2; int y = getHeight() / 2; int rh = getHeight() / 4; int rm = getHeight() / 3; double ah = ((double) hrs + min / 60.0) / 6.0 * Math.PI; double am = min / 30.0 * Math.PI; g.drawLine(x, y, (int) (x + rh * Math.sin(ah)), (int) (y - rh * Math.cos(ah))); g.drawLine(x, y, (int) (x + rm * Math.sin(am)), (int) (y - rm * Math.cos(am))); } g.setColor(colorRetainer); } public void run() { while (true) { repaint(); try { Thread.sleep(30 * 1000); } catch (InterruptedException ex) { break; } } } }