在 Java SE 平臺上使用 Headless 模式

類別: IT
標籤: java

這篇文章介紹怎樣在標準Java(Java SE,也稱作J2SE)平臺上用Headless模式。

Headless模式是在缺少顯示屏、鍵盤或者滑鼠時的系統配置。聽起來不可思議,但事實上你可以在這中模式下完成不同的操作,甚至是用圖形資料也可以。

哪裡才能用到此模式呢?想想你的應用不停的生成一張圖片,比如,當使用者每次登陸系統是都要生成一張認證圖片。當建立圖片時,你得應用既不需要顯示器也不需要鍵盤。讓我們假設一下,現在你的應用有個主架構或者專有伺服器,但這個服務沒有顯示器,鍵盤或者滑鼠。理想的決定是用環境的大量視覺計算能力而不是非視覺特性。在Headless模式下生成的圖片可以傳遞到Headful系統進行更深層次渲染。

在java.awt.toolkit和java.awt.graphicsenvironment類中有許多方法,除了對字型,影象和列印的操作外還有呼叫顯示器,鍵盤和滑鼠的方法。但是有一些類中,比如Canvas 和 Panel,可以在headless模式下執行。在J2SE 1.4平臺之後就提供了對Headless模式的支援。

注:這篇文章重點講的是Java SE6 平臺版本的文檔。任何API增加或其他增強Java SE平臺的規範由JSR270專家組(JSR 270 Expert Group.)的審查和批准

Toolkit

java.awt.Toolkit類是Abstract Window Toolkit (AWT)的 所有實現類的抽象父類。Toolkit的子類用於把各種AWT元件繫結到特定的本地toolkit實現上去。 

如果顯示裝置,鍵盤或滑鼠不支援的話,很多元件都會受影響。一個合適的類構造器應當丟擲一個HeadlessException異常:

    Button
    Checkbox
    Choice
    Dialog
    FileDialog
    Frame
    Label
    List
    Menu
    MenuBar
    MenuItem
    PopupMenu
    Scrollbar
    ScrollPane
    TextArea
    TextField
    Window

這種重量級的元件需要有一個作業系統級別上對等的圖形函式來支援它,在headless的機器上它們將不能正常工作。 

與Canvas、Panel和Image元件相關的元件不需要丟擲HeadlessException異常,因為這些元件在作業系統級別上的對等圖形函式可以使用空函式,然後作為輕量級元件來處理。
一個Headless的toolkit也會把Java元件繫結到本地資源上去,但是它只有在資源中不包含顯示裝置或輸入裝置時才會這樣做。 
Graphics Environment

java.awt.GraphicsEnvironment類是一個抽象類,它描述了在給定平臺中,可以在Java技術中使用的由GraphicsDevice物件和Font物件組成的集合。該GraphicsEnvironment中的資源可以是本地的也可以是遠端裝置。GraphicsDevice物件可以是顯示器,印表機或者圖形快取等,並且它們是Graphics2D 繪製函式的目標。每一個GraphicsDevice都有許多與之關聯的GraphicsConfiguration物件。這些物件指定了不同的配置環境,在這些配置環境中可以使用GraphicsDevice。
Table 1 顯示GraphicsEnvironment 方法,檢查Headless模式支援
Table 1.  Headless 模式方法   
   
方法 描述
public static boolean
isHeadless()
測試環境是否為headless, 對於是否不支援display  device,keyboard,mouse。如果這個方法returns true,theToolkitandGraphicsEnvironmentclasses 丟擲(thrown)依賴於display device, keyboard, mouse的aHeadlessExceptionis異常.
public boolean
isHeadlessInstance()
Returns  thisGraphicsEnvironmentcan 是否支援dieplay device,keyboard,mouse. 如果這個方法 returns  true,  theGraphicsEnvironmentthat 丟擲(throw)一個依賴於 display device, keyboard, mouse的aHeadlessExceptionis 異常.


注意:isHeadless()方法檢查特定的系統屬性,java.awt.headless而不是系統的硬體配置. 

HeadlessException 丟擲的程式碼,這取決於display device、keyboard、mouse在一個環境稱為不支援任何這些.唯一的例外是來自一個UnsupportedOperationException,本身就是來源於一個RuntimeException.
設定 Headless模式

使用Headless模式操作,您必須首先了解如何檢查和設定系統屬性與此相關的模式。此外,你必須瞭解如何建立一個預設的工具包使用工具箱的無頭實現類.

系統屬性配置

為了啟用headless模式,需要使用setProperty()方法去設定相應的系統屬性。本方法可以讓你用期望的值來設定系統屬性。

System.setProperty("java.awt.headless", "true");

上面的程式碼中,java.awt.headless是一個系統屬性,true是我們設定的值。

如果你想在一個相同的程式中使用headless和傳統環境,你可以使用下面的命令列來完成:

java -Djava.awt.headless=true 

建立預設Toolkit

如果名字為java.awt.headless的系統屬性被設定為true,那麼headless工具包就會被使用。接下來使用getDefaultToolkit()方法來建立一個headless toolkit的例項:

Toolkit tk = Toolkit.getDefaultToolkit();
Headless模式檢查

要檢查Headless模式的可用性,使用GraphicsEnvironment類的isHeadless()方法:
GraphicsEnvironment ge =GraphicsEnvironment.getLocalGraphicsEnvironment();boolean headless_check = ge.isHeadless();
該方法檢查java.awt.headless系統屬性。如果這個屬性有一個為true的值,那麼就會從工具包和依賴於一個顯示器,鍵盤,滑鼠的GraphicsEnvironment類的區域中丟擲一個HeadlessException。
在Headless模式中操作

設定好headless模式並建立一個headless工具包的例項後,您的應用程式可以執行以下操作:

    建立輕量級元件,如Canvas,Panel,和Swing元件,除了top級別.
    收集關於可用的字型、字型指標和字型設定的資訊
    設定顏色來渲染文字和圖形
    創造和獲取影象,為渲染準備圖片
    使用java.awt.PrintJob, java.awt.print.*, 和 javax.print.* 類進行列印。
    發出"嗶嗶"音訊。

Canvas(畫布)

下面的程式碼會在螢幕上繪製出一個空白的矩形區域,你可以在上面繪製線條。可以使用Canvas類建立一個新的Canvas元件。

final Canvas c = new Canvas(){	public void paint(Graphics g)	{		Rectangle r = getBounds();		g.drawLine(0, 0, r.width - 1, r.height - 1);		g.drawLine(0, r.height - 1, r.width - 1, 0);	}};

Fonts(字型)

這段程式碼顯示了怎麼使用Font類畫一個文字字串並設定文字的字型。Graphics物件是用來繪製這個字串的。

public void paint(Graphics g){	g.setFont(new Font("Arial", Font.ITALIC, 12));	g.drawString("Test", 32, 8);}

Colors

這段程式碼顯示瞭如何使用指定的紅,綠,藍的值來設定一條線的顏色。Graphics物件是用來繪製這條線的。

public void paint(Graphics g){	g.setColor(new Color(255, 127, 0));	g.drawLine(0, r.height - 1, r.width - 1, 0);}

Images

在下面的程式碼中,javax.imageio.ImageIO類的使用read()方法對圖1所示的grapefruit.jpg檔案進行解碼,並返回一個快取圖片。

Image i = null;try{	File f = new File("grapefruit.jpg");	i = ImageIO.read(f);}catch (Exception z){	z.printStackTrace(System.err);}

圖1。grapefruit.jpg影象檔案

Print

這段程式碼演示瞭如何列印已經準備好的畫布,你可以使用paint方法自定義印表機的的預設畫面。

