Easy to Learn Java: Programming Articles, Examples and Tips

Start with Java in a few days with Java Lessons or Lectures

Home

Code Examples

Java Tools

More Java Tools!

Java Forum

All Java Tips

Books

Submit News
Search the site here...
Search...
 

Swing Chapter 15. (Advanced topics) Layered Panes and custom MDI. Easy for reading, Click here!

Custom Search
Swing Chapter 15. (Advanced topics) Layered Panes and custom MDI. Easy for reading, Click here!

[ Return to Swing (Book) ]

Page: 4/7 



Previous Page Previous Page (3/7) - Next Page (5/7) Next Page
Subpages: 1. JLayeredPane 
2.
Using JLayeredPane to enhance interfaces 
3.
Creating a custom MDI: part I - Dragging panels 
4. Creating a custom MDI: part II - Resizability 
5. Creating a custom MDI: part III - Enhancements 
6. Creating a custom MDI: part IV - Selection and management 
7. Creating a custom MDI: part V - JavaBeans compliance 

15.4  Creating a custom MDI: part II - Resizability

In this stage, four distinct components are added to InnerFrame's NORTH, SOUTH, EAST, and WEST regions. Each of these components, defined by the NorthResizeEdge, SouthResizeEdge, EastResizeEdge, and WestResizeEdge inner classes respectively, provide the functionality needed to allow proper resizing in all directions. The title bar and content panel of InnerFrame are now wrapped inside another panel that is placed in InnerFrame's CENTER region. Additionaly, we add a label containing an icon to the WEST region of the title bar, and allow dynamic title bar height based on the size of the icon used.

Figure 15.6. Custom MDI: part II with default icon

<<file figure15-6.gif>>

Figure 15.7. Custom MDI: part II with large icon

<<file figure15-7.gif>>

The Code: InnerFrame.java

see \Chapter15\3\mdi

package mdi;

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

import javax.swing.event.*;

import javax.swing.border.EmptyBorder;

public class InnerFrame

extends JPanel

