zeyuphoenix

          愿我愛的人快樂,愿愛我的人快樂,為了這些,我愿意不快樂.

          JBorder組件邊框

          JavaBorder是用來呈現圍繞Swing組件邊緣邊框的對象,它本身是一個接口,里面定義了paintBordergetBorderInsetsisBorderOpaque三個需要實現的方法.如果想用自己的Border類來繪制組件的邊框,必須實現這三個方法,里面有很多布局和繪制的問題,比較麻煩.

          Java為了方便使用,提供了虛擬類AbstractBorder,繼承它就可以比較簡單的實現自己的邊框了,但還是有布局和重繪以及組件位置的問題需要自己實現,為此Java又提供了EmptyBorderCompoundBorderEtchedBorderLineBorderMatteBorderTitledBorder為我們可以使用的大部分Border提供了實現,并且創立了工廠類BorderFactory為各種Border實現提供實例.

          對于普通的BorderJavaBorderFactory已經滿足我們的要求了,但是如果我們需要的是特殊的Border,比如Border的標題是一個單選框,就必須使用我們自己的類來實現了.這里我們可以把我們需要繪制的Border也想象成一個容器,在它的基礎上繪制出自己的邊緣,需要填充的組件在放置在它的上面就可以了.

          先看比較簡單的例子,Sun官方給出了使用的普通例子:

          圖如下:

          依次創建了

               實現單色、任意厚度線邊框

          BorderFactory.createLineBorder(Color.black);

               具有浮雕化外觀效果的邊框(效果為凸起)

          BorderFactory.createEtchedBorder(EtchedBorder.RAISED);

               具有浮雕化外觀效果的邊框(效果為凹陷)

          BorderFactory.createEtchedBorder(EtchedBorder.LOWERED);

               具有凸出斜面邊緣的邊框

          BorderFactory.createRaisedBevelBorder();

               具有凹入斜面邊緣的邊框

          BorderFactory.createLoweredBevelBorder();

               不占用空間的空邊框

          BorderFactory.createEmptyBorder();

                多層指定圖標組成的、類似襯邊的邊框

          BorderFactory.createMatteBorder(-1, -1, -1, -1, icon)

               純色創建一個類似襯邊的邊框

          BorderFactory.createMatteBorder(1, 5, 1, 1, Color.red);

               多層指定圖標組成的、類似襯邊的邊框(只有一個邊有框)

          BorderFactory.createMatteBorder(0, 20, 0, 0, icon);

               創建一個空標題的新標題邊框,使其具有指定的邊框對象、默認的文本位置(位于頂線上)、默認的調整 (leading),以及默認的字體和文本顏色(由當前外觀確定)

          BorderFactory.createTitledBorder("title");

               向現有邊框添加一個標題,使其具有默認的位置(位于頂線上)、默認的調整 (leading),以及默認的字體和文本顏色(由當前外觀確定)

          BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.black), "title");

          BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED), "title");

          BorderFactory.createTitledBorder(BorderFactory.createLoweredBevelBorder(), "title");

          BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), "title");

          然后通過Border的方法設置它們的位置和顯示屬性:

          border.setTitleJustification(TitledBorder.CENTER);

                 border.setTitlePosition(TitledBorder.ABOVE_TOP);

               當然也可以再構造時給出這些屬性.

          向現有邊框添加一個標題,使其具有指定的位置、字體和顏色

          BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.black), "title", TitledBorder.CENTER, TitledBorder.ABOVE_TOP, new Font("宋體", Font.BOLD, 12);,Color.Red);

          創建一個合成邊框,指定了用于外部和內部邊緣的 border 對象

          BorderFactory.createCompoundBorder(raisedbevel, loweredbevel);

          內外Border可以任意組合,也可以為Null.



          接下來就是自己實現一個有特殊表現形式的Border,最基礎的方法是實現Border接口,實現paintBordergetBorderInsetsisBorderOpaque三個方法,這樣比較復雜,因為我們要修改的是BorderTitle,所以這里我繼承TitledBorder:

          /**

           * the title border that override it.

          */

          publicclass MyTitledBorder extends TitledBorder {

          它有一個屬性:

              /**

               * the component in the border.

               */

              protected JComponent component = null;

          代表放置在Border上的組件.

          再看它的構造函數:

              /**

               * Creates a TitledBorder instance.

               */

              public MyTitledBorder(JComponent component) {

                 this(null, component, LEFT, TOP);

              }

              public MyTitledBorder(Border border, JComponent component,

                     int titleJustification, int titlePosition) {

           super(border, null, titleJustification, titlePosition, null, null);

                 this.component = component;

                 if (border == null) {

                     this.border = super.getBorder();

                 }

              }

          它把Border上的組件傳入,并設置初始位置.

          然后是實現Border的部分方法,設置JComponet的位置,大小和布局等.

              /**

               * Reinitialize the insets parameter with this Border's current Insets.

               */

              @Override

              public Insets getBorderInsets(Component c, Insets insets) {

          用此邊框的當前 Insets 重新初始化 insets 參數.

          insets.top = EDGE_SPACING + TEXT_SPACING + borderInsets.top;

          insets.right = EDGE_SPACING + TEXT_SPACING + borderInsets.right;

          insets.bottom = EDGE_SPACING + TEXT_SPACING + borderInsets.bottom;

          insets.left = EDGE_SPACING + TEXT_SPACING + borderInsets.left;

          然后在根據Border的位置設置它的準確邊界:

          先是得出Border上組件的大小:

          if (component != null) {

              compHeight = component.getPreferredSize().height;

          }

          然后根據位置計算邊:

          caseBELOW_TOP:

              insets.top += compHeight + TEXT_SPACING;

          然后是

              /**

               * Paints the border for the specified component with the specified * position  and size.

               */

              @Override

             publicvoid paintBorder(Component c, Graphics g, int x, int y, int width, int height) {

          按照指定的位置和大小為指定的組件繪制邊框.

          先得出沒有邊框的容器的大小:

          Rectangle borderR = new Rectangle(x + EDGE_SPACING, y + EDGE_SPACING,

              width - (EDGE_SPACING * 2), height - (EDGE_SPACING * 2));

          然后得出邊框的大小和邊框上組件的大小:

          Insets insets = getBorderInsets(c);

          Rectangle compR = getComponentRect(rect, insets);

          然后根據Border上組件的位置,計算哪兒應該加上這個大小:

          例如在下面,意味著下面的Border會寬一點:

              caseBOTTOM:

                     diff = insets.bottom / 2 - borderInsets.bottom - EDGE_SPACING;

                     borderR.height -= diff;

          最后是繪制:

          border.paintBorder(c, g, borderR.x, borderR.y, borderR.width,

                        borderR.height);

                 Color col = g.getColor();

                 g.setColor(c.getBackground());

                 g.fillRect(compR.x, compR.y, compR.width, compR.height);

                 g.setColor(col);

                 component.repaint();

          最后一個方法是根據Border上組件和BorderInsets計算現在組件的寬度和最終組件要占據的位置大小:

              /**

               * get component Rectangle.

               */

          public Rectangle getComponentRect(Rectangle rect, Insets borderInsets) {

          先得出不算BoderInsets組件的大小:

          Dimension compD = component.getPreferredSize();

          Rectangle compR = new Rectangle(0, 0, compD.width, compD.height);

          然后根據位置進行換算,比如組件位于Border的下-右:

              caseBELOW_TOP:

                     compR.y = borderInsets.top - compD.height - TEXT_SPACING;

          caseRIGHT:

                     compR.x = rect.width - borderInsets.right - TEXT_INSET_H

                            - compR.width;

          最后把算好的compR返回就可以了.

          接著是一個接口,用處主要是標示Border內的所有組件是否可用,當然以后也可以添加新的接口:

          /**

           * set the panel enable or not.

          */

          publicinterface StateTransmitter {

          它只有一個需要實現的方法:

              /**

               * set panel enable.

               */

              publicvoid setChildrenEnabled(boolean enable);

          用來管理Border內的所有組件是否可用的.

          然后是這個接口的一個簡單實現,我們所有的組建需要放置在它的上面,當然你也可以自己實現,只需要實現StateTransmitter接口就可以了:

          /**

           * the panel that you can override it.<br>

           * if you want your panel title can change the panel state,you must override

          */

          publicclass MyPanel extends JPanel implements StateTransmitter {

          它只有一個實現方法,其它和Jpanel相同:

              @Override

              publicvoid setChildrenEnabled(boolean enable) {

                 Component[] children = this.getComponents();

                 for (int i = 0; i < children.length; i++) {

                     children[i].setEnabled(enable);

                 }

              }

          最后就是把自己寫好的MyTitledBorder類放置到指定JPanel組合成最終我們可以使用的特殊Border類了.

          publicclass MyTitledPane extends JPanel {

          它就是一個普通的JPanel,我們在它的上面放置了自己定義的特殊Border和我們以后需要放置的其他組件根容器,然后通過調整它的doLayout方法和setEnabled方法使它滿足我們的要求.

          它的屬性如下:

              /**

               * panel border.

               */

              private MyTitledBorder border = null;

              /**

               * the component in the title pane.

               */

              private JComponent component = null;

              /**

               * the title pane.

               */

              private JPanel panel = null;

              /**

               * is enable allow.

               */

              privatebooleantransmittingAllowed = false;

              /**

               * enable or not.

               */

              private StateTransmitter transmitter = null;

          然后是它的構造函數,在構造函數里我們需要初始化我的定制的特殊的Border和可以放置其它組件的根容器.

          public MyTitledPane(JComponent component) {

                 border = new MyTitledBorder(component);

                 setBorder(border);

                 panel = new JPanel();

                   add(component);

                 add(panel);

          設置可用與否的初始值:

                 transmittingAllowed = false;

                 transmitter = null;

          然后提供一個可以換Border上容器的方法:

              /**

               * remove old component and add new one.

               */

              publicvoid setTitleComponent(JComponent newComponent) {

                 remove(component);

                 add(newComponent);

                 border.setTitleComponent(newComponent);

                 component = newComponent;

              }

          接著重寫JPanelsetEnabled方法使它的子組件也不可用:

              @Override

              publicvoid setEnabled(boolean enable) {

                 super.setEnabled(enable);

                 if (transmittingAllowed && transmitter != null) {

                     transmitter.setChildrenEnabled(enable);

                 }

              }

          最后是重寫JPaneldoLayout方法,使布局自適應:

              /**

               * reset the pane layout.

               */

              @Override

              publicvoid doLayout() {

          先取得它的邊:

          Rectangle rect = getBounds();

          再去的Border的邊:

                 Rectangle compR = border.getComponentRect(rect, insets);

                 component.setBounds(compR);

          兩者去做合并:

                 rect.x += insets.left;

                 rect.y += insets.top;

                 rect.width -= insets.left + insets.right;

                 rect.height -= insets.top + insets.bottom;

          最后設置新的Layout的邊:

          panel.setBounds(rect);

          到此為止,一個我們自定義的特殊Border就完成了,我們可以如下使用它:

          final MyTitledPane mypane = new MyTitledPane(mycheBox);

          然后定義我們的JPanel,把它放置在Bordr面板上.

              MyPanel userPanel = new MyPanel();

              userPanel.add(new JButton("you add"));

              mypane.setTransmittingAllowed(true);

              mypane.setTransmitter(userPanel);

              mypane.getContentPane().add(userPanel);

          到此完成.

          posted on 2010-05-04 22:52 zeyuphoenix 閱讀(4477) 評論(0)  編輯  收藏 所屬分類: Java基本組件的使用

          導航

          <2010年5月>
          2526272829301
          2345678
          9101112131415
          16171819202122
          23242526272829
          303112345

          統計

          常用鏈接

          留言簿(52)

          隨筆分類

          隨筆檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 平泉县| 曲阜市| 睢宁县| 高密市| 百色市| 江阴市| 靖远县| 余干县| 肥东县| 万州区| 万荣县| 辉县市| 阿图什市| 枝江市| 紫金县| 西充县| 云龙县| 留坝县| 固原市| 博野县| 海原县| 阿瓦提县| 凌海市| 河西区| 平乡县| 镶黄旗| 洪洞县| 伊宁市| 武山县| 宿州市| 邻水| 明溪县| 伽师县| 庆城县| 淮阳县| 贡觉县| 东台市| 色达县| 通州市| 石门县| 广汉市|