程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 設計具有本機性能的跨平台Java UI:使用JNI來訪問SLIK皮膚接口

設計具有本機性能的跨平台Java UI:使用JNI來訪問SLIK皮膚接口

編輯:關於JAVA

簡介:您能編寫跨多種平台編譯、同時執行速度仍然像本機代碼一樣快的 Java 代碼嗎?這是一個困擾 Java 開發人員的難題,對於具有復雜 UI 的應用 程序來說尤為如此。在本文中,開發人員 Vladimir Silva 建議了一種針對這個 難題的有趣解決方案。您將學習如何使用 JNI 來訪問 SLIK,後者是一個跨平台 的 C API,它同時在 Windows 和 UNIX 上提供本機性能。

相對於諸如 C 和 C++ 這樣的傳統語言,Java 語言已主宰了中間層開發。 Java 語言在開發社區得到普遍接受的原因是它的面向對象設計、平台無關性, 以及豐富的支持 API。然而,它在設法將桌面作為一個真正的開發平台方面卻很 失敗——或許這是由於使得它主宰中間層的相同原因吧。平台無關性意味著相對 於本機 C 和 C++ 應用程序來說,性能會大大降低。

本文的目的是展示 Java 與簡單皮膚接口(Simplistic Skin Interface,也 稱為 SLIK)的綁定(請參閱 參考資料,獲取更多細節)。SLIK 是一個可用於 構建跨平台 GUI 的 C API。通過使用 Java 本機接口(Java Native Interface ,JNI),您可以將 Java 代碼綁定到 SLIK,從而設計出像 C 和 C++ 一樣執行 的跨平台用戶界面。

Java 語言和 C:動感二重唱

Java 技術支持與多種語言綁定,包括 C/C++、Fortran,等等。這一卓越特 性為開發人員帶來了無比的靈活性,允許他們編寫需要某些操作系統相關功能的 API。

為了證明 SLIK 的高級用戶界面功能,我將展示如何構建一個沒有矩形窗口 的 UI(也稱為 皮膚或 帶皮膚的窗口),它需要 Java 語言當前所沒有提供的 低級 API。Java 所提供的是使用 JNI 訪問任何操作系統相關服務的手段。在本 機端,C 是最佳的語言選擇,而我將使用的 SLIK 的修改版本提供了實現本文目 標的多平台 C API。

關於 JNI 的詳細介紹超出了本文的范圍;欲了解關於該主題的更多信息,請 參考下面的 參考資料小節。務必要牢記的一件重要事情是,SLIK 是用 C 編寫 的,並且您需要 JNI 來從用 Java 語言編寫的代碼中訪問它。

SLIK 概述

SLIK 是一個 C API,用於構建基於 WinAmp 風格的皮膚的高級用戶界面。此 類界面的例子包括像用於類 UNIX 系統的流行的 XMMS(X-Multimedia System, X-多媒體系統)和 XINE CD/DVD 播放器這樣的音頻和視頻播放器。 使用這個 API 作為 GUI 的基礎具有許多好處:

SLIK 包括一組增強的小部件,比如按鈕、菜單、窗口、列表,以及當前的窗 口工具包所沒有提供的高分辨率圖像。

該 API 可用於多平台設計,因為它的核心庫可同時在 Microsoft Windows 和類 UNIX 系統下編譯。

SLIK 可以實現為一個 Windows DLL 或 UNIX 共享對象庫,這意味著它可以 跨多個應用程序重用,並且易於維護。

SLIK 軟件由 GQmpeg 小組在 GNU 公共許可證(GNU Public License,GPL) 之下提供。GQmpeg 小組提供的 SLIK 版本僅在類 UNIX 系統上作為可執行文件 來編譯。我創建了一個修改後的版本,它可以同時工作在 Win32 和 UNIX 系統 上;這個版本以二進制的形式隨本文的源代碼一起提供(同時包括 Windows DLL 和 UNIX 共享對象或 SO 版本)。

我還同時提供了用於 UNIX 和 Windows 環境的 makefile。

SLIK 概述

SLIK 是一個 C API,用於構建基於 WinAmp 風格的皮膚的高級用戶界面。此 類界面的例子包括像用於類 UNIX 系統的流行的 XMMS(X-Multimedia System, X-多媒體系統)和 XINE CD/DVD 播放器這樣的音頻和視頻播放器。 使用這個 API 作為 GUI 的基礎具有許多好處:

SLIK 包括一組增強的小部件,比如按鈕、菜單、窗口、列表,以及當前的窗 口工具包所沒有提供的高分辨率圖像。

該 API 可用於多平台設計,因為它的核心庫可同時在 Microsoft Windows 和類 UNIX 系統下編譯。

SLIK 可以實現為一個 Windows DLL 或 UNIX 共享對象庫,這意味著它可以 跨多個應用程序重用,並且易於維護。

SLIK 軟件由 GQmpeg 小組在 GNU 公共許可證(GNU Public License,GPL) 之下提供。GQmpeg 小組提供的 SLIK 版本僅在類 UNIX 系統上作為可執行文件 來編譯。我創建了一個修改後的版本,它可以同時工作在 Win32 和 UNIX 系統 上;這個版本以二進制的形式隨本文的源代碼一起提供(同時包括 Windows DLL 和 UNIX 共享對象或 SO 版本)。

我還同時提供了用於 UNIX 和 Windows 環境的 makefile。

SLIK-Java 對象層次

圖 2 中的 UML 圖描繪了帶皮膚的窗口對象層次和 JSLIK 包的本機層。 JSLIK 對象層次的頂部是 GtkSkin 類。它封裝了一個帶皮膚的窗口,並為這樣 一個窗口提供以下有用功能:加載、卸載、最小化、圖標化,等等。它還能夠監 聽諸如鼠標移動、單擊、子窗口的派生以及拋出異常等事件。它不同於常規窗口 的地方在於,其幾何形狀和它們的所有子部件都基於從規格文件中加載的高分辨 率圖像。 GtkSkinNatives 類提供了調用實際繪制窗口的低級本機方法的接口。

圖 2. 非矩形窗口對象層次

圖 3 中的 UML 圖描繪了可以使用 SLIK 來創建的各種窗口小部件的層次。

圖 3. 小部件對象的 UML 圖

這些窗口小部件封裝了皮膚規格文件中定義的屬性,該文件默認被命名為 skindata ,並且連同必要的圖像文件一起位於皮膚目錄中。窗口小部件的屬性 包括幾何 XY 坐標、透明度,以及背景圖像。清單 1 包含了節選自本文的示例 皮膚之一的規格文件的內容。

清單 1. 皮膚規格文件節選

[main]
image = main-complete.png
transparent = FALSE
border = TRUE
border_left = 116
border_right = 63
[button_exit]
image = btn-12-exit.png
x = 252
y = 2
prelight = TRUE

欲了解關於這個文件的格式的完全描述,請參閱隨本文的源代碼提供的 SKIN-SPECS 文檔。

小部件概述

SLIK 提供了 WinAmp 風格的皮膚小部件,比如按鈕、滑塊、撥號盤、菜單、 子窗口、標簽和列表。正如您已經看到的那樣,諸如圖形、標簽等小部件屬性是 從一個默認名為 skindata 的皮膚規格文件中讀取的。其中一些小部件包括撥號 盤旋鈕(專門為多媒體播放器設計)、一個高度可定制的圖形列表(通常用於播 放列表)、菜單、按鈕、標簽和滑塊。這些小部件的基本版本如圖 4 所示。

圖 4. 示例小部件

這些抽象小部件能夠加載遠遠優於系統的默認窗口管理器的特定圖形樣式。 然而,許多小部件沒有在媒體播放器中廣泛使用,它們當前也不是小部件集的組 成部分。本文後面的 圖 5給出了這些增強的圖形樣式的一個例子。該圖描繪了 一個具有許多美妙圖形的類似 PDA 外觀的應用程序。

用 Java 語言編寫的一個示例皮膚客戶機

SLIK 的 JNI 接口能夠為 Java 客戶機提供同時在 Windows 和 UNIX/Linux 環境中創建皮膚對話框的能力。像使用傳統 GUI 工具包來構建的類一樣,帶皮 膚的客戶端將監聽高級事件,比如窗口的關閉、最小化或最大化。然而,這個基 於 SLIK 的類需要 SLIK 專用的接口來監聽任何帶皮膚的小部件的這些事件。清 單 2 說明了這些接口。(以下所有清單都取自 SkinDemo.java,這是本文與本 文配套的代碼包的一部分。請 單擊這裡來獲得這個文件的彩色語法顯示的完整 清單。)

清單 2 SLIK 事件接口

import jni.skin.slik.*;
import jni.skin.slik.evt.*;
import jni.skin.slik.widget.*;
import jni.skin.util.Debug;
public final class SkinDemo implements // listen for:
  WindowEventListener, // window evts: Window closed, mouse clicked, mouse dragged
   ButtonEventListener, // Button widget clicks
  ListEventListener,   // List evts: row clicked, etc...
  DialEventListener,  // Dial widget drags
  SliderEventListener, // Slider drags
   MenuEventListener  // Menu selection events
{
  ...

C 層中生成的 GTK 小部件事件將通過 JNI 級聯地返回到 Java 層。大多數 小部件屬性,比如標簽、XY 位置以及圖形,都是在皮膚規格文件中定義的。

加載皮膚數據文件

為了從磁盤加載皮膚規格文件,需要首先初始化 GtkSkin 類,然後注冊您希 望監聽其事件的小部件,並加載該文件,如清單 3 所示。

清單 3. 從磁盤加載皮膚規格文件

/*
* Main function
*/
public SkinDemo(String[] args) throws GtkSkinException
{
     ...
     // init gtk (create skin window) + JNI debug flag (TRUE/FALSE)
     skin = new GtkSkin("My App", GtkSkin.GTK_TRUE);
     // Init all widgets: for skin demo purposes (Widgets typically initialized when needed...)
     skin.initAllWidgets();
     // Create and register some widgets
     // See the SPEC file for details
     // example: [button_exit], [list_playlist], [number_song], ....
     // IMPORTANT: All widgets must exist in SPEC file
     // Widget data (imgs, lbls, etc. are defined in the spec file
     skin.registerWidget(new WText("title"), "Title goes here!");
     skin.registerWidget(new WButton ("exit"));
     skin.registerWidget(new WButton("iconify"
      ...
     /**
     * Listen for Skin Window main evts: KeyPress, Mouse motion and Mouse BTN press
     */
      skin.addWindowEventListener(this);
     // load/show
     skin.loadSkin(skinPath);
     skin.show();
}

GtkSkin("My App", GtkSkin.TRUE)調用將以調試模式初始化 GIMP 運行庫。 之後,皮膚規格文件中定義的所有 widget 都必須注冊,這樣 Java 層才會監聽諸如鼠標點擊等事件。除了 widget 事件之外,應用程序還必 須監聽窗口事件,比如最小化、最大化和關閉窗口命令。最後, loadSkin (path)方法調用將從磁盤讀取一個給定的文件路徑,而 show()將顯示該路徑。

使用小部件:撥號盤、滑塊和彈出菜單

撥號盤和滑塊小部件對於設計諸如視頻或音頻播放器等多媒體應用程序的用 戶界面很有用。與所有 SLIK 小部件一樣,諸如位置坐標、像素映射和字體等大 多數屬性都是在皮膚規格文件中定義的。Java 代碼注冊這些對象,以便從這些 對象接收事件,如清單 4 所示。

清單 4. 撥號盤、滑塊和彈出菜單

// dial widget
// see [dial_position] on the skin file for attributes
position = new WDial("position");
position.addDialListener(this);
skin.registerWidget(position);
// More documentation can be found on the SKIN-SPECS file
// in the src distribution of this article
// slider test: maps to [slider_volume] in skindata
volume = new WSlider("volume");
volume.addSliderListener(this);
skin.registerWidget(volume);
// popup menu sample
String [] menus =
{
// menu #1
"Menu 1" + WMenu.SUBMENU_DIVIDER + "Submenu-11" + WMenu.SUBMENU_DIVIDER +
"Submenu-12",
// menu #2
"Menu2" + WMenu.SUBMENU_DIVIDER + "Submenu21" + WMenu.SUBMENU_DIVIDER +
WMenu.MENU_DIVIDER + WMenu.SUBMENU_DIVIDER + "SubM31" ,
WMenu.MENU_DIVIDER,
"Menu3",
"Menu4"
};
popup = new WMenu("popup", menus, skinHandle);
popup.addMenuListener(this);
skin.registerWidget(popup, menus);
...

撥號盤小部件(廣播調諧器 / 播放器的典型組件)應該具有一個類似如下的 聲明:

WDial position = new WDial("position")

這裡, position 是皮膚數據文件( skindata)中定義的一個鍵,該文件包含諸如幾何形狀、圖 像等屬性。之後, position.addDialListener(this)調用將設置主類來監聽由 這個小部件激發的事件。 最後, skin.registerWidget(position)將從 C 層級 聯調用 Java 層,然後返回。相同的方法序列也適用於所有 JSLIK 小部件。

探索源代碼

本文已經提供了關於 SLIK 和 Java 平台在實踐中如何協同工作的介紹。為 了真正理解它究竟是如何工作的,您需要運行並研究源代碼。隨本文分發的代碼 包包含以下文件夾結構:

Slik_jni 文件夾結構

文件夾名稱 文件類型 classes 已編譯的 Java 類 myskins 示例皮膚 native Java JNI SLIK 庫 Win32/Linux src Java/C 源代碼

還有兩個提供用於測試目的的 shell 腳本:rundemo.bat 和 rundemo.sh。 雙擊針對您的平台的相應腳本將會運行演示程序,並加載默認的皮膚,如圖 5 所示。

圖 5. PDA 演示皮膚

演示皮膚 PDA

按 Play 按鈕將打開皮膚編輯器,您可以使用它來浏覽或修改構成此皮膚的 不同小部件。按 Back 按鈕將啟動打開文件對話框,您可以使用它來加載所提供 的許多示例皮膚。

可以容易地使用自己最喜歡的 IDE 來編譯該 Java 源代碼。代碼包中還提供 了二進制版本,不過如果想要自己編譯 C 代碼,相應的編譯說明已包括在這個 項目的 README 文件中。本文中的代碼已在以下平台上測試過:

Microsoft Windows 2000 和 XP。

Red Hat Linux 8.x 和 9,以及 SuSE Linux Workstation 8.x,兩者都是基 於 x86 的體系結構。

結束語

要成為桌面市場的重要競爭者,Java 開發人員被迫依賴 Java 本機接口 (Java Native Interface,JNI)來提供特定平台的用戶所預期的外觀和感覺以 及性能水平。

隨著 Linux 在桌面操作系統市場的增長,高級用戶界面將成為開發人員追求 的主要目標。如果 Linux 要與 Windows 競爭,它需要具有易用性和出色的圖形 和視覺效果。GIMP 工具包為這種轉變奠定了基石。

如今的 API,比如 WinAmp 和 Xine,都是平台相關的。SLIK 走出了實現統 一的第一步。而且由於 JNI 可用於訪問 SLIK API,因此 SLIK 代表了可同時供 兩個陣營使用的潛在工具。Java 開發人員可以編寫具有本機 GUI 性能水平的桌 面應用程序,而 Linux 開發人員能夠提供可容易地移植到 Windows 的一流 GUI 。

本文展示的 JNI API 將幫助您編寫無需更改即可同時運行在 Linux 和 Windows 之下的帶皮膚的 GUI。當然,您可以用 C 編寫代碼——如果那是您的 首選語言的話;但是本文展示的代碼將會給受到傳統用戶界面所包圍 Java 語言 迷帶來新的機會。

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