程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java的Swing編程中應用SwingWorker線程形式及頂層容器

Java的Swing編程中應用SwingWorker線程形式及頂層容器

編輯:關於JAVA

Java的Swing編程中應用SwingWorker線程形式及頂層容器。本站提示廣大學習愛好者:(Java的Swing編程中應用SwingWorker線程形式及頂層容器)文章只能為提供參考,不一定能成為您想要的結果。以下是Java的Swing編程中應用SwingWorker線程形式及頂層容器正文


應用SwingWorker線程形式

謹嚴地應用並發機制對Swing開辟人員來講異常主要。一個好的Swing法式應用並發機制來創立不會掉去呼應的用戶接口-不論是甚麼樣的用戶交互,法式總可以或許對其給出呼應。創立一個有呼應的法式,開辟人員必需學會若何在Swing框架中應用多線程。
一個Swing開辟人員將會與上面幾類線程打交道:
(1)Initial threads(初始線程),此類線程將履行初始化運用代碼。
(2)The event dispatch thread(事宜派發線程),一切的事宜處置代碼在這裡履行。年夜多半與Swing框架交互的代碼也必需履行這個線程。
(3)Worker threads(任務線程),也稱作background threads(後台線程),此類線程將履行一切消費時光的義務。
開辟人員不須要在代碼中顯式的創立這些線程:它們是由runtime或Swing框架供給的。開辟人員的任務就是應用這些線程來創立具有呼應的,耐久的Swing法式。
好像一切其他在Java平台上運轉的法式,一個Swing法式可以創立額定的線程和線程池,這須要應用本文行將引見的辦法。本文將引見以上這三種線程。任務線程的評論辯論將觸及到應用javax.swing.SwingWorker類。這個類有很多有效的特征,包含在任務線程義務與其他線程義務之間的通訊與協作。
1.初始線程
每一個法式都邑在運用邏輯開端時生成一系列的線程。在尺度的法式中,只要一個如許的線程:這個線程將挪用法式主類中的main辦法。在applet中初始線程是applet對象的結構子,它將挪用init辦法;這些actions能夠在一個單一的線程中履行,或在兩個或三個分歧的線程中,這些都根據Java平台的詳細完成。在本文中,我們稱這類線程為初始線程(initial threads)。
在Swing法式中,初始線程沒有許多工作要做。它們最根本的義務是創立一個Runnable對象,用於初始化GUI和為那些用於履行事宜派發線程中的事宜的對象編排次序。一旦GUI被創立,法式將重要由GUI事宜驅動,個中的每一個事宜驅動將惹起一個在事宜派發線程中事宜的履行。法式代碼可以編排額定的義務給事宜驅動線程(條件是它們會被很快的履行,如許才不會攪擾事宜的處置)或創立任務線程(用於履行消費時光的義務)。
一個初始線程編排GUI創立義務是經由過程挪用javax.swing.SwingUtilities.invokeLater或javax.swing.SwingUtilities.invokeAndWait。這兩個辦法都帶有一個獨一的參數:Runnable用於界說新的義務。它們獨一的差別是:invokerLater僅僅編排義務並前往;invokeAndWait將期待義務履行終了才前往。
看上面示例:

SwingUtilities.invokeLater(new Runnable()) {
 public void run() {
  createAndShowGUI();
 }
}

 在applet中,創立GUI的義務必需被放入init辦法中而且應用invokeAndWait;不然,初始進程將有能夠在GUI創立完之前完成,如許將有能夠湧現成績。在其他的情形下,編排GUI創立義務平日是初始線程中最初一個被履行的,所以應用invokeLater或invokeAndWait都可以。
為何初始線程不直接創立GUI?由於簡直一切的用於創立和交互Swing組件的代碼必需在事宜派發線程中履行。這個束縛將鄙人文中評論辯論。
 2.事宜派發線程
Swing事宜的處置代碼在一個特別的線程中履行,這個線程被稱為事宜派發線程。年夜部門挪用Swing辦法的代碼都在這個線程中被履行。如許做是需要的,由於年夜部門Swing對象是“非線程平安的”。
可以將代碼的履行想象成在事宜派發線程中履行一系列短小的義務。年夜部門義務被事宜處置辦法挪用,諸如ActionListener.actionPerformed。其他的義務將被法式代碼編排,應用invokeLater或invokeAndWait。在事宜派發線程中的義務必需可以或許被疾速履行完成,如若否則,未經處置的事宜被積存,用戶界面將變得“呼應緩慢”。
假如你須要肯定你的代碼能否是在事宜派發線程中履行,可挪用javax.swing.SwingUtilities.isEventDispatchThread。
 3.任務線程與SwingWorker