{

  // Unchanged code

  private static ImageIcon DEFAULT_FRAME_ICON =

    new ImageIcon(IMAGE_DIR+"default.gif");

  private static int BORDER_THICKNESS = 4;

  private static int WIDTH = 200;

  private static int HEIGHT = 200;

  private static int TITLE_BAR_HEIGHT = 25;

  private static int FRAME_ICON_PADDING = 2;

  private static int ICONIZED_WIDTH = 150;

  private static Color TITLE_BAR_BG_COLOR =

    new Color(108,190,116);

  private static Color BORDER_COLOR = new Color(8,90,16);

  private int m_titleBarHeight = TITLE_BAR_HEIGHT;

  private int m_width = WIDTH;

  private int m_height = HEIGHT;

  private int m_iconizedWidth = ICONIZED_WIDTH;

  private String m_title;

  private JLabel m_titleLabel;

  private JLabel m_iconLabel;

  private boolean m_iconified;

  private boolean m_iconizeable;

  private boolean m_resizeable;

  private boolean m_closeable;

  // used to wrap title bar and contentPanel

  private JPanel m_frameContentPanel;

  private JPanel m_titlePanel;

  private JPanel m_contentPanel;

  private JPanel m_buttonPanel;

  private JPanel m_buttonWrapperPanel;

  private InnerFrameButton m_iconize;

  private InnerFrameButton m_close;

  private ImageIcon m_frameIcon = DEFAULT_FRAME_ICON;

  private NorthResizeEdge m_northResizer;

  private SouthResizeEdge m_southResizer;

  private EastResizeEdge m_eastResizer;

  private WestResizeEdge m_westResizer;

  public InnerFrame() {

    this("");

  }

  public InnerFrame(String title) {

    this(title, null);

  }

  public InnerFrame(String title, ImageIcon frameIcon) {

    this(title, frameIcon, true, true, true);

  }

  public InnerFrame(String title, ImageIcon frameIcon,

   boolean resizeable, boolean iconizeable, boolean closeable) {

    super.setLayout(new BorderLayout());

    attachNorthResizeEdge();

    attachSouthResizeEdge();

    attachEastResizeEdge();

    attachWestResizeEdge();

    populateInnerFrame();

    setTitle(title);

    setResizeable(resizeable);

    setIconizeable(iconizeable);

    setCloseable(closeable);

    if (frameIcon != null)

      setFrameIcon(frameIcon);

  }

  protected void populateInnerFrame() {

    m_frameContentPanel = new JPanel();

    m_frameContentPanel.setLayout(new BorderLayout());

    createTitleBar();

    m_contentPanel = new JPanel();

    m_frameContentPanel.add(m_titlePanel, BorderLayout.NORTH);

    m_frameContentPanel.add(m_contentPanel, BorderLayout.CENTER);

    super.add(m_frameContentPanel, BorderLayout.CENTER);

  }

  public Component add(Component c) {

    return((m_contentPanel == null)

      ? null : m_contentPanel.add(c));

  }

  public void setLayout(LayoutManager mgr) {

    if (m_contentPanel != null)

      m_contentPanel.setLayout(mgr);

  }

  // Unchanged code

  public boolean isIconizeable() {

    return m_iconizeable;

  }

  public void setIconizeable(boolean b) {

    m_iconizeable = b;

    m_iconize.setVisible(b);

    m_titlePanel.revalidate();

  }

  public boolean isCloseable() {

    return m_closeable;

  }

  public void setCloseable(boolean b) {

    m_closeable = b;

    m_close.setVisible(b);

    m_titlePanel.revalidate();

  }

  public boolean isIconified() {

    return m_iconified;

  }

  public void setIconified(boolean b) {

    m_iconified = b;

    if (b) {

      m_width = getWidth();     // remember width

      m_height = getHeight();   // remember height

      setBounds(getX(), getY(), ICONIZED_WIDTH,

        m_titleBarHeight + 2*BORDER_THICKNESS);

      m_iconize.setIcon(RESTORE_BUTTON_ICON);

      m_iconize.setPressedIcon(PRESS_RESTORE_BUTTON_ICON);

      setResizeable(false);

    }

    else {

      setBounds(getX(), getY(), m_width, m_height);

      m_iconize.setIcon(ICONIZE_BUTTON_ICON);

      m_iconize.setPressedIcon(PRESS_ICONIZE_BUTTON_ICON);

      setResizeable(true);

    }

    revalidate();

  }

  ////////////////////////////////////////////

  //////////////// Title Bar /////////////////

  ////////////////////////////////////////////

  public void setFrameIcon(ImageIcon fi) {

    m_frameIcon = fi;

    if (fi != null) {

      if (m_frameIcon.getIconHeight() > TITLE_BAR_HEIGHT)

        setTitleBarHeight(

          m_frameIcon.getIconHeight() + 2*FRAME_ICON_PADDING);

      m_iconLabel.setIcon(m_frameIcon);

    }

    else setTitleBarHeight(TITLE_BAR_HEIGHT);

    revalidate();

  }

  public ImageIcon getFrameIcon() {

    return m_frameIcon;

  }

  public void setTitle(String s) {

    m_title = s;

    m_titleLabel.setText(s);

    m_titlePanel.repaint();

  }

  public String getTitle() {

    return m_title;

  }

  public void setTitleBarHeight(int h) {

    m_titleBarHeight = h;

  }

  public int getTitleBarHeight() {

    return m_titleBarHeight;

  }

  // create the title bar: m_titlePanel

  protected void createTitleBar() {

    m_titlePanel = new JPanel() {

      public Dimension getPreferredSize() {

        return new Dimension(InnerFrame.this.getWidth(),

          m_titleBarHeight);

      }

    };

    m_titlePanel.setLayout(new BorderLayout());

    m_titlePanel.setOpaque(true);

    m_titlePanel.setBackground(TITLE_BAR_BG_COLOR);

    m_titleLabel = new JLabel();

    m_titleLabel.setForeground(Color.black);

    // Unchanged code

    m_iconLabel = new JLabel();

    m_iconLabel.setBorder(new EmptyBorder(

      FRAME_ICON_PADDING, FRAME_ICON_PADDING,

      FRAME_ICON_PADDING, FRAME_ICON_PADDING));

    if (m_frameIcon != null)

      m_iconLabel.setIcon(m_frameIcon);

    m_titlePanel.add(m_titleLabel, BorderLayout.CENTER);

    m_titlePanel.add(m_buttonWrapperPanel, BorderLayout.EAST);

    m_titlePanel.add(m_iconLabel, BorderLayout.WEST);

    InnerFrameTitleBarMouseAdapter iftbma =

      new InnerFrameTitleBarMouseAdapter(this);

    m_titlePanel.addMouseListener(iftbma);

    m_titlePanel.addMouseMotionListener(iftbma);

  }

  // Unchanged code

  ///////////////////////////////////////////////

  //////////////// Resizability /////////////////

  ///////////////////////////////////////////////

  public boolean isResizeable() {

    return m_resizeable;

  }

  public void setResizeable(boolean b) {

    if (!b && m_resizeable == true) {

      m_northResizer.removeMouseListener(m_northResizer);

      m_northResizer.removeMouseMotionListener(m_northResizer);

      m_southResizer.removeMouseListener(m_southResizer);

      m_southResizer.removeMouseMotionListener(m_southResizer);

      m_eastResizer.removeMouseListener(m_eastResizer);

      m_eastResizer.removeMouseMotionListener(m_eastResizer);

      m_westResizer.removeMouseListener(m_westResizer);

      m_westResizer.removeMouseMotionListener(m_westResizer);

    }

    else if (m_resizeable == false) {

      m_northResizer.addMouseListener(m_northResizer);

      m_northResizer.addMouseMotionListener(m_northResizer);

      m_southResizer.addMouseListener(m_southResizer);

      m_southResizer.addMouseMotionListener(m_southResizer);

      m_eastResizer.addMouseListener(m_eastResizer);

      m_eastResizer.addMouseMotionListener(m_eastResizer);

      m_westResizer.addMouseListener(m_westResizer);

      m_westResizer.addMouseMotionListener(m_westResizer);

    }

    m_resizeable = b;

  }

  protected void attachNorthResizeEdge() {

    m_northResizer = new NorthResizeEdge(this);

    super.add(m_northResizer, BorderLayout.NORTH);

  }

  protected void attachSouthResizeEdge() {

    m_southResizer = new SouthResizeEdge(this);

    super.add(m_southResizer, BorderLayout.SOUTH);

  }

  protected void attachEastResizeEdge() {

    m_eastResizer = new EastResizeEdge(this);

    super.add(m_eastResizer, BorderLayout.EAST);

  }

  protected void attachWestResizeEdge() {

    m_westResizer = new WestResizeEdge(this);

    super.add(m_westResizer, BorderLayout.WEST);

  }

  class EastResizeEdge extends JPanel

  implements MouseListener, MouseMotionListener {

    private int WIDTH = BORDER_THICKNESS;

    private int MIN_WIDTH = ICONIZED_WIDTH;

    private boolean m_dragging;

    private JComponent m_resizeComponent;

    protected EastResizeEdge(JComponent c) {

      m_resizeComponent = c;

      setOpaque(true);

      setBackground(BORDER_COLOR);

    }

    public Dimension getPreferredSize() {

      return new Dimension(WIDTH, m_resizeComponent.getHeight());

    }

    public void mouseClicked(MouseEvent e) {}

    public void mouseMoved(MouseEvent e) {}

    public void mouseReleased(MouseEvent e) {

      m_dragging = false;

    }

    public void mouseDragged(MouseEvent e) {

      if (m_resizeComponent.getWidth() + e.getX() >= MIN_WIDTH)

        m_resizeComponent.setBounds(m_resizeComponent.getX(),

          m_resizeComponent.getY(),

          m_resizeComponent.getWidth() + e.getX(),

          m_resizeComponent.getHeight());

      else

        m_resizeComponent.setBounds(m_resizeComponent.getX(),

          m_resizeComponent.getY(),

          MIN_WIDTH, m_resizeComponent.getHeight());

      m_resizeComponent.validate();

    }

    public void mouseEntered(MouseEvent e) {

      if (!m_dragging)

        setCursor(Cursor.getPredefinedCursor(

          Cursor.E_RESIZE_CURSOR));

    }

    public void mouseExited(MouseEvent e) {

      if (!m_dragging)

        setCursor(Cursor.getPredefinedCursor(

          Cursor.DEFAULT_CURSOR));

    }

    public void mousePressed(MouseEvent e) {

      toFront();

      m_dragging = true;

    } 

  }

  class WestResizeEdge extends JPanel

  implements MouseListener, MouseMotionListener {

    private int WIDTH = BORDER_THICKNESS;

    private int MIN_WIDTH = ICONIZED_WIDTH;

    private int m_dragX, m_rightX;

    private boolean m_dragging;

    private JComponent m_resizeComponent;

    protected WestResizeEdge(JComponent c) {

      m_resizeComponent = c;

      setOpaque(true);

      setBackground(BORDER_COLOR);

    }

    public Dimension getPreferredSize() {

      return new Dimension(WIDTH, m_resizeComponent.getHeight());

    }

    public void mouseClicked(MouseEvent e) {}

    public void mouseMoved(MouseEvent e) {}

    public void mouseReleased(MouseEvent e) {

      m_dragging = false;

    }

    public void mouseDragged(MouseEvent e) {

      if (m_resizeComponent.getWidth()-

       (e.getX()-m_dragX) >= MIN_WIDTH)

        m_resizeComponent.setBounds(

          m_resizeComponent.getX() + (e.getX()-m_dragX),

          m_resizeComponent.getY(),

          m_resizeComponent.getWidth()-(e.getX()-m_dragX),

          m_resizeComponent.getHeight());

      else

        if (m_resizeComponent.getX() + MIN_WIDTH < m_rightX)

          m_resizeComponent.setBounds(m_rightX-MIN_WIDTH,

            m_resizeComponent.getY(),

            MIN_WIDTH, m_resizeComponent.getHeight());

        else

          m_resizeComponent.setBounds(m_resizeComponent.getX(),

            m_resizeComponent.getY(),

            MIN_WIDTH, m_resizeComponent.getHeight());

      m_resizeComponent.validate();

    }

    public void mouseEntered(MouseEvent e) {

      if (!m_dragging)

        setCursor(Cursor.getPredefinedCursor(

          Cursor.W_RESIZE_CURSOR));

    }

    public void mouseExited(MouseEvent e) {

      if (!m_dragging)

        setCursor(Cursor.getPredefinedCursor(

          Cursor.DEFAULT_CURSOR));

    }

    public void mousePressed(MouseEvent e) {

      toFront();

      m_rightX = m_resizeComponent.getX() +

        m_resizeComponent.getWidth();

      m_dragging = true;

      m_dragX = e.getX();

    } 

  }

  class NorthResizeEdge extends JPanel

  implements MouseListener, MouseMotionListener {

    private static final int NORTH = 0;

    private static final int NORTHEAST = 1;

    private static final int NORTHWEST = 2;

    private int CORNER = 10;

    private int HEIGHT = BORDER_THICKNESS;

    private int MIN_WIDTH = ICONIZED_WIDTH;

    private int MIN_HEIGHT = TITLE_BAR_HEIGHT+(2*HEIGHT);

    private int m_width, m_dragX, m_dragY, m_rightX, m_lowerY;

    private boolean m_dragging;

    private JComponent m_resizeComponent;

    private int m_mode;

    protected NorthResizeEdge(JComponent c) {

      m_resizeComponent = c;

      setOpaque(true);

      setBackground(BORDER_COLOR);

    }

    public Dimension getPreferredSize() {

      return new Dimension(m_resizeComponent.getWidth(), HEIGHT);

    }

    public void mouseClicked(MouseEvent e) {}

    public void mouseMoved(MouseEvent e) {

      if (!m_dragging) {

        if (e.getX() < CORNER) {

          setCursor(Cursor.getPredefinedCursor(

            Cursor.NW_RESIZE_CURSOR));

        }

        else if(e.getX() > getWidth()-CORNER) {

          setCursor(Cursor.getPredefinedCursor(

            Cursor.NE_RESIZE_CURSOR));

        }

        else {

          setCursor(Cursor.getPredefinedCursor(

            Cursor.N_RESIZE_CURSOR));

        }

      }

    }

    public void mouseReleased(MouseEvent e) {

      m_dragging = false;

    }

    public void mouseDragged(MouseEvent e) {

      int h = m_resizeComponent.getHeight();

      int w = m_resizeComponent.getWidth();

      int x = m_resizeComponent.getX();

      int y = m_resizeComponent.getY();

      int ex = e.getX();

      int ey = e.getY();

      switch (m_mode) {

        case NORTH:

          if (h-(ey-m_dragY) >= MIN_HEIGHT)

            m_resizeComponent.setBounds(x, y + (ey-m_dragY),

              w, h-(ey-m_dragY));

          else

              m_resizeComponent.setBounds(x,

                m_lowerY-MIN_HEIGHT, w, MIN_HEIGHT);

          break;

        case NORTHEAST:

          if (h-(ey-m_dragY) >= MIN_HEIGHT

          && w + (ex-(getWidth()-CORNER)) >= MIN_WIDTH)

            m_resizeComponent.setBounds(x,

              y + (ey-m_dragY), w + (ex-(getWidth()-CORNER)),

                h-(ey-m_dragY));

          else if (h-(ey-m_dragY) >= MIN_HEIGHT

          && !(w + (ex-(getWidth()-CORNER)) >= MIN_WIDTH))

            m_resizeComponent.setBounds(x,

              y + (ey-m_dragY), MIN_WIDTH, h-(ey-m_dragY));

          else if (!(h-(ey-m_dragY) >= MIN_HEIGHT)

          && w + (ex-(getWidth()-CORNER)) >= MIN_WIDTH)

            m_resizeComponent.setBounds(x,

              m_lowerY-MIN_HEIGHT, w + (ex-(getWidth()-CORNER)),

                MIN_HEIGHT);

          else

            m_resizeComponent.setBounds(x,

              m_lowerY-MIN_HEIGHT, MIN_WIDTH, MIN_HEIGHT);

          break;

        case NORTHWEST:

          if (h-(ey-m_dragY) >= MIN_HEIGHT

          && w-(ex-m_dragX) >= MIN_WIDTH)

            m_resizeComponent.setBounds(x + (ex-m_dragX),

              y + (ey-m_dragY), w-(ex-m_dragX),

                h-(ey-m_dragY));

          else if (h-(ey-m_dragY) >= MIN_HEIGHT

          && !(w-(ex-m_dragX) >= MIN_WIDTH)) {

            if (x + MIN_WIDTH < m_rightX)

              m_resizeComponent.setBounds(m_rightX-MIN_WIDTH,

                y + (ey-m_dragY), MIN_WIDTH, h-(ey-m_dragY));

            else

              m_resizeComponent.setBounds(x,

                y + (ey-m_dragY), w, h-(ey-m_dragY));

          }

          else if (!(h-(ey-m_dragY) >= MIN_HEIGHT)

          && w-(ex-m_dragX) >= MIN_WIDTH)

            m_resizeComponent.setBounds(x + (ex-m_dragX),

              m_lowerY-MIN_HEIGHT, w-(ex-m_dragX), MIN_HEIGHT);

          else

            m_resizeComponent.setBounds(m_rightX-MIN_WIDTH,

              m_lowerY-MIN_HEIGHT, MIN_WIDTH, MIN_HEIGHT);

          break;

      }

      m_rightX = x + w;

      m_resizeComponent.validate();

    }

    public void mouseEntered(MouseEvent e) {

      mouseMoved(e);

    }

    public void mouseExited(MouseEvent e) {

      if (!m_dragging)

        setCursor(Cursor.getPredefinedCursor(

          Cursor.DEFAULT_CURSOR));

    }

    public void mousePressed(MouseEvent e) {

      toFront();

      m_dragging = true;

      m_dragX = e.getX();

      m_dragY = e.getY();

      m_lowerY = m_resizeComponent.getY()

        + m_resizeComponent.getHeight();

      if (e.getX() < CORNER) {

        m_mode = NORTHWEST;

      }

      else if(e.getX() > getWidth()-CORNER) {

        m_mode = NORTHEAST;

      }

      else {

        m_mode = NORTH;    

      }

    } 

  }

  class SouthResizeEdge extends JPanel

  implements MouseListener, MouseMotionListener {

    private static final int SOUTH = 0;

    private static final int SOUTHEAST = 1;

    private static final int SOUTHWEST = 2;

    private int CORNER = 10;

    private int HEIGHT = BORDER_THICKNESS;

    private int MIN_WIDTH = ICONIZED_WIDTH;

    private int MIN_HEIGHT = TITLE_BAR_HEIGHT+(2*HEIGHT);

    private int m_width, m_dragX, m_dragY, m_rightX;

    private boolean m_dragging;

    private JComponent m_resizeComponent;

    private int m_mode;

    protected SouthResizeEdge(JComponent c) {

      m_resizeComponent = c;

      setOpaque(true);

      setBackground(BORDER_COLOR);

    }

    public Dimension getPreferredSize() {

      return new Dimension(m_resizeComponent.getWidth(), HEIGHT);

    }

    public void mouseClicked(MouseEvent e) {}

    public void mouseMoved(MouseEvent e) {

      if (!m_dragging) {

        if (e.getX() < CORNER) {

          setCursor(Cursor.getPredefinedCursor(

            Cursor.SW_RESIZE_CURSOR));

        }

        else if(e.getX() > getWidth()-CORNER) {

          setCursor(Cursor.getPredefinedCursor(

            Cursor.SE_RESIZE_CURSOR));

        }

        else {

          setCursor(Cursor.getPredefinedCursor(

            Cursor.S_RESIZE_CURSOR));

        }

      }

    }

    public void mouseReleased(MouseEvent e) {

      m_dragging = false;

    }

    public void mouseDragged(MouseEvent e) {

      int h = m_resizeComponent.getHeight();

      int w = m_resizeComponent.getWidth();

      int x = m_resizeComponent.getX();

      int y = m_resizeComponent.getY();

      int ex = e.getX();

      int ey = e.getY();

      switch (m_mode) {

        case SOUTH:

          if (h+(ey-m_dragY) >= MIN_HEIGHT)

           m_resizeComponent.setBounds(x, y, w, h+(ey-m_dragY));

          else

            m_resizeComponent.setBounds(x, y, w, MIN_HEIGHT);

          break;

        case SOUTHEAST:

          if (h+(ey-m_dragY) >= MIN_HEIGHT

            && w + (ex-(getWidth()-CORNER)) >= MIN_WIDTH)

            m_resizeComponent.setBounds(x, y,

              w + (ex-(getWidth()-CORNER)), h+(ey-m_dragY));

          else if (h+(ey-m_dragY) >= MIN_HEIGHT

            && !(w + (ex-(getWidth()-CORNER)) >= MIN_WIDTH))

            m_resizeComponent.setBounds(x, y,

              MIN_WIDTH, h+(ey-m_dragY));

          else if (!(h+(ey-m_dragY) >= MIN_HEIGHT)

            && w + (ex-(getWidth()-CORNER)) >= MIN_WIDTH)

            m_resizeComponent.setBounds(x, y,

              w + (ex-(getWidth()-CORNER)), MIN_HEIGHT);

          else

            m_resizeComponent.setBounds(x,

              y, MIN_WIDTH, MIN_HEIGHT);

          break;

        case SOUTHWEST:

          if (h+(ey-m_dragY) >= MIN_HEIGHT

            && w-(ex-m_dragX) >= MIN_WIDTH)

            m_resizeComponent.setBounds(x + (ex-m_dragX), y,

              w-(ex-m_dragX), h+(ey-m_dragY));

          else if (h+(ey-m_dragY) >= MIN_HEIGHT

            && !(w-(ex-m_dragX) >= MIN_WIDTH)) {

            if (x + MIN_WIDTH < m_rightX)

              m_resizeComponent.setBounds(m_rightX-MIN_WIDTH, y,

                MIN_WIDTH, h+(ey-m_dragY));

            else

              m_resizeComponent.setBounds(x, y, w,

                h+(ey-m_dragY));

          }

          else if (!(h+(ey-m_dragY) >= MIN_HEIGHT)

            && w-(ex-m_dragX) >= MIN_WIDTH)

            m_resizeComponent.setBounds(x + (ex-m_dragX), y,

              w-(ex-m_dragX), MIN_HEIGHT);

          else

            m_resizeComponent.setBounds(m_rightX-MIN_WIDTH,

              y, MIN_WIDTH, MIN_HEIGHT);

          break;

      }

      m_rightX = x + w;

      m_resizeComponent.validate();

    }

    public void mouseEntered(MouseEvent e) {

      mouseMoved(e);

    }

    public void mouseExited(MouseEvent e) {

      if (!m_dragging)

        setCursor(Cursor.getPredefinedCursor(

          Cursor.DEFAULT_CURSOR));

    }

    public void mousePressed(MouseEvent e) {

      toFront();

      m_dragging = true;

      m_dragX = e.getX();

      m_dragY = e.getY();

      if (e.getX() < CORNER) {

        m_mode = SOUTHWEST;

      }

      else if(e.getX() > getWidth()-CORNER) {

        m_mode = SOUTHEAST;

      }

      else {

        m_mode = SOUTH;    

      }

    } 

  }

}

