<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    FORTUNE

    THE WAY TO THE MASTER...
    posts - 49, comments - 18, trackbacks - 0, articles - 1
      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

    Java圖形用戶界面設計(轉

    Posted on 2006-02-24 17:26 fortune 閱讀(1038) 評論(0)  編輯  收藏 所屬分類: java技術

     

    深入了解布局管理器

    developerWorks
     

    將此頁作為電子郵件送

    未顯示需要 JavaScript 的文檔選項


    對此頁的評價

    幫助我們改進這些內容


    2002 年 7 月 05 日

    本文試圖通過作者自己的開發經歷介紹一些具體的應用實例,希望能給那些曾經象作者一樣苦悶的Java癡迷者一些幫助。

    前言

    隨著Internet的飛速發展,Java技術也得到了越來越廣泛的應用。而無論我們是采用J2SE、J2EE還是J2ME,GUI都是不能回避的問題。現在的應用軟件越來越要求界面友好、功能強大而又使用簡單。而眾所周知,在Java中進行GUI設計相對于其跨平臺、多線程等特性的實現要復雜和麻煩許多。這也是很多Java程序員抱怨的事情。但GUI已經成為程序發展的方向,所以我們也必須了解Java的GUI設計方法和特點。其實,采用Java提供的布局管理器接口和相應的布局管理類,我們也可以做出相當漂亮的界面來,當然實現起來肯定要比VB麻煩許多。本文試圖通過自己的開發經歷介紹一些具體的應用實例,希望能給那些曾經象我一樣苦悶的Java癡迷者一些幫助。



    回頁首


    Java中的布局管理器

    2.1 為什么要使用布局

    在實際編程中,我們每設計一個窗體,都要往其中添加若干組件。為了管理好這些組件的布局,我們就需要使用布局管理器。比如說,設計一個簡單的計算器,或一個文本編輯器等等。這些組件是讓JVM 自己任意安排呢?還是按照一定的位置關系進行規范的安排呢?當然應該選擇后者。將加入到容器的組件按照一定的順序和規則放置,使之看起來更美觀,這就是布局。在Java中,布局由布局管理器 (LayoutManager) 來管理。那么,我們在什么時候應該使用布局管理器?應選擇哪種布局管理器?又該怎樣使用布局管理器呢?

    如果你寫的是GUI程序,在使用AWT/Swing組件時就不應硬性設置組件的大小和位置,而應該使用Java的布局管理器(LayoutManager)來設置和管理可視組件的大小和位置,否則就有可能造成布局混亂。不信,你可以新建一個Frame(或JFrame),通過setBounds()方法往其中添加幾個Button(或JButton),一旦你將窗體拉大或縮小時,你會發現組件的排列完全不是按你所預想的那樣。為了解決這個問題,即當窗體(或容器)縮放時,組件位置也隨之合理調整,我們就需要使用布局管理器。

    為此,我們首先要知道Java的布局方式,Java提供的API中有些什么布局管理器,它們的布局特點是什么。

    2.2 Java的布局方式

    我們都知道,Java的GUI界面定義是由AWT類包和Swing類包來完成的。它在布局管理上采用了容器和布局管理分離的方案。也就是說,容器只管將其他組件放入其中,而不管這些組件是如何放置的。對于布局的管理交給專門的布局管理器類(LayoutManager)來完成。

    現在我們來看Java中布局管理器的具體實現。我們前面說過,Java中的容器類(Container),它們只管加入組件(Component),也就是說,它只使用自己的add()方法向自己內部加入組件。同時他記錄這些加入其內部的組件的個數,可以通過container.getComponentCount()方法類獲得組件的數目,通過container.getComponent(i)來獲得相應組件的句柄。然后LayoutManager類就可以通過這些信息來實際布局其中的組件了。

    Java已經為我們提供了幾個常用的布局管理器類,例如: FlowLayout、BorderLayout、GridLayout、GridBagLayout等。下面列表說明它們的布局特點:

    特點
    java.awt CardLayout 將組件象卡片一樣放置在容器中,在某一時刻只有一個組件可見
    java.awt FlowLayout 將組件按從左到右而后從上到下的順序依次排列,一行不能放完則折到下一行繼續放置
    java.awt GridLayout 形似一個無框線的表格,每個單元格中放一個組件
    java.awt BorderLayout 將組件按東、南、西、北、中五個區域放置,每個方向最多只能放置一個組件
    java.awt GridBagLayout 非常靈活,可指定組件放置的具體位置及占用單元格數目
    Javax.swing BoxLayout 就像整齊放置的一行或者一列盒子,每個盒子中一個組件
    Javax.swing SpringLayout 根據一組約束條件放置子組件
    Javax.swing ScrollPaneLayout 專用于JScrollPane,含一個Viewport,一個行頭、一個列頭、兩個滾動條和四個角組件
    Javax.swing OverlayLayout 以彼此覆蓋的形式疊置組件
    Javax.swing ViewportLayout JViewport的默認布局管理器

    事實上,在大多數情況下,綜合運用好這些布局管理器已可以滿足需要。當然對于特殊的具體應用,我們可以通過實現LayoutManager或LayoutManager2接口來定義自己的布局管理器。下面我們通過幾個實例來了解幾個常用的布局管理器的使用方法。



    回頁首


    GUI設計應用實例

    3.1 FlowLayout/GridLayout/BorderLayout的應用實例

    3.1.1應用背景

    假設我們要編寫一個簡單的計算器JApplet,其基本界面如下:




    3.1.2解決方法

    通過其界面要求可知,我們可以通過將"BackSpace"和"Clear"JButton放置在一個JPanel(1)中,采用FlowLayout布局;將顯示結果的JTextField和該JPanel一起放置到另外一個JPanel(2),采用GridLayout布局;而將其它的JButton則放置在另外一個JPanel(3)中,采用GridLayout布局;再將JPanel(2)和JPanel(3)加入該JApplet,即可實現界面需求。具體實現方法如下:

    
    /**以FlowLayout布局JPanel(1)*/
    JPanel p1 = new JPanel(new FlowLayout()); //默認組件從居中開始
    //加入"BackSpace"和"Clear"JButton
    p1.add(backButton);    
    p1.add(clearButton);
    /**以GridLayout布局JPanel(2)*/
    JPanel p2 = new JPanel(new GridLayout(2, 1));   //放置2行,每行1個組件
    //加入顯示結果的JTextField和JPanel(1)
    p2.add(displayField);  
    p2.add(p1);
    /**以GridLayout布局JPanel(3)*/
    JPanel p3 = new JPanel(new GridLayout(4, 5));   //放置4行,每行5個組件
    String buttonStr = "789/A456*B123-C0.D+=";
    for (int i = 0; i < buttonStr.length(); i++)
    this.addButton(p3, buttonStr.substring(i, i + 1));
    	
    //addButton方法
    	private void addButton(Container c, String s)
        {
            JButton b = new JButton(s);
            if (s.equals("A"))
                b.setText("sqrt");
            else if (s.equals("B"))
                b.setText("1/x");
            else if (s.equals("C"))
                b.setText("%");
            else if (s.equals("D"))
                b.setText("+/-");
            b.setForeground(Color.blue);
            c.add(b);
            b.addActionListener(this);
        }
    /**以BorderLayout布局JApplet*/
    	this.setLayout(new BorderLayout());
    this.add(p2, "North");
    this.add(p3, "Center");
    

    這樣,就一切OK啦。具體的實現代碼可參見附件中的CalculateApplet.java文件。

    3.2 帶工具欄和狀態欄的GridLayout/BorderLayout應用實例

    3.2.1實際問題

    在很多情況下我們需要動態設置工具欄和狀態欄,看下面的應用實例:




    以上是在視圖的工具欄和狀態欄都被復選的時候,以下分別為某一個沒選或都未選的情況。




    3.2.2解決方法

    
    	/**工具欄JToolBar采用從左開始的FlowLayout布局*/
    JToolBar toolBar = new JToolBar();	
    toolBar.setBorderPainted(false); //不畫邊界
        toolBar.setLayout(new FlowLayout(FlowLayout.LEFT));
    	
    /**窗體采用動態的BorderLayout布局,通過獲取工具欄或狀態欄的復選標記進行界面的動態調整*/
    JSplitPane splitPane = new JSplitPane();
    splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT); //設置統計窗口分隔條的方向
    splitPane.setDividerLocation(300); 	//設置分隔條的位置
    splitPane.setOneTouchExpandable(true);
    JCheckBoxMenuItem toolBarItem = new JCheckBoxMenuItem("工具欄(T)", true);
        JLabel statusLabel = new JLabel("當前統計目標:");
        JCheckBoxMenuItem statusBarItem = new JCheckBoxMenuItem("狀態欄(S)", true);
    
    /**設置系統窗體布局并動態設置工具欄和狀態欄*/
        private void setLayout()
        {
            if (toolBarItem.getState() &&' statusBarItem.getState())
            {
                this.getContentPane().add(BorderLayout.NORTH, toolBar);
                this.getContentPane().add(BorderLayout.CENTER, splitPane);
                this.getContentPane().add(BorderLayout.SOUTH, statusLabel);
            }
            else if (toolBarItem.getState() && !statusBarItem.getState())
            {
                this.getContentPane().add(BorderLayout.NORTH, toolBar);
                this.getContentPane().remove(statusLabel);
            }
            else if (statusBarItem.getState() && !toolBarItem.getState())
            {
                this.getContentPane().add(BorderLayout.SOUTH, statusLabel);
                this.getContentPane().remove(toolBar);
            }
            else if (!toolBarItem.getState() && !statusBarItem.getState())
            {
                this.getContentPane().remove(toolBar);
                this.getContentPane().remove(statusLabel);
            }
            this.show(); //添加或移去組件后刷新界面
        }
    

    通過該方法即可實現界面的動態刷新與調整。

    3.3 GridBagLayout應用實例

    3.3.1實際問題

    GridBagLayout是Java API提供的一個較復雜的布局管理器,利用好它可以解決許多實際編程中的令人煩惱的界面設計問題。看下面的界面應用實例:




    3.3.2解決方法

    這個界面的設計比較復雜,涉及多個標簽域(JLabel)、文本域(JTextField、JTextArea),且標簽域的大小還不一樣,如附件標簽;并當窗體縮放時,標簽域的大小應不改變,而文本域則必須自適應縮放。如何來實現呢?請看下面的代碼:(工具欄的實現不再贅述)

    
    /**系統的界面布局實現*/
    GridBagConstraints gridBag = new GridBagConstraints();
    gridBag.fill = GridBagConstraints.HORIZONTAL;  //以水平填充方式布局
        gridBag.weightx = 0;  //行長不變
        gridBag.weighty = 0;  //列高不變
        fromLabel.setForeground(Color.blue);
        fromLabel.setFont(new Font("Alias", Font.BOLD, 16));
        this.add(fromLabel, gridBag, 0, 1, 1, 1);  //指定發信人標簽位置
        receiveLabel.setForeground(Color.blue);
        receiveLabel.setFont(new Font("Alias", Font.BOLD, 16));
        this.add(receiveLabel, gridBag, 0, 2, 1, 1); //指定收信人標簽位置及大小
        ccLabel.setForeground(Color.blue);
        ccLabel.setFont(new Font("Alias", Font.BOLD, 16));
        this.add(ccLabel, gridBag, 0, 3, 1, 1); //指定抄送人標簽位置及大小
        subjectLabel.setForeground(Color.blue);
        subjectLabel.setFont(new Font("Alias", Font.BOLD, 16));
        his.add(subjectLabel, gridBag, 0, 4, 1, 1); //指定主題標簽位置及大小
        accessoryLabel.setForeground(Color.blue);
        accessoryLabel.setFont(new Font("Alias", Font.BOLD, 16));
        this.add(accessoryLabel, gridBag, 0, 5, 1, 1); //指定附件標簽位置及大小
    
        gridBag.weightx = 100; //行自適應縮放
        gridBag.weighty = 0;//列高不變
        fromField.setText("admin@watermelon.com");
       	this.add(fromField, gridBag, 1, 1, 2, 1); //指定發信人文本域(JTextField)位置及大小
        this.add(receiveField, gridBag, 1, 2, 2, 1); //指定收信人文本域(JTextField)位置及大小
        this.add(ccField, gridBag, 1, 3, 2, 1); //指定抄送人文本域(JTextField)位置及大小
        this.add(subjectField, gridBag, 1, 4, 2, 1); //指定主題文本域(JTextField)位置及大小
        accessoryArea.setEditable(false); 
    //設置不顯示水平滾動條(該JTextArea置于JScrollPane中)
    accessoryScroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        this.add(accessoryScroll, gridBag, 1, 5, 2, 1); //指定附件文本區(JTextArea)位置及大小
    
        gridBag.fill = GridBagConstraints.BOTH;//采用全填充方式布局
        gridBag.weightx = 100;//行自適應縮放
        gridBag.weighty = 100;//列自適應縮放
        mailArea.setBackground(Color.blue);
        mailArea.setForeground(Color.yellow);
        mailArea.setTabSize(4);
        //指定信件主體區(JTextArea)的位置及大小。(該JTextArea也置于JScrollPane中)
    	this.add(scroll, gridBag, 0, 6, 3, 1);
    
    	在上面用到一個方法add(),這個方法是自己定義的:
    private void add(Component c, GridBagConstraints gbc, int x, int y, int w, int h)
        {
            gbc.gridx = x;
            gbc.gridy = y;
            gbc.gridheight = h;
            gbc.gridwidth = w;
            this.getContentPane().add(c, gbc);
        }
    

    在用到GridBagLayout布局管理器的組件添加方法中,都可以重用它。事實上,你還可以在方法最前面加一個參數Container cn,而將方法中的this相應的改為cn,就可以通用于所有需要使用GridBagLayout進行布局管理的容器中。在下面的復雜例程中我們就會用到。

    3.4 綜合多個布局的復雜應用實例

    3.4.1實際問題

    請看下面的實際應用界面要求:


    (圖3.4-1)
    圖3.4-1

    (圖3.4-2)
    圖3.4-2

    (圖3.4-3)
    圖3.4-3

    在這個具體應用中,底部的JButton組是確定的,但JTabbedPane的每一個選項都不同,如何實現呢?

    3.4.2解決方案

    首先我們可以采用BorderLayout確定主題對話框的布局方式,實現方法如下:

    
    JTabbedPane dbTabPane = new JTabbedPane();
    …… //下面需要用到的JButton等組件變量定義(或聲明)
    private void initLayout()
    {
    initDBTabPane();//初始化JTabbedPane:DBTabPane組件
        this.getContentPane().add(BorderLayout.CENTER, dbTabPane);
    	//將JTabbedPane組件:dbTabPane布局于JDialog對話框的中間
            initButtonPanel();//初始化JPanel:ButtonPanel組件
            this.getContentPane().add(BorderLayout.SOUTH, buttonPanel);
    	//將JPanel組件:buttonPanel布局于JDialog對話框的底部(南面)
        }
    
    private void initDBTabPane()
    {
            JPanel loginPanel = new JPanel(new GridLayout(10, 1));
    //為保證兩個JCheckBox組件位于頂端,設置為共10行,每行一個組件的布局,但只
    //放置界面要求的兩個組件,這樣就保持了界面的美觀,否則如定義為
    //Gridlayout(2,1)則會使兩個組件居中,而且中間會隔開較長的距離。
    pwdBox.setMnemonic('P');
            loginPanel.add(pwdBox);
            dspBox.setMnemonic('D');
            loginPanel.add(dspBox);
            dbTabPane.add("Login", loginPanel); //設置"Login"JPanel(圖3.4-1)的布局
            needRadio.setMnemonic('N');
            allRadio.setMnemonic('A');
            cacheRadio.setMnemonic('U');
            radioPanel.setBorder(new TitledBorder("Load Option"));//加上邊界標題
            radioPanel.add(needRadio);
            radioPanel.add(allRadio);
            radioPanel.add(cacheRadio);
    //以上為加入需要的JRadioButton組件到指定的JPanel: radioPanel
            queryPanel.add(radioPanel);//加入含JRadioButton組的JPanel到queryPanel
            reqBox.setMnemonic('R');
            boxPanel.add(reqBox);
            saveBox.setMnemonic('S');
            boxPanel.add(saveBox);
            autoBox.setMnemonic('t');
            boxPanel.add(autoBox);
    //以上為加入需要的JCheckBox組到指定的JPanel:boxPanel
            queryPanel.add(boxPanel); //加入含JCheckBox組的JPanel到queryPanel
            dbTabPane.add("Query", queryPanel);//設置"Query"JPanel(圖3.4-2)的布局
            initDrvPanel();
        }
    
    /**設置"Drivers"JPanel(圖3.4-3)的布局*/
    private void initDrvPanel()
    {
            gridBag.fill = GridBagConstraints.HORIZONTAL;
            gridBag.weightx = 100;
            gridBag.weighty = 0;
            tipLabel.setForeground(Color.black);
            this.add(drvPanel, tipLabel, gridBag, 0, 0, 4, 1);
            urlLabel.setForeground(Color.black);
            this.add(drvPanel, urlLabel, gridBag, 0, 5, 4, 1);
            urlField.setEditable(false);
            this.add(drvPanel, urlField, gridBag, 0, 6, 4, 1);
            gridBag.weightx = 0;
            gridBag.weighty = 0;
            addButton.setMnemonic('A');
            this.add(drvPanel, addButton, gridBag, 3, 1, 1, 1);
            editButton.setMnemonic('E');
            this.add(drvPanel, editButton, gridBag, 3, 2, 1, 1);
            removeButton.setMnemonic('R');
            this.add(drvPanel, removeButton, gridBag, 3, 3, 1, 1);
            gridBag.fill = GridBagConstraints.BOTH;
            gridBag.weightx = 100;
            gridBag.weighty = 100;
           	//設置JTable組件:drvTable的從0到7行第0列的值
    for (int i = 0; i < 8; i++)
           		drvTable.setValueAt(drvStrs[i],i,0); 
    //設置JTable的列頭
    drvTable.getColumn(drvTable.getColumnName(0)).setHeaderValue("All Drivers");
            drvTable.setShowGrid(false);//設置不顯示網格線
            this.add(drvPanel, drvScroll, gridBag, 0, 1, 3, 4);
            dbTabPane.add("Drivers", drvPanel);
       }
    
    /**初始化底部JButton組的布局*/
    private void initButtonPanel()
        {
            JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
    //從右邊開始進行FlowLayout布局
    okButton.setMnemonic('O');
            buttonPanel.add(okButton);
            cancelButton.setMnemonic('C');
            buttonPanel.add(cancelButton);
            helpButton.setMnemonic('H');
            buttonPanel.add(helpButton);
        }
    
    /**給指定的容器cn在指定的(x,y)位置放置指定大小(寬度=w,高度=h)的組件c*/
    private void add(Container cn, Component c, GridBagConstraints gbc, int x, int y, int w, int h)
    {
            gbc.gridx = x;
            gbc.gridy = y;
            gbc.gridwidth = w;
            gbc.gridheight = h;
            cn.add(c, gbc);
        }
    



    回頁首


    結束語

    以上是本人在兩年多J2EE應用開發中,總結的關于用Java進行GUI設計的一些經驗,希望能給曾經象我一樣迷惘,但依舊對Java一往情深,至今仍在摸索探求Java GUI設計捷徑的朋友一些啟示。更希望借此機會拋磚引玉,與更多的朋友進行交流與探討。其實,在Java中所有的布局管理器都要實現一個接口,即LayoutManager Inerface或者是它的一個子接口LayoutManager2 Interface,后者用于更復雜的布局管理。如果在實際應用中,覺得Java API提供的這些布局管理器仍不夠用,你完全可以自己來實現其中某一個接口的方法,從而為你自己的具體GUI應用設計提供更好的布局管理。

    主站蜘蛛池模板: 亚洲爆乳成av人在线视菜奈实| 亚洲电影国产一区| 日韩亚洲产在线观看| 全免费毛片在线播放| 亚洲人和日本人jizz| 99热在线精品免费全部my| 亚洲a级成人片在线观看| AV大片在线无码永久免费| 亚洲国产福利精品一区二区| 精品国产sm捆绑最大网免费站| 亚洲av无码国产综合专区| 免费中文熟妇在线影片| 亚洲a∨国产av综合av下载| 免费又黄又爽的视频| 又大又硬又粗又黄的视频免费看| 无码人妻久久一区二区三区免费丨| 国产精品高清视亚洲一区二区| 色吊丝永久在线观看最新免费| 亚洲日韩在线中文字幕综合 | 一级做a爰片久久毛片免费陪 | 外国成人网在线观看免费视频| 亚洲最大的视频网站| 最新中文字幕免费视频| 四虎影视在线看免费观看| 久久精品国产亚洲麻豆| 在线精品一卡乱码免费| 国产精品亚洲色图| 久久久久久久综合日本亚洲| 久久国产免费福利永久| 国产成人精品亚洲| 亚洲av日韩av无码黑人| 精品熟女少妇AV免费观看| 一级做a爱过程免费视| 亚洲精品偷拍无码不卡av| 四虎影视永久免费观看网址| 国产永久免费高清在线| 国产午夜亚洲精品国产| 亚洲综合区小说区激情区| 亚洲一区二区免费视频| 国产尤物在线视精品在亚洲| 久久亚洲国产伦理|