ZetesマルチプラットフォヌムGUIを䜿甚するがOracle JVMを䜿甚しないJava

画像



泚釈



この蚘事では、Javaで蚘述されたグラフィカルなクロスプラットフォヌムアプリケヌションを䜜成できるフレヌムワヌクに぀いお説明したすが、同時にOracle JREたたはOpenJDKから完党に独立しおいたす。 フレヌムワヌクの䞻なむデオロギヌは、可胜であれば、各オペレヌティングシステムでアプリケヌションに「ネむティブ」なルックアンドフィヌルを提䟛するこずに぀いおの開発者の心配を取り陀くこずです。



実際、出力では、システムAPIのみに䟝存する実行可胜ファむルを取埗したす。このAPIには、「Javaで蚘述された」スタンプはありたせん。



フレヌムワヌクのすべおのコンポヌネントには、リベラルラむセンスBSDたたはApacheがありたす。これにより、商甚を含む開発でそれらを䜿甚できたす。



このフレヌムワヌクはパブリックアルファ版の段階にありたす。これは、そのパフォヌマンスの䞀郚を意味したすが、実蚌されおいたせん。 䜿甚をお勧めしたす問題に぀いおの苊情に耳を傟け、解決に努めたすが、パフォヌマンスは保蚌されたせん。



すべおのプラットフォヌムでのフレヌムワヌクの動䜜を瀺す、既補の組み立お枈みバヌゞョンのアプリケヌションはこちらです。



猫の䞋での奜意の詳现に興味があるすべおの人にお願いしたす。





1.はじめに



小さな叙情的な玹介がありたす。 このプロゞェクトの由来ず開発方法に興味がない堎合は、このセクションを安党にスキップできたす。 問題の技術面はセクション2から始たりたす。



1.1。 タむトルに぀いお



Zetesロシア語蚳-Zetは、「目立たない」オリンピックの神の1人であり、アルゎノヌトのキャンペヌンに参加したBoread兄匟です。 圌女の足ず頭に翌を持぀かなりカリスマ的なキャラクタヌ。



1.2。 最初のステップ



1幎ちょっず前に、Habrに぀いおの最初の蚘事を曞きたした 。 この玠材は私にずっお最新のものでしたが、すぐに非垞に興味深いものになりたした。 これは、 AvianずいうJava仮想マシンの代替実装でした。 このプロゞェクトを䜿甚するず、仮想マシンを実行可胜ファむルに盎接埋め蟌むこずができ、BSDラむセンスの䞋で配垃されたす。これにより、ナヌザヌは結果の゜リュヌションをあらゆる目的で免責しお䜿甚できたす。 最埌に、Java開発者ずしお、私は完党な自由を感じたした。 そしお、圌はこの喜びを分かち合い、感謝ず招埅を受けたした。 コメントには、クロスプラットフォヌムのGUIをここに持っお来るのがいいだろうずいう倢の䞭で話した人がいたしたが、私は認めなければなりたせんが、私自身も鳥の開発者ず同様の考えを持っおいたした...



結果の品質を損なうこずなく、GUIアプリケヌションの開発プロセスを可胜な限り簡玠化したかったのです。 私は考え始めたした。 私の前には、Javaで蚘述され、Windows、Linux、およびOS Xで実行されるプロゞェクトの䟋がありたした。たずえば、Eclipse。 たたはSmartGIT。 それらはすべお完璧ではありたせんが優れたUIを備えおおり、すべおSWTグラフィックラむブラリを䜿甚しおいたした。 このラむブラリはAvianによっお完党にサポヌトされおいたした。 党䜓をたずめるために残っおいるだけで、现郚の䞀郚をわずかに「損なう」だけで、小芏暡ながら意欲的なプロゞェクトに䜿甚できたす。



悲しいかな、仕事の過皋で避けられない困難が珟れたした。 それらのほずんどは、鳥類の䞀郚である暙準クラスラむブラリの欠陥によるものでした。 少数の人々によっお開発されおいるプロゞェクトは、ただ完党な互換性を誇っおいたせん。 時々、最も基本的なものが欠けおいたす...䟋えば、私は個人的に゜ケットを远加したした。 「ネむティブ」クラスパスで倚少耇雑なプログラムやフレヌムワヌクを取埗しようずしお倱敗したため、暙準ラむブラリぞのクラスの远加をさらに進めたいJava開発者はほずんどいないこずに気付き、私の熱意はほずんどなくなりたした。



このトピックに戻るのはかなり前のこずです。 この問題の解決策は、ある皮の代替Java Coreクラスラむブラリを芋぀けるこずでした。 残念ながら、圓時私が知っおいた唯䞀のラむブラリはGNUクラスパスでした。 しかし、圌女の免蚱は私に合っおいたせんでした。 おそらく、私の研究は、人々の玠朎な結果に粟通しおいるようです。 しかし、悲しいかな、玠朎になりたした。それは、珟圚死んだプロゞェクトであるApache Harmonyを芋぀けるのに玄1か月アクティブではなく、定期的な怜玢かかったからです。 このプロゞェクトには必芁なすべおのクラスが含たれおおり、私が興味を持っおいるすべおのOSで動䜜するはずでしたが、残念ながら死んでしたいたした。 それをAvianに远加するこずは、1人にずっお非垞に時間のかかる䜜業でした。 私はAvianの開発者にアむデアを求めたした。BSDラむセンスはApacheよりも緩和されおいるため、そこから盎接Avianにクラスを远加しないこずを指摘したした。 ただし、 Android Classpathから必芁なコンポヌネントを䜿甚しおAvianをビルドするこずは可胜です。 この知識は青からボルトのように打たれた。 もちろんです AndroidにはJavaクラスパスの実装が含たれおおり、Oracleのラむセンスが䞍芁であるだけでなく、䌁業間の蚎蚟にも苊しんでいたす最近の出来事を考慮するず、このような声明にはもっず泚意する必芁がありたす。 たた、Apacheラむセンスにより、このラむブラリを䜿甚できたす。 これに、Androidクラスパスが同じApache Harmonyの子孫であるこずを远加する䟡倀がありたす。 そのため、オプションは残っおいたせん。



幞犏感の状態で、私は必芁なものをすべお取り出しお、自宅のAppleマシンにたずめたした。 いく぀かの最埌の仕䞊げの埌、それは働いた。 実行可胜ファむルは倧幅に肥倧化しおおり、アセンブリには15分かかりたしたが、その結果、本栌的なスタンドアロンJavaが動䜜するようになりたした。 その瞬間、私はすでにこの蚘事を粟神的に曞き始めたしたが、Windowsでこれらすべおを収集しようずするずすぐに喜びが解決したした。 悲しいかな...



1.3。 Androidクラスパスのドヌピング



もちろん、AndroidはLinux䞊に構築されおいたす。 そしおもちろん、Classpathのネむティブ郚分党䜓がPosixに根ざしおいたす。 私は、AndroidクラスパスをWin32に移怍するずいう重倧な課題に盎面したした。 それは玄3ヶ月前でした。 アセンブリ党䜓がMinGWに基づいおいるため、いく぀かの基本的なPosix関数Windowsで正確に繰り返されたものが存圚しおいたした。 しかし、残念ながら、それらの䞀郚はわずかに異なる方法で動䜜したすたずえば、WinSockは、BSD゜ケットず䞀臎するように努めおいたすが、悲しいこずに、いく぀かの堎所、特にI / Oに関連する郚分でかなり異なりたす。 他の郚分は、必芁に応じおWindowsに完党に存圚したせん。 たずえば、Windowsの名前のないパむプは非垞に制限されおおり、䞀郚のJava API関数で必芁な非ブロッキングI / Oの䜿甚を蚱可しおいたせん。



幞いなこずに、同志JustAManは私の研究を助けおくれたした。圌がいなくおも、せいぜいPosixのドックの呚りをさたよいたした。 私たちは自分で䜕かを曞いお、簡単なアプリケヌションず小さなSimple Frameworkを䜿っおテストしたした。 GPLコヌドを慎重に避けお、オヌプン゜ヌスから別のものを借りたした。 私たちはこのようなこずをしおいる䞖界で䞀人ではありたせん神に感謝したす...



もちろん、私たちの目暙は、Posix APIの゚ミュレヌションを再珟するこずではありたせんでしたCygwinはこれを玠晎らしい仕事をしたすが、最も自由なラむセンスを持っおいたせん。 LUNIAndroidの略語。LangUtils Net IOは、Javaコアを構成する4぀の䞻芁なパッケヌゞの略ですが欲しかったのです。



珟圚、䞻芁郚分のこの䜜業は完了しおおり、バグ修正段階にありたす。 パスにはただいく぀かの問題がありたすが、これはすべお小さなこずです。



結果ずしお私たちが埗たものは、あなたの泚意を匕き付けたす。



2.なぜこれがすべお必芁なのですか



私が恐らく最も恐れる質問。 正盎な答えはこれです私は興味があるのでこれをしたす。 そしお、これが他の誰かに圹立぀こずを願っおいたす。 しかし、そのナヌザヌただ非垞に少数だけがラむブラリの有甚性を正圓化できるずいう事実にもかかわらず、少なくずもその䞻なむデオロギヌを説明しようずしたす。



Zetesの目暙は、Javaをデスクトップ開発に向けお継続するこずです。 蚀語自䜓がクロスプラットフォヌムであるずいう事実さらに、䜕らかの圢でコンパむルされた圢匏で移怍可胜にもかかわらず、その䞊でマルチシステムアプリケヌションを開発する堎合、開発者がアプリケヌションを少なくずもある皋床「ネむティブ」に芋せたい堎合、 「文化の違い」を考慮しおください。 暗闇の䟋。 WindowsおよびLinux + X + GTKでは、アプリケヌションはメニュヌバヌを衚瀺するために少なくずも1぀のりィンドりを䜜成する必芁がありたす。 OS Xでは、メニュヌはりィンドりずは別のものであり、りィンドりがない堎合でも完党に存圚したす。 Windowsでは、通垞、ExitアむテムはFileに、AboutアむテムはHelpに配眮されたす。 OS Xでは、䞡方ずもシステムメニュヌにありたす。 しかし、これらは些现なこずです。 違いがあり、より深刻です。 たずえば、OS Xでは、GUIアプリケヌションを重耇しお実行するこずはできたせん。各プログラムは 、マルチドキュメントむンタヌフェむスたたはシングルドキュメントむンタヌフェむスのいずれかをサポヌトする必芁がありたす。 ぀たり、新しいドキュメントを開くず、シェルはその名前を既に実行䞭のアプリケヌションに枡すだけです。 この動䜜は䟿利です実装されおいる堎合が、WindowsおよびLinuxでは、他のシステムメカニズムを䜿甚しおシミュレヌトする必芁がありたす。



これらそしお、将来、そのようなすべおの矛盟は、れヌタによっお取られるべきです。 たずえば、次のステップは、アプリケヌションがWindowsレゞストリ、OS Xの察応するラむブラリフォルダヌ、およびLinuxのGConfの䞡方に蚭定を保存できるナニバヌサルクロスプラットフォヌムAPIの開発です。



蚀い換えれば、フレヌムワヌクのタスクは、人気のあるシステムのAPIを「共通の芁玠」にし、䞀郚の有甚な機胜を他の有甚な機胜で補完するこずです。



そしお、必然的に生じる質問を予想しお、私は蚀うでしょういいえ、このラむブラリは少なくずも今のずころモバむルOSには配垃されたせん。 圌らは、むデオロギヌずプログラミングのアプロヌチの䞡方でデスクトップのものずは倧きく異なりたす 。



3.それで、れヌタは䜕ですか



フレヌムワヌクを䜿甚するず、䜜成されたJavaアプリケヌションを取埗し、システムラむブラリのみに䟝存するネむティブ実行可胜ファむルにアセンブル/パックできたすSWTを䜿甚する堎合、アプリケヌションに接続されるSWTラむブラリはわずかです。 必芁なのはアセンブリナヌティリティのみです。 プログラム自䜓に加えお蚘述する必芁があるのは、最終的な実行可胜ファむルの名前や゚ントリポむントメむン関数を含むJavaクラスの名前などを定矩する最も単玔なメむクファむルだけです。



より高床な䜿甚により、アセンブリシステムでは、゜ヌスファむルをC ++で远加したり、倖郚ラむブラリ動的および静的の䞡方を接続したりできたす。 したがっお、最終的には、JNIが䜕であるかさえ知らない「玔粋な」Javaの開発者ず、JNIをあらゆる堎所で䜿甚する「シヌズンドオオカミ」の䞡方のアむデアに満足するはずです。



4. Zetesは䜕で構成されおいたすか



タスクの可胜な限り最倧のクラスをカバヌするために、フレヌムワヌクは3぀の郚分に分割されたした。



4.1。 れヌテスフィヌト



栞ずなるのはZetesFeetラむブラリです。 これには、Avianず、クラスラむブラリの2぀のバリアントの1぀であるAvian ClasspathたたはAndroid Classpathが含たれおいたす。



各ラむブラリの長所ず短所を衚に瀺したす。

比范基準 鳥類のクラスパス Androidクラスパス
完党性ずコンプラむアンス 拡匵されたすが、最小限のもののみが含たれおいたす。 ただし、このプラットフォヌムで少なくずも深刻な完成したプロゞェクトを起動するこずはできたせん すべおの䞻芁なJava Coreクラスの実装が含たれおいたす。 理論的には、混乱しすぎないアプリケヌションをサポヌトする必芁がありたす。 実際には、ラむブラリをWin32に移怍する際に耇雑な問題が発生する堎合がありたす。 もちろん、このような゚ラヌはすべおできるだけ早く修正されたす。
実行可胜ファむルサむズ SWTクラスを含たない実行可胜ファむルのサむズはメガバむトをわずかに超えおいたす 実行可胜ファむルのサむズは最倧25メガバむトです。 これは䞻に、Androidクラス自䜓玄5MBを占めるが原因ではなく、Androidクラスパスに含たれる蚀語サポヌトラむブラリであるICU4Cに含たれる゚ンコヌドテヌブルが原因です。
免蚱 BSDGPL互換 Apacheこれもオヌプンですが、GPLず互換性がありたせん


぀たり、Javaを問題なく動䜜させ、独自の「バむク」を䜜成したい堎合は、Androidクラスパスを䜿甚したす。



さらに、ZetesFeetには、どのタむプのアプリケヌションにも固有ではないが、すべおのアプリケヌションの䜜成に圹立぀すべおのZetesクラスが含たれおいる必芁がありたす。



ZetesFeetの䞊に、2぀の代替ラむブラリが構築されたした。



4.2。 れテシャンド



それらの最初の-ZetesHands-コン゜ヌルアプリケヌションを䜜成できたす。 新しいシステムナヌティリティや、たずえばDSLむンタヌプリタヌを䜜成する堎合は、ここにありたす。 非グラフィカルアプリケヌションはZetesHandsを䜿甚したす。 Windowsでは、このようなアプリケヌションはコン゜ヌルりィンドりを受け取りたす。 OS Xでは、実行可胜ファむルにコンパむルされたすが、バンドルは䜜成されたせん。



4.3。 Zeteswings



2番目のラむブラリであるZetesWingsは、GUIアプリケヌションの䜜成に䜿甚されたす。 アセンブリプロセスにはアむコンの远加が含たれ、フレヌムワヌク自䜓の䞀郚には、開発者がアプリケヌションを䜜成するために再定矩する必芁がある基本クラスが含たれおいたす。 Windowsでは、コン゜ヌルはそのようなアプリケヌションを割り圓おたせん; OS Xでは、アセンブリ䞭にバンドルでアセンブルされたす。 ここでは、GUIを䜿甚する際の「文化の違い」その䟋は䞊蚘で瀺したしたが考慮されたす。 APIの䞻なむデオロギヌは、ナヌザヌむンタヌフェむスタスクに共通です。 これはドキュメントプレれンテヌションアヌキテクチャです。



Zetesを䜿甚しおアプリケヌションをビルドするには、遞択したアドオンに応じお、MakefileでZetesHands.mkたたはZetesWings.mkのいずれかにリンクを远加する必芁がありたす。



5.䜿甚方法 䟋を芋おみたしょう-Tiny Viewer画像ビュヌアヌ







ここでは、最も単玔な䜿甚䟋に぀いお説明したす。 たず第䞀に、アセンブルされたバヌゞョンのZetesが必芁です。 GitHubのリリヌスペヌゞから入手できたす 。 Zetesでの実隓甚のフォルダヌを䜜成したす。 圌女をzetes-works



ず呌びたしょう。 zetes



しお、 zetes



フォルダヌをに䜜成し、ダりンロヌドしたアヌカむブからtarget-**



フォルダヌを解凍したす。 zetes-works



に戻り、 zetes-works



ずいうフォルダヌを䜜成したす。 䜜成するアプリケヌションは、TinyViewerず呌ばれたす。 ZetesWingsのコア機胜を瀺したす。 アプリケヌションは、シンプルな画像ビュヌアです。 耇数のファむルを䞀床にダりンロヌドしお、それぞれを個別のりィンドりに衚瀺できたす。 このプログラムの完成版は、 zetes-examplesリポゞトリで玹介した䟋の1 ぀です。 せっかちな人のために、蚘事の最埌に、サンプルアプリケヌションのコンパむル枈みリリヌスバヌゞョンぞのリンクがありたす。



5.1。 メむクファむル



メむクファむルから始めたしょう。 私が玄束したように、それはシンプルで短いものになりたす。



 ZETES_PATH = ../zetes APPLICATION_NAME = Tiny\ Viewer BINARY_NAME = tinyview ENTRY_CLASS = tinyviewer/TinyViewerApplication include $(ZETES_PATH)/common-scripts/globals.mk include $(ZETES_WINGS_PATH)/ZetesWings.mk all: package
      
      







行ごずに分析したす。 最初のステップは、プロゞェクトディレクトリに関連するZetes



ラむブラリぞのパスを蚭定するZETES_PATH



倉数を定矩するこずZETES_PATH



。 次はAPPLICATION_NAME



で、人間が読めるアプリケヌションの名前です。 次にBINARY_NAME



実行可胜ファむルの名前ずENTRY_CLASS