PrinterJob pj = PrinterJob.getPrinterJob();pj.setPrintable(new Printable(){   public int print(Graphics g, PageFormat pf, int pageIndex)   {	   if (pageIndex > 0)	   {		   return Printable.NO_SUCH_PAGE;	   }	   ((Graphics2D)g).translate(pf.getImageableX(),								 pf.getImageableY());	   // Paint canvas.	   c.paint(g);	   return Printable.PAGE_EXISTS;   }});

Beep

下面的這段程式碼展示瞭如果使用 Toolkit類的beep方法發出嘟嘟聲。

Toolkit tk = Toolkit.getDefaultToolkit();tk.beep();

使用Headless模式簡單例子

以下的HeadlessBasics例子運用了文章中描述的所有功能。

要執行這個的例子,需要用javac對下面的程式碼進行編譯。複製grapefruit.jpg圖片檔案到HeadlessBasics類所在的目錄下面。

import java.awt.*;import java.io.*;import java.awt.print.*;import javax.imageio.*;public class HeadlessBasics{    public static void main(String[] args)    {        // Set system property.        // Call this BEFORE the toolkit has been initialized, that is,        // before Toolkit.getDefaultToolkit() has been called.        System.setProperty("java.awt.headless", "true");        // This triggers creation of the toolkit.        // Because java.awt.headless property is set to true, this        // will be an instance of headless toolkit.        Toolkit tk = Toolkit.getDefaultToolkit();        // Standard beep is available.        tk.beep();        // Check whether the application is        // running in headless mode.        GraphicsEnvironment ge =        GraphicsEnvironment.getLocalGraphicsEnvironment();        System.out.println("Headless mode: " + ge.isHeadless());        // No top levels are allowed.        boolean created = false;        try        {            Frame f = new Frame("Frame");            created = true;        }        catch (Exception z)        {            z.printStackTrace(System.err);            created = false;        }        System.err.println("Frame is created: " + created);        // No other components except Canvas and Panel are allowed.        created = false;        try        {            Button b = new Button("Button");            created = true;        }        catch (Exception z)        {            z.printStackTrace(System.err);            created = false;        }        System.err.println("Button is created: " + created);                // Canvases can be created.        final Canvas c = new Canvas()        {            public void paint(Graphics g)            {                Rectangle r = getBounds();                g.drawLine(0, 0, r.width - 1, r.height - 1);                // Colors work too.                g.setColor(new Color(255, 127, 0));                g.drawLine(0, r.height - 1, r.width - 1, 0);                // And fonts                g.setFont(new Font("Arial", Font.ITALIC, 12));                g.drawString("Test", 32, 8);            }        };        // And all the operations work correctly.        c.setBounds(32, 32, 128, 128);        // Images are available.        Image i = null;        try        {            File f = new File("grapefruit.jpg");            i = ImageIO.read(f);        }        catch (Exception z)        {            z.printStackTrace(System.err);        }        final Image im = i;                // Print system is available.        PrinterJob pj = PrinterJob.getPrinterJob();        pj.setPrintable(new Printable()        {            public int print(Graphics g, PageFormat pf, int pageIndex)            {                if (pageIndex > 0)                {                    return Printable.NO_SUCH_PAGE;                }                ((Graphics2D)g).translate(pf.getImageableX(),                                          pf.getImageableY());                // Paint the canvas.                c.paint(g);                // Paint the image.                if (im != null)                {                    g.drawImage(im, 32, 32, 64, 64, null);                }                return Printable.PAGE_EXISTS;            }        });        try        {            pj.print();        }        catch (Exception z)        {            z.printStackTrace(System.err);        }    }}

圖2顯示了這個例子中的列印輸出結果

圖2。HeadlessBasics的列印輸出。

此外,你可以看到以下的資訊:

Headless mode: truejava.awt.HeadlessExceptionat java.awt.GraphicsEnvironment.checkHeadless(Unknown Source)at java.awt.Window.<init>(Unknown Source)at java.awt.Frame.<init>(Unknown Source)at HeadlessBasics.main(HeadlessBasics.java:24)Frame is created: falsejava.awt.HeadlessExceptionat java.awt.GraphicsEnvironment.checkHeadless(Unknown Source)at java.awt.Button.<init>(Unknown Source)at HeadlessBasics.main(HeadlessBasics.java:39)Button is created: false

注:出於演示的目的,最初的程式碼會導致此應用程式丟擲2個java.awt.HeadlessExceptions異常。

作為上一種方式的替代,你可以把標準輸出資訊放到一個檔案中,然後把檔案列印出來。在這種情況下,使用下面的命令列來執行這個例子:

java HeadlessBasics 2> standard_output.txt 

把現有的應用程式轉換為Headless模式。

你怎麼把現有的應用程式轉換為可執行的headless模式?要執行此轉換的最有效的方法是分析你的原始碼以確定任何的功能都是依賴於Headless模式的。換句話說,要實現相同的功能,你必須找到那些會丟擲HeadlessException異常的類和方法,然後使用獨立的headless模式替換這些類和方法。

你可以使用Java SE 6 API說明來判斷一個特定的類或方法是否支援headless模式。如果一個特定的元件不支援headless模式,你的程式需要捕獲的唯一的異常是HeadlessException。它會在其它可能的異常之前被丟擲。這也是為什麼在本節的程式碼示例"舉例: 使用Headless模式"中,沒有什麼特殊的必要性來捕獲其它異常。

你肯定會發現其它有用的方法來使用headless模式帶來的好處。我們希望本文能幫你完成此項任務,在Java SE平臺中玩出一片新天地。 
獲取更多資訊 

AWT Enhancements in J2SE 1.4: Headless Support
J2SE 1.4 platform documentation: HeadlessException
The New Modality API in Java SE 6
The java.awt.Toolkit Class
The java.awt.GraphicsEnvironment Class
關於作者

Artem Ananiev 是位於 Saint Petersburg的Sun Microsystems公司的一名軟體工程師,俄羅斯人。之前他曾經在Abstract Window Toolkit (AWT) 專案中工作過幾年,他主要的技能領域是模態,機器人和多屏系統。 

Alla Redko  是位於 Saint Petersburg的 Sun Microsystems公司的技術作者,俄羅斯人。她為AWT專案編寫技術文件,並且負責更新Java使用者手冊。在到Sun任職之前,她已經作為技術作者工作了八年。
在 Java SE 平臺上使用 Headless 模式原文請看這裡

推薦文章