Subclassing question...

null
bjgAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

imladrisCommented:
The first thing the multilinebutton does is call multilinelabel's paint method. Shortly AFTER, it calls setBackground. This will "cover" the string.

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
bjgAuthor Commented:
I also added update(Graphics g) inside the MultiLineLabel.  The problem is that when I process any of the mouseEvents, it seems to just keep repainting or something.  It's hard to explain, but if you want, I could send you the code, and you can test it and see what it is doing.  If this is ok, please send me your email address...
0
bjgAuthor Commented:
MultiLineLabel.java


import java.awt.*;
import java.util.StringTokenizer;

public class MultiLineLabel extends Canvas
{
      //Alignment Constants
          public static final int LEFT = 0, CENTER = 1, RIGHT = 2;

      protected String             m_label;
      protected int             m_alignment;

         protected int             m_marginWidth = 10;
          protected int             m_marginHeight = 10;
          protected int             m_numLines;
          protected String[]             m_lines;
          protected int[]             m_lineWidths;
          protected int             m_maxWidth;
          protected int             m_lineHeight;
          protected int             m_lineAscent;
          protected boolean             m_measured = false;

      /*** Two versions of the constructor ***/
          public MultiLineLabel(String label, int alignment)
      {
            this.m_label = label;
              this.m_alignment = alignment;
              processLabel();        
          }
   
          public MultiLineLabel(String label)
      {
            this(label, LEFT);
          }
   
      /*** Public Accessor Methods ***/
          public void setLabel(String label)
      {
            this.m_label = label;
              processLabel();
              m_measured = false;
              repaint();
          }
   
          public void setFont(Font f)
      {
            super.setFont(f);
            m_measured = false;
            repaint();
          }
   
          public void setForeground(Color c)
      {
            super.setForeground(c);
              repaint();
          }

      public void setBackground(Color c)
      {      
            super.setBackground(c);
            repaint();
      }
   
          public void setAlignment(int a)
      {
            m_alignment = a;
              repaint();
          }
   
          public String getLabel()
      {
              return m_label;
          }
   
          public int getAlignment()
      {
            return m_alignment;
          }
   
          public Dimension getPreferredSize()
      {
            if (!m_measured)
                  measure();
              return new Dimension(m_maxWidth + 2*m_marginWidth,
                             m_numLines * m_lineHeight + 2*m_marginHeight);
          }
   
          public Dimension getMinimumSize()
      {
            return getPreferredSize();
          }

      public void update(Graphics g)
      {
            System.out.println("in MultiLineLabel().update()");
            paint(g);
      }
   
      /*** Paint the graphics ***/
          public void paint(Graphics g)
      {
            int x, y;
              Dimension size = this.getSize();  
              if (!m_measured)
                  measure();
              y = m_lineAscent + (size.height - m_numLines * m_lineHeight)/2;
              for (int i = 0; i < m_numLines; i++, y += m_lineHeight)
            {
                  switch(m_alignment)
                  {
                            default:
                            case LEFT:      
                              x = m_marginWidth;
                              break;
                            case CENTER:    
                              x = (size.width - m_lineWidths[i])/2;
                              break;
                            case RIGHT:    
                              x = size.width - m_marginWidth - m_lineWidths[i];
                              break;
                  }
                  g.drawString(m_lines[i], x, y);
              }
          }
   
      /***
            This protected method parses through the label and checks
            for new line characters ('\n').  It also stores each line,
            the number of lines, and each line's width.
      ***/      
          protected void processLabel()
      {
            StringTokenizer t = new StringTokenizer(m_label, "\n");
              m_numLines = t.countTokens();
              m_lines = new String[m_numLines];
              m_lineWidths = new int[m_numLines];
              for (int i = 0; i < m_numLines; i++)
                  m_lines[i] = t.nextToken();
          }
   
      /***
            This protected method measures each line to determine the maximum
            width and height of the label.
      ***/
          protected void measure()
      {
            FontMetrics fm = this.getToolkit().getFontMetrics(this.getFont());
              m_lineHeight = fm.getHeight();
              m_lineAscent = fm.getAscent();
              m_maxWidth = 0;
              for (int i = 0; i < m_numLines; i++)
            {
                  m_lineWidths[i] = fm.stringWidth(m_lines[i]);
                  if (m_lineWidths[i] > m_maxWidth)
                        m_maxWidth = m_lineWidths[i];
              }
              m_measured = true;
          }
}
0
Exploring SQL Server 2016: Fundamentals

Learn the fundamentals of Microsoft SQL Server, a relational database management system that stores and retrieves data when requested by other software applications.

bjgAuthor Commented:
Actually, MultiLineButton is called KeyButton

KeyButton.java

import java.awt.*;
import java.awt.event.*;
import java.util.*;

public class KeyButton extends MultiLineLabel
{
          private boolean pressed = true;
          private boolean isOn = false;

      private int width, height;
        private ActionListener actionListener;
          private String actionCommand;

           private Font m_font = new Font("SansSerif", Font.PLAIN, 9);

          private int keyvalue;

          public KeyButton(String label, ActionListener listener, int width,
                        int height, int alignment, int keyvalue)
      {
            super(label, alignment);

            this.width = width;
            this.height = height;
            this.keyvalue = keyvalue;
            this.actionListener = listener;
            this.actionCommand = String.valueOf(keyvalue);
            this.setFont(m_font);
            enableEvents(AWTEvent.MOUSE_EVENT_MASK);
          }

          public KeyButton(String label, ActionListener listener, int width,
                        int height, int keyvalue)
      {
            this(label, listener, width, height, CENTER, keyvalue);
          }
   
          public KeyButton(String label, ActionListener listener, int keyvalue)
      {
            this(label, listener, 30, 30, CENTER, keyvalue);
          }

      public int getKeyValue()
          {
            return keyvalue;
      }

      public void setKeyValue(int newval)
      {
            keyvalue = newval;
      }
   
          public void setKeyOn(boolean yesno)
          {
            isOn = yesno;
            repaint();
          }

          public boolean isKeyOn()
          {
            return isOn;
          }      
   
          public Dimension getPreferredSize()
      {
            if (!super.m_measured) super.measure();
                  return new Dimension(width,height);
          }
   
          public Dimension getMinimumSize()
      {
            return getPreferredSize();
          }

      public void update(Graphics g)
      {
            System.out.println("in KeyButton().update()");
            paint(g);
      }
   
          public void paint(Graphics g)
      {
            super.paint(g);

            int x, y;
              Dimension size = this.getSize();  

            if (isOn)
                  super.setBackground(Color.green);
              else
                  super.setBackground(Color.lightGray);

              if(pressed)
            {
                  //Make the button look like it is pressed.
                    g.setColor(Color.black);
                    g.drawRect(0,0,size.width-1, size.height-1);
              } else
            {
                  //Make the button look like it is raised.
                  g.setColor(Color.darkGray);
                    g.drawRect(0,0,size.width-1, size.height-1);
                  g.drawRect(0,0,size.width-2, size.height-2);
                    g.setColor(Color.white);
                    g.drawRect(1,1,size.width, size.height);
                  g.drawRect(2,2,size.width-2, size.height-2);
              }
          }
   
          public void addActionListener(ActionListener listener)
          {
                actionListener = AWTEventMulticaster.add(actionListener, listener);
            enableEvents(AWTEvent.MOUSE_EVENT_MASK);
          }

      public void removeActionListener(ActionListener listener)
      {
            actionListener = AWTEventMulticaster.remove(actionListener, listener);
         }

      public void setActionCommand(String command)
      {
            actionCommand = command;
      }

      public String getActionCommand()
      {
            return actionCommand;
      }

          public void processMouseEvent(MouseEvent e)
      {
            switch(e.getID())
            {
                      case MouseEvent.MOUSE_PRESSED:
                        pressed = true;
                        this.repaint();
                        break;
                      case MouseEvent.MOUSE_RELEASED:
                        if(actionListener != null)
                        {
                                 actionListener.actionPerformed(new ActionEvent(
                                     this, ActionEvent.ACTION_PERFORMED, actionCommand));
                        }
                        if (pressed)
                                  pressed = false;
                            this.repaint();
                        break;
                      case MouseEvent.MOUSE_ENTERED:
                            if (pressed)
                              pressed = false;
                        this.repaint();
                        break;
                      case MouseEvent.MOUSE_EXITED:
                        if (!pressed)
                                  pressed = true;
                        this.repaint();
                        break;
             }
             super.processMouseEvent(e);
         }
}



0
imladrisCommented:
Sorry, I appear to have been a bit too quick off the mark. I thought the setBackground call would floodfill the component with the specified colour. But closer inspection indicates that it is the update method that does that with a fillRect call. And you have correctly overridden the update method.

As for the repeating, the paint method in KeyButton is calling super.setBackground. And the setBackground method in Multilinelabel is calling repaint, which will (shortly) cause paint to be called again etc. etc.

setBackground and -Foreground should not call repaint. In fact there is no apparent need for them to be overridden at all. A call to setBackground will eventually bubble up the inheritance hierarchy far enough for the right thing to occur quite on its own.

0
bjgAuthor Commented:
Well, I took out the overridden setForeground and setBackground methods, and that has helped a little, but I am still having the problem where when I call mouseEntered() and I want the button to be raised, and then call mouseExited() and want the button to be sunken, it is not processing correctly.  The button's state initially is set to pressed, which makes the button appear pressed or sunken.  When the mouse enters over the button, the button's state is set to not pressed and I repaint(), and when the mouse exits the button, it's state is set to pressed and I repaint again.  Same goes true for mousePressed and mouseReleased.  But once I perform any of these actions, the button stays in the not pressed state.  Why is this happening?
0
imladrisCommented:
Sorry, I don't see the answer to that one. Your logic seems reasonably enough. When MOUSE_EXITED occurs the pressed variable will always be made true, and then a repaint is requested. This should cause paint to be executed with the press variable still in the true state. The only thing I can suggest here is to emit a print trail (with System.out.println or some such thing) to verify the execution path and variable states.

0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Java

From novice to tech pro — start learning today.