Understanding The Code:

Class InnerFrame

New class variables:

ImageIcon DEFAULT_FRAME_ICON: default image used for the frame icon =

int BORDER_THICKNESS: default thickness of resize edges (borders).

int FRAME_ICON_PADDING: default thickness of padding around the title bar icon label.

int ICONIZED_WIDTH: default width in the iconified state.

Color BORDER_COLOR: default resize border background color.

New instance variables:

int m_titleBarHeight: title bar height.

int m_width: used for recalling the frame's previous width when deiconifying.

int m_height: used for recalling the frame's previous height when deiconifying.

int m_iconizedWidth: frame width in the iconified state.

JLabel m_iconLabel: label used to display the frame icon in the title bar.

boolean m_iconizeable: determines whether the frame can be iconified.

boolean m_resizeable: determines whether the frame is resizable.

boolean m_closeable: determines whether the frame is closeable.

JPanel m_frameContentPanel: used to wrap the title bar and contentPanel for placement in InnerFrame's CENTER region.

ImageIcon m_frameIcon: the frame icon displayed by m_iconLabel in the title bar.

NorthResizeEdge m_northResizer: Used for north, northeast, and northwest resizing.

SouthResizeEdge m_southResizer: Used for south, southeast, and southwest resizing,

EastResizeEdge m_eastResizer: Used for east resizing.

WestResizeEdge m_westResizer: Used for west reszing.

There are noew four InnerFrame constructors. The first creates an InnerFrame with no title and default frame icon. The second creates an InnerFrame with a title and default icon, and the third creates one with both a title and a specified frame icon. The first three constructors all end up calling the fourth to do the actual work.

The fourth InnerFrame constructor calls four methods to attach our custom resize components to its edges. Then our populateInnerFrame() method is called which is responsible for encapsulating the title bar and content panel in m_frameContentPanel, which is then added to the CENTER of InnerFrame. The constructor ends by calling methods to set the title, frame icon, and resizeable, iconizeable, and closeable properties (discussed below).

The add() and setLayout() methods of JComponent are overridden to perform these actions on the content panel contained inside m_frameContentPanel. Thus, anything we add to InnerFrame will be placed in m_contentPanel, and any layout we assign to InnerFrame will actually be assigned to m_contentPanel.

Note: This functionality is not on par with fundamental Swing containers such as JFrame, and JInternalFrame which use a JRootPane to manage their contents. We will fix this in the next section by implementing the RootPaneContainer interface.

The setIconizeable() and setCloseable() methods set their respective properties and hide or show the corresponding title bar buttons using setVisible(). We call revalidate() to perform any layout changes that may be necessary after a button is shown or hidden.