當一個Swing法式須要履行一個長時光的義務,平日將應用一個任務線程來完成。每一個義務在一個任務線程中履行,它是一個javax.swing.SwingWorker類的實例。SwingWorker類是籠統類;你必需界說它的子類來創立一個SwingWorker對象;平日應用匿名外部類來這做這些。
SwingWorker供給一些通訊與掌握的特點:
(1)SwingWorker的子類可以界說一個辦法,done。當後台義務完成的時刻,它將主動的被事宜派發線程挪用。
(2)SwingWorker類完成java.util.concurrent.Future。這個接口許可後台義務供給一個前往值給其他線程。該接口中的辦法還供給許可撤消後台義務和肯定後台義務是被完成了照樣被撤消的功效。
(3)後台義務可以經由過程挪用SwingWorker.publish來供給中央成果,事宜派發線程將會挪用該辦法。
(4)後台義務可以界說綁定屬性。綁定屬性的變更將觸發事宜,事宜派發線程將挪用事宜處置法式來處置這些被觸發的事宜。
4.簡略的後台義務
上面引見一個示例,這個義務異常簡略,但它是潛伏地消費時光的義務。TumbleItem applet導入一系列的圖片文件。假如這些圖片文件是經由過程初始線程導入的,那末將在GUI湧現之前有一段延遲。假如這些圖片文件是在事宜派發線程中導入的,那末GUI將有能夠湧現暫時沒法呼應的情形。
為懂得決這些成績,TumbleItem類在它初始化時創立並履行了一個StringWorker類的實例。這個對象的doInBackground辦法,在一個任務線程中履行,將圖片導入一個ImageIcon數組,而且前往它的一個援用。接著done辦法,在事宜派發線程中履行,獲得前往的援用,將其放在applet類的成員變量imgs中。如許做可以許可TumbleItem類連忙創立GUI,而不用期待圖片導入完成。
上面的示例代碼界說和完成了一個SwingWorker對象。

SwingWorker worker = new SwingWorker<ImageIcon[], Void>() {
 @Override
 public ImageIcon[] doInBackground() {
  final ImageIcon[] innerImgs = new ImageIcon[nimgs];
  for (int i = 0; i < nimgs; i++) {
   innerImgs[i] = loadImage(i+1);
  }
  return innerImgs;
 }
 
 @Override
 public void done() {
  //Remove the "Loading images" label.
  animator.removeAll();
  loopslot = -1;
  try {
   imgs = get();
  } catch (InterruptedException ignore) {}
  catch (java.util.concurrent.ExecutionException e) {
   String why = null;
   Throwable cause = e.getCause();
   if (cause != null) {
    why = cause.getMessage();
   } else {
    why = e.getMessage();
   }
   System.err.println("Error retrieving file: " + why);
  }
 }
};

     一切的繼續自SwingWorker的子類都必需完成doInBackground;完成done辦法是可選的。
留意,SwingWorker是一個范型類,有兩個參數。第一個類型參數指定doInBackground的前往類型。同時也是get辦法的類型,它可以被其他線程挪用以取得來自於doInBackground的前往值。第二個類型參數指定中央成果的類型,這個例子沒有前往中央成果,所以設為void。
應用get辦法,可使對象imgs的援用(在任務線程中創立)在事宜派發線程中獲得應用。如許便可以在線程之間同享對象。
現實上有兩個辦法來獲得doInBackground類前往的對象。
(1)挪用SwingWorker.get沒有參數。假如後台義務沒有完成,get辦法將壅塞直到它完成。
(2)挪用SwingWorker.get帶參數指定timeout。假如後台義務沒有完成,壅塞直到它完成-除非timeout期滿,在這類情形下,get將拋出java.util.concurrent.TimeoutException。
5.具有中央成果的義務
讓一個正在任務的後台義務供給中央成果是很有效處的。後台義務可以挪用SwingWorker.publish辦法來做到這個。這個辦法接收很多參數。每一個參數必需是由SwingWorker的第二個類型參數指定的一種。
可以籠罩(override)SwingWorker.process來保留由publish辦法供給的成果。這個辦法是由事宜派發線程挪用的。來自publish辦法的成果集平日是由一個process辦法搜集的。
我們看一下Filpper.java供給的實例。這個法式經由過程一個後台義務發生一系列的隨機布爾值測試java.util.Random。就比如是一個投硬幣實驗。為了申報它的成果,後台義務應用了一個對象FlipPair。

private static class FlipPair {
 private final long heads, total;
 FlipPair(long heads, long total) {
  this.heads = heads;
  this.total = total;
 }
}

heads表現true的成果;total表現總的扔擲次數。
後台法式是一個FilpTask的實例:
private class FlipTask extends SwingWorker<Void, FlipPair> {
由於義務沒有前往一個終究成果,這裡不須要指定第一個類型參數是甚麼,應用Void。在每次“扔擲”前任務挪用publish:

@Override
protected Void doInBackground() {
 long heads = 0;
 long total = 0;
 Random random = new Random();
 while (!isCancelled()) {
  total++;
  if (random.nextBoolean()) {
   heads++;
  }
  publish(new FlipPair(heads, total));
 }
 return null;
}

因為publish經常被挪用,很多的FlipPair值將在process辦法被事宜派發線程挪用之前被搜集;process僅僅存眷每次前往的最初一組值,應用它來更新GUI:

protected void process(List pairs) {
 FlipPair pair = pairs.get(pairs.size() - 1);
 headsText.setText(String.format("%d", pair.heads));
 totalText.setText(String.format("%d", pair.total));
 devText.setText(String.format("%.10g",
   ((double) pair.heads)/((double) pair.total) - 0.5));
}

 6.撤消後台義務
挪用SwingWorker.cancel來撤消一個正在履行的後台義務。義務必需與它本身的撤消機制分歧。有兩個辦法來做到這一點:
(1)當收到一個interrupt時,將被終止。
(2)挪用SwingWorker.isCanceled,假如SwingWorker挪用cancel,該辦法將前往true。
 7.綁定屬性和狀況辦法
SwingWorker支撐bound properties,這個在與其他線程通訊時很有感化。供給兩個綁定屬性:progress和state。progress和state可以用於觸發在事宜派發線程中的事宜處置義務。
經由過程完成一個property change listener,法式可以捕獲到progress,state或其他綁定屬性的變更。
 
7.1The progress Bound Variable
Progress綁定變量是一個整型變量,變更規模由0到100。它預界說了setter (the protected SwingWorker.setProgress)和getter (the public SwingWorker.getProgress)辦法。
 
7.2The state Bound Variable
State綁定變量的變更反應了SwingWorker對象在它的性命周期中的變更進程。該變量中包括一個SwingWorker.StateValue的列舉類型。能夠的值有:
(1)PENDING
這個狀況連續的時光為從對象的樹立曉得doInBackground辦法被挪用。
(2)STARTED
這個狀況連續的時光為doInBackground辦法被挪用前一刻直到done辦法被挪用前一刻。
(3)DONE
對象存在的殘剩時光將堅持這個狀況。
須要前往以後state的值可挪用SwingWorker.getState。
 
7.3Status Methods
兩個由Future接口供給的辦法,異樣可以申報後台義務的狀況。假如義務被撤消,isCancelled前往true。另外,假如義務完成,即要末正常的完成,要末被撤消,isDone前往true。


應用頂層容器

Swing供給3種頂層容器類:JFrame,JDialog,JApplet。當應用這三個類時,你必需留意以下幾點:
 
(1).為了顯示在屏幕上,每一個GUI組件必需是包括條理(containment hierarchy)的一部門。包括條理是組件的一個樹型構造,最頂層的容器是它的根。

(2).每一個GUI組件只能被包括一次。假如一個組件曾經在一個容器中,這時候試圖將它參加到一個新的容器,則這個組件會從第一個容器移除,並參加到第二個容器中。

(3).每一個頂層容器都有一個內容面板(content pane),普通情形下,這個內容面板會包括(直接或直接地)一切頂層容器GUI的可視組件。

(4).可以在頂層容器中參加一個菜單條(menu bar)。平日這個菜單條被放置在頂層容器中,但在內容面板外。

1.頂層容器與包括條理
每一個應用Swing組件的法式都至多有一個頂層容器。這個頂層容器是包括條理的根節點—這個條理會包括一切將在這個頂層容器中湧現的Swing組件。
    平日情形下,一個零丁的基於Swing GUI的運用法式至多有一個包括條理,且它的根節點是JFrame。舉例來講,假如一個運用法式具有一個窗口和兩個對話框,那末這個運用法式將會有三個包括條理,也即會有三個頂層容器。一個包括條理將JFrame作為它的根節點,兩外兩個包括條理各有一個JDialog作為它的根節點。
一個基於Swing組件的小法式(applet)至多含有一個包括條理,而且可以肯定個中必有一個是以JApplet作為其根節點的。例如,一個小法式帶有一個對話框,則它會有兩個包括條理。在閱讀器窗口中的組件將會置於一個包括條理,它的根節點是一個JApplet對象。對話框會有一個包括條理,它的根節點是一個JDialog對象。
 
2.將組件參加到內容面板中
上面的代碼操作是下面的例子中獲得frame的內容面板並參加黃色標簽:
frame.getContentPane().add(yellowLabel, BorderLayout.CENTER);
 
如代碼所示,必需先找到頂層容器的內容面板,經由過程辦法getContentPane完成。默許的內容面板是一個簡略的中央容器,它繼續自JComponent,應用一個BorderLayout作為它的面板治理器。
定制一個內容面板很簡略—設置面板治理器或添加邊框。這裡必需留意,getContentPane辦法將前往一個Container對象,而不是JComponent對象。這意味著假如須要應用JComponent的部門功效,還必需將前往值停止類型轉換或創立你本身的組件來作為內容面板。我們的實例平日采取的是第二種方法. 由於第二種辦法比擬清晰晴明。 另外一種我們有時會應用的辦法就是簡略地將一個本身界說組件添加進內容面板, 完整隱瞞住內容面板。
假如你創立你本身的內容面板, 那末請留意確認它是不通明的. 一個不通明的JPanel將是一個不錯的選擇. 留意, 默許情形下JPanel的結構治理為FlowLayout, 你也許會想要用其它的結構治理器調換它。
為了使一個組件成為內容面板, 你須要應用頂層容器的setContentPane辦法, 例如:

//Create a panel and add components to it.
JPanel contentPane = new JPanel(new BorderLayout());
contentPane.setBorder(someBorder);
contentPane.add(someComponent, BorderLayout.CENTER);
contentPane.add(anotherComponent, BorderLayout.PAGE_END);
//Make it the content pane.
//contentPane.setOpaque(true);
topLevelContainer.setContentPane(contentPane);

 
留意: 不要應用通明的容器作為內容面板, 如JScrollPane, JSplitPane和JTabbedPane. . 一個通明的內容面板將招致組件凌亂. 雖然你可使任何的通明的Swing組件經由過程setOpaque(true)辦法來使其不通明化, 但當一些組件被設置成完整不通明後看上去會不太對勁. 例如, 一個標簽面板.
 
3.添加一個菜單欄 (Adding a Menu Bar)
從實際下去講每個頂層容器都可以有一個菜單欄. 但現實注解菜單欄僅湧現於Frame或許Applet中. 為到達添加一個菜單欄到頂層容器, 你須要創立一個JMenuBar對象, 組裝上一些菜單, 然後呼喚setJMenuBar辦法. TopLevelDemo實例經由過程以下代碼添加一個菜單欄到它的Frame中.

frame.setJMenuBar(cyanMenuBar);

 
4.根容器 (The Root Pane)
每一個頂層容器都依附於一個隱式的稱為根容器的中央容器. 這個根容器治理著內容面板和菜單欄, 而且連同兩個或許兩個以上的其它容器(見圖中Layered Pane等). 你平日不須要懂得關於應用Swing組件根容器方面的常識.  但是, 假如你想截獲鼠標的點擊或許在多重組件長進行繪畫舉措, 那末你須要知曉根容器.

上文曾經講述了關於內容面板與可選的菜單欄的內容,此處不再復述. 根容器中包括的別的兩個組件, 是結構面板和玻璃面板. 結構面板直接包括菜單欄和內容面板, 而且許可你對所添加的其它組件停止Z坐標排序. 玻璃面板平日用來截獲產生在頂層中的輸出舉措, 而且異樣可以用來在多重組件長進行繪畫.

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved