swing外觀美化,組件美化

jack_gogo 12年前發布 | 147K 次閱讀 substance swingx Swing Java開發 Thread

1. Substance

將一個 Java 應用程序和一個本地操作系統整合起來是比較麻煩的,主要是因為 Swing 的組件是人工繪制的。可以改變的就是 Java 外觀和效果,允許 JVM 將應用程序的組件顯示委托給本地外觀和效果。因此,當使用 Windows? 外觀和效果時,Swing 應用程序看起來像 Windows 應用程序;當使用 Mac 外觀和效果時,它們看起來 Mac 應用程序。

Swing 附帶的標準、本地外觀和效果,以及它自己的平臺獨立感覺和效果,稱為 Metal。另外,Substance 是一個開源項目,Kirill Grouchnikov 開發的,提供十幾種換膚外觀和效果。想要嘗試, 從 Java.net 下載 Substance

  1. 將 substance.jar 文件添加到您的 CLASSPATH
  2. 將以下系統屬性添加到您應用程序的啟動項:

    </tr> </tbody> </table>

  3. 在第 2 步中替換 lookandfeelname 變量,嘗試下列值:
  4. -Dswing.defaultlaf=org.jvnet.substance.skin.lookandfeelname

    </tr> </tbody> </table>
    </li> </ol>

    圖 1 展示了一個帶有默認 Metal 外觀和效果的 Java 應用程序,而圖 2 中的是 Substance Raven 外觀和效果:


    圖 1. Java 平臺的 Metal 外觀和效果
    有 Java 平臺默認的 Metal 外觀和效果的 GUI 的屏幕抓圖。

    圖 2. Substance 的 Raven 外觀和效果
    有 Substance Raven 外觀和效果的同一 GUI 的屏幕截圖。


    </div>

    2. SwingX

    Swing 框架包括您需要的大部分標準控件,包括樹、表、列表等等。但是它還缺少一些更為現代的控件,比如樹形表。SwingX 項目(SwingLabs 的一部分)提供一個豐富的組件集,包括:

    • 表、樹和列表的分類、過濾、和突出顯示
    • Find/search
    • Auto-completion
    • Login/authentication 框架
    • TreeTable 組件
    • Collapsible panel 組件
    • Date picker 組件
    • Tip-of-the-Day 組件

    要嘗試它,從 SwingLabs 下載 SwingX JAR 并將它添加到您的 CLASSPATH,或者僅將以下依賴項添加到您的 Maven POM 文件:

         SubstanceAutumnLookAndFeel
         SubstanceBusinessBlackSteelLookAndFeel
         SubstanceBusinessBlueSteelLookAndFeel
         SubstanceBusinessLookAndFeel
         SubstanceChallengerDeepLookAndFeel
         SubstanceCremeCoffeeLookAndFeel
         SubstanceCremeLookAndFeel
         SubstanceDustCoffeeLookAndFeel
         SubstanceDustLookAndFeel
         SubstanceEmeraldDuskLookAndFeel
         SubstanceMagmaLookAndFeel
         SubstanceMistAquaLookAndFeel
         SubstanceMistSilverLookAndFeel
         SubstanceModerateLookAndFeel
         SubstanceNebulaBrickWallLookAndFeel
         SubstanceNebulaLookAndFeel
         SubstanceOfficeBlue2007LookAndFeel
         SubstanceOfficeSilver2007LookAndFeel
         SubstanceRavenGraphiteGlassLookAndFeel
         SubstanceRavenGraphiteLookAndFeel
         SubstanceRavenLookAndFeel
         SubstanceSaharaLookAndFeel
         SubstanceTwilightLookAndFeel
        <dependency>
          <groupId>org.swinglabs</groupId>
          <artifactId>swingx</artifactId>
          <version>1.6</version>
        </dependency>

    圖 3 中的樹形表是 SwingX 組件的一個示例:


    圖 3. SwingX TreeTable 組件
    顯示 SwingX TreeTable 控件的 GUI 屏幕截圖。

    構建一個 SwingX TreeTable

    使用 SwingX JXTreeTable 控件,構建一個樹形表是非常簡單的。想象一下:您表中的每行可能有列數據,也可能有子節點。SwingX 提供一個模型類,可以擴展來提供這一功能,稱為 org.jdesktop.swingx.treetable.AbstractTreeTableModel。清單 1 展示了一個樹形表模型實現的示例:


    清單 1. MyTreeTableModel.java
                  
    package com.geekcap.swingx.treetable;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import org.jdesktop.swingx.treetable.AbstractTreeTableModel;
    
    public class MyTreeTableModel extends AbstractTreeTableModel 
    {
        private MyTreeNode myroot;
    
        public MyTreeTableModel()
        {
            myroot = new MyTreeNode( "root", "Root of the tree" );
    
            myroot.getChildren().add( new MyTreeNode( "Empty Child 1", 
              "This is an empty child" ) );
    
            MyTreeNode subtree = new MyTreeNode( "Sub Tree", 
              "This is a subtree (it has children)" );
            subtree.getChildren().add( new MyTreeNode( "EmptyChild 1, 1", 
              "This is an empty child of a subtree" ) );
            subtree.getChildren().add( new MyTreeNode( "EmptyChild 1, 2", 
              "This is an empty child of a subtree" ) );
            myroot.getChildren().add( subtree );
    
            myroot.getChildren().add( new MyTreeNode( "Empty Child 2", 
              "This is an empty child" ) );
    
        }
    
        @Override
        public int getColumnCount() 
        {
            return 3;
        }
    
        @Override
        public String getColumnName( int column )
        {
            switch( column )
            {
            case 0: return "Name";
            case 1: return "Description";
            case 2: return "Number Of Children";
            default: return "Unknown";
            }
        }
    
        @Override
        public Object getValueAt( Object node, int column ) 
        {
            System.out.println( "getValueAt: " + node + ", " + column );
            MyTreeNode treenode = ( MyTreeNode )node;
            switch( column )
            {
            case 0: return treenode.getName();
            case 1: return treenode.getDescription();
            case 2: return treenode.getChildren().size();
            default: return "Unknown";
            }
        }
    
        @Override
        public Object getChild( Object node, int index ) 
        {
            MyTreeNode treenode = ( MyTreeNode )node;
            return treenode.getChildren().get( index );
        }
    
        @Override
        public int getChildCount( Object parent ) 
        {
            MyTreeNode treenode = ( MyTreeNode )parent;
            return treenode.getChildren().size();
        }
    
        @Override
        public int getIndexOfChild( Object parent, Object child ) 
        {
            MyTreeNode treenode = ( MyTreeNode )parent;
            for( int i=0; i>treenode.getChildren().size(); i++ )
            {
                if( treenode.getChildren().get( i ) == child )
                {
                    return i;
                }
            }
    
            return 0;
        }
    
         public boolean isLeaf( Object node )
         {
             MyTreeNode treenode = ( MyTreeNode )node;
             if( treenode.getChildren().size() > 0 )
             {
                 return false;
             }
             return true;
         }
    
         @Override
         public Object getRoot()
         {
             return myroot;
         }
    }

    清單 2 顯示了一個定制的樹節點:


    清單 2. MyTreeNode.java
                  
    class MyTreeNode
    {
        private String name;
        private String description;
        private List<MyTreeNode> children = new ArrayList<MyTreeNode>();
    
        public MyTreeNode() 
        {
        }
    
        public MyTreeNode( String name, String description ) 
        {
            this.name = name;
            this.description = description;
        }
    
        public String getName() 
        {
            return name;
        }
    
        public void setName(String name) 
        {
            this.name = name;
        }
    
        public String getDescription() 
        {
            return description;
        }
    
        public void setDescription(String description) 
        {
            this.description = description;
        }
    
        public List<MyTreeNode> getChildren() 
        {
            return children;
        }
    
        public String toString()
        {
            return "MyTreeNode: " + name + ", " + description;
        }
    }

    如果您想使用這個樹形表模型,您將需要創建一個它的實例,然后將實例傳遞到 JXTreeTable 構造器,像這樣:

    private MyTreeTableModel treeTableModel = new MyTreeTableModel();
    private JXTreeTable treeTable = new JXTreeTable( treeTableModel );

    現在,您可以將 treeTable 添加到任何 Swing 容器,比如 JPanel 或者 JFrame 的內容面板。


    3. RSyntaxTextArea

    Swing 所缺少的另一個組件是一個帶有語法高亮顯示功能的文本編輯器。如果您編寫了一個 XML 文檔,那么就會知道它對于直觀區別標記、屬性、屬性值和標記值是多么的有幫助。FifeSoft 的開發人員已經構建了一組豐富的組件,您可以在基于 Swing 的 Java 應用程序中使用它們,其中之一是 RSyntaxTextArea 組件。

    RSyntaxTextArea 支持大多數開箱即用的編程語言,包括 C、C++、Perl、PHP、以及 Java,還有 HTML、JavaScript、XML、甚至 SQL。

    圖 4 是一個 RSyntaxTextArea組件的屏幕截圖,顯示了一個 XML 文件:


    圖 4. RSyntaxTextArea 顯示一個 XML 文件
    RSyntaxTextArea 組件的屏幕抓圖,顯示一個 XML 文件。

    將語法高亮顯示添加到 Swing 應用程序

    首先,從 Sourceforge 下載 RSyntaxTextArea JAR 文件。如果您正在使用 Maven,您可能想將它安裝到您的本地庫中,使用像這樣一個命令:

    mvn install:install-file -DgroupId=com.fifesoft -DartifactId=rsyntaxtextarea
     -Dversion=1.0 -Dpackaging=jar -Dfile=/path/to/file

    當您將 JAR 文件添加到您的項目之后,您就可以開始在您的應用程序中創建一個 RSyntaxTextArea 實例了,并且如果您想要滾動功能,就將它添加到 RTestScrollPane 中,然后調用 setSyntaxEditingStyle() 方法,為它傳遞一個 SyntaxConstants。例如,清單 3 創建了一個可滾動的 RSyntaxTextArea,以 XML 形式呈現文本:


    清單 3. 在 Swing 中語法高亮顯示
                  
    RSyntaxTextArea text = new RSyntaxTextArea();
    add( new RTextScrollPane( text ) );
    text.setSyntaxEditingStyle( SyntaxConstants.SYNTAX_STYLE_XML );


    4. Java Look-and-Feel Graphics Repository

    Microsoft 做得比較好的一點是確保 Windows 應用程序有一個一致的外觀和效果。如果您在很久之前就已經在編寫 Java Swing 應用程序了,您可能會遇到 Oracle 的 Java Look-and-Feel Graphics Repository。如果沒有,那您是比較幸運的。Java Look-and-Feel Graphics Repository 含有一個系列標準應用程序行為圖標,比如 File->New 和 Edit->Copy,以及比較深奧的命令,比如媒體控制、瀏覽器導航功能、Java 開發人員的編程圖標。圖 5 展示了一個從 Oracle 網站抓取的圖標:


    圖 5. Java Look-And-Feel Graphics Repository 圖標
    RSyntaxTextArea 顯示一個 XML 文件

    如果 Java Look-And-Feel Graphics Repository 只提供預構建圖形,那就太好了,但是它還提供標準約定,您構建或命名菜單、工具欄,以及快捷鍵時都要使用這些約定。比如,復制功能應該使用快捷鍵 Ctrl-C(稱為 Copy)實現,而且提供了一個 Copy 工具提示。當在菜單中時,復制函數的助記符應該是 CP、或者至少應該是 Y

    使用 Java Look-And-Feel Graphics Repository 圖標

    要試用 圖 5 中顯示的一些預構建圖形,從 Oracle 中 下載 Java Look-and-Feel Graphics Repository JAR,并添加到您的 CLASSPATH。然后,您需要從 JAR 文件內將圖標作為資源加載:圖標是以下格式的:

    ...
    toolbarButtonGraphics/general/Copy16.gif
    toolbarButtonGraphics/general/Copy24.gif
    toolbarButtonGraphics/general/Cut16.gif
    toolbarButtonGraphics/general/Cut24.gif
    toolbarButtonGraphics/general/Delete16.gif
    toolbarButtonGraphics/general/Delete24.gif
    ...

    所有圖標都包含在 toolbarButtonGraphics 目錄下,分成兩類在 圖 5 中顯示。在這種情況下,我們將考慮從總類中復制、剪切、粘貼和刪除。名稱中的 “16” 和 “24” 反映了圖標的大小:16x16 或 24x24。您可以創建一個 ImageIcon 圖標添加到文件中,例如:

    Class class = this.getClass();
    String urlString = "/toolbarButtonGraphics/general/Cut16.gif"
    URL url = class.getResource( urlString );
    ImageIcon icon = new ImageIcon( url );


    5. Swing 線程

    在本文發布示例時,您可能遇一些奇怪內容,看起來像運行時錯誤。如果是這樣,您的應用程序有可能出現了一個常見的線程處理錯誤。許多 Java 開發人員不明白,Swing 應用程序應該運行在它們自己的線程中,而不是主執行線程中。Swing 將忽略這種錯誤 ,但是迄今為止引入的很多組件卻不會。

    Java 平臺提供了一個名為 SwingUtilities 的類,可以幫助您將您的 Swing 應用程序發布到它自己的線程上,該類有一個 invokeLater() 方法,您可以用來啟動 Swing 應用程序。清單 4 顯示了使用 SwingUtilities.invokeLater() 方法發布的 JXTreeTable


    清單 4. SwingXExample.java
                  
    package com.geekcap.swingx;
    
    import java.awt.BorderLayout;
    import java.awt.Dimension;
    import java.awt.Toolkit;
    
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.JTabbedPane;
    import javax.swing.SwingUtilities;
    
    import org.jdesktop.swingx.JXTreeTable;
    
    import com.geekcap.swingx.treetable.MyTreeTableModel;
    
    public class SwingXExample extends JFrame 
    {
        private JTabbedPane tabs = new JTabbedPane();
    
        private MyTreeTableModel treeTableModel = new MyTreeTableModel();
        private JXTreeTable treeTable = new JXTreeTable( treeTableModel );
    
        public SwingXExample()
        {
            super( "SwingX Examples" );
    
            // Build the tree table panel
            JPanel treeTablePanel = new JPanel( new BorderLayout() );
            treeTablePanel.add( new JScrollPane( treeTable ) );
            tabs.addTab( "JXTreeTable", treeTablePanel );
    
            // Add the tabs to the JFrame
            add( tabs );
    
            setSize( 1024, 768 );
            Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
            setLocation( d.width / 2 - 512, d.height/2 - 384 );
            setVisible( true );
            setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        }
    
    
        public static void main( String[] args )
        {
            AppStarter starter = new AppStarter( args );
            SwingUtilities.invokeLater( starter );
        }
    }
    
    class AppStarter extends Thread
    {
        private String[] args;
    
        public AppStarter( String[] args )
        {
            this.args = args;
        }
    
        public void run()
        {
            SwingXExample example = new SwingXExample();
        }
    }

    構造器將 JFrame 的可視度設置為 true,當 Swing 運行在應用程序的主線程上是,這是不被允許的。清單 4 創建了一個單獨的類 AppStarter,它擴展 Thread 并創建 SwingXExample 類。main() 方法創建一個 AppStarter 類實例,并將它傳遞給 SwingUtilities.invokeLater() 方法,來正確啟動應用程序。盡量養成以這種方式運行您 Swing 應用程序的習慣 — 不僅是因為它正確,而且如果不這樣做,有些第三方組件可能無法運行。


    結束語

    Swing 是一個功能強大的庫,允許您在 Java 平臺上構建用戶界面,但是它缺少一些您想合并到您應用程序中的現代組件。在本文中,我為您提供一些有用的技巧,來美化(并現代化)您的 Swing 應用程序。像 Substance、SwingX 這類開源項目以及 Java Look-And-Feel Graphics Repository 使得在 Java 平臺上構建豐富的用戶界面比較容易。參閱 參考資料 部分,了解關于這些項目和 Swing 編程的更多信息。


    參考資料

    學習

    • 關于...您不知道的 5 件事”:了解 Java 平臺中您還有多少不知道的知識,這個系列專門將煩瑣的 Java 技術變成非常有用的編程技巧。

    • Swing 簡介”(Michael Abernethy,developerWorks,2005 年 6 月):這是一個兩部分教程的第一部分,簡要介紹了 Swing 庫中的一些基礎組件。

    • 關于 Maven 您不知道的 5 件事”(Steven Haines,developerWorks,2010 年 9 月):對于很多 Java 開發人員來說,Maven 是一個良好的構建工具,但是它也提供一個完整管理應用程序聲明周期的工具集 — 其中幾個在本文中做了介紹。

    • Swing threading and the event-dispatch thread”(John Zukowski,JavaWorld,2007 年 8 月):跟蹤 Swing 的單線程事件模型,從 Java 1.0 到源頭 JavaBeans 組件模型和 AWT 中,然后以一個常用的啟動模式顯示安裝 bug,并顯示如何修復它。

    • Substance (Swing) Sightings Volume 1”(Kirill Grouchnikov,Pushing Pixels,2007 年 8 月):選擇有 Substance 皮膚的外觀和效果的、由 Substance 創建者 Kirill Grouchnikov 編譯的、正在運行的應用程序的屏幕截圖。

    • Java Reference Guide:SwingX ”(Steven Haines,InformIT,2009 年 11 月):了解更多關于 SwingX 以及使用它來為 Java 應用程序 UI 構造樹形表的信息。

    • developerWorks Java 技術專區:這里有數百篇關于 Java 編程每個方面的文章

    獲得產品和技術

    • 下載 Substance:擴展各種可以在您的 Swing 應用程序中實現的外觀和效果。

    • 下載 SwingX:這個 SwingLabs 項目為 Swing UI 工具包帶來了很多豐富的應用程序組件。

    • 下載 RSyntaxTextArea:您可以在您的基于 Swing 的 Java 應用程序中使用的豐富組件集合之一,由 FifeSoft 開發。

    • 下載 Java Look-and-Feel Graphics Repository:專用于 Java 外觀和效果的一系列工具欄按鈕圖形,由 Oracle 的 Java Software Human Interface 小組開發。
 本文由用戶 jack_gogo 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!