私はSwingを使用してアプリケーションのGUIを作成していますが、コードの保守と読みやすさのために、システム全体で一貫したパターンに従いたいと考えています。
私が読んだほとんどの記事や本(または少なくとも本のセクション)は、さまざまなコンポーネントを作成および配置する方法について多くの例を提供しているように見えますが、完全なGUIを作成する全体像は無視してください。
アプリケーションのGUIを設計するための最良のヒントは何ですか。また、GUIアプリケーションを設計またはリファクタリングするときは、どのようなパターンに従いますか。
レイアウトマネージャーを使用します。今はハードコードされた位置ですべてを配置する方が簡単だと思うかもしれませんが(特にグラフィカルレイアウトツールを使用する場合)、GUIを更新したり、国際化したりすると、後継者はあなたを嫌います。 (これについては私を信じてください。私は最初からレイアウトマネージャーを使用すると言っていた人であり、私を無視した人の後継者でした。)
フォーム、ダイアログを定義するためにJDialog、JFrame、またはJInternalFrameから派生することはありません...
むしろJPanelから派生しています。これにより、次の利点が得られます。
GUIレイアウトデザイナー(ビルダー)の使用は避けてください。後でそれはあなたのコードをはるかにきれいにしそして維持することをより簡単にするでしょう。
並行性の実用的な知識はしばしば控えめに述べられていると思います。レスポンシブGUIと効率的なバックエンドを構築するには、Swingのスレッドポリシーと一般的な同期手法に精通している必要があります。
これは、GUIの仕組みではなく、GUIが表すものについてのより抽象的な高レベルの回答です。
タスクによっては、ユーザーがGUIの動作を概念的に把握できるようにするのが難しい場合があります。私はGUIを含むかなりトリッキーな作業を行いましたが、最も成功したアプローチは、複雑なコントロールセットを使用して、ユーザーが期待するレイアウトに配置することでした。
たとえば、T1回線の両端に1つずつある2つのデバイスを管理するシステムを作成しました(モデムのようなものです)。 「ループバックの作成、遠端信号のテスト、近端ビットパターンのテスト、さまざまなビットパターンの送信など」のようなフィールドは、コントロールを理解するのが非常に困難でした(これは非常に単純化されており、これよりもはるかに悪かったです)
私は問題を本当に理解しなければならなかったので、私は常にこの問題で顧客を助けたテクニカルサポートの担当者に行きました。彼は私にマニュアルの図を見せて、その図でさまざまなコントロールが何をしたかを私に説明してくれました。
ダイアグラムを取り、グラフィックを使用して再作成し(ほとんどの場合、単純な線画ですが、両端とそれらの間の接続を示しています)、グラフィックの領域を使用してコントロールとフィードバック(色の変更)を表しました。 。信号が出ているのが視覚的にわかりました。遠端でループバックをオンにすると、回線が信号を発信回線にループバックしていることがわかります。次に、近端が他の回線に送信しているパターンを取得し始めると、色が変化することがわかります。 。
「コントロール」はこれよりもかなり複雑でしたが、GUIは、顧客が問題を理解するために必要なものに正確に縮小しました。
この後、これまでこのようなことを理解できなかったとお客様から言われましたが、今では完全に理解できています。
このプレゼンテーションは、GUI実装の配線よりもはるかに重要でした。
mvcはあなたの友達です。
ユーザーがアクションボタンを複数回クリックしたときに、あまりにも多くのスレッドを生成しないようにします。最初のクリックでボタンを無効にし、バックグラウンドスレッドでアクションを生成し、完了したら、ボタンを再度有効にします。これは、実行時間の短いタスクでは問題にならない場合があります。
実際の作業を行うためにコールバックがスレッドから生成される習慣を身に付けてください。そうすれば、コールバックの1つが時間のかかるモンスターに変わっても、GUIがフリーズすることはありません。
MVCパターンを多用します。これが私が意味することの簡単な例です:
class Person
{
String firstName;
String lastName;
// and getters and setters...
}
class PersonSwingModel
{
private Person person;
private javax.swing.text.PlainDocument firstName;
private javax.swing.text.PlainDocument lastName;
// and getters and setters...
// Create some method like init() that initializes PlainDocument values
// to attributes in model.
}
class SavePersonAction extends AbstractAction
{
private PersonSwingModel model;
// and getters and setters...
}
class PersonSwingView extends JFrame
{
private PersonSwingModel model;
private javax.swing.JTextField firstName;
private javax.swing.JTextField lastName;
private SavePersonAction savePersonAction; // hook up to JButton/JMenuItem
// and getters and setters...
// Create some method like init() which binds PlainDocument to JTextField
// and Actions to JButtons or JMenuItems
}
JFrameやJPanelの拡張に反対する人もいます。私はしません。私のために働きます。
また、LayoutManagersを使用します。 GridBagLayoutは非常に強力です。これを使用する場合は、いくつかのGridBagConstraints定数(LABEL_GBCやFIELD_GBCなど)を定義し、それらを再利用し続けます。
構成が簡単になる場合は、継承を避けてください。
たとえば、私はこのようなものをたくさん見ました:
public class CustomerSupportApp extends JFrame {
JList<Customer> customers;
OtherBusinessComponent importantComponent;
etc. etc
}
これは、ビジネスロジックとプレゼンテーションを組み合わせたものです。それは困難から不可能への変更を行うだけです。
より良いのは:
public class CustomerSupportApp {
JList<Customer> customers;
OtherBusinessComponent importantComponent;
// The app HAS-A frame but not IS-A frame
JFrame frame;
etc. etc
}
テキストをアプリにコーディングしないようにしてください。 Swing guiは、データ駆動型として非常に簡単に記述できます。GUIをxmlファイル(コンポーネント名と位置/レイアウト属性を含む)で定義することを検討してください。
私はたくさんのプロパティシート(コントロールの山であり、ページごとに)があるシステムで作業しました。データ駆動型にしないと、保守や国際化は事実上不可能です。
GUIビルダーを使用する場合は、回避できる可能性がある場合は、出力するコードを変更しないでください。外部クラスからGUIにバインドすることをお勧めします。ビルダーなしでそれをしなければならない場合に何が起こるかを考えてください-移植するのは難しいでしょうか?無理だよ?
スイングの落とし穴を理解します。AWTスレッドからGUIコンポーネントを変更するだけで、AWTスレッドをできるだけ早く返します(100ミリ秒以上かかることを行う必要がある場合は、新しいスレッドを生成します)。
コードをドライに保つために最善を尽くしてください--SwingGUIでは実際のプログラミングの課題になる可能性があります-繰り返しますが、データ駆動型コードは、新しいJButton( "...")のようなコードを常に繰り返さないことがわかった唯一の方法です。 ;
データがプロパティシートベースの場合は、コントロールをデータに関連付けるためのバインディングメカニズムの作成を真剣に検討してください。 DRYコードの適切な目標は、データベースからGUIにデータを取得し、ユーザーに編集して取得させるための、コントロールごとの0(ゼロ)コントロール固有のコード行です。 DBに戻ります。これは、データを変更するだけで新しいコントロールを追加できることを意味します。
GUIを1つのクラスに、ロジックを別のクラスまたは複数のクラスに、可能な限り配置します。 MVC(Model-View-Controller) パターンを使用する場合、これは自動的に行われます。これを行わないと、GUIはすぐに保守不可能なほど複雑になります。
JFrame、JDialog、JPanel、JButton、Janythingクラスを拡張することは想定されていません(ただし、テーブルの動作に対する特定の拡張は、拡張した場合にのみ使用できます)。カスタムコンポーネントを実行したい場合は、JComponentを拡張できます。モデル(抽象モデルの拡張など)、リスナー(アダプターの拡張など)を実装することになっている場合は、それだけです。通常、swingコンポーネントを拡張する必要はありません。拡張する必要はありません。拡張すると、コードがスーパークラスの実装に関連付けられるため、拡張しない方がよいでしょう。
アプリケーションフレームワークAPIをご覧ください( https://appframework.dev.Java.net/ および http://Java.Sun.com/developer/technicalArticles/javase/swingappfr / 。これは、swingアプリケーションを構築するための優れたAPIです。例:すべてのスタイル(色、フォント、アイコンなど)は、単純な構成ファイルで定義されています。
あなたが直面する主な問題は、GUIアプリケーションのテスト容易性だと思います。
そのため、保守性と単体テストの容易さに関して、実際のアプリケーションロジック(モデル)をビューに認識させるように指示するModel View Controller(MVC)やその他の派生物ではなく、「Presenterfirst」イディオムに傾倒しています。最高のリソースは、考えとしてそれを紹介したグループの ウェブサイト です。
このようなアプローチを使用すると、アプリケーションのさまざまな要素を初期化するために多くの定型コードが必要になるため、依存性注入フレームワークを使用することもお勧めします。 Guice で解決しました。