The setIconified() method is modified store the width and height of InnerFrame before it is iconified. The size of an iconified InnerFrame is now determined by the title bar height, which is in turn determined by the frame icon size, and the thickness of the resize edges:

      setBounds(getX(), getY(), ICONIZED_WIDTH,

        m_titleBarHeight + 2*BORDER_THICKNESS);

Whenever an iconification occurs we call setResizable(false) to remove mouse listeners from each resize edge. If a deiconification occurs we call setResizable(true) to add mouse listeners back to each resize edge. Also, the width and height saved in an iconification is used to set the size of InnerFrame when it is deiconified.

The title bar code has several methods added to it. setFrameIcon() is responsible for replacing the icon in the title bar icon label, m_iconLabel, and calculating the new title bar height based on this change:

  public void setFrameIcon(ImageIcon fi) {

    m_frameIcon = fi;

    if (fi != null) {

      if (m_frameIcon.getIconHeight() > TITLE_BAR_HEIGHT)

        setTitleBarHeight(m_frameIcon.getIconHeight()

          + 2*FRAME_ICON_PADDING);

      m_iconLabel.setIcon(m_frameIcon);

    }

    else setTitleBarHeight(TITLE_BAR_HEIGHT);

    revalidate();

  }

The title bar height will never be smaller than TITLE_BAR_HEIGHT (25). If the icon's height is greater than this default value the title bar height will then be based on that icon's height, plus the default icon padding, FRAME_ICON_PADDING, above and below the icon. This is necessary because when the frame icon is added to the title bar within our createTitleBar() method, it is placed in a JLabel surrounded by an EmptyBorder as follows:

    m_iconLabel.setBorder(new EmptyBorder(

      FRAME_ICON_PADDING, FRAME_ICON_PADDING,

      FRAME_ICON_PADDING, FRAME_ICON_PADDING));

