top

【JDK8】迎接 JavaFX 8(2)

分享:

【JDK8】迎接 JavaFX 8(1)<< 前情

接著上一篇 JavaFX 2與8的比較,本篇將繼續介紹兩者間的差別。

列印功能

使用JavaFX 2開發應用程式,會發現JavaFX 2並沒有提供列印功能,因此欲列印內容,需自訂實作Java AWT的java.awt.print.Printable介面之類別,並實作Printable介面的print()方法,方可處理列印功能。

首先介紹如何實作Java AWT的Printable介面。

當執行列印時,首先以PrinterJob類別的getPrinterJob()方法建立PrinterJob物件,接著以setPrintable()方法顯示列印對話盒,其中setPrintable()方法之參數painterPrintable介面型別,setPrintable()方法並不負責實際的列印動作,實際動作是由傳入之painter物件執行,painter物件需實作Printable介面,例如以下為自訂實作Printable介面之DocToPrinter類別,其中Printable介面的print()方法需被定義:

public class DocToPrinter implements java.awt.print.Printable {
  ...
  public int print(Graphics g, PageFormat pageFormat, int pageIndex) {
    Graphics2D g2d = (Graphics2D) g;
    ...
  }
  ...
}

程式中以PageFormatgetImageableX()getImageableY()方法取得版面可列印範圍的左上角座標,並利用java.awt.Graphics2Dtranslate()方法將所要列印的位置移到列印頁面的左上角:

g2d.translate(pageFormat.getImageableX(), pageFormat.getImageableY());

g2d.setClip((int)(pageFormat.getImageableX()/scale),
  (int)(pageFormat.getImageableY()/scale),
  (int)(pageFormat.getImageableWidth()/scale), 
  (int)(pageFormat.getImageableHeight()/scale));
...
g2d.translate(g2d.getClipBounds().getX(), g2d.getClipBounds().getY());

【執行結果】

下圖為列印的執行結果,將開啟列印對話盒:

19-5

至於版面設定,首先以PrinterJob類別的getPrinterJob()方法建立PrinterJob物件,待建立之後則以pageDialog()方法顯示版面設定對話盒:

try {
  PrinterJob prnJob = PrinterJob.getPrinterJob();
  // 顯示版面設定對話盒以設定邊界、列印方向、
  // 紙張大小、紙張來源、印表機等
  pf = prnJob.pageDialog(prnJob.defaultPage()) ;
}
catch (Exception ex) {...}

【執行結果】

下圖為版面設定之執行結果,此為作業系統之版面設定對話盒:

19-6

但由於上述實作Printable介面的方式稍為複雜,因此Java SE 6.0新增列印功能,僅需以Java Swing的JTextComponent抽象類別之print()方法處理,相當簡單,例如:

try {
  // 列印內容
  jtextarea.print();
}
catch (PrinterException ex) {...}

【執行結果】

此方法將顯示Java樣式的列印對話盒,如下圖所示,有別於上述的列印對話盒,此外列印的格式亦不同,請比較兩者間之差異:

19-7

有了上述的瞭解之後,接著說明JavaFX 8新增的列印功能。

JavaFX 8新增PrinterPrinterJob類別,類似於Java AWT的PrinterJob類別,但不似Java AWT般複雜。

當執行列印時,首先以Printer類別的getDefaultPrinter()方法取得作業系統預設的印表機,接著以createPageLayout()方法設定版面配置,如紙張大小 (A4NA_LETTER)、列印方向 (LANDSCAPEPORTRAIT)、上下左右邊界等,例如:

Printer printer = Printer.getDefaultPrinter();
// 分別設定A4紙張、直垂列印方向、預設邊界
PageLayout pageLayout = printer.createPageLayout(
  Paper.A4, PageOrientation.PORTRAIT, Printer.MarginType.DEFAULT);

接著以PrinterJob類別的createPrinterJob()方法建立PrinterJob物件,以作為列印序列 (Queue) 之用,並以PrinterJob類別的printPage()方法列印,當列印完成時,則以PrinterJob類別的endJob()方法結束列印序列,例如:

PrinterJob job = PrinterJob.createPrinterJob();

if (job != null) {
  boolean success = job.printPage(node);

  if (success) {
    job.endJob();
  }
}

DatePicker

JavaFX 8新增DatePicker類別,用以選擇日期,使用上相當簡單,當點選DatePicker時,將觸發動作事件 (Action Event),藉由getValue()方法則可取得所選擇的日期,例如:

final DatePicker datepicker = new DatePicker();
datepicker.setOnAction(event -> {
  // 取得所選擇的日期
  LocalDate date = datepicker.getValue();
  System.out.println("選擇的日期為: " + date);
});

【執行結果】

以下為未點選DatePicker時的樣式:

DP-1

以下為點選DatePicker時的樣式:

DP-2

3D

JavaFX 8新增3D功能,與之前JavaFX 2的模擬3D不大一樣,例如新增Shape3D抽象類別,繼承自Shape3D抽象類別的3D物體包括Box, Cylinder, MeshView, Sphere等類別。

Shape3D抽象類別定義以下屬性:

  • cullFace:沿用自OpenGL的GL_CULL_FACE。多邊體 (Polygon) 是由數個面 (Facet) 所組成,每一個面由數個頂點 (Vertex) 所設定,在描繪3D物體時,面對鏡頭的一面稱為Front Face,背對鏡頭的一面稱為Back Face,由於描繪3D物體需要複雜的計算,因此為增加執行效率,通常會省略描繪背對鏡頭的一面,此功能稱為Cull Face。在OpenGL中,以glCullFace()方法設定省略描繪Front Face或Back Face,欲啟用Cull Face功能,則以glEnable(GL_CULL_FACE)方法設定。JavaFX 8的Shape3D抽象類別沿用OpenGL此一功能,以cullFace屬性設定是否省略描繪Front Face或Back Face,分別為CullFace.FRONTCullFace.BACKCullFace.NONE,代表省略描繪Front Face、Back Face或不省略。
  • drawMode:定義3D物體的繪製方式,分別為DrawMode.FILLDrawMode.LINE,代表填滿3D物體表面或以Wireframe方式呈現。
  • material:定義3D物體表面的材質。

以下是以Box類別分別以Wireframe、填色與貼圖等方式呈現立方體:

Box-1Box-6Box10

以下是以Cylinder類別分別以Wireframe、填色與貼圖等方式呈現圓柱體,此外Cylinder類別可設定divisions參數,設定圓柱體的分割等分,請參考第四張圖以divisions參數將圓柱體設定為八角柱體 (Octagonal Prism):

Cylinder1Cylinder4Cylinder06Cylinder08

以下是以Sphere類別分別以Wireframe、填色與貼圖等方式呈現球體,與Cylinder類別相同,同樣可設定divisions參數,設定球體的分割等分,請參考第四張圖以divisions參數設定球體的分割等分:

Sphere1Sphere4Sphere5Sphere10

TriangleMesh

TriangleMesh類別以頂點座標 (Vertex Coordinates)、三角形所形成的面 (Facet) 與貼圖 (Texture) 三者組成3D物體,為目前大部份3D軟體所使用的方法。

以立方體 (Cube) 為例,共有八個頂點與六個面,但就TriangleMesh而言,各個面是由兩個三角形所組成,因此共需設定八個頂點與十二個三角形,此外以「右手定則」定義各面的上下方向。下圖為立方體以Wireframe方式呈現的結果,可藉此瞭解如何以三角形組成面:

TriangleMesh01

下圖是以填滿方式 (DrawMode.FILL) 呈現的結果:

TriangleMesh02

再加上貼圖 (Texture):

TriangleMesh03

瞭解TriangleMesh如何建立3D物體的概念之後,理論上只要知道頂點與如何形成各三角形的面,則可建立3D物體,但最困難的地方也就是頂點的取得。以下為一些特殊幾何物體的示範:

TriangleMesh23
正十二面體 (Dodecahedron)

TriangleMesh20
正二十面體 (Icosahedron)

TriangleMesh48
截角八面體 (Truncated Octahedron)

TriangleMesh57
扭棱立方體 (Snub Cube)

TriangleMesh62
大斜方截半立方體 (Truncated Cuboctahedron)

TriangleMesh29
立方半八面體 (Cubohemioctahedron)

TriangleMesh39
大十二面體 (Great Dodecahedron)

TriangleMesh36
大二十面體 (Great Icosahedron)

相關範例請參考:

https://sites.google.com/site/leohkkimo/demo/javafx-3d

PhongMaterial

JavaFX使用Phong Shading著色法,又稱為Phong Interpolation或Normal-Vector Interpolation Shading,是由美國越南裔學者Bùi Tường Phong所發明,1973年發表於博士論文"Illumination of Computer-Generated Images", Department of Computer Science, University of Utah, UTEC-CSs-73-129, July 1973,因此以其姓氏Phong (裴)命名。

Phong Reflection Model是由Ambient Light (環境光)、Diffuse Light (漫射光) 與Specular Light (鏡面光) 三者所組成。

JavaFX以PhongMaterial類別處理Phong Material,並細分為Bump Map, Diffuse Map, Self Illumination Map, Specular Map, Diffuse Color, Specular Color, 與Specular Power,前四者Map用以設定貼圖、接著Color用以設定著色、最後Power用以設定強度,並定義以下屬性:

  • bumpMap: The bump map of this PhongMaterial, which is a normal map stored as a RGB Image.
  • diffuseColor: The diffuse color of this PhongMaterial.
  • diffuseMap: The diffuse map of this PhongMaterial.
  • selfIlluminationMap: The self illumination map of this PhongMaterial.
  • specularColor: The specular color of this PhongMaterial.
  • specularMap: The specular map of this PhongMaterial.
  • specularPower: The specular power of this PhongMateria.

以下為分別設定Bump Map、Difffuse Map與Specular Map貼圖的效果:

earth04

以下為分別設定Difffuse Color與Specular Color的效果:

earth07

我們將在後續的內容中說明JavaFX 8的3D、TriangleMeshPhongMaterial功能。

【參考資料】

[1] 黃嘉輝,深入研究JavaFX 2。
[2] 黃嘉輝,JavaFX遊戲程式設計。
[3] 黃嘉輝,深入研究JavaFX Swing。
[4] Java Official Web Site:http://www.oracle.com/technetwork/java/index.html
[5] JavaFX:http://www.oracle.com/technetwork/java/javafx
[6] JavaFX 8.0 API Specification.
[7] Java Platform, Standard Edition 8 API Specification.
[8] JDK 8 Certified System Configurations.
[9] H. M. Cundy, A. P. Rollett, Mathematical Models, Tarquin Publications, 1981.
[10] G. Sellers, R. S. Wright, N. Haemel, OpenGL SuperBible: Comprehensive Tutorial and Reference (6th Edition), Addison-Wesley Professional, 2013.

後續 >> 【JDK8】Nashorn 與 Java API(一)

分享:
按讚!加入 CodeData Facebook 粉絲群

留言

留言請先。還沒帳號註冊也可以使用FacebookGoogle+登錄留言

關於作者

黃嘉輝副教授,目前任職於國立臺北商業大學企業管理學系,喜歡寫程式,特別愛Java,範例可參考教學網站

熱門論壇文章

熱門技術文章