Swing Form Reflective Library

少し前に、Java Swingでフォームを迅速に生成するためのライブラリを作成することに思いつきました。 どうやってこれに来たのか教えてあげましょう。



問題の声明



確かに、多くはSwingコンポーネントを使用してjava-beanの編集を定期的に実装する必要があります。 たとえば、さまざまなディレクトリ。 JDKは保守的であり、開発者の生活を大いに促進するような「すぐに使える」ものを提供しません。 いずれの場合も、次のような記述が必要です。

GridBagPanel panel = new GridBagPanel(){{ add( new JLabel( "Name" ), 0, 0 ); add( new JTextField( person.getName() ) {{ getDocument().addDocumentListener( new DocumentListener() { public void insertUpdate( final DocumentEvent e ) { person.setName( getText() ); } public void removeUpdate( final DocumentEvent e ) { person.setName( getText() ); } public void changedUpdate( final DocumentEvent e ) { person.setName( getText() ); } } ); }}, 0, 1 ); //      ... }};
      
      





すでに多くのコードがあります。 ただし、ハンドラーに検証を追加する必要がある場合もあります。



あなたの人生を楽にするためのさまざまなアプローチがあります。



自転車の発明に対する渇望に駆られて、私はあなたができるフォーム生成の最小限のライブラリを書くことにしました:



このライブラリを使用するコードがどのように見えるかを説明します



デフォルトのフォーム



ここではすべてが簡単です。クラスを与え、フォームを取得します。

 Form<Person> form = FormBuilder.map( Person.class ).buildForm(); myFrame.add( form.asComponent() ); Person person = new Person(); person.setName( "john smith" ); // ... further initialization form.setValue( person );
      
      





コンポーネントの場所



おそらく、ケースの80%で、各フィールドに必要なコンポーネントは2つだけです。名前付きのラベルとエディター自体です。 古典的なアプローチはこれです。フィールドの名前を尋ね、コンポーネントを取得します。

 Form<Person> form = FormBuilder.map( Person.class ).with( new PropertyNameBeanMapper<Person>() {      @Override      public JComponent mapBean( PropertyNameContext<Person> ctx ) {        JPanel panel = new JPanel( new BorderLayout() );        panel.add( ctx.label( "name" ), BorderLayout.NORTH );        panel.add( ctx.editor( "name" ), BorderLayout.CENTER );        return panel;      } } ).buildForm();
      
      





文字列をより信頼性の高いものに置き換えることは可能ですか? たとえば、次のように:

 Form<Person> form = FormBuilder.map( Person.class ).with( new SampleBeanMapper<Person>() {      @Override      protected JComponent mapBean( Person sample, SampleContext<Person> ctx ) {        Box box = Box.createHorizontalBox();        box.add( ctx.label( sample.getName() ) );        box.add( ctx.editor( sample.getName() ) );        return box;      } } ).buildForm();
      
      





どのメソッドが呼び出されるかをコンテキストに伝えるサンプルとして動的プロキシを使用する場合( CGLIBライブラリの使用例 )、このコードは完全に機能します。 このアプローチはスレッドセーフではありませんが、GUIです。



マッピング



ctx.label()を使用すると、すべてが明確になります-JLabelが返されます。 そして、ctx.editor()は何を返すべきですか? コンテキスト内には、エディターがそのタイプに応じてフィールドごとに選択するマッピングが必要です。 しかし、少し拾います。 そして、それがカスタムコンポーネントである場合は? 設定が必要なポイントがいくつかあります。



たとえば、 サードパーティのカレンダーコンポーネントの場合、この構成は次のようになります。

 class DateToDateChooserMapper implements TypeMapper<JDateChooser, Date> { public Class<Date> getValueClass() { return Date.class; } public JDateChooser createEditorComponent() { return new JDateChooser(); } public Date getValue( final JDateChooser editorComponent ) { return editorComponent.getDate(); } public void setValue(final JDateChooser editorComponent, final Date value) { editorComponent.setDate( value ); } public void handleChanges(final JDateChooser editorComponent, final ChangeHandler changeHandler) { editorComponent.getDateEditor() .addPropertyChangeListener( "date", new PropertyChangeListener() { public void propertyChange( final PropertyChangeEvent evt ) { changeHandler.onChange( BackgroundMarker.INSTANCE ); } } ); } }
      
      







ここで、changeHandlerは、コンポーネントの変更についてシステムに通知するのに役立ちます。 デフォルトでは、BeanはHibernate Validatorを使用して検証されます。 ValidationMarkerには、その結果(この場合はBackgroundMarker)が通知され、失敗したコンポーネントの外観を変更する方法が決定されます。



このタイプのすべてのフィールドにマッピングを指定する必要がある場合、コードは単純に見えます。

 Form<Person> form = FormBuilder.map( Person.class ).use( new StringToTextAreaMapper() ).buildForm();
      
      





特定のフィールドについては、もう少し複雑です。

 Form<Person> form = FormBuilder.map( Person.class ) .useForProperty( "description", new StringToTextAreaMapper() ) .buildForm();
      
      





繰り返しますが、動的プロキシを使用し、文字列ではなくメソッドにバインドして、型チェックを提供することは可能ですか? 多少面倒ですが、可能です:

 Form<Person> form = FormBuilder.map( Person.class ).useForGetters( new GetterMapper<Person>() {      @Override      public void mapGetters( Person beanSample, GetterConfig config ) {        config.use( beanSample.getDescription(), new StringToTextAreaMapper() );      } } ).buildForm();
      
      







おわりに



しばらく前にこのライブラリを書きましたが、今ではコミュニティに提出することにしました。 現在、私はこのライブラリのScala用アダプターを作成していますが、これまでのところかなり簡単なことがわかりました。 おそらく、次の投稿でこれを説明します。



ライブラリとMavenリポジトリの詳細な説明が記載されたウィキは、Google Code: code.google.com/p/swing-formbuilderにあります。

ソースをGitHubに転送しました: github.com/aeremenok/swing-formbuilder



All Articles