隨筆 - 18  文章 - 96  trackbacks - 0
          <2007年9月>
          2627282930311
          2345678
          9101112131415
          16171819202122
          23242526272829
          30123456


          常用鏈接

          留言簿(4)

          隨筆檔案

          相冊

          我的兄弟們

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          看來我們的JTextField之旅也到了一個階段,已經很不錯了,現在我們來改造JButton,讓那個呆板的Swing看起來舒服一些。

          還是先放上完成后的效果圖:

          普通的狀態


          鼠標滑過


          鼠標按下

          和代碼:
            1 /**
            2  * @(#)RJButton.java  0.1.0  2007-9-11
            3  */
            4 package ruislan.rswing;
            5 
            6 import java.awt.AlphaComposite;
            7 import java.awt.Color;
            8 import java.awt.Font;
            9 import java.awt.GradientPaint;
           10 import java.awt.Graphics;
           11 import java.awt.Graphics2D;
           12 import java.awt.RenderingHints;
           13 import java.awt.Shape;
           14 import java.awt.event.MouseAdapter;
           15 import java.awt.event.MouseEvent;
           16 import java.awt.geom.RoundRectangle2D;
           17 
           18 import javax.swing.JButton;
           19 
           20 /**
           21  * Custom JButton
           22  * 
           23  * @version 0.1.0
           24  * @author ruislan <a href="mailto:z17520@126.com"/>
           25  */
           26 public class RButton extends JButton {
           27     private static final long serialVersionUID = 39082560987930759L;
           28     public static final Color BUTTON_COLOR1 = new Color(205255205);
           29     public static final Color BUTTON_COLOR2 = new Color(5115447);
           30     // public static final Color BUTTON_COLOR1 = new Color(125, 161, 237);
           31     // public static final Color BUTTON_COLOR2 = new Color(91, 118, 173);
           32     public static final Color BUTTON_FOREGROUND_COLOR = Color.WHITE;
           33     private boolean hover;
           34 
           35     public RButton() {
           36         setFont(new Font("system", Font.PLAIN, 12));
           37         setBorderPainted(false);
           38         setForeground(BUTTON_COLOR2);
           39         setFocusPainted(false);
           40         setContentAreaFilled(false);
           41         addMouseListener(new MouseAdapter() {
           42             @Override
           43             public void mouseEntered(MouseEvent e) {
           44                 setForeground(BUTTON_FOREGROUND_COLOR);
           45                 hover = true;
           46                 repaint();
           47             }
           48 
           49             @Override
           50             public void mouseExited(MouseEvent e) {
           51                 setForeground(BUTTON_COLOR2);
           52                 hover = false;
           53                 repaint();
           54             }
           55         });
           56     }
           57 
           58     @Override
           59     protected void paintComponent(Graphics g) {
           60         Graphics2D g2d = (Graphics2D) g.create();
           61         int h = getHeight();
           62         int w = getWidth();
           63         float tran = 1F;
           64         if (!hover) {
           65             tran = 0.3F;
           66         }
           67 
           68         g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
           69                 RenderingHints.VALUE_ANTIALIAS_ON);
           70         GradientPaint p1;
           71         GradientPaint p2;
           72         if (getModel().isPressed()) {
           73             p1 = new GradientPaint(00new Color(000), 0, h - 1,
           74                     new Color(100100100));
           75             p2 = new GradientPaint(01new Color(00050), 0, h - 3,
           76                     new Color(255255255100));
           77         } else {
           78             p1 = new GradientPaint(00new Color(100100100), 0, h - 1,
           79                     new Color(000));
           80             p2 = new GradientPaint(01new Color(255255255100), 0,
           81                     h - 3new Color(00050));
           82         }
           83         g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
           84                 tran));
           85         RoundRectangle2D.Float r2d = new RoundRectangle2D.Float(00, w - 1,
           86                 h - 12020);
           87         Shape clip = g2d.getClip();
           88         g2d.clip(r2d);
           89         GradientPaint gp = new GradientPaint(0.0F0.0F, BUTTON_COLOR1, 0.0F,
           90                 h, BUTTON_COLOR2, true);
           91         g2d.setPaint(gp);
           92         g2d.fillRect(00, w, h);
           93         g2d.setClip(clip);
           94         g2d.setPaint(p1);
           95         g2d.drawRoundRect(00, w - 1, h - 12020);
           96         g2d.setPaint(p2);
           97         g2d.drawRoundRect(11, w - 3, h - 31818);
           98         g2d.dispose();
           99         super.paintComponent(g);
          100     }
          101 }
          102 


          注意代碼中的幾個部分:

          首先是paintComponent方法中最后一行,我們調用了父類的paintComponent方法,這是因為我們要靠父類來繪制字符,但是父類的這個方法除了繪制字符之外還會繪制其他的,所以我們需要關閉掉其他的(當然我們也可以自己來繪制字符,但是JButton提供了方法為什么不用呢),所以我們在構造方法那里調用了:
          setBorderPainted(false);
          setFocusPainted(false);
          setContentAreaFilled(false);
          告訴父類不用繪制邊框,不用繪制焦點,不用繪制內容部分,這部分我們自己來搞*o*。

          然后就是這一句了g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)告訴繪制API我們需要平滑一點,否則繪制出來會有很多鋸齒喲。

          接下來的這一句g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,tran))告訴繪圖API我們需要繪制一個有透明度的,tran就是透明度(0-1)。

          然后就是將邊框的邊角變直角為圓角,我們繪制一個RoundRectangle2D,這個就是邊角都為圓角的方形,然后我們根據這個方形來clip我們的方形,這樣方形就被RoundRectangle2D的圓角方形包裹,從而變成了圓角方形。

          最后就是繪制外邊線和內邊線,通過改變內邊線和外邊線的色變從而造成陷入或者突出效果。

          整個JButton改造完畢,如果你能夠活用clip的話,你也可以做一個五角星的JButton喲。

          整個源代碼我連同Eclipse工程文件已經打包成zip放在我的文件里面,下載鏈接如下:
          http://www.aygfsteel.com/Files/ruislan/rswing-0.1.0.zip

          posted on 2007-09-11 12:24 ruislan 閱讀(5560) 評論(20)  編輯  收藏

          FeedBack:
          # re: JButton大改造 2007-09-11 13:14 千里冰封
          不錯不錯,寫得很好
          期待樓主更好的作品,有機會共同研究一下SWING:)  回復  更多評論
            
          # re: JButton大改造[未登錄] 2007-09-11 18:28 zc
          樓主,源代碼可以不帶行號嗎?這樣直接COPY到編輯器里還要自己修改,非常的麻煩。  回復  更多評論
            
          # re: JButton大改造 2007-09-11 18:34 ruislan
          好好好
          我就遷就你們這些懶人,下次不帶行號了。  回復  更多評論
            
          # re: JButton大改造 2007-09-11 21:36 Rene
          樓住能否公布一下你Blogspot的地址呢?
          或者在頁面上加個鏈接就更好了^_^  回復  更多評論
            
          # re: JButton大改造 2007-09-11 23:32 BeanSoft
          更好的方法是開發一個 ButtonUI. Swing 本身的 MVC 就是這樣分的. 呵呵, 這樣不影響原始的 JButton 的代碼.

          /**
          * $ $ License.
          *
          * Copyright $ L2FProd.com
          *
          * Licensed under the Apache License, Version 2.0 (the "License");
          * you may not use this file except in compliance with the License.
          * You may obtain a copy of the License at
          *
          * http://www.apache.org/licenses/LICENSE-2.0
          *
          * Unless required by applicable law or agreed to in writing, software
          * distributed under the License is distributed on an "AS IS" BASIS,
          * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
          * See the License for the specific language governing permissions and
          * limitations under the License.
          */
          package com.l2fprod.common.swing.plaf.blue;

          import java.awt.Color;
          import java.awt.Graphics;

          import javax.swing.AbstractButton;
          import javax.swing.BorderFactory;
          import javax.swing.JComponent;
          import javax.swing.plaf.basic.BasicButtonUI;

          /**
          * BlueishButtonUI. <br>
          *
          */
          public class BlueishButtonUI
          extends BasicButtonUI {

          private static Color blueishBackgroundOver = new Color(224, 232, 246);
          private static Color blueishBorderOver = new Color(152, 180, 226);

          private static Color blueishBackgroundSelected = new Color(193, 210, 238);
          private static Color blueishBorderSelected = new Color(49, 106, 197);

          public BlueishButtonUI() {
          super();
          }

          public void installUI(JComponent c) {
          super.installUI(c);

          AbstractButton button = (AbstractButton)c;
          button.setRolloverEnabled(true);
          button.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
          }

          public void paint(Graphics g, JComponent c) {
          AbstractButton button = (AbstractButton)c;
          if (button.getModel().isRollover()
          || button.getModel().isArmed()
          || button.getModel().isSelected()) {
          Color oldColor = g.getColor();
          if (button.getModel().isSelected()) {
          g.setColor(blueishBackgroundSelected);
          } else {
          g.setColor(blueishBackgroundOver);
          }
          g.fillRect(0, 0, c.getWidth() - 1, c.getHeight() - 1);

          if (button.getModel().isSelected()) {
          g.setColor(blueishBorderSelected);
          } else {
          g.setColor(blueishBorderOver);
          }
          g.drawRect(0, 0, c.getWidth() - 1, c.getHeight() - 1);

          g.setColor(oldColor);
          }

          super.paint(g, c);
          }

          }
            回復  更多評論
            
          # re: JButton大改造 2007-09-12 00:39 ruislan
          BeanSoft兄,何必舍近求遠去找一個L2fprod呢,JDK里面就有現成的Metal和windows等等LookAndFeel的范例。

          不過我想問一下,LookAndFeel的這種設計是一種MVC嗎?也許在下駑鈍,理解的是一種策略模式,將組件的paint方式交給了各個LookAndFeel的實現來完成,然后由用戶通過UIManager來決定裝載的不同,從而調用不同的繪制策略。

          “更好的”方法比“更適合”的方法獲得的效率差太多了,如果采用了BeanSoft兄的方案,那不知道要有多少步才能看到在下這個界面了,繼承LookAndFeel,寫ButtionUI,...,啟動程序的時候裝載這個LookAndFeel類...,在下只是改造一下JButton,何必非要為了JButton弄一個LookAndFeel出來呢。其實為什么大家都喜歡Spring多過EJB呢,為了迎合一個框架我們做得無用功太多了,而Spring給了我們自由的選擇,但為了Spring我們也做了很多無用的東西,所以才有了AppFuse(大師說代碼生成是罪惡,所以我們也該反對AppFuse?),才有了ruby on rails。聰明的人雖然也會按照成規辦事,但是他會選擇最適合他的成規,如果沒有他寧愿嘗試創新,否則,也不會有這么多新的框架如春筍般冒出來了。

          也許可能會覺得我太注重實際的結果,用戶的感受而忽略了作為一名不斷上進的開發人員需要的學者學術般的研究和討論,這可能才是BeanSoft兄“更好的”含義吧。我會多多改進的。

          P.S 怎么感覺像是DDL和蝎在討論什么才是藝術?嗯  回復  更多評論
            
          # re: JButton大改造 2007-09-12 06:58 BeanSoft
          我倒... 我有沒說你要開發 Look and Feel, 實際上ButtonUI 類和任何 L&F 無關, 用 L2fprod 也只是懶得寫更多代碼而已. 我也是跟你討論 Swing 呢, 不是嗎? 只需要一步就能看到效果, 不需要多少步. PS 我以前可是狠狠學過一陣 Swing, 理解的不對的地方還可以繼續討論. 我這也不是學術般的討論, 也是實用出發. 我不喜歡高談闊論, 只喜歡代碼說話.

          Swing 的 MVC 我不想贅述, 我想說的是要改外觀用 ButtonUI 會更方便一些而已, 不用對原來的界面邏輯代碼做太多改動. 剛才那個例子用法很簡單,
          button.setUI(new BlueishButtonUI()); 即可改變單個按鈕的外觀, 而 L&F 是為了改變所有組件的外觀.

          用法示例:
          import java.awt.FlowLayout;

          import javax.swing.JButton;
          import javax.swing.WindowConstants;

          public class NewJFrame extends javax.swing.JFrame {
          private JButton jButton1;
          private JButton jButton2;

          public static void main(String[] args) {
          NewJFrame inst = new NewJFrame();
          inst.setVisible(true);
          }

          public NewJFrame() {
          super();
          initGUI();
          // 設置 UI 來加入不同的繪制方法, 可以切換不同的繪制方法, 例如換膚
          jButton1.setUI(new BlueishButtonUI());
          }

          private void initGUI() {
          try {
          FlowLayout thisLayout = new FlowLayout();
          getContentPane().setLayout(thisLayout);
          setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
          {
          jButton1 = new JButton();
          getContentPane().add(jButton1);
          jButton1.setText("自定義外觀,需要UI嗎?需要");
          }
          {
          jButton2 = new JButton();
          getContentPane().add(jButton2);
          jButton2.setText("默認外觀");
          }
          pack();
          setSize(400, 300);
          } catch (Exception e) {
          e.printStackTrace();
          }
          }

          }
            回復  更多評論
            
          # re: JButton大改造 2007-09-12 08:52 交口稱贊
          一個SWT死忠幸福的看著樓上一群人

          呵呵。  回復  更多評論
            
          # re: JButton大改造 2007-09-12 13:28 BeanSoft
          呵呵, SWT 啥時候能換膚作出像 Office 2003, 2007 那樣漂亮的界面就好了. 說實話 SWT 也土的掉渣.  回復  更多評論
            
          # re: JButton大改造 2007-09-12 13:36 ruislan
          我也改造過SWT的,是有點古板,土的掉渣這個就有點...  回復  更多評論
            
          # re: JButton大改造 2007-09-12 13:39 darkhe
          又頂。  回復  更多評論
            
          # re: JButton大改造 2007-09-12 15:22 交口稱贊
          @BeanSoft

          SWT是跟本地操作系統界面一致,這是他最大的優點啊
          比如你用XP換個什么蘋果主題,swt自動就是這個主題的樣子。

          樓主的代碼,放到swt里也差不多。
          也能定義一堆PP的swt控件。  回復  更多評論
            
          # re: JButton大改造 2007-09-12 21:58 天若無情
          樓主有時間的話可以考慮用Graphics直接在AWT上繪制些控件并加上Event處理,Swing雖然以AWT為基礎,但很多地方都被優化了,圖像緩存也不用考慮太多,如果要在AWT開發的系統使用還需要很多修改(或者說,我習慣重寫JRE發布[反正Sun犯不上告我……],能將Swing部分包去掉就可以節省不少的資源,既然重繪界面,干脆徹底點,只留AWT作基礎就好了。)。即使不考慮版本的兼容性與大小,也是盡量用Graphics繪制從界面到事件觸發的算法比較值得學習。  回復  更多評論
            
          # re: JButton大改造 2007-09-13 09:34 Matthew Chen
          UI delegate 是swing在mvc基礎上加的一些提高靈活性的擴展,外觀同樣是隨操作系統本地的外觀呈現的,awt只是swing最底層的基礎,老實說這個基礎薄弱而且過于依賴平臺對等體,swing就好像借awt這只雞生的蛋,用的只是那個殼,而繪制了其他的一切來確保了幾乎沒有平臺差異,可能用慣了swt的對awt不會怎么反感,但是用慣了swing的卻不會想去用awt。
          覺得setUI的方法確實比在button上編碼修改好,起碼可以動態裝卸。其實swing只對平臺共有的個性化組件使用了UI delegate,自然是認為這些組件才被用戶視為理當呈現為平臺上的樣子,而如樓主的這個例子,使得任何平臺和任何laf下按鈕都會是同一個樣子,談不上有什么問題,這個看項目的需要。
          swing是個不錯的平臺差異化下桌面解決方法。  回復  更多評論
            
          # re: JButton大改造 2007-09-13 11:04 天若無情
          Swing和AWT的關系其實非常微妙,Swing的基礎組件,都是以AWT的底層白板組件實現,或者說繪制的。它以一種理論上的純Java方式,將AWT中所有無用部分加以摒棄。也就是說,AWT可以做到的,Swing一定可以做到,而Swing做得到的,AWT不一定可以做到。但是對Swing特性的依賴,一定會某種程度減少代碼的可移植性。比如說,我現在有一組完全以Graphics在AWT白板上繪制的圖形控件,那么在C#中使用它的話,大體只是算法的移植,只需要很少的代碼修改就可以在C#中實現相同的效果。但是以Swing為基礎的話,由于其自父類JComponent起便開始加入自己的本地化算法,轉為C#平臺就需要更多的事件與參數轉換(主要體現在圖象的緩存與變更上)。

          事實上是,如果我有完全AWT為基礎開發的一組控件,我想將其轉為Swing,需要做什么呢?很簡單,將所有awt包轉為swing包,并且加上j開頭就好,別無其他,因為Swing底層繼承自JComponent起便繼承自Container,而反之則是不可能的。

          從SWT完全摒棄Swing這種做法上,我們就已經可以感知這種行為的意義何在,他為將來的擴充和發展提供了堅實的基礎。

          本人開源項目:
          http://looframework.sourceforge.net/

          www.open-open.com

          雖然不是一個Java控件項目,但是原理上是非常類似的,完全以AWT開發。(或者說,近乎完全繪制的界面,不需要Swing。)

            回復  更多評論
            
          # re: JButton大改造 2007-09-13 11:27 天若無情
          我要說的是,這類以繪制而非繼承Swing組件為主的應用,完全可以采用AWT作為底層,這樣效率上會更高,而且算法更容易移植。  回復  更多評論
            
          # re: JButton大改造 2007-10-21 21:25 classic20082003@163.com
          樓主知道怎么樣把圖片變成控件么。比如說frame
          window 之類的!  回復  更多評論
            
          # re: JButton大改造 2007-12-17 18:14 lan
          有人編過計算器嗎  回復  更多評論
            
          # re: JButton大改造 2008-01-25 01:08 damagegod
          @天若無情
          非常不錯。呵呵。  回復  更多評論
            
          # re: JButton大改造 2008-07-24 12:41 法法
          樓主的文章很不錯,非常感謝。  回復  更多評論
            

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          主站蜘蛛池模板: 文水县| 晋中市| 高陵县| 和田市| 九龙县| 寿宁县| 吉林市| 铁岭市| 新竹县| 汕头市| 霍邱县| 凤山县| 斗六市| 江源县| 句容市| 连江县| 靖西县| 九龙城区| 鹰潭市| 泰宁县| 嘉兴市| 乌拉特中旗| 汪清县| 武宁县| 神池县| 榕江县| 都昌县| 东乌| 蓬溪县| 朝阳市| 德保县| 高邑县| 宣汉县| 宜兴市| 勐海县| 逊克县| 翁源县| 大姚县| 灵台县| 利辛县| 胶州市|