用Java实现的Status Bar (2/3)- StatusbarBuilder.java

来源:互联网 发布:大魔术师 知乎 编辑:程序博客网 时间:2024/05/16 08:17
相关文章:
  • 关于StatusbarBuilder的说明: 介绍API说明、设计思路以及当前存在的问题。
  • SlightBevelBorder.java :SlightBevelBorder类源代码。
  • StatusbarBuilder.java:StatusbarBuilder类源代码。
  • TestStatusbar.java:测试程序
  • /*===============================================================================

     * StatusbarBuilder.java

     *===============================================================================

     *  This program is free software; you can redistribute it and/or modify

     *  it under the terms of the GNU General Public License as published by

     *  the Free Software Foundation; either version 2 of the License, or

     *  (at your option) any later version.

     * 

     *  This program is distributed in the hope that it will be useful,

     *  but WITHOUT ANY WARRANTY; without even the implied warranty of

     *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

     *  GNU General Public License for more details.

     * 

     *  You should have received a copy of the GNU General Public License

     *  along with this program; if not, write to the Free Software

     *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

     *===============================================================================

     * auth:    Jason

     * CSDN ID:    Unagain

     * Email:    tl21cen@hotmail.com

     * date:    2006-4-11

     *===============================================================================

     */

    package tl.util;

     

    import java.awt.BorderLayout;

    import java.awt.Color;

    import java.awt.Component;

    import java.awt.Cursor;

    import java.awt.Dimension;

    import java.awt.Graphics;

    import java.awt.Point;

    import java.awt.Rectangle;

    import java.awt.Window;

    import java.awt.event.MouseEvent;

    import java.awt.event.WindowAdapter;

    import java.awt.event.WindowEvent;

    import java.util.Hashtable;

     

    import javax.swing.Box;

    import javax.swing.BoxLayout;

    import javax.swing.JComponent;

    import javax.swing.JFrame;

    import javax.swing.JLabel;

    import javax.swing.JPanel;

    import javax.swing.border.AbstractBorder;

    import javax.swing.border.BevelBorder;

    import javax.swing.border.EmptyBorder;

    import javax.swing.event.MouseInputAdapter;

    import javax.swing.text.JTextComponent;

     

    //class StatusBar extends JComponent {

    public class StatusbarBuilder {

        //final static Dimension XGAP = new Dimension(2, 0);

     

        private JPanel bar;

     

        /**

         * matains all instances created, each instance associate

         * with an existing window object.<br>

         * you can create and to obtain a instance using newInstance

         * method with a specified window object.

         */

        private static

        Hashtable<Window, StatusbarBuilder> instances =

           new Hashtable<Window, StatusbarBuilder>();

     

        private Window window;

     

        final public static int PLAIN = 0;

     

        final public static int LOWERED = 1;

     

        /**

         *  @deprecated

         */

        final public static int RAISED = 2;

     

        // for builder

        private static int commonBarStyle = LOWERED;

     

        // for instance

        private AbstractBorder border = null;

     

        // test

        private int style;

     

        /**

         * only two style can be used for the bar, PLAIN or

         * LOWERED. I try to make cell's border to be RAISED

         * earlier, but it looks ugly.

         * <br><i>WARNING: </i>result of this method can only

         * effect the instance created next but not an instance

         * has been created prior. And you also be caution that

         * the effect will be acting for any instance created

         * subsequently until you invoked it again to set other

         * value. <br>

         * call reset method can reset all properties changed to

         *  be default.

         * @param style

         */

        public static void setBarStyle(int style) {

           if (style < PLAIN || style > LOWERED) {

               commonBarStyle = PLAIN;

           } else {

               commonBarStyle = style;

           }

        }

     

        // for builder

        private static Color commonBkColor = null;

        // for instance

        private Color bkColor = null;

     

        /**

         * set background color of bar.

         * <br><i>WARNING: </i>result of this method can only

         * effect the instance created next but not an instance

         * has been created prior. And you also be caution that

         * the effect will be acting for any instance created

         * subsequently until you invoked it again to set other

         * value. <br>

         * call reset method can reset all properties changed to

         *  be default.

         * @param color

         */

        public static void setBackground(Color color) {

            commonBkColor = color;

        }

     

        final static int DEFAULT_HEIGHT = 23;

        private static int commonHeight = 0;

        private int height = 0;

     

        /**

         * set the height of cell in bar

         * <br><i>WARNING: </i>result of this method can only

         * effect the instance created next but not an instance

         * has been created prior. And you also be caution that

         * the effect will be acting for any instance created

         * subsequently until you invoked it again to set other

         * value. <br>

         * call reset method can reset all properties changed to

         *  be default.

         * @param height

         */

        public static void setHeight(int height) {

            commonHeight = height;

        }

     

        final static int DEFAULT_GAP_WIDTH = 2;

        private static int gapWidth = DEFAULT_GAP_WIDTH;

        private int gw = 0;

     

        /**

        * In fact, it is used to set the width of gap.

         * <br><i>WARNING: </i>result of this method can only

         * effect the instance created next but not an instance

         * has been created prior. And you also be caution that

         * the effect will be acting for any instance created

         * subsequently until you invoked it again to set other

         * value. <br>

         * call reset method can reset all properties changed to

         *  be default.

         * @param width

         */

        public static void setGap(int width) {

            gapWidth = width;

        }

       

        private static JComponent commonNotice = null;

        private JComponent notice;

        /**

         * I think perhaps you've got a custom component that

         * can show help message more effective.

         * I hope it can be used on this bar directly.

         * <br><i>WARNING: </i>result of this method can only

         * effect the instance created next but not an instance

         * has been created prior. And you also be caution that

         * the effect will be acting for any instance created

         * subsequently until you invoked it again to set other

         * value. <br>

         * call reset method can reset all properties changed to

         *  be default.

         * @param comp a custom component can show help message.

         */

        public static void setNotice(JComponent comp) {

            commonNotice = comp;

        }

       

        public static void reset() {

            commonBarStyle = LOWERED;

            commonBkColor = null;

            commonHeight = DEFAULT_HEIGHT;

            gapWidth = DEFAULT_GAP_WIDTH;

            commonNotice = null;

        }

       

        /**

         * send a message to bar, so can be appeared in bar.<br>

         * <i>be cauthion</i> that it will do nothing if it is a custom

         * component you applied, and it isn't an instance of JLabel

         * and any other subclass of JTextComponent.

         * @param s a message

         */

        public void notice(String s) {

           if (notice instanceof JLabel) {

               ((JLabel)notice).setText(s);

           } else if (notice instanceof JTextComponent) {

               ((JTextComponent)notice).setText(s);

           }

        }

       

        /**

         * By default, notice cell hasn't border. so this method

         * can be use to set whether notice cell can has a border.

         *  

         * @param style @see @link

         */

        public void setNoticeStyle (int style) {

           if (style == PLAIN) {

               if (border instanceof EmptyBorder) {

                   notice.setBorder(border);

               } else {

                   notice.setBorder(

                      new EmptyBorder(1,1,1,1));

               }

           } else if (style == LOWERED) {

               if (border instanceof BevelBorder) {

                   notice.setBorder(border);

               } else {

                   notice.setBorder(

                      new SlightBevelBorder(BevelBorder.LOWERED));

               }          

           }

        }

     

        /**

         * Create a status bar for the window given. by default, the

         * window use BorderLayout as its layout mananger, and the

         * status bar created will reside on bottom of the window.

         * 

         * @param window

         * @return

         */

        public static StatusbarBuilder getInstance(Window window) {

            return getInstance(window, BorderLayout.PAGE_END);

        }

     

        /**

         * Create a status bar for a window given. User apply 

         * constraints for status to reside in the window.

         *

         * @param window

         * @param constraints

         * @return

         */

        public static StatusbarBuilder getInstance(Window window,

               Object constraints) {

           // get instance from pool.

            StatusbarBuilder instance = instances.get(window);

     

           // create a new instance if there isn't a instance associate

           // the window.

           if (instance == null) {

               instance = new StatusbarBuilder();

     

               // pool the new instance.

               instances.put(window, instance);

     

               window.add(instance.bar, constraints);

               instance.window = window;          

     

               // create a monitor on window, so that statusbar can be

               // released before window wiil be deactivate.

               window.addWindowListener(new WindowAdapter() {

                   public void windowClosed(WindowEvent e) {

                       Window window = e.getWindow();

                       System.out.println(window);

                       StatusbarBuilder inst = instances.get(window);

                       System.out.println(inst);

                      inst = null;

                       instances.remove(window);

                       System.out.println("gfgfff");

                   }

               });

           }

            return instance;

        }

     

        private RBCorner corner;

        /**

         * create a inew instance of status bar. Each status bar created

         * belones to a window specified.

         */

        private StatusbarBuilder() {

           bar = new JPanel();

            bar.setLayout(new BoxLayout(bar, BoxLayout.LINE_AXIS));

            bar.setBorder(new EmptyBorder(2, 0, 1, 1));

     

           // initialize instance variable.

            height = commonHeight == 0 ? DEFAULT_HEIGHT : commonHeight;

     

            bkColor = commonBkColor == null ? bar.getBackground() : commonBkColor;

     

           // prepare border

           style = commonBarStyle;

           if (commonBarStyle == LOWERED) {

               border = new SlightBevelBorder(BevelBorder.LOWERED);

           } else if (commonBarStyle == RAISED) {

               border = new SlightBevelBorder(BevelBorder.RAISED);

           } else {

               border =

               //new LineBorder(bkColor);

               new EmptyBorder(2, 2, 2, 2);

           }

     

           // initialize a gap used for separate cells.

           // gw = gapWidth == 0 ? DEFAULT_GAP_WIDTH : gapWidth;

           gw = gapWidth;

     

            bar.setBackground(bkColor);

            //bar.setMinimumSize(new Dimension(50, height));

            //bar.setMaximumSize(new Dimension(5000, height));      

     

            bar.add(Box.createRigidArea(new Dimension(0, height)));

          

            corner = new RBCorner();

            corner.setBorder(border);

            bar.add(corner);

     

           // At first, it used to show notice such as help message.

           // In addition, it used to fill increased space if bar

           // was stretched.

           if (commonNotice == null) {

               notice = new JLabel();

           } else {

               notice = commonNotice;

           }

            notice.setMinimumSize(new Dimension(50, height));

            notice.setMaximumSize(new Dimension(5000, height));      

     

            //notice.setBorder(border);

            bar.add(notice);

            bar.add(createGap());

        }

     

        // 增加显示格。在添加到Container之前,设置其Border

        /**

         * add a cell to the bar, and its height will be

         * changed to predefined height.

         *

         * @param comp

         */

        public void add(JComponent comp) {

            Dimension minSize = comp.getMinimumSize();

            Dimension prefSize = comp.getPreferredSize();

            Dimension maxSize = comp.getMaximumSize();

     

           add(comp, minSize.width, prefSize.width, maxSize.width);

        }

     

        /**

         * add a cell with a specified solid width.

         *  

         * @param comp

         * @param solidWidth

         */

        public void add(JComponent comp, int solidWidth) {

           add(comp, solidWidth, solidWidth, solidWidth);

        }

     

        /**

         * add a cell with specified minimum width and max width.

         * @param comp

         * @param minWidth

         * @param maxWidth

         */

        public void add(JComponent comp, int minWidth, int maxWidth) {

           add(comp, minWidth, minWidth, maxWidth);

        }

     

        /**

         * add a component to the bar with specified minimum

         * width, preffered width and maximum width.<br>

         * The effect doesn't observable. It seens that width

         * of other cell won't change until notice cell reduced

         * to its minimum size when the window's width reduced.  

         *

         * @param comp

         * @param minWidth

         * @param prefWidth

         * @param maxWidth

         */

        public void add(JComponent comp, int minWidth, int prefWidth, int maxWidth) {

           if (comp != corner) {

               bar.remove(corner);

           }

          

            comp.setBorder(border);

     

            comp.setMinimumSize(new Dimension(minWidth, height));

            comp.setPreferredSize(new Dimension(prefWidth, height));

            comp.setMaximumSize(new Dimension(maxWidth, height));

     

           // 按默认的添加方式,显示格会挤在一起,所以之间填充一个水平的刚性支撑。

            //System.out.println(bar.add(gap));

            //bar.add(gap);

          

            bar.add(comp);

          

            bar.add(createGap());

          

           if (comp != corner) {

               bar.add(corner);

           }      

        }

       

        private Component createGap() {

            Component gap;

           if (gw == 0) {

               gap = Box.createHorizontalStrut(0);

           } else {

               if (commonBarStyle == PLAIN) {

                   gap = new Gap(gw);

               } else {

                   gap = Box.createHorizontalStrut(gw);

               }

           }

            return gap;

        }

     

        private class SolidCell extends JComponent {

           int cellWidth;

     

            SolidCell(int width) {

               super();

               this.cellWidth = width;

           }

     

            public Dimension getMinimumSize() {

               return new Dimension(cellWidth, height);

           }

     

            public Dimension getMaximumSize() {

               return new Dimension(cellWidth, height);

           }

     

            public Dimension getPreferredSize() {

               return new Dimension(cellWidth, height);

           }

        }

     

        class Gap extends SolidCell {

            public Gap(int width) {

               super(width);

           }

     

            public void paint(Graphics g) {

               super.paint(g);

               g.setColor(bkColor.darker());

               g.drawLine(0, 0, 0, height-1);

     

               g.setColor(bkColor.brighter().brighter());

               g.drawLine(1, 0, 1, height-1);

           }

        }

     

        final static int DEFAULT_CORNER_WIDTH = 18;

        /**

         * Do you take notice of that there is a manner of

         * status bar in many other programs, that you can drag

         * the right-bottom corner to resize the window? <br>

         * Okey, I just want to achieve it. I've spent many

         * more hours on it, but it isn't ideal yet.<br>

         * Be it so.

         *  

         * @author Jason

         */

        class RBCorner extends SolidCell {

            Rectangle resizeArea;

            public RBCorner() {

               super(DEFAULT_CORNER_WIDTH);         

               ResizeAdapter mouseAdapter =

                   new ResizeAdapter();

              

               addMouseMotionListener(mouseAdapter);

               addMouseListener(mouseAdapter);

           }

          

           /**

            * this class in response to monitor several mouse

            * events, as response, it changes Cursor when mouse

            * over and leave it, and it can also resize the

            * window that it resides in when you drag it.

            *

            * @author Jason

            */

           class ResizeAdapter

            extends MouseInputAdapter{

               Cursor oldCursor;

               boolean entered;

               boolean holded;

               Point p;

              

               public void mouseDragged(MouseEvent e) {

                   Point p1 = e.getPoint();

                   window.setSize(

                       window.getWidth() + (p1.x - p.x),

                       window.getHeight() + (p1.y - p.y)

                      );

                   p = p1;

               }

               public void mousePressed(MouseEvent e) {

                   p = e.getPoint();

                   holded = true;

               }

               public void mouseReleased(MouseEvent e) {

                   p = null;

                   holded = false;

                   window.validate();

                   window.repaint();

               }

               public void mouseEntered(MouseEvent e) {

                   entered = true;

                   oldCursor = getCursor();

                   setCursor(

                       Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR));            

               }

               public void mouseExited(MouseEvent e) {

                   if (entered) {

                       setCursor(oldCursor);

                       entered = false;

                   }            

               }          

           }

     

            public void paint(Graphics g) {

               super.paint(g);

                Rectangle r = g.getClipBounds();

               Color c = g.getColor();

     

               for (int i = 0; i < 3; i++) {

                   g.setColor(Color.GRAY);

                   g.drawLine(r.width - i * 4 - 4, r.height - 1, r.width - 1,

                          r.height - i * 4 - 4);

                   g.drawLine(r.width - i * 4 - 5, r.height - 1, r.width - 1,

                          r.height - i * 4 - 5);

     

                   g.setColor(Color.WHITE);

                   g.drawLine(r.width - i * 4 - 6, r.height - 1, r.width - 1,

                          r.height - i * 4 - 6);

               }

               g.setColor(Color.LIGHT_GRAY);

               g.drawLine(r.width - 13, r.height - 1, r.width - 1, r.height - 1);

               g.drawLine(r.width - 1, r.height - 13, r.width - 1, r.height - 1);

           }

        }

    }

    原创粉丝点击