This label is then added to the WEST region of m_titlePanel (the title bar).

The custom resize components are the key to making InnerFrame resizable. They are built as inner classes inside InnerFrame and are discussed below. Before we discuss them in detail, it is helpful to clarify InnerFrame's structure. Figure 15.5 illustrates this and shows which cursor will appear when the mouse pointer is placed over different portions of each resize edge (this functionality is something we have come to expect from frames in any modern desktop environment):

Figure 15.5. InnerFrame structure and resize edge cursor regions

<<file figure15-5.gif>>

The Cursor class defines several class fields representing pre-defined cursor icons that we use in the resize classes discussed below:

  N_RESIZE_CURSOR, NE_RESIZE_CURSOR, NW_RESIZE_CURSOR, S_RESIZE_CURSOR,

  SE_RESIZE_CURSOR, SW_RESIZE_CURSOR, E_RESIZE_CURSOR, W_RESIZE_CURSOR,

  DEFAULT_CURSOR

Note: Upon first inspection you might think it would be easier to implement your own border and build resizable functionality into that. The problem is that borders are not part of the Component hierarchy. That is, they do not inherit from the Component class. In fact, every border is a subclass of AbstractBorder which is a direct subclass of Object. There is no way to associate mouse events with a border.

Class InnerFrame.EastResizeEdge

EastResizeEdge is the component that is placed in the east portion of InnerFrame's BorderLayout. This component allows resizing InnerFrame horizontally. This is the simplest of the four edges because when it is used to resize, InnerFrame always stays in the same location (defined by its northwest corner) and the height doesn't change. Two class variables and two instance variables are necessary:

int WIDTH: constant thickness.

int MIN_WIDTH: minimum width of m_resizeComponent.

boolean m_dragging: true when dragging.

JComponent m_resizeComponent: the component to resize.

The constructor, as with all of the resize edge component constructors, takes a JComponent as a parameter. This JComponent is the component that is resized whenever the edge detects a mouse drag event. The setPreferredSize() method ensures that our edges will have a constant thickness.

Note: We have designed these components to be significantly generic, while still being encapsulated as inner classes. They can easily be modified for use within other classes or as stand-alone resizable utility components. In the next chapter we create a package called resize which contains each of these classes as separate entities that can be wrapped around any JComponent. See section 16.4. (For the resize package source code, refer to \Chapter16\2\resize.)

The mouseEntered() method is used to detect whenever the cursor is over this edge. When invoked it changes the cursor to E_RESIZE_CURSOR. The mouseExited() method changes the cursor back to the normal DEFAULT_CURSOR when the mouse leaves this component. In both methods cursor changes only occur when the m_dragging flag is false  (i.e. when the border is not being dragged). We do not want the cursor to change while we are resizing.

The mousePressed() method sets the m_dragging flag and moves the component associated with this resize edge to the foremost position in its JLayeredPane layer (in other words it calls toFront()). The mouseDragged method actually handles the resizing and defines two cases to ensure that m_resizeComponent's width is never made smaller than MIN_WIDTH.

Class InnerFrame.WestResizeEdge

WestResizeEdge works very similar to EastResizeEdge except that it must handle an extra case in resizing because the position, as well as width, of m_resizeComponent changes. An extra variable, m_rightX, is used to keep track of the coordinate of the northeast corner of m_resizeComponent to ensure that the right side of  m_resizeComponent never moves during a resize.

Class InnerFrame.NorthResizeEdge, InnerFrame.SouthResizeEdge

NorthResizeEdge and SouthResizeEdge are very complicated because there are three regions in each. The left-most and right-most portions are reserved for resizing in the northwest, southwest, and northeast, southeast directions. The most complicated cases are resizing from the northwest and southwest corners because the height, width, as well as both the x and y coordinates of m_resizeComponent can change. Thus, the mouseDragged method in each of these classes is quite extensive.

Note: You are encouraged to work through this code and understand each case. We will not explain it in detail because of its repetitive and mathematical nature.

After each mouse drag, validate()is called on m_resizeComponent to lay out its contents again. If we did not include this we would see that as we resized an InnerFrame the size change and rendering of its contents would not occur properly. (Try this by commenting out these lines in each of the resize edge classes.) Validation forces the container to lay out its contents based on the current size. Normally we would call revalidate() rather than validate() for  the sake thread safety. However, there are often performance bottlenecks associated with revalidate() when performing fast resizes because these requests get forwarded, queued, and coalesced by the RepaintManager service (see chapter 2 for more about validation and painting). By making the direct call to validate() we ensure that the layout will be performed immediately, and with rapid resizing this does make a difference.

Running The Code

Figure 15.6 shows LayeredPaneDemo in action. First try resizing frames from all directions to see that this works as expected. Now try replacing the frame icon with one of a different size (you can use the tiger.gif image included in this example's directory). You will see that the title bar and the minimum height of our frames changes accordingly. Figure 15.7 shows our InnerFrames with a much larger frame icon.



[ Return to Swing (Book) ]


Top 10 read Java Articles
 Get free "1000 Java Tips eBook"

 Java Calendar and Date: good to know facts and code examples

 Array vs ArrayList vs LinkedList vs Vector: an excellent overview and examples

 How can I convert any Java Object into byte array? And byte array to file object

 The Java Lesson 1: What is Java?

 How do I compare two dates and times, date between dates, time between times and

 Maven vs Ant or Ant vs Maven?

 How to open, read, write, close file(s) in Java? Examples on move, rename and de

 Java Array

 Java: JLabel font and color


[ More in News Section ]
Java Lessons

The Java Lesson 1:
What is Java?
The Java Lesson 2:
Anatomy of a simple Java program
The Java Lesson 3:
Identifiers and primitive data types
The Java Lesson 4:
Variables, constants, and literals
The Java Lesson 5:
Arithmetic operations, conversions, and casts
The Java Lesson 6:
Boolean expressions and operations
The Java Lesson 7:
Bitwise operations
The Java Lesson 8:
Flow control with if and else
The Java Lesson 9:
switch statements
The Java Lesson 10:
for, while, and do-while statements
The Java Lesson 11:
Using break and continue
The Java Lesson 12:
Class methods and how they are called
The Java Lesson 13:
Using the Math class
The Java Lesson 14:
Creating and calling custom class methods
The Java Lesson 15:
Overloading class methods
The Java Lesson 16:
An introduction to objects and object references
The Java Lesson 17:
The String class
The Java Lesson 18:
The StringBuffer class
The Java Lesson 19:
Initializing and processing arrays of primitives
The Java Lesson 20:
Initializing and processing arrays of objects
The Java Lesson 23:
Inheritance and overriding inherited methods
The Java Lesson 24:
abstract classes and polymorphism
The Java Lesson 25:
Interfaces, instanceof, and object conversion and casting
The Java Lesson 26:
Introduction to graphical programming and the java.awt packa
The Java Lesson 27:
The Component class
The Java Lesson 28:
Containers and simple layout managers
The Java Lesson 29:
The Color and Font classes
The Java Lesson 30:
Drawing geometric shapes
The Java Lesson 31:
Choice, List, and Checkbox controls
The Java Lesson 32:
Using the Scrollbar graphical control
The Java Lesson 33:
Menus and submenus
The Java Lesson 34:
An introduction to applets and the Applet class
The Java Lesson 35:
Essential HTML to launch an applet and pass it parameters
The Java Lesson 36:
Mouse event processing
Java Lesson 37:
Menus and submenus
Java Lesson 38:
The WindowListener interface and the WindowAdapter class
Java Lesson 39:
An introduction to GridBagLayout
Java Lesson 40:
An introduction to the Java Collections API
Java Lesson 41:
Exception handling with try, catch, and finally blocks
Java Lesson 42:
Claiming and throwing exceptions
Java Lesson 43:
Multithreading, the Thread class, and the Runnable interface
Java Lesson 44:
An introduction to I/O and the File and FileDialog classes
Java Lesson 45:
Low-level and high-level stream classes
Java Lesson 46:
Using the RandomAccessFile class
Java Lessons by
Joh Huhtala: Update

Latest articles
 Java Profiler JProbe to Resolve Performance Problems Faster

 SSL with GlassFish v2, page 5

 SSL with GlassFish v2, page 4

 SSL with GlassFish v2, page 3

 SSL with GlassFish v2, page 2

 The Java Lesson 2: Anatomy of a simple Java program, page 2

 New site about Java for robots and robotics: both software and hardware.

 Exceptions -III: What's an exception and why do I care?

 Exceptions -II: What's an exception and why do I care?

 Exceptions: What's an exception and why do I care?

 Double your Java code quality in 10 minutes, here is receipt

 Murach's Java Servlets and JSP

 How to get ascii code from a char in Java?

 Can we just try without catch? Yes!

 Make Tomcat page load faster

 Make your Tomcat More secure - limit network address for certain IP addresses

 New Java book online starts now here...

 Implementing RESTful Web Services in Java

 Firefox trimming from 1 GB to 40 Mb with many tabs opened

 SSL with GlassFish v2

 My request to replublish Tech Tips

 Search JavaFAQ.nu site here

 New Advanced Installer for Java 6.0 brings XML updates and imports 3rd party MSI

 EJB programming restrictions

 Maven vs Ant or Ant vs Maven?

 Why Java does not use default value which it should?

 How to unsign signed bytes in Java - your guide is here

 The Java Lesson 3: Identifiers and primitive data types. Page 2

 The Java Lesson 7: Bitwise operations with good examples, click here! Page 4

 The Java Lesson 7: Bitwise operations with good examples, click here! Page 3


[ More in News Section ]


Home Code Examples Java Forum All Java Tips Books Submit News, Code... Search... Offshore Software Tech Doodling

RSS feed Java FAQ RSS feed Java FAQ News     

    RSS feed Java Forums RSS feed Java Forums

All logos and trademarks in this site are property of their respective owner. The comments are property of their posters, all the rest 1999-2006 by Java FAQs Daily Tips.

Interactive software released under GNU GPL, Code Credits, Privacy Policy