1. /*
  2. * @(#)JColorChooser.java 1.47 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing;
  8. import java.awt.*;
  9. import java.awt.event.*;
  10. import java.beans.*;
  11. import java.io.*;
  12. import java.util.*;
  13. import javax.swing.colorchooser.*;
  14. import javax.swing.plaf.ColorChooserUI;
  15. import javax.swing.event.*;
  16. import javax.accessibility.*;
  17. /**
  18. * <code>JColorChooser</code> provides a pane of controls designed to allow
  19. * a user to manipulate and select a color.
  20. * For information about using color choosers, see
  21. * <a
  22. href="http://java.sun.com/docs/books/tutorial/uiswing/components/colorchooser.html">How to Use Color Choosers</a>,
  23. * a section in <em>The Java Tutorial</em>.
  24. *
  25. * <p>
  26. *
  27. * This class provides three levels of API:
  28. * <ol>
  29. * <li>A static convenience method which shows a modal color-chooser
  30. * dialog and returns the color selected by the user.
  31. * <li>A static convenience method for creating a color-chooser dialog
  32. * where <code>ActionListeners</code> can be specified to be invoked when
  33. * the user presses one of the dialog buttons.
  34. * <li>The ability to create instances of <code>JColorChooser</code> panes
  35. * directly (within any container). <code>PropertyChange</code> listeners
  36. * can be added to detect when the current "color" property changes.
  37. * </ol>
  38. * <p>
  39. * <strong>Warning:</strong>
  40. * Serialized objects of this class will not be compatible with
  41. * future Swing releases. The current serialization support is
  42. * appropriate for short term storage or RMI between applications running
  43. * the same version of Swing. As of 1.4, support for long term storage
  44. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  45. * has been added to the <code>java.beans</code> package.
  46. * Please see {@link java.beans.XMLEncoder}.
  47. *
  48. *
  49. * @beaninfo
  50. * attribute: isContainer false
  51. * description: A component that supports selecting a Color.
  52. *
  53. *
  54. * @version 1.47 12/19/03
  55. * @author James Gosling
  56. * @author Amy Fowler
  57. * @author Steve Wilson
  58. */
  59. public class JColorChooser extends JComponent implements Accessible {
  60. /**
  61. * @see #getUIClassID
  62. * @see #readObject
  63. */
  64. private static final String uiClassID = "ColorChooserUI";
  65. private ColorSelectionModel selectionModel;
  66. private JComponent previewPanel;
  67. private AbstractColorChooserPanel[] chooserPanels = new AbstractColorChooserPanel[0];
  68. private boolean dragEnabled;
  69. /**
  70. * The selection model property name.
  71. */
  72. public static final String SELECTION_MODEL_PROPERTY = "selectionModel";
  73. /**
  74. * The preview panel property name.
  75. */
  76. public static final String PREVIEW_PANEL_PROPERTY = "previewPanel";
  77. /**
  78. * The chooserPanel array property name.
  79. */
  80. public static final String CHOOSER_PANELS_PROPERTY = "chooserPanels";
  81. /**
  82. * Shows a modal color-chooser dialog and blocks until the
  83. * dialog is hidden. If the user presses the "OK" button, then
  84. * this method hides/disposes the dialog and returns the selected color.
  85. * If the user presses the "Cancel" button or closes the dialog without
  86. * pressing "OK", then this method hides/disposes the dialog and returns
  87. * <code>null</code>.
  88. *
  89. * @param component the parent <code>Component</code> for the dialog
  90. * @param title the String containing the dialog's title
  91. * @param initialColor the initial Color set when the color-chooser is shown
  92. * @return the selected color or <code>null</code> if the user opted out
  93. * @exception HeadlessException if GraphicsEnvironment.isHeadless()
  94. * returns true.
  95. * @see java.awt.GraphicsEnvironment#isHeadless
  96. */
  97. public static Color showDialog(Component component,
  98. String title, Color initialColor) throws HeadlessException {
  99. final JColorChooser pane = new JColorChooser(initialColor != null?
  100. initialColor : Color.white);
  101. ColorTracker ok = new ColorTracker(pane);
  102. JDialog dialog = createDialog(component, title, true, pane, ok, null);
  103. dialog.show(); // blocks until user brings dialog down...
  104. return ok.getColor();
  105. }
  106. /**
  107. * Creates and returns a new dialog containing the specified
  108. * <code>ColorChooser</code> pane along with "OK", "Cancel", and "Reset"
  109. * buttons. If the "OK" or "Cancel" buttons are pressed, the dialog is
  110. * automatically hidden (but not disposed). If the "Reset"
  111. * button is pressed, the color-chooser's color will be reset to the
  112. * color which was set the last time <code>show</code> was invoked on the
  113. * dialog and the dialog will remain showing.
  114. *
  115. * @param c the parent component for the dialog
  116. * @param title the title for the dialog
  117. * @param modal a boolean. When true, the remainder of the program
  118. * is inactive until the dialog is closed.
  119. * @param chooserPane the color-chooser to be placed inside the dialog
  120. * @param okListener the ActionListener invoked when "OK" is pressed
  121. * @param cancelListener the ActionListener invoked when "Cancel" is pressed
  122. * @return a new dialog containing the color-chooser pane
  123. * @exception HeadlessException if GraphicsEnvironment.isHeadless()
  124. * returns true.
  125. * @see java.awt.GraphicsEnvironment#isHeadless
  126. */
  127. public static JDialog createDialog(Component c, String title, boolean modal,
  128. JColorChooser chooserPane, ActionListener okListener,
  129. ActionListener cancelListener) throws HeadlessException {
  130. Window window = JOptionPane.getWindowForComponent(c);
  131. ColorChooserDialog dialog;
  132. if (window instanceof Frame) {
  133. dialog = new ColorChooserDialog((Frame)window, title, modal, c, chooserPane,
  134. okListener, cancelListener);
  135. } else {
  136. dialog = new ColorChooserDialog((Dialog)window, title, modal, c, chooserPane,
  137. okListener, cancelListener);
  138. }
  139. dialog.addWindowListener(new ColorChooserDialog.Closer());
  140. dialog.addComponentListener(new ColorChooserDialog.DisposeOnClose());
  141. return dialog;
  142. }
  143. /**
  144. * Creates a color chooser pane with an initial color of white.
  145. */
  146. public JColorChooser() {
  147. this(Color.white);
  148. }
  149. /**
  150. * Creates a color chooser pane with the specified initial color.
  151. *
  152. * @param initialColor the initial color set in the chooser
  153. */
  154. public JColorChooser(Color initialColor) {
  155. this( new DefaultColorSelectionModel(initialColor) );
  156. }
  157. /**
  158. * Creates a color chooser pane with the specified
  159. * <code>ColorSelectionModel</code>.
  160. *
  161. * @param model the <code>ColorSelectionModel</code> to be used
  162. */
  163. public JColorChooser(ColorSelectionModel model) {
  164. selectionModel = model;
  165. updateUI();
  166. dragEnabled = false;
  167. }
  168. /**
  169. * Returns the L&F object that renders this component.
  170. *
  171. * @return the <code>ColorChooserUI</code> object that renders
  172. * this component
  173. */
  174. public ColorChooserUI getUI() {
  175. return (ColorChooserUI)ui;
  176. }
  177. /**
  178. * Sets the L&F object that renders this component.
  179. *
  180. * @param ui the <code>ColorChooserUI</code> L&F object
  181. * @see UIDefaults#getUI
  182. *
  183. * @beaninfo
  184. * bound: true
  185. * hidden: true
  186. * description: The UI object that implements the color chooser's LookAndFeel.
  187. */
  188. public void setUI(ColorChooserUI ui) {
  189. super.setUI(ui);
  190. }
  191. /**
  192. * Notification from the <code>UIManager</code> that the L&F has changed.
  193. * Replaces the current UI object with the latest version from the
  194. * <code>UIManager</code>.
  195. *
  196. * @see JComponent#updateUI
  197. */
  198. public void updateUI() {
  199. setUI((ColorChooserUI)UIManager.getUI(this));
  200. }
  201. /**
  202. * Returns the name of the L&F class that renders this component.
  203. *
  204. * @return the string "ColorChooserUI"
  205. * @see JComponent#getUIClassID
  206. * @see UIDefaults#getUI
  207. */
  208. public String getUIClassID() {
  209. return uiClassID;
  210. }
  211. /**
  212. * Gets the current color value from the color chooser.
  213. * By default, this delegates to the model.
  214. *
  215. * @return the current color value of the color chooser
  216. */
  217. public Color getColor() {
  218. return selectionModel.getSelectedColor();
  219. }
  220. /**
  221. * Sets the current color of the color chooser to the specified color.
  222. * The <code>ColorSelectionModel</code> will fire a <code>ChangeEvent</code>
  223. * @param color the color to be set in the color chooser
  224. * @see JComponent#addPropertyChangeListener
  225. *
  226. * @beaninfo
  227. * bound: false
  228. * hidden: false
  229. * description: The current color the chooser is to display.
  230. */
  231. public void setColor(Color color) {
  232. selectionModel.setSelectedColor(color);
  233. }
  234. /**
  235. * Sets the current color of the color chooser to the
  236. * specified RGB color. Note that the values of red, green,
  237. * and blue should be between the numbers 0 and 255, inclusive.
  238. *
  239. * @param r an int specifying the amount of Red
  240. * @param g an int specifying the amount of Green
  241. * @param b an int specifying the amount of Blue
  242. * @exception IllegalArgumentException if r,g,b values are out of range
  243. * @see java.awt.Color
  244. */
  245. public void setColor(int r, int g, int b) {
  246. setColor(new Color(r,g,b));
  247. }
  248. /**
  249. * Sets the current color of the color chooser to the
  250. * specified color.
  251. *
  252. * @param c an integer value that sets the current color in the chooser
  253. * where the low-order 8 bits specify the Blue value,
  254. * the next 8 bits specify the Green value, and the 8 bits
  255. * above that specify the Red value.
  256. */
  257. public void setColor(int c) {
  258. setColor((c >> 16) & 0xFF, (c >> 8) & 0xFF, c & 0xFF);
  259. }
  260. /**
  261. * Sets the <code>dragEnabled</code> property,
  262. * which must be <code>true</code> to enable
  263. * automatic drag handling (the first part of drag and drop)
  264. * on this component.
  265. * The <code>transferHandler</code> property needs to be set
  266. * to a non-<code>null</code> value for the drag to do
  267. * anything. The default value of the <code>dragEnabled</code>
  268. * property
  269. * is <code>false</code>.
  270. *
  271. * <p>
  272. *
  273. * When automatic drag handling is enabled,
  274. * most look and feels begin a drag-and-drop operation
  275. * when the user presses the mouse button over the preview panel.
  276. * Some look and feels might not support automatic drag and drop;
  277. * they will ignore this property. You can work around such
  278. * look and feels by modifying the component
  279. * to directly call the <code>exportAsDrag</code> method of a
  280. * <code>TransferHandler</code>.
  281. *
  282. * @param b the value to set the <code>dragEnabled</code> property to
  283. * @exception HeadlessException if
  284. * <code>b</code> is <code>true</code> and
  285. * <code>GraphicsEnvironment.isHeadless()</code>
  286. * returns <code>true</code>
  287. *
  288. * @since 1.4
  289. *
  290. * @see java.awt.GraphicsEnvironment#isHeadless
  291. * @see #getDragEnabled
  292. * @see #setTransferHandler
  293. * @see TransferHandler
  294. *
  295. * @beaninfo
  296. * description: Determines whether automatic drag handling is enabled.
  297. * bound: false
  298. */
  299. public void setDragEnabled(boolean b) {
  300. if (b && GraphicsEnvironment.isHeadless()) {
  301. throw new HeadlessException();
  302. }
  303. dragEnabled = b;
  304. }
  305. /**
  306. * Gets the value of the <code>dragEnabled</code> property.
  307. *
  308. * @return the value of the <code>dragEnabled</code> property
  309. * @see #setDragEnabled
  310. * @since 1.4
  311. */
  312. public boolean getDragEnabled() {
  313. return dragEnabled;
  314. }
  315. /**
  316. * Sets the current preview panel.
  317. * This will fire a <code>PropertyChangeEvent</code> for the property
  318. * named "previewPanel".
  319. *
  320. * @param preview the <code>JComponent</code> which displays the current color
  321. * @see JComponent#addPropertyChangeListener
  322. *
  323. * @beaninfo
  324. * bound: true
  325. * hidden: true
  326. * description: The UI component which displays the current color.
  327. */
  328. public void setPreviewPanel(JComponent preview) {
  329. if (previewPanel != preview) {
  330. JComponent oldPreview = previewPanel;
  331. previewPanel = preview;
  332. firePropertyChange(JColorChooser.PREVIEW_PANEL_PROPERTY, oldPreview, preview);
  333. }
  334. }
  335. /**
  336. * Returns the preview panel that shows a chosen color.
  337. *
  338. * @return a <code>JComponent</code> object -- the preview panel
  339. */
  340. public JComponent getPreviewPanel() {
  341. return previewPanel;
  342. }
  343. /**
  344. * Adds a color chooser panel to the color chooser.
  345. *
  346. * @param panel the <code>AbstractColorChooserPanel</code> to be added
  347. */
  348. public void addChooserPanel( AbstractColorChooserPanel panel ) {
  349. AbstractColorChooserPanel[] oldPanels = getChooserPanels();
  350. AbstractColorChooserPanel[] newPanels = new AbstractColorChooserPanel[oldPanels.length+1];
  351. System.arraycopy(oldPanels, 0, newPanels, 0, oldPanels.length);
  352. newPanels[newPanels.length-1] = panel;
  353. setChooserPanels(newPanels);
  354. }
  355. /**
  356. * Removes the Color Panel specified.
  357. *
  358. * @param panel a string that specifies the panel to be removed
  359. * @return the color panel
  360. * @exception IllegalArgumentException if panel is not in list of
  361. * known chooser panels
  362. */
  363. public AbstractColorChooserPanel removeChooserPanel( AbstractColorChooserPanel panel ) {
  364. int containedAt = -1;
  365. for (int i = 0; i < chooserPanels.length; i++) {
  366. if (chooserPanels[i] == panel) {
  367. containedAt = i;
  368. break;
  369. }
  370. }
  371. if (containedAt == -1) {
  372. throw new IllegalArgumentException("chooser panel not in this chooser");
  373. }
  374. AbstractColorChooserPanel[] newArray = new AbstractColorChooserPanel[chooserPanels.length-1];
  375. if (containedAt == chooserPanels.length-1) { // at end
  376. System.arraycopy(chooserPanels, 0, newArray, 0, newArray.length);
  377. }
  378. else if (containedAt == 0) { // at start
  379. System.arraycopy(chooserPanels, 1, newArray, 0, newArray.length);
  380. }
  381. else { // in middle
  382. System.arraycopy(chooserPanels, 0, newArray, 0, containedAt);
  383. System.arraycopy(chooserPanels, containedAt+1,
  384. newArray, containedAt, (chooserPanels.length - containedAt - 1));
  385. }
  386. setChooserPanels(newArray);
  387. return panel;
  388. }
  389. /**
  390. * Specifies the Color Panels used to choose a color value.
  391. *
  392. * @param panels an array of <code>AbstractColorChooserPanel</code>
  393. * objects
  394. *
  395. * @beaninfo
  396. * bound: true
  397. * hidden: true
  398. * description: An array of different chooser types.
  399. */
  400. public void setChooserPanels( AbstractColorChooserPanel[] panels) {
  401. AbstractColorChooserPanel[] oldValue = chooserPanels;
  402. chooserPanels = panels;
  403. firePropertyChange(CHOOSER_PANELS_PROPERTY, oldValue, panels);
  404. }
  405. /**
  406. * Returns the specified color panels.
  407. *
  408. * @return an array of <code>AbstractColorChooserPanel</code> objects
  409. */
  410. public AbstractColorChooserPanel[] getChooserPanels() {
  411. return chooserPanels;
  412. }
  413. /**
  414. * Returns the data model that handles color selections.
  415. *
  416. * @return a <code>ColorSelectionModel</code> object
  417. */
  418. public ColorSelectionModel getSelectionModel() {
  419. return selectionModel;
  420. }
  421. /**
  422. * Sets the model containing the selected color.
  423. *
  424. * @param newModel the new <code>ColorSelectionModel</code> object
  425. *
  426. * @beaninfo
  427. * bound: true
  428. * hidden: true
  429. * description: The model which contains the currently selected color.
  430. */
  431. public void setSelectionModel(ColorSelectionModel newModel ) {
  432. ColorSelectionModel oldModel = selectionModel;
  433. selectionModel = newModel;
  434. firePropertyChange(JColorChooser.SELECTION_MODEL_PROPERTY, oldModel, newModel);
  435. }
  436. /**
  437. * See <code>readObject</code> and <code>writeObject</code> in
  438. * <code>JComponent</code> for more
  439. * information about serialization in Swing.
  440. */
  441. private void writeObject(ObjectOutputStream s) throws IOException {
  442. s.defaultWriteObject();
  443. if (getUIClassID().equals(uiClassID)) {
  444. byte count = JComponent.getWriteObjCounter(this);
  445. JComponent.setWriteObjCounter(this, --count);
  446. if (count == 0 && ui != null) {
  447. ui.installUI(this);
  448. }
  449. }
  450. }
  451. /**
  452. * Returns a string representation of this <code>JColorChooser</code>.
  453. * This method
  454. * is intended to be used only for debugging purposes, and the
  455. * content and format of the returned string may vary between
  456. * implementations. The returned string may be empty but may not
  457. * be <code>null</code>.
  458. *
  459. * @return a string representation of this <code>JColorChooser</code>
  460. */
  461. protected String paramString() {
  462. StringBuffer chooserPanelsString = new StringBuffer("");
  463. for (int i=0; i<chooserPanels.length; i++) {
  464. chooserPanelsString.append("[" + chooserPanels[i].toString()
  465. + "]");
  466. }
  467. String previewPanelString = (previewPanel != null ?
  468. previewPanel.toString() : "");
  469. return super.paramString() +
  470. ",chooserPanels=" + chooserPanelsString.toString() +
  471. ",previewPanel=" + previewPanelString;
  472. }
  473. /////////////////
  474. // Accessibility support
  475. ////////////////
  476. protected AccessibleContext accessibleContext = null;
  477. /**
  478. * Gets the AccessibleContext associated with this JColorChooser.
  479. * For color choosers, the AccessibleContext takes the form of an
  480. * AccessibleJColorChooser.
  481. * A new AccessibleJColorChooser instance is created if necessary.
  482. *
  483. * @return an AccessibleJColorChooser that serves as the
  484. * AccessibleContext of this JColorChooser
  485. */
  486. public AccessibleContext getAccessibleContext() {
  487. if (accessibleContext == null) {
  488. accessibleContext = new AccessibleJColorChooser();
  489. }
  490. return accessibleContext;
  491. }
  492. /**
  493. * This class implements accessibility support for the
  494. * <code>JColorChooser</code> class. It provides an implementation of the
  495. * Java Accessibility API appropriate to color chooser user-interface
  496. * elements.
  497. */
  498. protected class AccessibleJColorChooser extends AccessibleJComponent {
  499. /**
  500. * Get the role of this object.
  501. *
  502. * @return an instance of AccessibleRole describing the role of the
  503. * object
  504. * @see AccessibleRole
  505. */
  506. public AccessibleRole getAccessibleRole() {
  507. return AccessibleRole.COLOR_CHOOSER;
  508. }
  509. } // inner class AccessibleJColorChooser
  510. }
  511. /*
  512. * Class which builds a color chooser dialog consisting of
  513. * a JColorChooser with "Ok", "Cancel", and "Reset" buttons.
  514. *
  515. * Note: This needs to be fixed to deal with localization!
  516. */
  517. class ColorChooserDialog extends JDialog {
  518. private Color initialColor;
  519. private JColorChooser chooserPane;
  520. static private JButton cancelButton;
  521. public ColorChooserDialog(Dialog owner, String title, boolean modal,
  522. Component c, JColorChooser chooserPane,
  523. ActionListener okListener, ActionListener cancelListener)
  524. throws HeadlessException {
  525. super(owner, title, modal);
  526. initColorChooserDialog(c, chooserPane, okListener, cancelListener);
  527. }
  528. public ColorChooserDialog(Frame owner, String title, boolean modal,
  529. Component c, JColorChooser chooserPane,
  530. ActionListener okListener, ActionListener cancelListener)
  531. throws HeadlessException {
  532. super(owner, title, modal);
  533. initColorChooserDialog(c, chooserPane, okListener, cancelListener);
  534. }
  535. protected void initColorChooserDialog(Component c, JColorChooser chooserPane,
  536. ActionListener okListener, ActionListener cancelListener) {
  537. //setResizable(false);
  538. this.chooserPane = chooserPane;
  539. String okString = UIManager.getString("ColorChooser.okText");
  540. String cancelString = UIManager.getString("ColorChooser.cancelText");
  541. String resetString = UIManager.getString("ColorChooser.resetText");
  542. Container contentPane = getContentPane();
  543. contentPane.setLayout(new BorderLayout());
  544. contentPane.add(chooserPane, BorderLayout.CENTER);
  545. /*
  546. * Create Lower button panel
  547. */
  548. JPanel buttonPane = new JPanel();
  549. buttonPane.setLayout(new FlowLayout(FlowLayout.CENTER));
  550. JButton okButton = new JButton(okString);
  551. getRootPane().setDefaultButton(okButton);
  552. okButton.setActionCommand("OK");
  553. if (okListener != null) {
  554. okButton.addActionListener(okListener);
  555. }
  556. okButton.addActionListener(new ActionListener() {
  557. public void actionPerformed(ActionEvent e) {
  558. hide();
  559. }
  560. });
  561. buttonPane.add(okButton);
  562. cancelButton = new JButton(cancelString);
  563. // The following few lines are used to register esc to close the dialog
  564. Action cancelKeyAction = new AbstractAction() {
  565. public void actionPerformed(ActionEvent e) {
  566. ((AbstractButton)e.getSource()).fireActionPerformed(e);
  567. }
  568. };
  569. KeyStroke cancelKeyStroke = KeyStroke.getKeyStroke((char)KeyEvent.VK_ESCAPE, false);
  570. InputMap inputMap = cancelButton.getInputMap(JComponent.
  571. WHEN_IN_FOCUSED_WINDOW);
  572. ActionMap actionMap = cancelButton.getActionMap();
  573. if (inputMap != null && actionMap != null) {
  574. inputMap.put(cancelKeyStroke, "cancel");
  575. actionMap.put("cancel", cancelKeyAction);
  576. }
  577. // end esc handling
  578. cancelButton.setActionCommand("cancel");
  579. if (cancelListener != null) {
  580. cancelButton.addActionListener(cancelListener);
  581. }
  582. cancelButton.addActionListener(new ActionListener() {
  583. public void actionPerformed(ActionEvent e) {
  584. hide();
  585. }
  586. });
  587. buttonPane.add(cancelButton);
  588. JButton resetButton = new JButton(resetString);
  589. resetButton.addActionListener(new ActionListener() {
  590. public void actionPerformed(ActionEvent e) {
  591. reset();
  592. }
  593. });
  594. int mnemonic = UIManager.getInt("ColorChooser.resetMnemonic", -1);
  595. if (mnemonic != -1) {
  596. resetButton.setMnemonic(mnemonic);
  597. }
  598. buttonPane.add(resetButton);
  599. contentPane.add(buttonPane, BorderLayout.SOUTH);
  600. if (JDialog.isDefaultLookAndFeelDecorated()) {
  601. boolean supportsWindowDecorations =
  602. UIManager.getLookAndFeel().getSupportsWindowDecorations();
  603. if (supportsWindowDecorations) {
  604. getRootPane().setWindowDecorationStyle(JRootPane.COLOR_CHOOSER_DIALOG);
  605. }
  606. }
  607. applyComponentOrientation(((c == null) ? getRootPane() : c).getComponentOrientation());
  608. pack();
  609. setLocationRelativeTo(c);
  610. }
  611. public void show() {
  612. initialColor = chooserPane.getColor();
  613. super.show();
  614. }
  615. public void reset() {
  616. chooserPane.setColor(initialColor);
  617. }
  618. static class Closer extends WindowAdapter implements Serializable{
  619. public void windowClosing(WindowEvent e) {
  620. cancelButton.doClick();
  621. Window w = e.getWindow();
  622. w.hide();
  623. }
  624. }
  625. static class DisposeOnClose extends ComponentAdapter implements Serializable{
  626. public void componentHidden(ComponentEvent e) {
  627. Window w = (Window)e.getComponent();
  628. w.dispose();
  629. }
  630. }
  631. }
  632. class ColorTracker implements ActionListener, Serializable {
  633. JColorChooser chooser;
  634. Color color;
  635. public ColorTracker(JColorChooser c) {
  636. chooser = c;
  637. }
  638. public void actionPerformed(ActionEvent e) {
  639. color = chooser.getColor();
  640. }
  641. public Color getColor() {
  642. return color;
  643. }
  644. }