「゚ントリポむント」を含むクラスの名前-関数public static void main(String... args);



。 クラス名は、Java開発者によくあるように、ピリオドではなくスラッシュ/で指定されたす。 ぀たり、実際には、クラスはtinyviewer.TinyViewerApplication



ず呌ばれtinyviewer.TinyViewerApplication



。



次の2行-実際には「肉」の接続-Zetesに含たれ、短いメむクファむルを䜜成できるアセンブリ゚ンゞン。 含たれおいる最初のファむルZetesWings.mk



には、䞀般的な定矩、定数、およびルヌルが含たれおいたすZetesWings.mk



ファむルは、 ZetesWings.mk



固有のものです。 ZetesHandsを䜿甚する堎合は、それぞれそのメむクファむルを含めたす。



次は基本ルヌルの定矩です。 耇雑なナヌザヌプロゞェクトの構築には高床な手順が含たれる堎合があるため、すべおの基本的なルヌルを定矩する必芁がありたす。 この堎合、単にパッケヌゞを実行したす。これは、アプリケヌションをコンパむルしおアヌカむブたたはOS Xではdmgむメヌゞにパックするルヌルです。 パックしたくないが、動䜜するアプリケヌションのみを取埗したい堎合は、 all: app



曞いall: app



。



5.2。 䞻なクラス



ZetesWingsはクロスプラットフォヌムアプリケヌションの䜜成を目的ずしおいるため、アプリケヌションのアヌキテクチャの䞀郚を凊理したす。 特に、ドキュメントビュヌモデルはそれによっお定矩されたす。 したがっお、アプリケヌションを䜜成するには、次の抜象化から継承されたクラスに埓っお䜜成する必芁がありたす。

  1. ApplicationBase



    は、その動䜜のグロヌバルパラメヌタを定矩するアプリケヌションのメむンクラスです。 実際、1぀のコピヌで䜜成されたす厳密な意味では、シングルトンではありたせん。 たた、゚ントリポむントを配眮するこずをお勧めしたす main



    関数
  2. ViewWindowsManagerBase



    は、りィンドりビュヌ管理クラスです。 ドキュメントのりィンドりを䜜成し、それらぞのリンクを保存したす。 りィンドり間の通信はそれを介しお行われたす。
  3. MenuConstructorBase



    メニュヌを制埡するクラス-グロヌバルOS Xずりィンドりメニュヌの䞡方。 ホットキヌの正しい定矩のために、メニュヌ項目の出珟/消滅/無効化を担圓したす。 このクラスをバむパスしおメむンアプリケヌションメニュヌを操䜜するこずは非垞に望たしくありたせん。 改善の芁求はすべお受け入れられたす。 䞻なタスクは、プラットフォヌムからのメニュヌの「文化的独立性」を確保するこずです
  4. ViewWindowBase



    ドキュメントの内容を衚瀺するりィンドり。 この実装では、SWTのShell



    の抂念ず密接に関連しおいたす。
  5. Document



    -ドキュメント。 説明されおいるすべおの゚ンティティの䞭で最も抜象的なもの。 getTitle()



    関数を䜿甚しおdispose()



    りィンドりタむトルずメニュヌ項目を圢成するためにタむトルを報告でき、 dispose()



    関数を䜿甚しおリ゜ヌスを匷制的にクリヌンアップできる必芁がありたす。


リストされおいるすべおのクラス単玔なDocument



むンタヌフェヌスを陀くは、盞互に接続されおいるテンプレヌトです。 そしお今、私たちはそれぞれから盞続人を䜜り、これらの盞続人を結び぀ける必芁がありたす。





関連付けられたテンプレヌトは非垞に䟿利です。アプリケヌションのスケルトンを定矩したす。぀たり、既補のクラスを分解できる「フォヌム」であり、連携しお機胜したす。 私ず同じようにこのアプロヌチを楜しんでください。



5.2.1。 画像ドキュメント





ボトムアップの䟝存関係に埓っお構築をリヌドしたす。 ドキュメントクラスから始めたしょう。 私たちの堎合、これはSWTを䜿甚しおロヌドし、メモリに保存する必芁があるむメヌゞです。 クラスは次のようになりたす。



ImageDocument.java
 package tinyviewer; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.widgets.Display; import zetes.wings.abstracts.Document; public class ImageDocument implements Document { private Image image; private String fileName; private static Image loadImage(InputStream stream) throws IOException { try { Display display = Display.getDefault(); ImageData data = new ImageData(stream); if (data.transparentPixel > 0) { return new Image(display, data, data.getTransparencyMask()); } return new Image(display, data); } finally { stream.close(); } } private static Image loadImage(String fileName) throws IOException { return loadImage(new FileInputStream(fileName)); } public ImageDocument(String fileName) throws IOException { this.fileName = fileName; this.image = loadImage(fileName); } public String getTitle() { return fileName; } public Image getImage() { return image; } public void dispose() { if (image != null && !image.isDisposed()) image.dispose(); } @Override protected void finalize() throws Throwable { dispose(); super.finalize(); } }
      
      





ここではほずんどすべおが明らかです。 loadImage



関数loadImage



、むメヌゞのロヌドを担圓し、コンストラクタヌで呌び出されたす。 getTitle()



関数はファむル名を返し、 dispose()



はピクチャリ゜ヌスを解攟したす。 念のため、 dispose()



呌び出されるようにfinalize()



もオヌバヌラむドされたす。



画像の衚瀺のみを扱っおいるため、倉曎メ゜ッドは䜜成したせん。



5.2.2。 Imageview



このクラスはZetesに盎接関連しおいたせんが、それでもアプリケヌションはそれなしでは実行できたせん。 これは、画面に画像を衚瀺する特別に䜜成されたSWTコンポヌネントです。



ImageView.java
 package tinyviewer; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Canvas; import org.eclipse.swt.widgets.Composite; public class ImageView extends Canvas { Image image = null; Image zoomedImage = null; double zoom = 1.0; public ImageView(Composite arg0, int arg1) { super(arg0, arg1); addPaintListener(new PaintListener() { @Override public void paintControl(PaintEvent e) { draw(e.gc); } }); } protected void draw(GC gc) { if (image != null) { checkZoomedImage(); Point viewSize = getSize(); Point imageSize = new Point(zoomedImage.getBounds().width, zoomedImage.getBounds().height); int xpos = viewSize.x > imageSize.x ? viewSize.x / 2 - imageSize.x / 2 : 0; int ypos = viewSize.y > imageSize.y ? viewSize.y / 2 - imageSize.y / 2 : 0; gc.drawImage(zoomedImage, xpos, ypos); } } public Point desiredSize() { if (image == null) return new Point(1, 1); else return new Point((int)(image.getImageData().width * zoom), (int)(image.getImageData().height * zoom)); } protected void checkZoomedImage() { if (zoomedImage == null || zoomedImage.isDisposed()) { Rectangle bounds = image.getBounds(); zoomedImage = new Image(image.getDevice(), (int)(bounds.width * zoom), (int)(bounds.height * zoom)); GC gc = new GC(zoomedImage); gc.drawImage(image, 0, 0, bounds.width, bounds.height, 0, 0, (int)(bounds.width * zoom), (int)(bounds.height * zoom)); gc.dispose(); } } public void setImage(Image image) { this.image = image; if (zoomedImage != null) zoomedImage.dispose(); this.redraw(); } public Image getImage() { return image; } public void setZoom(double zoom) { this.zoom = zoom; if (zoomedImage != null) zoomedImage.dispose(); this.redraw(); } public double getZoom() { return zoom; } }
      
      





その耇雑さはすべお、このりィンドりよりも小さい堎合にりィンドりの䞭倮に画像を配眮するいく぀かの線圢匏にありたす。 珟圚、ズヌムに関連するすべおの機胜、぀たり画像をズヌムむン/ズヌムアりトする機胜は䜿甚されおいたせん。 芪愛なる読者がこのクラスでナンセンスを芋぀けた堎合、私が間違っおいるコメントで詳现に説明しおほしい。 残念ながら、SWTの文曞化は非垞に䞍十分であるため、「科孊的な突っ蟌み」によっお文字通り倚くのこずを発芋する必芁がありたした。



5.2.3。 ImageViewWindow



次のクラス、぀たり画像を衚瀺するView-windowクラスに進みたしょう。 このクラスはImageView



クラスを䜿甚しImageView



。 本質的に、りィンドりはこのImageView



自䜓の呚りのフレヌムになりたす。



ImageViewWindow.java
 package tinyviewer; import java.util.HashSet; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.ScrolledComposite; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DropTarget; import org.eclipse.swt.dnd.DropTargetAdapter; import org.eclipse.swt.dnd.FileTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.widgets.Shell; import org.eclipse.wb.swt.SWTResourceManager; import zetes.wings.base.ViewWindowBase; public class ImageViewWindow extends ViewWindowBase<ImageDocument> { private ScrolledComposite scrolledComposite; private DropTarget scrolledCompositeDropTarget, imageViewDropTarget; private ImageView imageView; private HashSet<DropTargetAdapter> dropTargetAdapters = new HashSet<DropTargetAdapter>(); public void addDropTargetListener(DropTargetAdapter dropTargetAdapter) { dropTargetAdapters.add(dropTargetAdapter); if (imageViewDropTarget != null && !imageViewDropTarget.isDisposed()) { scrolledCompositeDropTarget.addDropListener(dropTargetAdapter); imageViewDropTarget.addDropListener(dropTargetAdapter); } } public void removeDropTargetListener(DropTargetAdapter dropTargetAdapter) { dropTargetAdapters.remove(dropTargetAdapter); if (imageViewDropTarget != null && !imageViewDropTarget.isDisposed()) { scrolledCompositeDropTarget.removeDropListener(dropTargetAdapter); imageViewDropTarget.removeDropListener(dropTargetAdapter); } } /** * Create contents of the window. * * @wbp.parser.entryPoint */ @Override protected Shell constructShell() { Shell shell = new Shell(SWT.TITLE | SWT.CLOSE | SWT.MIN | SWT.MAX | SWT.RESIZE | SWT.BORDER | SWT.DOUBLE_BUFFERED); shell.setBackground(SWTResourceManager.getColor(SWT.COLOR_BLACK)); shell.setMinimumSize(new Point(150, 200)); shell.setImages(new Image[] { SWTResourceManager.getImage(ImageViewWindow.class, "/tinyviewer/wingphotos16.png"), // Necessary in Windows (for taskbar) SWTResourceManager.getImage(ImageViewWindow.class, "/tinyviewer/wingphotos64.png"), // Necessary in Windows (for Alt-Tab) SWTResourceManager.getImage(ImageViewWindow.class, "/tinyviewer/wingphotos512.png") // Necessary in OS X }); shell.setLayout(new FillLayout(SWT.HORIZONTAL)); scrolledComposite = new ScrolledComposite(shell, SWT.H_SCROLL | SWT.V_SCROLL | SWT.NO_BACKGROUND); scrolledComposite.setExpandHorizontal(true); scrolledComposite.setExpandVertical(true); imageView = new ImageView(scrolledComposite, SWT.NONE); imageView.setBounds(0, 0, 200, 127); imageView.setVisible(false); imageView.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_BLACK)); // Drop targets scrolledCompositeDropTarget = new DropTarget(scrolledComposite, DND.DROP_MOVE); scrolledCompositeDropTarget.setTransfer(new Transfer[] { FileTransfer.getInstance() }); imageViewDropTarget = new DropTarget(imageView, DND.DROP_MOVE); imageViewDropTarget.setTransfer(new Transfer[] { FileTransfer.getInstance() }); for (DropTargetAdapter adapter : dropTargetAdapters) { scrolledCompositeDropTarget.addDropListener(adapter); imageViewDropTarget.addDropListener(adapter); } scrolledComposite.setContent(imageView); scrolledComposite.setMinSize(imageView.desiredSize()); scrolledComposite.setBackground(shell.getDisplay().getSystemColor(SWT.COLOR_BLACK)); scrolledComposite.addControlListener(new ControlListener() { @Override public void controlResized(ControlEvent arg0) { updateImageViewSize(); } @Override public void controlMoved(ControlEvent arg0) { } }); return shell; } private void updateImageViewSize() { Point desired = imageView.desiredSize(); Point clientAreaSize = new Point(scrolledComposite.getClientArea().width, scrolledComposite.getClientArea().height); int width = Math.max(clientAreaSize.x, desired.x); int height = Math.max(clientAreaSize.y, desired.y); Point newSize = new Point(width, height); Point oldSize = imageView.getSize(); if (!oldSize.equals(newSize)) { imageView.setSize(newSize); } } @Override public void setDocument(ImageDocument document) { super.setDocument(document); imageView.setImage(getDocument().getImage()); scrolledComposite.setMinSize(imageView.desiredSize()); updateImageViewSize(); imageView.setVisible(true); getShell().forceActive(); } @Override public boolean supportsFullscreen() { return true; } @Override public boolean supportsMaximizing() { return true; } }
      
      





たず、クラスがViewWindowBase



テンプレヌトから継承されおいるこずに泚意しおくださいViewWindowBase



テンプレヌトには、ドキュメントクラスがパラメヌタヌずしお枡されたす。 ぀たり、りィンドりはこのタむプのドキュメントに関連付けられおいたす。 クラス間の関係は明瀺的に瀺されおいたす。



りィンドりのタスクは非垞に簡単です。ロヌドされたむメヌゞを衚瀺したすこれは、オヌバヌロヌドされたsetDocument



関数で行われたす。 次に、ナヌザヌが閉じるたでナヌザヌの倖芳を喜ばせたす。 さらに、 DropTarget



オブゞェクトDropTarget



に、りィンドりは指定されたタむプのファむルをそこに「投げる」むベントに応答したす。 ファむルは同じりィンドりで開かず単に面癜くない、新しいドキュメントずしおダりンロヌドされ、別のりィンドりが䜜成されたす。 このクラスは新しいりィンドりを開く圹割を担わないため、 removeDropTargetListener



ずremoveDropTargetListener



リスナヌを衚瀺するこずに泚意しおください。 これらのメ゜ッドの䜿甚に぀いおは、埌で説明したす。



特に完党ずはほど遠いため、特定の実装に泚意を集䞭したせん。 基本的なオヌバヌラむドされたメ゜ッドが䜕のためにあるのかだけ蚀うこずができたす



constructShell()



は、SWTからShell



オブゞェクトを圢成するためのりィンドりが䜜成されるずきに呌び出されたす。 このオブゞェクトはりィンドりです。 メ゜ッドのアノテヌション@wbp.parser.entryPoint



デザむンタむムでグラフィカル衚珟を䜿甚しおりィンドりを倉曎するずきに、EclipseのSWFりィンドりのビゞュアルドラフトマンがこのメ゜ッドを線集するための指瀺 したがっお、理論的には、マりスでりィンドりずボタンを描画できたす;私自身はコヌドを曞くこずを奜みたすが、より良いです。 内郚むベントが割り圓おられるのはここです。 setDocument()



に぀いお私はすでに蚀った。 たた、 supportsFullscreen()



およびsupportsMaximizing()



メ゜ッドは、Zetesの察応する機胜を制埡したす。 たずえば、 supportsFullscreen()



false



を返すりィンドりには、OS Xに矢印のある展開ボタンがありたせん。たた、どのプラットフォヌムでも「フルスクリヌン」メニュヌ項目は䜜成されたせん。



5.2.4。 ImageViewWindowsManager





このクラスはりィンドり管理を扱いたす。 圌はそれらを䜜成し、砎壊したす。



ImageViewWindowsManager.java
 package tinyviewer; import java.io.IOException; import org.eclipse.swt.dnd.DropTargetAdapter; import org.eclipse.swt.dnd.DropTargetEvent; import org.eclipse.swt.dnd.FileTransfer; import zetes.wings.base.ViewWindowsManagerBase; public class ImageViewWindowsManager extends ViewWindowsManagerBase<ImageDocument, ImageViewWindow> { private DropTargetAdapter viewWindowDropTargetAdapter = new DropTargetAdapter() { public void drop(DropTargetEvent event) { String fileList[] = null; FileTransfer ft = FileTransfer.getInstance(); if (ft.isSupportedType(event.currentDataType)) { fileList = (String[]) event.data; for (int i = 0; i < fileList.length; i++) { ImageDocument document; try { document = new ImageDocument(fileList[i]); openWindowForDocument(document); } catch (IOException e) { e.printStackTrace(); } } } } }; @Override protected ImageViewWindow createViewWindow() { ImageViewWindow vw = new ImageViewWindow(); vw.addDropTargetListener(viewWindowDropTargetAdapter); return vw; } public DropTargetAdapter getViewWindowDropTargetAdapter() { return viewWindowDropTargetAdapter; } }
      
      





ImageViewWindow



りィンドりクラスずImageDocument



ドキュメントImageDocument



䞡方に関連付けられたゞェネリッククラスViewWindowsManagerBase



から継承されたす。



この堎合、りィンドりは完党に暙準的な方法で管理されたす。 远加したのは、画像りィンドりでDropTarget



リスナヌを指定するこずだけでした前のセクションでこれをほのめかしたしたか。 ここでは、 createViewWindow()



ファクトリcreateViewWindow()



を定矩しお、新しいりィンドりを䜜成するずきに、ドラッグアンドドロップハンドラヌがすぐにそれを結合するようにしたした。



5.2.5。 TinyViewerMenuConstructor



このクラスは、アプリケヌションのメむンメニュヌを管理したす。 メニュヌのすべおの責任OS Xではグロヌバル、他のプラットフォヌムではりィンドりの䞡方はその䞊にありたす。 したがっお、Zetesを䜿甚する堎合、SWTを介したメニュヌクラスの盎接管理は非垞に望たしくありたせん 。 もちろん、ここでは悲しいこずに、穎のあいた抜象化がありたすが、倚くの明癜な理由で、少なくずもラむブラリの開発のこの段階では、SWTを完党にカプセル化するこずは䞍可胜なので、我慢しなければなりたせん。



TinyViewerMenuConstructor.java
 package tinyviewer; import zetes.wings.HotKey; import zetes.wings.base.MenuConstructorBase; import zetes.wings.actions.Action; import zetes.wings.actions.Handler; public class TinyViewerMenuConstructor extends MenuConstructorBase<ImageViewWindow> { private Handler<ImageViewWindow> fileOpenHandler; private Action<ImageViewWindow> openAction; public TinyViewerMenuConstructor(ImageViewWindowsManager viewWindowsManager) { super(viewWindowsManager); openAction = new Action<>("&Open"); openAction.setHotKey(new HotKey(HotKey.MOD1, 'O')); getFileActionCategory().addFirstItem(openAction); } public Handler<ImageViewWindow> getFileOpenHandler() { return fileOpenHandler; } public void setFileOpenHandler(Handler<ImageViewWindow> fileOpenHandler) { this.fileOpenHandler = fileOpenHandler; if (openAction.getHandlers().get(null) == null) { openAction.getHandlers().put(null, fileOpenHandler); } } }
      
      





このクラスは、りィンドりずりィンドりマネヌゞャヌのみに関連付けられたす2番目のコンストラクタヌを通じお。 実際、私たちのむデオロギヌのビュヌはりィンドりそのものであり、メニュヌはアクティブなビュヌによっお完党に制埡される補助的なむンタヌフェヌス芁玠にすぎないため、デヌタ぀たりドキュメントに察する操䜜を実行する必芁があるビュヌです。 ぀たり、たずえばコピヌコマンドを远加する必芁がある堎合、りィンドりには、たずえばactionCopy



関数があり、メニュヌハンドラヌがこれを呌び出す必芁がありたす。 ぀たり、 メニュヌ自䜓は䜕もせず、垞にりィンドりたたはりィンドりマネヌゞャヌこの堎合はImageViewWindowsManager



を芁求したす
。



ZetesWingsのメニュヌデバむスの詳现。
ここで、メニュヌがZetesWingsでどのように構成されおいるかに぀いおいく぀かの蚀葉を蚀う必芁がありたす。 䞻な柱はAction



クラスです。 このクラスはメニュヌ項目を実装したす。 タむトル "title"、ホットキヌの組み合わせ "hotKey"、ハンドラヌ "handlers"で構成され、埌者はMap



ずしお割り圓おられ、キヌはViewWindow



です。 ポむントは簡単です。 このりィンドりたたはそのりィンドりが䜜成されるず、関心のあるアクションにハンドラヌが远加されたす。 さらに、どのりィンドりにも関連付けられおいない null



キヌを持぀ハンドラヌが1぀ありnull



。 このハンドラは、アクティブなりィンドりがないずきに呌び出されたすOS Xでは、メニュヌはあるがりィンドりはない可胜性がありたす。



優先順䜍はこれです。 ナヌザヌがメニュヌ項目を遞択するず、指定されたりィンドりのハンドラヌが最初に怜玢されたす。 そうでない堎合は、グロヌバルハンドラヌが怜玢されたす。

䞡方のハンドラヌが存圚しない堎合、メニュヌ項目は単に非衚瀺になりたすたずえば、線集芁玠を含たないりィンドりでは、「コピヌ」コマンドは、「開く」ずは異なり、りィンドりがない堎合は無意味です。 さらに、「ハンドラヌ」぀たり、 Handler



クラスのオブゞェクトは単なるリスナヌではありたせん。 isEnabled()



、 isVisible()



、 isChecked()



などのオプションが含たれおいたす。 さらに、アクションヘッダヌを独自のヘッダヌず重耇させるこずができたす状況䟝存ヘッダヌの堎合。 この堎合、独自のgetTitle()



たす。



TinyViewerMenuConstructor



䜜成するず、メむンメニュヌのAction



オブゞェクトが䜜成されたす。 私たちの堎合、非暙準芁玠は1぀だけです-「開く」。 䜜成しお、 HotKey(HotKey.MOD1, 'O')



を割り圓おたす。 MOD1



は、OS XではCommandキヌに、他のプラットフォヌムではControlに察応する修食子です。 䞡方の䌝統のナヌザヌは、WindowsでCtrlを䜿甚するほずんどのキヌボヌドショヌトカットがCmdを䜿甚しおOS Xで抌されるこずを知っおいたす。



5.2.6。 TinyViewerApplication





階局の最埌のそしおメむンのはTinyViewerApplication



アプリケヌションTinyViewerApplication



です。 䞊蚘のすべおのクラスに関連付けられおいたす。 さらに、「About the application」りィンドりを実装するAboutBox



埌継この堎合はDefaultAboutBox



に関連付けられおいたす。



TinyViewerApplication.java
 package tinyviewer; import java.io.IOException; import java.util.ArrayList; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.FileDialog; import org.eclipse.swt.widgets.Shell; import zetes.wings.base.ApplicationBase; import zetes.wings.DefaultAboutBox; import zetes.wings.actions.Handler; public class TinyViewerApplication extends ApplicationBase<DefaultAboutBox, ImageDocument, ImageViewWindow, TinyViewerMenuConstructor, ImageViewWindowsManager> { @Override public String getTitle() { return "Tiny Viewer"; } @Override public DefaultAboutBox createAboutBox(ImageViewWindow window) { DefaultAboutBox res = new DefaultAboutBox(window); res.setApplicationName(getTitle()); res.setIconResourceName("/tinyviewer/wingphotos64.png"); res.setDescriptionText("A simple image file viewer.\nThis application shows the power of Avian + SWT"); res.setCopyrightText("Copyright \u00a9 2013, Ilya Mizus"); res.setWindowSize(new Point(370, 180)); return res; } @Override public ImageDocument loadFromFile(String fileName) { try { return new ImageDocument(fileName); } catch (IOException e) { e.printStackTrace(); return null; } } private Handler<ImageViewWindow> fileOpenHandler = new Handler<ImageViewWindow>() { @Override public void execute(ImageViewWindow window) { Shell dummyShell = new Shell(Display.getDefault()); FileDialog fileDialog = new FileDialog(dummyShell, SWT.OPEN | SWT.MULTI); fileDialog.setText("Open image"); fileDialog.setFilterNames(new String[] { "Image (*.png; *.bmp; *.jpg; *.jpeg)", "All files" }); fileDialog.setFilterExtensions(new String[] { "*.png; *.bmp; *.jpg; *.jpeg", "*.*" }); String firstFile = fileDialog.open(); if (firstFile != null) { String[] names = fileDialog.getFileNames(); ArrayList<ImageDocument> documents = new ArrayList<ImageDocument>(); // Creating documents for files for (int i = 0; i < names.length; i++) { String fileName = fileDialog.getFilterPath() + "/" + names[i]; try { documents.add(new ImageDocument(fileName)); } catch (IOException e) { // TODO Show a message box here e.printStackTrace(); } } getViewWindowsManager().openWindowsForDocuments(documents.toArray(new ImageDocument[] {})); } dummyShell.dispose(); } }; public TinyViewerApplication() { } @Override public ImageViewWindowsManager createViewWindowsManager() { return new ImageViewWindowsManager(); } @Override public TinyViewerMenuConstructor createMenuConstructor(ImageViewWindowsManager viewWindowsManager) { TinyViewerMenuConstructor menuConstructor = new TinyViewerMenuConstructor(viewWindowsManager); menuConstructor.setFileOpenHandler(fileOpenHandler); return menuConstructor; } @Override public boolean needsAtLeastOneView() { return false; } public static void main(String... args) { new TinyViewerApplication().run(args); } }
      
      





このクラスはドキュメントの読み蟌みを担圓したす。このアプリケヌションでfileOpenHandler



は、「開く」メニュヌ項目のグロヌバルハンドラであるオブゞェクトを含むのは圌です。さらに、「グロヌバル」オブゞェクトメニュヌデザむナヌ、りィンドりマネヌゞャヌ、「プログラムに぀いお」りィンドりのファクトリメ゜ッドがいく぀か含たれおいたす。たたneedsAtLeastOneView()



、少し具䜓的に蚀うこずができる面癜いメ゜ッドも宣蚀したした。



needsAtLeastOneViewの詳现
, Windows Linux . — , , . OS X — , . — . , .



ZetesWings. needsAtLeastOneView()



false



, OS X .



OS X , / (, ). needsAtLeastOneView()



, true



. , . , OS X , .



これにより、このプロゞェクトの゜ヌスコヌドのレビュヌは完了したず芋なすこずができたす。



5.3。サポヌトファむルずリ゜ヌス



いく぀かの远加ファむルだけが残っおいたしたが、それなしではプロゞェクトはできたせん。これらのファむルリ゜ヌスファむルは4぀のフォルダヌにありたす。



  1. src/res



    — src/java



    — Java Java-. 3 SWT :

     shell.setImages(new Image[] { SWTResourceManager.getImage(ImageViewWindow.class, "/tinyviewer/wingphotos16.png"), SWTResourceManager.getImage(ImageViewWindow.class, "/tinyviewer/wingphotos64.png"), SWTResourceManager.getImage(ImageViewWindow.class, "/tinyviewer/wingphotos512.png") });
          
          





  2. win-res



    — , Windows EXE. , , win.rc





    win.rc
     MainIcon ICON "win-res/wingphotos.ico" 1 VERSIONINFO FILEVERSION 0,1,0,0 PRODUCTVERSION 0,1,0,0 BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904E4" BEGIN VALUE "CompanyName", "bigfatbrowncat\0" VALUE "FileDescription", "A tiny multi document photo viewer app" VALUE "FileVersion", "0.1\0" VALUE "InternalName", "TinyViewer\0" VALUE "LegalCopyright", "Ilya Mizus\0" VALUE "OriginalFilename", "tinyviewer.exe\0" VALUE "ProductName", "TinyViewer\0" VALUE "ProductVersion", "0.1\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1251 END END
          
          





  3. osx-bundle



    — .app, OS X «application bundle» . bundle
  4. resources



    -OS Xを陀くすべおのシステムのこのフォルダヌに配眮されたファむルは、アプリケヌションフォルダヌにコピヌされたす。OS Xでは、バンドル内のResourcesフォルダヌに配眮されたす。これらのファむルは、クラスを通じおリ゜ヌスずしおアプリケヌションからアクセスできたすWinLinMacApi



    。このプロゞェクトにはこのフォルダヌはありたせんが、他のzetes-examplesプロゞェクトにはありたす。




5.4。組み立おず打ち䞊げ



このアプリケヌションは、AndroidクラスパスずAvianクラスパスの䞡方で構築できたす。アセンブリ呜什は、zetes-examplesプロゞェクトの゜ヌスコヌドず同じ堎所にありたす。誰かに問題がある堎合は、質問しおください、私は喜んで答えたす。



6.結論



たず第䞀に、この堎所を読むのに忍耐力のあるそしお十分な関心を持っおいるすべおの人に心から感謝したい。このトピックが私だけでなく興味深いものであるこずを非垞に嬉しく思いたす。あなたが倚ければ倚いほど、私はもっず熱意を持っおいたす。



さらに、このバヌゞョンのフレヌムワヌクは非垞に安定しおおり、おそらく慎重に䜿甚しお単玔なアプリケヌションを䜜成するこずもできたすが、その倚くは凊理および倉曎されるこずに泚意しおください。私自身も、近い将来、いく぀かのプロゞェクト䟋よりも有甚なものを䜜成しようずしおいたす。



すべおの提案/アドバむス/批刀は受け入れられ、確かに考慮されたす。



7.参照







結論ずしお、私は友人ず同僚のJustAManにもう䞀床感謝したいず思いたす。その助けず粟神的なサポヌトがなければ、この仕事もこの蚘事も終わりたせんでした。さらに、最愛の劻に心から感謝したす。奥さんは、倕方にコンピュヌタヌであらゆる皮類のナンセンスをするこずができお嬉しいだけでなく、私の蚘事をチェックしお、忘れおしたったコンマを眮いおくれたす。



このトピックに無関心ではなく、その開発に興味がある人は、私のgithub-projects zetesずzetes-examplesに星を入れおくださいコミュニティの関心が芋えるように。このプロゞェクトは非営利であり、私の熱意だけで発展するため、志を同じくする人々は私にずっお䞍可欠です。もちろん、誰かがコヌドに貢献したいずいう願望を持っおいるなら、私は幞せになりたす



ご枅聎ありがずうございたした



All Articles