FORTUNE

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

           

          深入了解布局管理器

          developerWorks
           

          將此頁(yè)作為電子郵件送

          未顯示需要 JavaScript 的文檔選項(xiàng)


          對(duì)此頁(yè)的評(píng)價(jià)

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


          2002 年 7 月 05 日

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

          前言

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



          回頁(yè)首


          Java中的布局管理器

          2.1 為什么要使用布局

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

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

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

          2.2 Java的布局方式

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

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

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

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

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



          回頁(yè)首


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

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

          3.1.1應(yīng)用背景

          假設(shè)我們要編寫(xiě)一個(gè)簡(jiǎn)單的計(jì)算器JApplet,其基本界面如下:




          3.1.2解決方法

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

          
          /**以FlowLayout布局JPanel(1)*/
          JPanel p1 = new JPanel(new FlowLayout()); //默認(rèn)組件從居中開(kāi)始
          //加入"BackSpace"和"Clear"JButton
          p1.add(backButton);    
          p1.add(clearButton);
          /**以GridLayout布局JPanel(2)*/
          JPanel p2 = new JPanel(new GridLayout(2, 1));   //放置2行,每行1個(gè)組件
          //加入顯示結(jié)果的JTextField和JPanel(1)
          p2.add(displayField);  
          p2.add(p1);
          /**以GridLayout布局JPanel(3)*/
          JPanel p3 = new JPanel(new GridLayout(4, 5));   //放置4行,每行5個(gè)組件
          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啦。具體的實(shí)現(xiàn)代碼可參見(jiàn)附件中的CalculateApplet.java文件。

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

          3.2.1實(shí)際問(wèn)題

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




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




          3.2.2解決方法

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

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

          3.3 GridBagLayout應(yīng)用實(shí)例

          3.3.1實(shí)際問(wèn)題

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




          3.3.2解決方法

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

          
          /**系統(tǒng)的界面布局實(shí)現(xiàn)*/
          GridBagConstraints gridBag = new GridBagConstraints();
          gridBag.fill = GridBagConstraints.HORIZONTAL;  //以水平填充方式布局
              gridBag.weightx = 0;  //行長(zhǎng)不變
              gridBag.weighty = 0;  //列高不變
              fromLabel.setForeground(Color.blue);
              fromLabel.setFont(new Font("Alias", Font.BOLD, 16));
              this.add(fromLabel, gridBag, 0, 1, 1, 1);  //指定發(fā)信人標(biāo)簽位置
              receiveLabel.setForeground(Color.blue);
              receiveLabel.setFont(new Font("Alias", Font.BOLD, 16));
              this.add(receiveLabel, gridBag, 0, 2, 1, 1); //指定收信人標(biāo)簽位置及大小
              ccLabel.setForeground(Color.blue);
              ccLabel.setFont(new Font("Alias", Font.BOLD, 16));
              this.add(ccLabel, gridBag, 0, 3, 1, 1); //指定抄送人標(biāo)簽位置及大小
              subjectLabel.setForeground(Color.blue);
              subjectLabel.setFont(new Font("Alias", Font.BOLD, 16));
              his.add(subjectLabel, gridBag, 0, 4, 1, 1); //指定主題標(biāo)簽位置及大小
              accessoryLabel.setForeground(Color.blue);
              accessoryLabel.setFont(new Font("Alias", Font.BOLD, 16));
              this.add(accessoryLabel, gridBag, 0, 5, 1, 1); //指定附件標(biāo)簽位置及大小
          
              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è)置不顯示水平滾動(dòng)條(該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);
          
          	在上面用到一個(gè)方法add(),這個(gè)方法是自己定義的:
          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í)上,你還可以在方法最前面加一個(gè)參數(shù)Container cn,而將方法中的this相應(yīng)的改為cn,就可以通用于所有需要使用GridBagLayout進(jìn)行布局管理的容器中。在下面的復(fù)雜例程中我們就會(huì)用到。

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

          3.4.1實(shí)際問(wèn)題

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


          (圖3.4-1)
          圖3.4-1

          (圖3.4-2)
          圖3.4-2

          (圖3.4-3)
          圖3.4-3

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

          3.4.2解決方案

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

          
          JTabbedPane dbTabPane = new JTabbedPane();
          …… //下面需要用到的JButton等組件變量定義(或聲明)
          private void initLayout()
          {
          initDBTabPane();//初始化JTabbedPane:DBTabPane組件
              this.getContentPane().add(BorderLayout.CENTER, dbTabPane);
          	//將JTabbedPane組件:dbTabPane布局于JDialog對(duì)話(huà)框的中間
                  initButtonPanel();//初始化JPanel:ButtonPanel組件
                  this.getContentPane().add(BorderLayout.SOUTH, buttonPanel);
          	//將JPanel組件:buttonPanel布局于JDialog對(duì)話(huà)框的底部(南面)
              }
          
          private void initDBTabPane()
          {
                  JPanel loginPanel = new JPanel(new GridLayout(10, 1));
          //為保證兩個(gè)JCheckBox組件位于頂端,設(shè)置為共10行,每行一個(gè)組件的布局,但只
          //放置界面要求的兩個(gè)組件,這樣就保持了界面的美觀,否則如定義為
          //Gridlayout(2,1)則會(huì)使兩個(gè)組件居中,而且中間會(huì)隔開(kāi)較長(zhǎng)的距離。
          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"));//加上邊界標(biāo)題
                  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)格線(xiàn)
                  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));
          //從右邊開(kāi)始進(jìn)行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);
              }
          



          回頁(yè)首


          結(jié)束語(yǔ)

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

          主站蜘蛛池模板: 玛纳斯县| 蒙自县| 沾益县| 任丘市| 太原市| 宁远县| 河西区| 东宁县| 从化市| 西和县| 莆田市| 会理县| 新河县| 陵川县| 山东| 固安县| 江山市| 乌兰浩特市| 合山市| 开封县| 庆安县| 阳泉市| 西充县| 灌阳县| 讷河市| 新巴尔虎右旗| 鹤壁市| 晋州市| 瓮安县| 凌云县| 双辽市| 甘孜县| 五大连池市| 金华市| 眉山市| 德钦县| 万荣县| 吉水县| 郯城县| 阳朔县| 治县。|