溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

讓 Eclipse 插件程序具有二維作圖能力(轉(zhuǎn))

發(fā)布時間:2020-08-07 19:00:40 來源:ITPUB博客 閱讀:181 作者:rainytag 欄目:編程語言
大多數(shù) Java 開發(fā)人員同意 Swing/AWT 只有一個方面強(qiáng)于 Eclipse 平臺的標(biāo)準(zhǔn)窗口小部件工具箱(Standard Widget Toolkit),這就是 Java 2D。直到現(xiàn)在仍然沒有容易的方法將 Java 2D 的快捷性能與 SWT 用戶界面組件的更強(qiáng)的可移植性、功能和性能集成到一起,但是這一點(diǎn)就會改變了。在繼他的頗受歡迎的介紹從 Swing 應(yīng)用程序移植到 SWT 的教程之后的這篇文章中,Java 開發(fā)人員和 Eclipse 熱衷者 Yannick Saillet,展示了在 SWT 組件和 Draw2D 圖形中繪制二維圖像有多容易。
SWT (標(biāo)準(zhǔn)窗口小部件工具箱,Standard Widget Toolkit)是在 Eclipse 平臺上使用的窗口小部件工具箱。它也可以作為 Swing/AWT 的一個重要替代產(chǎn)品,用于構(gòu)建任何類型的 Java GUI 應(yīng)用程序。隨著 Eclipse 平臺在過去兩年里的日趨流行,SWT 已經(jīng)進(jìn)入大家的視線,并且最近它已經(jīng)開始在一些應(yīng)用程序中取代 Swing/AWT。SWT 的流行源自這樣一個事實(shí):它是跨平臺的工具箱,利用了窗口小部件的本性,并有一個與 Swing 及其他現(xiàn)代工具箱同樣強(qiáng)大的功能。使用 SWT,就不用在可移植性、功能和性能之間做取舍了。

事實(shí)上,Swing/AWT 只在一個方面明顯強(qiáng)于 SWT,這就是 Java 2D。Java 2D 是一個強(qiáng)大的 API,是在 JDK 1.2 中引入的。它使 Java 開發(fā)人員在 AWT 組件上繪制時可以使用復(fù)雜的二維變換(平移、旋轉(zhuǎn)、縮放、錯切等)。不幸的是,Java 2D 設(shè)計為只在 AWT 或者 Swing 工具箱上使用,而 SWT 還沒有提供這種擴(kuò)展的二維能力。因此,許多開發(fā)人員發(fā)現(xiàn)他們必須選擇是在 Java 平臺上使用 Java 2D 還是放棄它令人興奮的功能而使用 SWT。

不過,在本文中您將了解到如何同時擁有這兩方面的好處。我將展示一個簡單的技術(shù),利用該技術(shù)可以在 SWT 組件和 Draw2D 圖像上繪制 Java 2D 圖像。為了理解這個例子,讀者應(yīng)當(dāng)熟悉 Java 2D、AWT 和 SWT。具有一些 Eclipse 平臺的 GEF(圖形編輯框架,Graphical Editing Framework)的經(jīng)驗(yàn)也是有幫助的。

屏外圖像技術(shù)
本文展示一種簡單的技術(shù),利用該技術(shù),您可以用 Java 2D 功能在任何 SWT 窗口小部件或者 Draw2D 圖像上繪制。為了彌補(bǔ) SWT 上缺少 Java 2D 的不足,用一個屏外(offscreen)AWT 圖像接收 Java 2D 繪制操作,并將它們轉(zhuǎn)換為獨(dú)立于工具箱的像素值。再用另一個由 SWT 工具箱創(chuàng)建的 屏外圖像將這些像素信息繪制在任何 SWT 組件上。圖 1 顯示了 AWT 屏外圖像轉(zhuǎn)換為 SWT 圖像再繪制在 SWT 窗口小部件上的過程。

圖 1. 屏外圖像技術(shù)允許在 SWT 上使用 Java 2D


圖 1 中顯示的屏外 AWT 圖像被初始化為透明背景。然后對屏外圖像的圖形上下文調(diào)用 Java 2D 方法。像所有 AWT 圖像一樣,屏外圖像的圖形上下文自動支持 Java 2D。完成了所有特定于 Java 2D 的繪制后,提取 AWT 圖像的像素值并傳送到一個屏外 SWT 圖像中。然后用工具箱的 GC.drawImage(...) 方法在 SWT 組件上繪制這個 SWT 圖像,就像所有正常圖像一樣。

我將在下面幾節(jié)中完成這個過程中的每一步。

創(chuàng)建 AWT 屏外圖像
對于 AWT 屏外圖像,要使用 java.awt.image.BufferedImage 實(shí)例。BufferedImage 是一個可以通過它的 API 訪問其像素數(shù)據(jù)的圖像。訪問到了圖像的像素值就可以在以后將它轉(zhuǎn)換為 SWT 圖像。

構(gòu)建一個 AWT 緩沖圖像的最簡單方法是使用構(gòu)造函數(shù) public BufferedImage(int width, int height, int imageType)。前兩個參數(shù)表明圖像具有的大小。第三個參數(shù)是指定要創(chuàng)建的圖像 類型 的常量。圖像類型 ?? 可能的值是在類 BufferedImage 中聲明的常量 TYPE_XXX 之一 ?? 表明像素值是如何存儲在圖像中的。在彩色圖像中一般使用以下幾種最重要的圖像類型:

TYPE_BYTE_INDEXED:這種圖像類型的圖像將使用一個索引顏色模型。索引顏色模型 的意思是圖像中使用的每一種顏色都是在一組顏色中索引的。像素值只包含這個像素的顏色在顏色模型中的索引。這種類型的圖像局限于 256 種顏色 ?? 也就是顏色模型的大小。以這種方式存儲像素信息可以很緊湊地表示圖像,因?yàn)槊恳粋€像素都只用一個字節(jié)編碼。


TYPE_INT_RGB:這種類型常量表明圖像使用直接顏色模型。直接顏色模型 的意思是每一個像素的值包含關(guān)于其顏色的完整信息。TYPE_INT_RGB 表明每一個像素都是用一個整數(shù)(四字節(jié))編碼的。每一個像素中編碼的信息是這個像素所使用的顏色的紅、綠和藍(lán)(RGB)成分。每一種顏色成分都用一個字節(jié)編碼。因?yàn)檎麄€像素值是用四個字節(jié)編碼的,所以有一個字節(jié)是未使用的。這種圖像的內(nèi)部表示占用的內(nèi)存是使用索引顏色模型的圖像的四倍,但是這種圖像可以使用的顏色數(shù)增加到了 1 百 60 萬(256 x 256 x 256)。


TYPE_INT_ARGB:與 TYPE_INT_RGB 一樣,這種類型的圖像使用直接顏色模型并用四個字節(jié)編碼每一個像素。不同之處在于,這里用 TYPE_INT_RGB 沒有使用的第四個字節(jié)表示像素的透明度,有時也稱為顏色的 alpha 成分。這種類型的圖像可以有透明的背景,也可以是半透明的。
為了讓屏外圖像技術(shù)可以工作,需要只將受到 Java 2D 繪制影響的像素傳送到 SWT 組件的表面。為了保證這一點(diǎn),初始圖像必須有透明背景。因此,對于 AWT 屏外圖像,使用的緩沖圖像類型為 TYPE_INT_ARGB。

繪制和提取圖像
這個過程的下一步是用 Java 2D 繪制圖像。首先取得它的 Graphics2D 上下文??梢杂梅椒?createGraphics2D() 或者調(diào)用 getGraphics() 做到這一點(diǎn)。在這個上下文上繪制將會自動修改圖像的像素數(shù)據(jù)。在繪制完成后,可以用方法 getRGB(int startX, int startY, int w, int h, int rgbArray, int offset, int scansize) 容易且高效地提取圖像的像素值。這個方法可以將圖像中矩形區(qū)域的像素數(shù)據(jù)傳輸?shù)揭粋€整數(shù)數(shù)組中。getRGB() 方法的參數(shù)如下:

startX, startY 是要提取的區(qū)域左上角圖像的坐標(biāo)。


w, h 是要提取的區(qū)域的寬度和高度。


rgbArray 是接收像素值的整數(shù)數(shù)組。


offset 是數(shù)組中接收第一個像素值的位置的索引。


scansize 是圖像中相鄰兩行中具有相同行索引的像素的索引偏移值。如果這個值與要提取的區(qū)域的寬度相同,那么一行的第一個像素就會存儲在數(shù)組中前一行最后一個像素后面的索引位置。如果這個值大于提取區(qū)域的寬度,那么數(shù)組中,在一行最后和下一行開始之間就會有一些未使用的索引。
存儲像素數(shù)據(jù)
圖 2 顯示 BufferedImage.getRGB(...) 如何在提取了 AWT 圖像的矩形區(qū)域后填充整數(shù)緩沖區(qū)。圖中下面的部分表示整數(shù)緩沖區(qū)。每一個框表示緩沖區(qū)中包含一個像素 4 字節(jié) ARBG 值的一個值。括號中的數(shù)字表示像素在圖像中的坐標(biāo)。

圖 2. 從 AWT 圖像中提取像素值


在這種情況下,不使用任何 offset,這意味著第一個像素將保存在緩沖區(qū)索引 0 的位置。scansize 的值取要提取的區(qū)域的寬度,這意味著提取的一行中的第一個像素會接著前一行的最后一個像素的緩沖區(qū)位置。使用這些參數(shù),整數(shù)的緩沖區(qū)就一定會足夠大,可以包含 w*h 個整數(shù)。

當(dāng)每一個像素的顏色信息都存儲到了一個整數(shù)的簡單緩沖區(qū)后,就可以將這些信息傳輸?shù)?SWT 屏外圖像中。

創(chuàng)建 SWT 圖像
SWT Image 類似于 AWT BufferedImage,因?yàn)樗南袼財?shù)據(jù)可以有直接讀或者寫操作訪問。這意味著可以通過直接讀取或者修改圖像的數(shù)據(jù),來設(shè)置或者取得圖像中任何像素或者任何一組像素的顏色值。不過, SWT API 與相應(yīng)的 AWT API 有很大不同,并且更容易使用。

SWT 的 Image 類提供了幾個構(gòu)造函數(shù),可以完成以下任務(wù):

通過將一個文件名或者一個 InputStream 作為參數(shù)傳遞給構(gòu)造函數(shù)裝載一個現(xiàn)有的圖像。圖像的格式必須是所支持的格式之一:BMP、GIF、JPG、PNG、Windows ICO 等。


構(gòu)造一個指定大小的空圖像??梢酝ㄟ^修改其像素值或者向它拷貝一個 SWT 圖形上下文的內(nèi)容 (GC) 來繪制該圖像。


構(gòu)造一個用像素值的現(xiàn)有緩沖區(qū)進(jìn)行初始化的圖像。
您將使用第三個構(gòu)造函數(shù)創(chuàng)建一個 SWT 圖像,它是所繪制的 AWT 圖像的副本。

關(guān)于 ImageData 類
有關(guān)圖像的像素數(shù)據(jù)的信息包含在它的 ImageData 中。ImageData 是一個包含有關(guān)圖像大小、調(diào)色板、顏色值和透明度信息的類。應(yīng)當(dāng)特別關(guān)注以下 ImageData 字段:

width 和 height 指定圖像的大小。


depth 指定圖像的顏色深度。可能的值為 1、2、4、8、16、24 或者 32,指定編碼每一個像素的值所使用的位數(shù)。


palette 包含一個 PaletteData 對象,它存儲有關(guān)圖像的顏色模型的信息。與 AWT 一樣,SWT 的顏色模型可以是索引或者直接的。如果顏色模型是索引的,那么 PaletteData 包含顏色索引。如果它是直接的,那么它包含轉(zhuǎn)換(shift)信息,表明應(yīng)當(dāng)如何從像素的整數(shù)值中提取出顏色的 RGB 成分。


data 包含包含有像素值的字節(jié)緩沖區(qū)。與 AWT 緩沖區(qū)不同,SWT 緩沖區(qū)不是包含每一個像素的一種顏色值的整數(shù)數(shù)組。相反,它包含字節(jié)值。字節(jié)編碼的方法取決于所使用的顏色深度。對于一個 8 位的圖像,數(shù)組中的一個字節(jié)正好表示圖像中一個像素的值。對于 16 位圖像,每一個像素值編碼為緩沖區(qū)中的兩個字節(jié)。這兩個字節(jié)以最低有效字節(jié)順序存儲。對于 24 或者 32 位圖像,每一個像素值以最高有效位字節(jié)順序編碼為緩沖區(qū)中的三個或者四個字節(jié)。


bytesPerLine 表明緩沖區(qū)中有多少字節(jié)用于編寫圖像中一行像素的所有像素值。


transparentPixel 定義用于圖像中透明度的像素值。
我們將使用帶有一個透明度顏色信道的 24 位圖像。圖像中的每一個像素都編碼為數(shù)組中的三個字節(jié),順序?yàn)榧t、綠和藍(lán)成分。

轉(zhuǎn)換圖像
知道了圖像數(shù)據(jù)就可以容易地將 AWT 圖像轉(zhuǎn)換為 SWT 圖像。只要將(由 AWT 圖像利用 getRGB(...) 返回的)整數(shù)緩沖區(qū)轉(zhuǎn)換為 SWT 圖像所使用的字節(jié)緩沖。圖 3 顯示了在 SWT 圖像的緩沖區(qū)中這些值是如何存儲的。

圖 3. 將像素值寫入 SWT 圖像

如圖 2 中一樣,上圖中下面的部分顯示了圖像緩沖區(qū)的內(nèi)部表示。括號中的數(shù)字顯示在緩沖區(qū)中表示其顏色值的那個像素的坐標(biāo)。

盡管每一個像素都用三個字節(jié)編碼,但是對于 24 位圖像,緩沖區(qū)中一行像素的大小并不總是 3*width。緩沖區(qū)中兩行像素之間可能有一些索引未使用。要知道圖像中每一行像素真正使用了多少字節(jié)(這樣就可知道緩沖區(qū)中下一行從哪個索引位置開始),必須使用 ImageData 字段的 bytesPerLine 值。

SWT 到 Java 2D 渲染器
清單 1 顯示實(shí)現(xiàn)了屏外圖像技術(shù)的一般性渲染器(renderer)的源代碼。這個渲染器可以在 SWT 組件或者 Draw2D 圖像上繪制時透明地使用 Java 2D 例程。

清單 1. SWT/Draw2D Java 2D renderer

package swtgraphics2d;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;

import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.PaletteData;
import org.eclipse.swt.widgets.Display;

/**
* Helper class allowing the use of Java 2D on SWT or Draw2D graphical
* context.
* @author Yannick Saillet
*/
public class Graphics2DRenderer {
private static final PaletteData PALETTE_DATA =
new PaletteData(0xFF0000, 0xFF00, 0xFF);

private BufferedImage awtImage;
private Image swtImage;
private ImageData swtImageData;
private int[] awtPixels;

/** RGB value to use as transparent color */
private static final int TRANSPARENT_COLOR = 0x123456;

/**
* Prepare to render on a SWT graphics context.
*/
public void prepareRendering(GC gc) {
org.eclipse.swt.graphics.Rectangle clip = gc.getClipping();
prepareRendering(clip.x, clip.y, clip.width, clip.height);
}

/**
* Prepare to render on a Draw2D graphics context.
*/
public void prepareRendering(org.eclipse.draw2d.Graphics graphics) {
org.eclipse.draw2d.geometry.Rectangle clip =
graphics.getClip(new org.eclipse.draw2d.geometry.Rectangle());
prepareRendering(clip.x, clip.y, clip.width, clip.height);
}

/**
* Prepare the AWT offscreen image for the rendering of the rectangular
* region given as parameter.
*/
private void prepareRendering(int clipX, int clipY, int clipW, int clipH) {
// check that the offscreen images are initialized and large enough
checkOffScreenImages(clipW, clipH);
// fill the region in the AWT image with the transparent color
java.awt.Graphics awtGraphics = awtImage.getGraphics();
awtGraphics.setColor(new java.awt.Color(TRANSPARENT_COLOR));
awtGraphics.fillRect(clipX, clipY, clipW, clipH);
}

/**
* Returns the Graphics2D context to use.
*/
public Graphics2D getGraphics2D() {
if (awtImage == null) return null;
return (Graphics2D) awtImage.getGraphics();
}

/**
* Complete the rendering by flushing the 2D renderer on a SWT graphical
* context.
*/
public void render(GC gc) {
if (awtImage == null) return;

org.eclipse.swt.graphics.Rectangle clip = gc.getClipping();
transferPixels(clip.x, clip.y, clip.width, clip.height);
gc.drawImage(swtImage, clip.x, clip.y, clip.width, clip.height,
clip.x, clip.y, clip.width, clip.height);
}

/**
* Complete the rendering by flushing the 2D renderer on a Draw2D
* graphical context.
*/
public void render(org.eclipse.draw2d.Graphics graphics) {
if (awtImage == null) return;

org.eclipse.draw2d.geometry.Rectangle clip =
graphics.getClip(new org.eclipse.draw2d.geometry.Rectangle());
transferPixels(clip.x, clip.y, clip.width, clip.height);
graphics.drawImage(swtImage, clip.x, clip.y, clip.width, clip.height,
clip.x, clip.y, clip.width, clip.height);
}

/**
* Transfer a rectangular region from the AWT image to the SWT image.
*/
private void transferPixels(int clipX, int clipY, int clipW, int clipH) {
int step = swtImageData.depth / 8;
byte[] data = swtImageData.data;
awtImage.getRGB(clipX, clipY, clipW, clipH, awtPixels, 0, clipW);
for (int i = 0; i < clipH; i++) {
int idx = (clipY + i) * swtImageData.bytesPerLine + clipX * step;
for (int j = 0; j < clipW; j++) {
int rgb = awtPixels[j + i * clipW];
for (int k = swtImageData.depth - 8; k >= 0; k -= 8) {
data[idx++] = (byte) ((rgb >> k) & 0xFF);
}
}
}
if (swtImage != null) swtImage.dispose();
swtImage = new Image(Display.getDefault(), swtImageData);
}

/**
* Dispose the resources attached to this 2D renderer.
*/
public void dispose() {
if (awtImage != null) awtImage.flush();
if (swtImage != null) swtImage.dispose();
awtImage = null;
swtImageData = null;
awtPixels = null;
}

/**
* Ensure that the offscreen images are initialized and are at least
* as large as the size given as parameter.
*/
private void checkOffScreenImages(int width, int height) {
int currentImageWidth = 0;
int currentImageHeight = 0;
if (swtImage != null) {
currentImageWidth = swtImage.getImageData().width;
currentImageHeight = swtImage.getImageData().height;
}

// if the offscreen images are too small, recreate them
if (width > currentImageWidth || height > currentImageHeight) {
dispose();
width = Math.max(width, currentImageWidth);
height = Math.max(height, currentImageHeight);
awtImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
swtImageData = new ImageData(width, height, 24, PALETTE_DATA);
swtImageData.transparentPixel = TRANSPARENT_COLOR;
awtPixels = new int[width * height];
}
}
}



這個渲染器包含在一個實(shí)用程序類中。這個類包含并管理屏外圖像技術(shù)所需要的 AWT 和 SWT 屏外圖像的引用。還要注意:

字段 swtImageData 和 awtPixels 分別是在像素轉(zhuǎn)移時包含 SWT 圖像的像素值的緩沖區(qū)和用于包含 AWT 圖像的像素值的緩沖區(qū)。


常量 TRANSPARENT_COLOR 包含一個作為 SWT 圖像中透明顏色的 RGB 值。因?yàn)楸仨毝x作為透明度信道的顏色以繪制背景,所以必須為此保留一個顏色值。在代碼中我使用了隨機(jī)值 0x123456。所有使用這個顏色值的像素都按透明處理。如果這個值所表示的顏色有可能在繪制操作中用到,可以用另一個值表示透明度。
渲染器是如何工作的
SWT/Draw2D Java 2D 渲染器的工作過程如下:

在可以使用渲染器之前,必須以至少與要繪制的區(qū)域一樣的尺寸初始化其屏外圖像和緩沖區(qū)。這是通過調(diào)用方法 prepareRendering(...) 完成的。根據(jù)是在 SWT 還是 Draw2D 圖形上下文中進(jìn)行渲染,這個方法以一個 SWT GC 或者一個 Draw2D Graphics 對象作為參數(shù)。


接下來,prepareRendering 從圖形上下文中提取剪裁矩形(clip rectangle)?? 剪裁矩形 是可以修改其中像素的最大矩形區(qū)域。


然后調(diào)用 private 方法 prepareRendering(int clipX, int clipY, int clipW, int clipH) 準(zhǔn)備要渲染的屏外圖像。這個方法獨(dú)立于所使用的圖形上下文的類型,它可以是 SWT 或者 Draw2D。prepareRendering() 方法的工作過程如下:


它首先檢查 AWT 和 SWT 屏外圖像已實(shí)例化并足以包含要繪制的區(qū)域,這是由方法 checkOffScreenImages(clipW, clipH) 完成的。


如果屏外圖像已經(jīng)實(shí)例化,但是不夠大,就會放棄它并以所需要大小重新創(chuàng)建一個。如果屏外圖像大于要繪制的區(qū)域,那么就會重復(fù)使用它,并只修改相應(yīng)于要繪制的區(qū)域的那一部分。


完成這種檢查后,用為透明度信道保留的顏色 TRANSPARENT_COLOR 填充繪制區(qū)域。這個圖像就可以用來進(jìn)行 Java 2D 操作了。



當(dāng)渲染器準(zhǔn)備好進(jìn)行剪裁區(qū)域中的 Java 2D 繪制操作后,可以從 BufferedImage AWT 獲得 Java 2D Graphics2D 上下文。這個圖形上下文將用于所有 Java 2D 繪制例程。每一次繪制操作修改 AWT 屏外圖像。


當(dāng)所有 Java 2D 繪制操作都完成后,繪制區(qū)域的像素必須從 AWT 轉(zhuǎn)換為 SWT 屏外圖像,然后繪制到 SWT 或者 Draw2D 圖形上下文中。這個操作是由方法 render(GC) 或者 render(Graphics) 完成的。這兩個方法都在內(nèi)部調(diào)用 private 方法 transferPixels(...),該方法將像素從 AWT 轉(zhuǎn)換為 SWT。


如果不再需要渲染器了或者必須釋放資源,可以調(diào)用 dispose() 方法,以清除渲染器所使用的屏外圖像和緩沖區(qū)。這會釋放資源,但是在再次需要渲染器時要花時間重新創(chuàng)建緩沖區(qū)。需要根據(jù)組件重新繪制的頻度以及重新繪制區(qū)域應(yīng)有多大來判斷應(yīng)當(dāng)什么時候調(diào)用 dispose()。
一個使用示例
清單 2 顯示如何用渲染器在 SWT Canvas 上繪制一些旋轉(zhuǎn)文字。

清單 2. 在 SWT Canvas 上的使用示例

Canvas canvas = new Canvas(shell, SWT.NO_BACKGROUND);
final Graphics2DRenderer renderer = new Graphics2DRenderer();

canvas.addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
Point controlSize = ((Control) e.getSource()).getSize();

GC gc = e.gc; // gets the SWT graphics context from the event

renderer.prepareRendering(gc); // prepares the Graphics2D renderer

// gets the Graphics2D context and switch on the antialiasing
Graphics2D g2d = renderer.getGraphics2D();
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);

// paints the background with a color gradient
g2d.setPaint(new GradientPaint(0.0f, 0.0f, java.awt.Color.yellow,
(float) controlSize.x, (float) controlSize.y, java.awt.Color.white));
g2d.fillRect(0, 0, controlSize.x, controlSize.y);

// draws rotated text
g2d.setFont(new java.awt.Font("SansSerif", java.awt.Font.BOLD, 16));
g2d.setColor(java.awt.Color.blue);

g2d.translate(controlSize.x / 2, controlSize.y / 2);
int nbOfSlices = 18;
for (int i = 0; i < nbOfSlices; i++) {
g2d.drawString("Angle = " + (i * 360 / nbOfSlices) + "u00B0", 30, 0);
g2d.rotate(-2 * Math.PI / nbOfSlices);
}

// now that we are done with Java 2D, renders Graphics2D operation
// on the SWT graphics context
renderer.render(gc);

// now we can continue with pure SWT paint operations
gc.drawOval(0, 0, controlSize.x, controlSize.y);
}
});




代碼說明:

創(chuàng)建一次渲染器,并在每次需要重新繪制畫布(canvas) 時重復(fù)使用它。


實(shí)例化畫布,并在它上面添加一個 PaintListener 以執(zhí)行繪制操作。


從 PaintEvent 獲得圖形上下文 gc。


渲染器是在圖形上下文中準(zhǔn)備的,這意味著屏外圖像可以接受繪制操作。


在下一步,獲得 Java 2D 圖形上下文 g2d。


然后實(shí)現(xiàn)一組 Java 2D 繪制操作以用漸變顏色繪制背景并且每 20 度繪制一個旋轉(zhuǎn)的文字。這個過程使用圖形上下文的平移和幾個旋轉(zhuǎn)。


最后,調(diào)用 render(GC) 方法以將 Java 2D 繪制操作傳輸?shù)? SWT 圖形上下文。可以在同一繪制例程中使用 Java 2D 和純 SWT 繪制操作。
渲染操作的結(jié)果
渲染操作的結(jié)果如圖 4 所示。在這個例子中,沒有丟棄渲染器,在每次繪制 Canvas 時可以重復(fù)使用它的屏外圖像和內(nèi)部緩沖區(qū),這樣可以節(jié)省實(shí)例化和垃圾收集的時間。記住,如果畫布不需要經(jīng)常重新繪制,并且渲染器所占用的資源非常重要,那么可以在每次繪制操作后丟棄渲染器。

圖 4. 使用示例:用 Java 2D 例程幫助繪制 SWT


清單 3 顯示如何在 Draw2D 圖像中實(shí)現(xiàn)同樣的例子。在這里是通過覆蓋 Figure 的方法 paintClientArea(Graphics) 來實(shí)現(xiàn)繪制 Figure。Graphics2DRenderer 的使用與上一個例子完全一樣。惟一的區(qū)別是,方法 prepareRendering 和 render 這一次是以一個 Draw2D Graphics 而不是一個 SWT GC 為參數(shù)調(diào)用的。

清單 3. 對 Draw2D 圖的使用示例

final Graphics2DRenderer renderer = new Graphics2DRenderer();

IFigure figure = new Figure() {
protected void paintClientArea(org.eclipse.draw2d.Graphics graphics) {
Dimension controlSize = getSize();
renderer.prepareRendering(graphics); // prepares the Graphics2D renderer

// gets the Graphics2D context
Graphics2D g2d = renderer.getGraphics2D();

(...) // does the Java 2D painting

// now that we are done with Java 2D, renders Graphics2D operation
// on the Draw2D graphics context
renderer.render(graphics);

// now we can continue with pure Draw2D paint operations
graphics.drawOval(0, 0, controlSize.width, controlSize.width);
}
};



結(jié)束語
本文展示的簡單技術(shù),使得將 Java 2D 功能集成到 SWT 和 GEF 應(yīng)用程序中成為可能并且相當(dāng)容易。我一步一步地展示了如何結(jié)合 SWT 和 Java 2D 的最好功能并將結(jié)果繪制到任何 SWT 組件或者 GEF Draw2D 圖像上。這里展示的技術(shù)就像代碼示例這樣簡單:只用幾行代碼就可以實(shí)現(xiàn),不需要依賴任何外部庫,也不需要啟動一個 AWT 線程。

本文提供的實(shí)現(xiàn)代碼可以用于任何 SWT 或者 GEF 應(yīng)用程序。屏外(offscreen)圖像技術(shù)可以在所有平臺上工作,包括 Linux/Motif 這樣的平臺,在這些地方,SWT 和 AWT 不能共同存在于同一個應(yīng)用程序中。由于這種技術(shù)所依據(jù)的操作不比將像素值從 AWT 圖像轉(zhuǎn)換為 SWT 圖像更復(fù)雜,所以也可以將這種技術(shù)用于 SWT 中其他基于 AWT 的作圖 API 的轉(zhuǎn)換。[@more@]
向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI