<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 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    Java圖形用戶界面設(shè)計(轉(zhuǎn)

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

     

    深入了解布局管理器

    developerWorks
     

    將此頁作為電子郵件送

    未顯示需要 JavaScript 的文檔選項


    對此頁的評價

    幫助我們改進這些內(nèi)容


    2002 年 7 月 05 日

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

    前言

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



    回頁首


    Java中的布局管理器

    2.1 為什么要使用布局

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

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

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

    2.2 Java的布局方式

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

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

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

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

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



    回頁首


    GUI設(shè)計應(yīng)用實例

    3.1 FlowLayout/GridLayout/BorderLayout的應(yīng)用實例

    3.1.1應(yīng)用背景

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




    3.1.2解決方法

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

    
    /**以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個組件
    //加入顯示結(jié)果的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啦。具體的實現(xiàn)代碼可參見附件中的CalculateApplet.java文件。

    3.2 帶工具欄和狀態(tài)欄的GridLayout/BorderLayout應(yīng)用實例

    3.2.1實際問題

    在很多情況下我們需要動態(tài)設(shè)置工具欄和狀態(tài)欄,看下面的應(yīng)用實例:




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




    3.2.2解決方法

    
    	/**工具欄JToolBar采用從左開始的FlowLayout布局*/
    JToolBar toolBar = new JToolBar();	
    toolBar.setBorderPainted(false); //不畫邊界
        toolBar.setLayout(new FlowLayout(FlowLayout.LEFT));
    	
    /**窗體采用動態(tài)的BorderLayout布局,通過獲取工具欄或狀態(tài)欄的復(fù)選標記進行界面的動態(tài)調(diào)整*/
    JSplitPane splitPane = new JSplitPane();
    splitPane.setOrientation(JSplitPane.VERTICAL_SPLIT); //設(shè)置統(tǒng)計窗口分隔條的方向
    splitPane.setDividerLocation(300); 	//設(shè)置分隔條的位置
    splitPane.setOneTouchExpandable(true);
    JCheckBoxMenuItem toolBarItem = new JCheckBoxMenuItem("工具欄(T)", true);
        JLabel statusLabel = new JLabel("當前統(tǒng)計目標:");
        JCheckBoxMenuItem statusBarItem = new JCheckBoxMenuItem("狀態(tài)欄(S)", true);
    
    /**設(shè)置系統(tǒng)窗體布局并動態(tài)設(shè)置工具欄和狀態(tài)欄*/
        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(); //添加或移去組件后刷新界面
        }
    

    通過該方法即可實現(xiàn)界面的動態(tài)刷新與調(diào)整。

    3.3 GridBagLayout應(yīng)用實例

    3.3.1實際問題

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




    3.3.2解決方法

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

    
    /**系統(tǒng)的界面布局實現(xiàn)*/
    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);  //指定發(fā)信人標簽位置
        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; //行自適應(yīng)縮放
        gridBag.weighty = 0;//列高不變
        fromField.setText("admin@watermelon.com");
       	this.add(fromField, gridBag, 1, 1, 2, 1); //指定發(fā)信人文本域(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); 
    //設(shè)置不顯示水平滾動條(該JTextArea置于JScrollPane中)
    accessoryScroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        this.add(accessoryScroll, gridBag, 1, 5, 2, 1); //指定附件文本區(qū)(JTextArea)位置及大小
    
        gridBag.fill = GridBagConstraints.BOTH;//采用全填充方式布局
        gridBag.weightx = 100;//行自適應(yīng)縮放
        gridBag.weighty = 100;//列自適應(yīng)縮放
        mailArea.setBackground(Color.blue);
        mailArea.setForeground(Color.yellow);
        mailArea.setTabSize(4);
        //指定信件主體區(qū)(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布局管理器的組件添加方法中,都可以重用它。事實上,你還可以在方法最前面加一個參數(shù)Container cn,而將方法中的this相應(yīng)的改為cn,就可以通用于所有需要使用GridBagLayout進行布局管理的容器中。在下面的復(fù)雜例程中我們就會用到。

    3.4 綜合多個布局的復(fù)雜應(yīng)用實例

    3.4.1實際問題

    請看下面的實際應(yīng)用界面要求:


    (圖3.4-1)
    圖3.4-1

    (圖3.4-2)
    圖3.4-2

    (圖3.4-3)
    圖3.4-3

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

    3.4.2解決方案

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

    
    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組件位于頂端,設(shè)置為共10行,每行一個組件的布局,但只
    //放置界面要求的兩個組件,這樣就保持了界面的美觀,否則如定義為
    //Gridlayout(2,1)則會使兩個組件居中,而且中間會隔開較長的距離。
    pwdBox.setMnemonic('P');
            loginPanel.add(pwdBox);
            dspBox.setMnemonic('D');
            loginPanel.add(dspBox);
            dbTabPane.add("Login", loginPanel); //設(shè)置"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);//設(shè)置"Query"JPanel(圖3.4-2)的布局
            initDrvPanel();
        }
    
    /**設(shè)置"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;
           	//設(shè)置JTable組件:drvTable的從0到7行第0列的值
    for (int i = 0; i < 8; i++)
           		drvTable.setValueAt(drvStrs[i],i,0); 
    //設(shè)置JTable的列頭
    drvTable.getColumn(drvTable.getColumnName(0)).setHeaderValue("All Drivers");
            drvTable.setShowGrid(false);//設(shè)置不顯示網(wǎng)格線
            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);
        }
    



    回頁首


    結(jié)束語

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

    主站蜘蛛池模板: 最近国语视频在线观看免费播放| 久久免费视频网站| 暖暖免费在线中文日本| 国产三级免费观看| 亚洲精品视频在线播放| 一级特黄录像视频免费| 国产片AV片永久免费观看| 在线播放高清国语自产拍免费| 亚洲AV天天做在线观看| 一个人免费观看日本www视频| 婷婷亚洲综合五月天小说| 妞干网在线免费视频| 久久免费观看视频| 国产亚洲AV手机在线观看| 婷婷亚洲综合五月天小说在线| 欧美大尺寸SUV免费| 亚洲欧洲AV无码专区| 国产一卡二卡四卡免费| 亚洲另类图片另类电影| 999久久久免费精品国产| eeuss在线兵区免费观看| 国产美女亚洲精品久久久综合| 国内精品免费麻豆网站91麻豆| 人碰人碰人成人免费视频| 亚洲精品国产精品乱码不卞| 精品特级一级毛片免费观看| 又粗又黄又猛又爽大片免费| 无遮挡呻吟娇喘视频免费播放| 亚洲国产精品自在拍在线播放| 全黄A免费一级毛片| 亚洲av片不卡无码久久| 国产成人免费爽爽爽视频 | 久久亚洲国产成人影院| 成人免费午间影院在线观看| 亚洲sm另类一区二区三区| 免费国产成人高清在线观看麻豆 | 99久久久精品免费观看国产| 国精产品一区一区三区免费视频 | 成人性生活免费视频| 69视频在线观看免费| 亚洲伊人久久大香线焦|