Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4290656

Custom AbstractButton implementation fails with Metal L&F

XMLWordPrintable

    • beta
    • generic
    • generic



      Name: skT88420 Date: 11/11/99


      java version "1.2.2"
      Classic VM (build JDK-1.2.2-W, native threads, symcjit)


      Creating a custom AbstractButton implementation that behaves like a JButton
      doesn't work with Metal Look&Feel (Windows and Motif l&f are ok).
      Below is a source code that doesn't work (to be compiled with JDK 1.2.x).


      //-----------------------------------
      // MyCustomButton.java

      import javax.swing.*;
      import java.io.ObjectOutputStream;
      import java.io.ObjectInputStream;
      import java.io.IOException;
      import javax.accessibility.*;
      import java.awt.image.*;
      import javax.swing.plaf.*;
      import javax.swing.event.*;


      class MyCustomButton extends AbstractButton {


        public static void main(String[] args) {
          try {
            // Windows & Motif l&f are correct
            //UIManager.setLookAndFeel(new
      com.sun.java.swing.plaf.windows.WindowsLookAndFeel());
            //UIManager.setLookAndFeel(new
      com.sun.java.swing.plaf.motif.MotifLookAndFeel());

            // Metal l&f is not!
            UIManager.setLookAndFeel(new javax.swing.plaf.metal.MetalLookAndFeel());
            JFrame frame = new JFrame("Sun Bug Report");
            MyCustomButton button = new MyCustomButton();
            frame.getContentPane().add(button);
            frame.setSize(200,200);
            frame.setVisible(true);
          } catch (Exception e) { e.printStackTrace();}
        }


        //////////////////////////////////////////
        // Original SWING 1.2.2 JButton Implementation
        //////////////////////////////////////////

      /*
      * @version 1.73 09/01/98
       * @author Jeff Dinkins
       * @see ButtonGroup
       */
      //public class JButton extends AbstractButton implements Accessible {

          /**
           * @see #getUIClassID
           * @see #readObject
           */
          private static final String uiClassID = "ButtonUI";

          private boolean defaultCapable = true;

          /**
           * Creates a button with no set text or icon.
           */
          public MyCustomButton() {
              this(null, null);
          }
          
          /**
           * Creates a button with an icon.
           *
           * @param icon the Icon image to display on the button
           */
          public MyCustomButton(Icon icon) {
              this(null, icon);
          }
          
          /**
           * Creates a button with text.
           *
           * @param text the text of the button
           */
          public MyCustomButton(String text) {
              this(text, null);
          }
          
          /**
           * Creates a button with initial text and an icon.
           *
           * @param text the text of the button.
           * @param icon the Icon image to display on the button
           */
          public MyCustomButton(String text, Icon icon) {
              // Create the model
              setModel(new DefaultButtonModel());

              // initialize
              init(text, icon);
          }

          /**
           * Notification from the UIFactory that the L&F
           * has changed.
           *
           * @see JComponent#updateUI
           */
          public void updateUI() {
              setUI((ButtonUI)UIManager.getUI(this));
          }
          

          /**
           * Returns a string that specifies the name of the L&F class
           * that renders this component.
           *
           * @return "ButtonUI"
           * @see JComponent#getUIClassID
           * @see UIDefaults#getUI
           * @beaninfo
           * expert: true
           * description: A string that specifies the name of the L&F class.
           */
          public String getUIClassID() {
              return uiClassID;
          }


          /**
           * Returns whether or not this button is the default button
           * on the RootPane.
           *
           * @return "boolean"
           * @see JRootPane#setDefaultButton
           * @beaninfo
           * description: Whether or not this button is the default button
           */
          public boolean isDefaultButton() {
              JRootPane root = SwingUtilities.getRootPane(this);
              if (root != null) {
                  return (AbstractButton) root.getDefaultButton() == this;
              }
              return false;
          }

          /**
           * Returns whether or not this button is capable of being
           * the default button on the RootPane.
           *
           * @return "boolean"
           * @see #setDefaultCapable
           * @see #isDefaultButton
           * @see JRootPane#setDefaultButton
           */
          public boolean isDefaultCapable() {
              return defaultCapable;
          }

          /**
           * Sets whether or not this button is capable of being
           * the default button on the RootPane.
           *
           * @return "boolean"
           * @see #isDefaultCapable
           * @beaninfo
           * bound: true
           * attribute: visualUpdate true
           * description: Whether or not this button can be the default button
           */
          public void setDefaultCapable(boolean defaultCapable) {
              boolean oldDefaultCapable = this.defaultCapable;
              this.defaultCapable = defaultCapable;
              firePropertyChange("defaultCapable", oldDefaultCapable, defaultCapable);
          }


          /**
           * See readObject() and writeObject() in JComponent for more
           * information about serialization in Swing.
           */
          private void writeObject(ObjectOutputStream s) throws IOException {
              s.defaultWriteObject();
      if ((ui != null) && (getUIClassID().equals(uiClassID))) {
      ui.installUI(this);
      }
          }


          /**
           * Returns a string representation of this JButton. This method
           * is intended to be used only for debugging purposes, and the
           * content and format of the returned string may vary between
           * implementations. The returned string may be empty but may not
           * be <code>null</code>.
           *
           * @return a string representation of this JButton.
           */
          protected String paramString() {
      String defaultCapableString = (defaultCapable ? "true" : "false");

      return super.paramString() +
      ",defaultCapable=" + defaultCapableString;
          }


      /////////////////
      // Accessibility support
      ////////////////

          /**
           * Get the AccessibleContext associated with this JComponent
           *
           * @return the AccessibleContext of this JComponent
           * @beaninfo
           * expert: true
           * description: The AccessibleContext associated with this Button.
           */
          public AccessibleContext getAccessibleContext() {
              if (accessibleContext == null) {
                  accessibleContext = new AccessibleJButton();
              }
              return accessibleContext;
          }

          /**
           * The class used to obtain the accessible role for this object.
           * <p>
           * <strong>Warning:</strong>
           * Serialized objects of this class will not be compatible with
           * future Swing releases. The current serialization support is appropriate
           * for short term storage or RMI between applications running the same
           * version of Swing. A future release of Swing will provide support for
           * long term persistence.
           */
          protected class AccessibleJButton extends AccessibleAbstractButton {
          
              /**
               * Get the role of this object.
               *
               * @return an instance of AccessibleRole describing the role of the
               * object
               * @see AccessibleRole
               */
              public AccessibleRole getAccessibleRole() {
                  return AccessibleRole.PUSH_BUTTON;
              }
          } // inner class AccessibleJButton

      }


      //----------------------------------------


      The execution of this class generates the following exception:


      ============================================
      Exception occurred during event dispatching:
      java.lang.ClassCastException: MyCustomButton
      at
      javax.swing.plaf.metal.MetalBorders$ButtonBorder.paintBorder(MetalBorders.java:6
      2)
      at javax.swing.border.CompoundBorder.paintBorder(CompoundBorder.java:99)
      at javax.swing.JComponent.paintBorder(JComponent.java:484)
      at javax.swing.AbstractButton.paintBorder(AbstractButton.java:752)
      at javax.swing.JComponent.paint(JComponent.java:639)
      at javax.swing.JComponent.paintWithBuffer(JComponent.java:3701)
      at javax.swing.JComponent._paintImmediately(JComponent.java:3646)
      at javax.swing.JComponent.paintImmediately(JComponent.java:3496)
      at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:365)
      at
      javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(SystemEventQueueU
      tilities.java:191)
      at
      javax.swing.SystemEventQueueUtilities.processRunnableEvent(SystemEventQueueUtili
      ties.java:366)
      at
      javax.swing.SystemEventQueueUtilities.access$0(SystemEventQueueUtilities.java:36
      2)
      at
      javax.swing.SystemEventQueueUtilities$RunnableTarget.processEvent(SystemEventQue
      ueUtilities.java:403)
      at java.awt.Component.dispatchEventImpl(Component.java:2394)
      at java.awt.Component.dispatchEvent(Component.java:2307)
      at java.awt.EventQueue.dispatchEvent(EventQueue.java:287)
      at
      java.awt.EventDispatchThread.pumpOneEvent(EventDispatchThread.java:101)
      at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:92)
      at java.awt.EventDispatchThread.run(EventDispatchThread.java:83)
      Exception occurred during event dispatching:
      java.lang.ClassCastException: MyCustomButton
      at
      javax.swing.plaf.metal.MetalBorders$ButtonBorder.paintBorder(MetalBorders.java:6
      2)
      at javax.swing.border.CompoundBorder.paintBorder(CompoundBorder.java:99)
      at javax.swing.JComponent.paintBorder(JComponent.java:484)
      at javax.swing.AbstractButton.paintBorder(AbstractButton.java:752)
      at javax.swing.JComponent.paint(JComponent.java:639)
      at javax.swing.JComponent.paintChildren(JComponent.java:452)
      at javax.swing.JComponent.paint(JComponent.java:641)
      at javax.swing.JComponent.paintChildren(JComponent.java:452)
      at javax.swing.JComponent.paint(JComponent.java:641)
      at javax.swing.JLayeredPane.paint(JLayeredPane.java:547)
      at javax.swing.JComponent.paintChildren(JComponent.java:452)
      at javax.swing.JComponent.paint(JComponent.java:626)
      at java.awt.Container.paint(Container.java:773)
      at sun.awt.windows.WComponentPeer.handleEvent(WComponentPeer.java:117)
      at java.awt.Component.dispatchEventImpl(Component.java:2447)
      at java.awt.Container.dispatchEventImpl(Container.java:1035)
      at java.awt.Window.dispatchEventImpl(Window.java:749)
      at java.awt.Component.dispatchEvent(Component.java:2307)
      at java.awt.EventQueue.dispatchEvent(EventQueue.java:287)
      at
      java.awt.EventDispatchThread.pumpOneEvent(EventDispatchThread.java:101)
      at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:92)
      at java.awt.EventDispatchThread.run(EventDispatchThread.java:83)

      ==============================================================


      The problem is caused by line 62 of file MetalBorders.java, that reads

      JButton button = (JButton) c;

      instead it should be (like it is in the other look&feel code)

      AbstractButton button = (AbstractButton) c;

      Regards
      (Review ID: 97750)
      ======================================================================

            kereminsunw Konstantin Eremin (Inactive)
            skonchad Sandeep Konchady
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: