整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          來,教你做個(gè)屬于自己的 Markdown 編輯器

          選擇

          優(yōu)質(zhì)文章,及時(shí)送達(dá)

          本文原載于 SegmentFault 社區(qū)

          作者:薛勤

          原始沖動(dòng)

          最近一直在學(xué)習(xí) Electron 開發(fā)桌面應(yīng)用程序,目的是想做一個(gè)桌面編輯器,雖然一直在使用 Typora 這款神器,但無奈 Typora 太過國際化,在國內(nèi)水土不服,無法滿足我的一些需求。

          比如實(shí)現(xiàn)本地圖片上傳到云端(mac 版可以借助 iPic),無法幫我把本地圖片和文章一起發(fā)布到像 SegmentFault 等國內(nèi)知名博客平臺(tái),要么使用一些免費(fèi)或付費(fèi)的圖床,借助類似 iPic 的工具,把圖片一鍵上傳到云端。

          我個(gè)人也嘗試過七牛云的免費(fèi) 10G 存儲(chǔ)空間,但是說實(shí)話,這些免費(fèi)的空間到最后一定是為了讓你成為付費(fèi)用戶,各種限制各種吐槽在網(wǎng)上很容易可以搜索到。

          免費(fèi)的圖床如新浪微博等,還算是比較好的圖床工具,相比一些網(wǎng)絡(luò)上的壓根不知道啥公司甚至是歸屬個(gè)人的免費(fèi)圖床,新浪應(yīng)該是比較靠譜的,相對(duì)來說可以保證圖片的存活時(shí)間,我個(gè)人用過一些免費(fèi)的圖床網(wǎng)站,記得印象深刻的就是服務(wù)器出問題,網(wǎng)站掛個(gè)公告,曾經(jīng)的圖片再去訪問就是默認(rèn)的 404。

          雖然新浪家大業(yè)大不是說倒閉就倒閉的,圖片相對(duì)穩(wěn)定可靠,不過新浪的圖片服務(wù)器會(huì)檢測訪問來源 Referer 來防止外部網(wǎng)站引用,造成訪問 403。

          總結(jié)起來就是一句話,圖片還是隨著文章一鍵發(fā)布到博客平臺(tái)比較好。要丟一起丟~

          心理掙扎

          緣起這個(gè)動(dòng)機(jī),但是下定決心依舊是困難重重。

          我個(gè)人是一個(gè) Java 工程師,雖說搞過 Andorid、HTML 前端,但對(duì)前端深感不適的我果斷放棄了。對(duì)于桌面程序開發(fā),我連 Swing 都不會(huì),造一個(gè) Markdown 編輯器有點(diǎn)難,何況還要加上這些定制功能。

          猶猶豫豫,還是決定去嘗試一下。于是調(diào)研寫跨平臺(tái)的一些途徑。

          先嘗試 Swing,不過 Swing 不好實(shí)現(xiàn)我期望的一些功能,改成 JavaFX 倒是可以,不過說實(shí)話,寫起來很累,太過繁瑣,就放棄了。最后把目光瞄向 electron,就它了,HTML+Js+Css,聽起來就很簡單,事實(shí)證明,無論是測試還是打包都很方便。

          決定之后,便開始進(jìn)行 Electron 的系統(tǒng)學(xué)習(xí)。

          邁出第一步

          第一步就是安裝 Electron 的本地開發(fā)環(huán)境,這也是大多數(shù)應(yīng)用開發(fā)的第一步。

          你需要安裝 Node.js 在你的本地電腦,Electron 也是依賴于 Node.js 的環(huán)境,嚴(yán)格來說, Electron 通過將 Chromium 和 Node.js 合并到同一個(gè)運(yùn)行時(shí)環(huán)境中,并將其打包為Mac,Windows 和 Linux 系統(tǒng)下的應(yīng)用來實(shí)現(xiàn)這一目的。

          關(guān)于 Electron 的具體開發(fā)流程,這里不再贅述,你完全可以在開發(fā)中使用Web前端開發(fā)的思維,除了在處理多個(gè)窗口之間交互的時(shí)候,就不得不了解Eelctron的進(jìn)程機(jī)制。

          主進(jìn)程和渲染進(jìn)程

          Electron 運(yùn)行 package.json 的 main 腳本的進(jìn)程被稱為主進(jìn)程。在主進(jìn)程中運(yùn)行的腳本通過創(chuàng)建 web 頁面來展示用戶界面。一個(gè) Electron 應(yīng)用總是有且只有一個(gè)主進(jìn)程。

          由于 Electron 使用了 Chromium 來展示 web 頁面,所以 Chromium 的多進(jìn)程架構(gòu)也被使用到。每個(gè) Electron 中的 web 頁面運(yùn)行在它自己的渲染進(jìn)程中。

          在普通的瀏覽器中,web 頁面通常在沙盒環(huán)境中運(yùn)行,并且無法訪問操作系統(tǒng)的原生資源。然而 Electron 的用戶在 Node.js 的 API 支持下可以在頁面中和操作系統(tǒng)進(jìn)行一些底層交互。

          主進(jìn)程與渲染進(jìn)程的區(qū)別

          主進(jìn)程使用 BrowserWindow 實(shí)例創(chuàng)建頁面。每個(gè) BrowserWindow 實(shí)例都在自己的渲染進(jìn)程里運(yùn)行頁面。當(dāng)一個(gè) BrowserWindow 實(shí)例被銷毀后,相應(yīng)的渲染進(jìn)程也會(huì)被終止。

          主進(jìn)程管理所有的 web 頁面和它們對(duì)應(yīng)的渲染進(jìn)程。每個(gè)渲染進(jìn)程都是獨(dú)立的,它只關(guān)心它所運(yùn)行的 web 頁面。

          在頁面中調(diào)用與 GUI 相關(guān)的原生 API 是不被允許的,因?yàn)樵?web 頁面里操作原生的 GUI 資源是非常危險(xiǎn)的,而且容易造成資源泄露。如果你想在 web 頁面里使用 GUI 操作,其對(duì)應(yīng)的渲染進(jìn)程必須與主進(jìn)程進(jìn)行通訊,請(qǐng)求主進(jìn)程進(jìn)行相關(guān)的 GUI 操作。

          主進(jìn)程與渲染進(jìn)程通信

          那么進(jìn)程間如何通訊?

          Electron 為主進(jìn)程( main process)和渲染器進(jìn)程(renderer processes)通信提供了多種實(shí)現(xiàn)方式,如可以使用 ipcRenderer 和 ipcMain 模塊發(fā)送消息,使用 remote 模塊進(jìn)行 RPC 方式通信。

          你還可以用 Electron 內(nèi)的 IPC 機(jī)制實(shí)現(xiàn)。將數(shù)據(jù)存在主進(jìn)程的某個(gè)全局變量中,然后在多個(gè)渲染進(jìn)程中使用 remote 模塊來訪問它。

          示例代碼:

          // 在主進(jìn)程中
          global.sharedObject = {
          someProperty: 'default value'
          }

          // 在第一個(gè)頁面中
          require('electron').remote.getGlobal('sharedObject').someProperty = 'new value'

          // 在第二個(gè)頁面中
          console.log(require('electron').remote.getGlobal('sharedObject').someProperty)

          使用 Electron 的 API

          Electron 在主進(jìn)程和渲染進(jìn)程中提供了大量 API 去幫助開發(fā)桌面應(yīng)用程序, 在主進(jìn)程和渲染進(jìn)程中,你可以通過require的方式將其包含在模塊中以此,獲取 Electron 的 API

          const electron = require('electron')

          所有 Electron 的 API 都被指派給一種進(jìn)程類型。許多 API 只能被用于主進(jìn)程或渲染進(jìn)程中,但其中一些 API 可以同時(shí)在上述兩種進(jìn)程中使用。每一個(gè) API 的文檔都將聲明你可以在哪種進(jìn)程中使用該 API。

          Electron 中的窗口是使用 BrowserWindow 類型創(chuàng)建的一個(gè)實(shí)例, 它只能在主進(jìn)程中使用。

          // 這樣寫在主進(jìn)程會(huì)有用,但是在渲染進(jìn)程中會(huì)提示'未定義'
          const { BrowserWindow } = require('electron')

          const win = new BrowserWindow

          因?yàn)檫M(jìn)程之間的通信是被允許的, 所以渲染進(jìn)程可以調(diào)用主進(jìn)程來執(zhí)行任務(wù)。Electron 通過 remote 模塊暴露一些通常只能在主進(jìn)程中獲取到的 API。為了在渲染進(jìn)程中創(chuàng)建一個(gè) BrowserWindow 的實(shí)例,通常使用 remote 模塊為中間件:

          // 這樣寫在渲染進(jìn)程中時(shí)行得通的,但是在主進(jìn)程中是'未定義'
          const { remote } = require('electron')
          const { BrowserWindow } = remote

          const win = new BrowserWindow

          Tips:關(guān)注微信公眾號(hào):Java后端,每日技術(shù)博文推送。

          使用 Node.js 的 API

          Electron 同時(shí)在主進(jìn)程和渲染進(jìn)程中對(duì) Node.js 暴露了所有的接口。這里有兩個(gè)重要的定義:

          1) 所有在 Node.js 可以使用的 API,在 Electron 中同樣可以使用。在 Electron 中調(diào)用如下代碼是有用的:

          const fs = require('fs')

          const root = fs.readdirSync('/')

          // 這會(huì)打印出磁盤根級(jí)別的所有文件
          // 同時(shí)包含'/'和'C:\'。
          console.log(root)


          2) 你可以在你的應(yīng)用程序中使用 Node.js 的模塊。選擇您最喜歡的 npm 模塊。npm 提供了目前世界上最大的開源代碼庫,那里包含良好的維護(hù)、經(jīng)過測試的代碼,提供給服務(wù)器應(yīng)用程序的特色功能也提供給 Electron。

          例如,在你的應(yīng)用程序中要使用官方的 AWS SDK,你需要首先安裝它的依賴:

          npm install --save aws-sdk

          然后在你的 Electron 應(yīng)用中,通過 require 引入并使用該模塊,就像構(gòu)建 Node.js 應(yīng)用程序那樣:


          // 準(zhǔn)備好被使用的S3 client模塊
          const S3 = require('aws-sdk/clients/s3')

          有一個(gè)非常重要的提示: 原生 Node.js 模塊 (即指,需要編譯源碼過后才能被使用的模塊) 需要在編譯后才能和 Electron 一起使用。

          最終產(chǎn)品殺青落地

          終于搞明白了 Electron 的應(yīng)用架構(gòu),那么接著就要進(jìn)入產(chǎn)品的開發(fā)階段。比較慶幸的是,ELectron 的 UI 完全由 CSS+HTML 組成,這部分可用的框架太多了,我選擇了又老又知名的 BootStarp 框架搭建界面 UI,還引用了 JS 框架 JQuery。選擇了 electron-store 作為本地存儲(chǔ)文件,至于最關(guān)鍵的 Markdown 語法解析,對(duì)比了一番主流解析框架,最終選擇了 markdown-it。貼一下效果圖:

          這款軟件我給他起名為 JustWrite,意思就是現(xiàn)在就寫,也是在督促自己吧,畢竟猶豫徘徊,等于白來。

          現(xiàn)在軟件的功能除了包含一鍵發(fā)布本地文章加本地圖片到 SegmentFault 等平臺(tái),我還打算將他打造為一個(gè)體驗(yàn)不錯(cuò)的 Markdown 寫作軟件。現(xiàn)在你閱讀的這篇文章,就是我使用 JustWrite 書寫的,使用的字體是我個(gè)人喜歡的幼圓體,除此之外,還有六款風(fēng)格迥異的字體可以切換使用。字號(hào)也是可以動(dòng)態(tài)放大或者縮小,還可以關(guān)閉右側(cè)預(yù)覽,專注于寫作,如下圖所示:

          這些截圖是我截屏后使用快捷鍵 Ctrl+V 一鍵粘貼的,圖片會(huì)自動(dòng)放到當(dāng)前 md文件所在目錄下的 picture 文件夾內(nèi)。

          關(guān)于 JustWrite 從構(gòu)思到實(shí)踐的心路歷程大致就以上這些了,這次開發(fā) JustWrite 也讓我過了一把產(chǎn)品經(jīng)理的癮,基本已經(jīng)滿足了我的日常需求。如果你有更好的想法和創(chuàng)意也可以告訴我,說不定第二天就會(huì)實(shí)現(xiàn)了。

          GitHub:

          https://github.com/yueshutong/JustWrite

          前我發(fā)了一篇文章講述跨平臺(tái)的GUI技術(shù),其中提到了javafx。對(duì)此很多人表示疑惑,認(rèn)為javafx是落伍的開發(fā)技術(shù)。對(duì)此,我想專門寫一篇文章來做個(gè)介紹。

          其實(shí)很多人并沒有聽說過javafx。現(xiàn)在最新的java教材,在講到GUI技術(shù)的時(shí)候,還是以swing和awt為主。swing和awt是上一代的Java GUI技術(shù),現(xiàn)在很多銀行、國企的嵌入式設(shè)備還跑著swing和awt寫出來的程序。javafx是為了替代swing而產(chǎn)生的庫,它同時(shí)支持Windows, MacOS, Linux三種平臺(tái)的客戶端程序開發(fā)。對(duì)于移動(dòng)端(主要是IOS和Android),開源的javafxports以及相關(guān)的商業(yè)軟件歸于Gluon旗下,對(duì)于手機(jī)端做了額外的適配,使得javafx也可以在移動(dòng)設(shè)備上運(yùn)行。所以,javafx是真正的跨平臺(tái)客戶端開發(fā)技術(shù)。縱觀其他客戶端技術(shù),Electron只支持Windows, MacOS和Linux,Qt對(duì)于移動(dòng)端的支持尚不完善,C#開發(fā)GUI程序就更不必說了。

          和傳統(tǒng)的java GUI技術(shù)相比,javafx在美觀度和運(yùn)行效率上都有大幅度的提升。javafx對(duì)各平臺(tái)的GPU圖形API做了封裝,支持在各種平臺(tái)上的硬件加速,因此開發(fā)者完全可以使用javafx開發(fā)大型的三維系統(tǒng)軟件。下面是javafx兩個(gè)案例程序,分別展示了圖表和三維圖形。

          javafx圖表

          javafx 3D

          javafx是典型的前后端分離的開發(fā)模式。通過fxml繪制界面,css修飾頁面的樣式,java程序則用作后端控制。這種模式與web開發(fā)是極為相似的,也提高了程序的可維護(hù)性。

          有的同學(xué)可能會(huì)認(rèn)為用java做客戶端程序不合理。但是Matlab、IDEA、Eclipse等軟件都是java寫出來的,而且它們都取得了重大的成功。其實(shí)技術(shù)是用來實(shí)現(xiàn)目的的,只要能完成需求,客戶不會(huì)管你用的什么技術(shù)實(shí)現(xiàn)的。而且由于javafx是真正跨平臺(tái)的GUI技術(shù),開發(fā)軟件的時(shí)候,不需要給windows, Mac, Linux, Android, IOS分別配團(tuán)隊(duì),只需要一份代碼就可以了(或者只需要做少量平臺(tái)適配相關(guān)的修改)。Office、visual studio這種大型軟件,因?yàn)闆]有使用跨平臺(tái)的技術(shù)開發(fā),微軟現(xiàn)在想把它們遷移到新的平臺(tái)就非常困難。

          2018年JDK11發(fā)布之后,Oracle將javafx歸于openjdk項(xiàng)目之中,目的是為了加速javafx的發(fā)展速度。目前,jdk8中集成了javafx,而后續(xù)版本的jdk則移除了javafx,目的是實(shí)現(xiàn)模塊化。如果想在jdk11中使用javafx,可以通過maven導(dǎo)入javafx的依賴,也可以自行下載javafx并放到j(luò)dk中,總體而言并不麻煩。不過初學(xué)者還是使用jdk8比較好,熟悉之后再升級(jí)到j(luò)dk11。

          除了使用javafx庫中的組件進(jìn)行開發(fā)以外,開發(fā)者還可以使用javafx中的webview開發(fā)程序,這也是很多微信小程序和移動(dòng)端程序常用的開發(fā)模式。雖然這種開發(fā)方式降低了運(yùn)行速度,但是開發(fā)速度則大大提高,因?yàn)榍岸说墓ぞ哝湆?duì)于開發(fā)GUI程序?qū)嵲谑沁^于友好。javafx的webview加載和運(yùn)行速度其實(shí)還算比較快的,筆者曾經(jīng)對(duì)不同框架下的webview性能做過測試,發(fā)現(xiàn)2012年發(fā)布的javafx webview比2020年的Qt、安卓的webview速度還快,僅次于Electron(畢竟Electron是正經(jīng)的套殼瀏覽器)。javafx的webview對(duì)HTML5的支持非常好,對(duì)css的支持稍微差點(diǎn),但是基本不影響使用。

          使用IDEA + scenebuilder是目前最好的開發(fā)javafx程序的方案。其中IDEA支持css和fxml的語法提示和高亮,scenebuilder是所見即所得的fxml生成器,可以通過拖拽的方式繪制界面。不過我不推薦拖拽組件,因?yàn)檫@種方式構(gòu)建界面是有限制的,不能做出復(fù)雜的界面效果,而且自適應(yīng)屏幕大小的時(shí)候也比較麻煩。繪制網(wǎng)頁的時(shí)候也是這樣,一般都不用編輯器,手寫HTML + CSS是最好的。

          如果想要學(xué)習(xí)javafx的話,可以看我上面一篇關(guān)于跨平臺(tái)GUI技術(shù)對(duì)比的文章。后面我也會(huì)陸續(xù)更新javafx相關(guān)的技術(shù)指導(dǎo)。

          到目前為止,我們編寫的程序都是通過鍵盤接收輸入,在控制臺(tái)屏幕上顯示結(jié)果。絕大多數(shù)用戶并不喜歡這種交互方式。現(xiàn)代的程序早已不采用這種操作方法,網(wǎng)絡(luò)程序更是如此。

          從本章開始,我們將介紹如何編寫使用圖形用戶界面(GUI)的Java程序。其中,主要講述如何編寫定義屏幕上的窗口大小和位置的程序;如何在窗口中采用多種字體顯示文本;如何顯示圖像等等。這些都是需要掌握的編程技能,在后續(xù)章節(jié)中,將會(huì)使用這些技術(shù)編寫一些很有趣味的程序。

          Swing概述

          在Java 1.0剛剛出現(xiàn)的時(shí)候,包含了一個(gè)用于基本GUI程序設(shè)計(jì)的類庫,Sun將它稱為抽象窗

          口工具箱(Abstract Window Toolkit,AWT)。基本AWT庫采用將處理用戶界面元素的任務(wù)委派給每個(gè)目標(biāo)平臺(tái)(Windows、Solaris、Macintosh等等)的本地GUI工具箱的方式,由本地GUI工具箱負(fù)責(zé)用戶界面元素的創(chuàng)建和動(dòng)作。例如,如果使用最初的AWT在Java窗口中放置一個(gè)文本框,就會(huì)有一個(gè)低層的“對(duì)等體”文本框,用它來實(shí)際地處理文本輸入。從理論上說,結(jié)果程序可以運(yùn)行在任何平臺(tái)上,但觀感(look and feel)的效果卻依賴于目標(biāo)平臺(tái),因此,Sun公司的口號(hào)是“一次編寫,隨處使用”。

          對(duì)于簡單的應(yīng)用程序來說,基于對(duì)等體方法的效果還是不錯(cuò)的,但是,要想編寫依賴于本地用戶界面元素的高質(zhì)量、可移植的圖形庫就會(huì)顯現(xiàn)出缺陷了。例如,菜單、滾動(dòng)條和文本域這些用戶界面元素,在不同的平臺(tái)上,操作行為存在著一些微妙的差別。因此,要想給予用戶一致的、可預(yù)見性的界面操作方式是相當(dāng)困難的。而且,有些圖形環(huán)境(如X11/Motif)并沒有像Windows或Macintosh這樣豐富的用戶界面組件集合。這也就將基于對(duì)等體的可移植庫限制在了“最小公分母”的范圍內(nèi)。其結(jié)果使AWT構(gòu)建的GUI應(yīng)用程序看起來沒有Windows或Macintosh應(yīng)用程序顯示的那么漂亮,也沒有提供那些平臺(tái)用戶所認(rèn)知的功能。更加糟糕的是,在不同平臺(tái)上的AWT用戶界面庫中存在著不同的bug。研發(fā)人員必須在每一個(gè)平臺(tái)上測試他們的應(yīng)用程序,因此人們嘲弄地將AWT稱為“一次編寫,到處調(diào)試”。

          在1996年,Netscape創(chuàng)建了一種稱為IFC(Internet Foundation Class)的GUI庫,它采用了與AWT完全不同的工作方式。它將按鈕、菜單這樣的用戶界面元素繪制在空白窗口上,而對(duì)等體只需要?jiǎng)?chuàng)建和繪制窗口。因此,Netscape的IFC部件在程序運(yùn)行的所有平臺(tái)上的外觀和動(dòng)作都一樣。Sun與Netscape合作完善了這種方式,創(chuàng)建了一個(gè)名為Swing(有時(shí)稱為Swing集)的用戶界面庫。Swing可作為Java 1.1的擴(kuò)展部分使用,現(xiàn)已成為JDK 1.2標(biāo)準(zhǔn)庫的一部分,

          就像Duke Ellington所說的那樣:“如果沒有Swing,Java圖形界面就沒有任何意義”。現(xiàn)在,Swing是不對(duì)等基于GUI工具箱的正式名字。它已是Java基礎(chǔ)類庫(Java Foundation Class,JFC)的一部分。完整的JFC十分龐大,其中包含的內(nèi)容遠(yuǎn)遠(yuǎn)大于Swing GUI工具箱。JFC特性不僅僅包含了Swing組件,而且還包含了一個(gè)可訪問的API、一個(gè)2D API和一個(gè)可拖拽的API。

          注意:Swing沒有完全替代AWT,而是基于AWT架構(gòu)之上。Swing僅僅提供了能力更加強(qiáng)大的用戶界面組件。尤其在采用Swing編寫的程序中,還需要使用基本的AWT處理事件。從現(xiàn)在開始,“Swing”是指“被繪制的”非對(duì)等體用戶界面類;“AWT”是指像事件處理這樣的窗口工具箱的低層機(jī)制。

          當(dāng)然,在用戶屏幕上顯示基于Swing用戶界面的元素要比顯示AWT的基于對(duì)等體組件的速度慢一些。鑒于以往的經(jīng)驗(yàn),對(duì)于任何一臺(tái)現(xiàn)代的計(jì)算機(jī)來說,微小的速度差別無妨大礙。另外,由于下列幾點(diǎn)無法抗拒的原因,驅(qū)使人們選擇Swing:

          ? Swing擁有一個(gè)豐富、便捷的用戶界面元素集合。

          ? Swing對(duì)低層平臺(tái)依賴的很少,因此與平臺(tái)相關(guān)的bug很少。

          ? Swing給予不同平臺(tái)的用戶一致的感觀效果。

          所有這些意味著Swing擁有履行Sun提出的“一次編寫,到處運(yùn)行”承諾的能力。

          不過,上面第三點(diǎn)存在著一個(gè)潛在的問題:如果在所有平臺(tái)上用戶界面元素看起來都一樣,那么,它們就有可能與本地控件不一樣,而這些平臺(tái)的用戶對(duì)此可能并不熟悉。

          Swing采用了一種很巧妙的方式來解決這個(gè)問題。在程序員編寫Swing程序時(shí),可以為程序指定專門的“觀感”。

          例如,圖7-1和圖7-2展示了同一個(gè)程序在Windows 和Motif平臺(tái)下運(yùn)行的觀感。


          注意:盡管本書并沒有打算介紹有關(guān)設(shè)定“觀感”的方式,但Java程序員可以對(duì)已存在的觀感進(jìn)行擴(kuò)展,甚至還可以設(shè)計(jì)全新的觀感。設(shè)計(jì)Swing組件的繪制方式是一個(gè)很繁瑣的過程。有些程序員已經(jīng)做過一些這樣的工作,尤其是將Java移植到信息亭(kiosk)終端和手持設(shè)備這樣的非傳統(tǒng)平臺(tái)上。請(qǐng)參閱 http://www.javooto.com,其中包含了一系列有趣的觀感實(shí)現(xiàn)。

          JDK 5.0引入了一種被稱為Synth的新觀感方式,使用它處理比較容易。在Synth中,可以通過指定圖像文件和XML描述符定義一種新觀感,而不需要編寫任何代碼。

          此外,Sun開發(fā)了一種被稱為“Metal”的獨(dú)立于平臺(tái)的觀感。現(xiàn)在,市場上人們將它稱為“Java觀感”。不過,絕大多數(shù)程序員還繼續(xù)沿用著“Metal”這個(gè)術(shù)語,在本書中也將這樣稱呼。

          有些人批評(píng)Metal有點(diǎn)笨重,而在版本5.0中看起來卻煥然一新(請(qǐng)看圖7-3)。

          現(xiàn)在,Metal外觀支持多種主題,每一種主題的顏色和字體都有微小的變化。

          默認(rèn)的主題叫做“Ocean”。在本文中,所有的圖形程序都將采用Swing的Metal觀感和Ocean主題。

          注意:絕大多數(shù)Java用戶界面程序設(shè)計(jì)都采用Swing,但有一個(gè)特別的例外。Eclipse集成開發(fā)環(huán)境使用了一種與AWT類似,且被稱為SWT的圖形工具箱,它可以映射到不同平臺(tái)的本地組件上。

          有關(guān)SWT的描述可以在網(wǎng)站http://www.eclipse.org/ articles/找到。

          最后,給大家一個(gè)忠告,如果使用過Visual Baisc或C# 編寫Microsoft Windows應(yīng)用程序,就應(yīng)該了解這些產(chǎn)品提供的圖形布局工具和資源編輯器帶來的便利。這些工具可以用來設(shè)計(jì)應(yīng)用程序的外觀,然后生成大部分(有時(shí)是全部)GUI代碼。盡管也有一些Java程序設(shè)計(jì)的GUI構(gòu)造器,但它們與相應(yīng)的Windows工具相比較起來還很不成熟。不管怎樣,要想完全地掌握?qǐng)D形用戶界面程序(乃至有效地使用這些工具),就需要知道如何手工地創(chuàng)建用戶界面。當(dāng)然,通常需要編寫大量的代碼。

          創(chuàng)建框架

          在Java中,頂層窗口(就是沒有包含在其他窗口中的窗口)被稱為框架(frame)。在AWT庫中有一個(gè)稱為Frame的類,用于描述頂層窗口。這個(gè)類的Swing版本名為JFrame,它擴(kuò)展于Frame類。JFrame是極少數(shù)幾個(gè)不繪制在畫布上的Swing組件之一。因此,它的修飾部件(按鈕、標(biāo)題欄、圖標(biāo)等)由用戶的窗口系統(tǒng)繪制,而不是由Swing繪制。

          警告:大多數(shù)的Swing組件類都以“J”開頭,例如,JButton、JFrame等等。在Java中有Button和Frame這樣的類,但它們屬于AWT組件。如果偶然地忘記了書寫“J”,程序仍然可以進(jìn)行編譯和運(yùn)行,但是將Swing和AWT組件混合在一起使用將會(huì)導(dǎo)致視覺和行為的不一致。

          在本節(jié)中,將介紹有關(guān)Swing的JFrame的常用方法。例7-1給出了一個(gè)在屏幕中顯示一個(gè)空框架的簡單程序。如圖7-4所示。

          例7-1 SimpleFrameTest.java

          下面逐行地討論一下這個(gè)程序。

          Swing類位于javax.swing包中。包名javax表示這是一個(gè)Java擴(kuò)展包,而不是核心包。Swing類實(shí)際上是對(duì)Java 1.1的擴(kuò)展。由于Swing類不是核心層次的一部分,所以盡可能地將Swing類加載到Java 1.1兼容的瀏覽器中(瀏覽器的安全管理器不允許添加任何以“java.”開頭的包)。在Java 2平臺(tái)上,Swing包不再是擴(kuò)展部分,而是核心層的一部分。任何與Java 2兼容的Java實(shí)現(xiàn)都必須提供Swing類。不過,為了與Java 1.1代碼兼容,保留了javax名字。(實(shí)際上,Swing包最早是com.sun.java.swing,后來在Java 2的beta版本中簡化為java.awt.swing,最后在Java 2后期的beta版本中又改回為com.java.swing,在Java程序員的抗議呼聲下,最終改為javax.swing。)

          在默認(rèn)情況下,框架的大小為0×0像素,這種框架沒有什么實(shí)際意義。我們定義了一個(gè)子類SimpleFrame,它的構(gòu)造器將框架大小設(shè)置為300×200像素。在SimpleFrameTest類的main方法中,程序?qū)⒂蓜?chuàng)建一個(gè)SmpleFrame對(duì)象開始運(yùn)行。

          接下來,我們定義了用戶關(guān)閉這個(gè)框架時(shí)的響應(yīng)動(dòng)作。對(duì)于這個(gè)程序而言,我們只是讓程序退出。選擇這個(gè)響應(yīng)動(dòng)作的語句是:

          frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

          在包含多個(gè)框架的程序中,不能因?yàn)橛脩絷P(guān)閉了其中的一個(gè)框架就讓程序退出。在默認(rèn)情況下,用戶關(guān)閉窗口時(shí)只是將框架隱藏了起來,而程序并沒有終止。

          簡單地構(gòu)造一個(gè)框架并不自動(dòng)顯示出來,框架起初是不可見的。這就給程序員了一個(gè)機(jī)會(huì),可以在框架第一次顯示之前往其中添加組件。為了顯示框架,main方法需要調(diào)用框架的setVisible方法。

          然后,main方法退出。需要注意,退出main并沒有終止程序,終止的只是主線程。目前顯示的框架激活了用戶界面線程,以保持程序處于激活狀態(tài)。

          注意:在JDK 5.0以前的版本中,可以使用JFrame類從超類Window繼承show方法。Window類的超類是Component,其中也有一個(gè)show方法。在JDK 1.2中不提倡使用Component.show。如果想要顯示一個(gè)組件,建議調(diào)用setVisible(true)。然而,JDK 1.4以前的版本,并沒有反對(duì)使用Window.show方法。事實(shí)上,這個(gè)方法很實(shí)用,它可以讓窗口可見,且置于其他窗口的前面。遺憾的是,由于不提倡使用它,隨之也失去了這一好處,JDK 5.0也不贊成使用show顯示窗口。

          圖7-4中顯示的是運(yùn)行例7-1程序的結(jié)果,它只是一個(gè)很乏味的頂層窗口。在這個(gè)圖中看到的標(biāo)題欄和外框裝飾(比如,重置窗口大小的拐角)都是由操作系統(tǒng)繪制的,而不是Swing庫。如果在X Windows下運(yùn)行同樣的程序,對(duì)框架的裝飾是不一樣的。Swing庫負(fù)責(zé)繪制框架內(nèi)的所有內(nèi)容。在這個(gè)程序中,只用默認(rèn)的背景色填充了框架。

          注意:在JDK 1.4中,可以調(diào)用frame.setUndecorated(true) 關(guān)閉所有框架裝飾。

          注意:在前面的例子中編寫了兩個(gè)類,一個(gè)用于定義框架類,另一個(gè)包含了創(chuàng)建和顯示框架對(duì)象的main方法。在很多程序中,經(jīng)常會(huì)發(fā)現(xiàn)main方法被包裝成一個(gè)很簡捷的類,如下所示:


          從某種意義上說,調(diào)用框架類中的main方法的代碼啟動(dòng)程序是比較簡單的。這樣不必引入其他的輔助類。然而,有相當(dāng)多的程序員感覺這種程序風(fēng)格有點(diǎn)混亂。

          因此,更愿意將啟動(dòng)程序的類與定義用戶界面的類分開。

          覺得文章不錯(cuò)的話,可以轉(zhuǎn)發(fā)關(guān)注小編一波,每天持續(xù)更新好文!!!

          明天講框架定位和在面板中顯示信息~~


          主站蜘蛛池模板: 国产精品一区二区AV麻豆| 大香伊人久久精品一区二区 | 久久精品一区二区影院 | 国产福利电影一区二区三区久久老子无码午夜伦不 | 鲁丝片一区二区三区免费| 插我一区二区在线观看| 无码少妇一区二区| 午夜视频一区二区| 台湾无码AV一区二区三区| 国产精品免费一区二区三区四区| 97se色综合一区二区二区| 国产SUV精品一区二区88L | 日本免费电影一区二区| 日本激情一区二区三区| 国产一区二区三区免费看| 精品国产亚洲一区二区三区| 亚洲丰满熟女一区二区哦| 北岛玲在线一区二区| 日本在线不卡一区| 无码人妻精品一区二区三区不卡| 亚洲日本一区二区三区在线不卡| 日韩一区二区在线观看视频| 人妻精品无码一区二区三区 | 国产亚洲福利一区二区免费看| 中文无码精品一区二区三区 | 一区二区三区高清视频在线观看| 国产精品无码一区二区三区电影 | 成人精品视频一区二区三区不卡 | 精品人妻无码一区二区色欲产成人| 精品一区二区三区四区电影 | 国产成人精品一区二区A片带套| 午夜肉伦伦影院久久精品免费看国产一区二区三区 | 在线观看国产一区亚洲bd| 中文字幕无码一区二区免费 | AV鲁丝一区鲁丝二区鲁丝三区| 好吊妞视频一区二区| 亚洲国产国产综合一区首页| 中文字幕AV一区二区三区| 国模无码视频一区二区三区| 日本精品高清一区二区| 日韩免费一区二区三区在线|