2013-03-19 75 views
0

我有一个可以在运行时修改的模型。这里有一个例子:从动态模型生成视图

public class JavaMethod 
{ 
    private String   name; 
    private List<Parameter> parameters; 
    private boolean   isConstructor; // this is an example 
} 

的参数可以有不同的类型(integerbooleanstringfloat ...)和不同的有效值。例如,名为年龄的整数参数只能包含正整数。

问题是我想用Swing生成视图来配置JavaMethod对象,但我不确定正确的方法。

例如,年龄是一个正整数的参数将被链接到延伸JTextField的类别,以防止输入负的任何字母。另一个整数参数名为numberOfFingers其范围从8到12将链接到延伸JComboBox的类,该类允许选择该范围内的选项。

我可以通过给Parameter对象生成适当的Swing组件的任务来做到这一点,但我的模型会知道如何生成视图。

什么是这样的模型生成视图的正确方法? 所有我能想到的(没有涉及视图生成的模型)是控制器中的一种巨型开关,通过阅读参数的细节选择好的组件。

感谢

+0

我会搜索“Java属性表”,看看你想出什么 – MadProgrammer 2013-03-19 19:26:14

+0

谢谢,我实际上正在为模型对象制作属性表。 – phil 2013-03-19 20:12:25

+0

按照表/树API的工作原理思考一下。基本上,您想要将渲染器/编辑器组件注册到您的视图中。这将允许视图检查参数类型并决定如何最好地呈现/编辑该值。那么您显然需要决定最佳行为方式来为最常见的数据类型定义默认实现 – MadProgrammer 2013-03-19 20:34:19

回答

0

解决此问题的最佳方法是使用访问者模式。

例如:有关此图案here

import java.awt.EventQueue; 
import java.util.ArrayList; 
import java.util.Iterator; 
import java.util.List; 

import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JTextField; 
import javax.swing.WindowConstants; 

public class Main 
{ 
    public static class JavaMethod implements Iterable<Parameter> 
    { 
     private List<Parameter> parameters; 

     public JavaMethod() 
     { 
      this.parameters = new ArrayList<>(); 
      // This is an example 
      this.parameters.add(new IntegerParameter()); 
      this.parameters.add(new StringParameter()); 
     } 

     @Override 
     public Iterator<Parameter> iterator() 
     { 
      return this.parameters.iterator(); 
     } 
    } 

    public static interface Parameter 
    { 
     public void accept(ParameterVisitor visitor); 
    } 

    public static class IntegerParameter implements Parameter 
    { 
     public int value = 10; 

     @Override 
     public void accept(final ParameterVisitor visitor) 
     { 
      visitor.visit(this); 
     } 
    } 

    public static class StringParameter implements Parameter 
    { 
     public String value = "Hello"; 

     @Override 
     public void accept(final ParameterVisitor visitor) 
     { 
      visitor.visit(this); 
     } 
    } 

    public static interface ParameterVisitor 
    { 
     void visit(StringParameter stringParameter); 
     void visit(IntegerParameter integerParameter); 
    } 

    public static class ParameterSwingVisitor implements ParameterVisitor 
    { 
     private final JComponent container; 

     public ParameterSwingVisitor(final JComponent container) 
     { 
      this.container = container; 
     } 

     @Override 
     public void visit(final StringParameter stringParameter) 
     { 
      this.container.add(new JTextField(stringParameter.value)); 
     } 

     @Override 
     public void visit(final IntegerParameter integerParameter) 
     { 
      // This could be a custom component to pick numbers 
      this.container.add(new JLabel(String 
        .valueOf(integerParameter.value))); 
     } 

    } 

    public static void main(final String[] args) 
    { 
     EventQueue.invokeLater(new Runnable() 
     { 
      @Override 
      public void run() 
      { 
       JPanel myPanel = new JPanel(); // view 
       JavaMethod myMethod = new JavaMethod(); // model 

       final ParameterVisitor visitor = new ParameterSwingVisitor(
         myPanel); 

       for (final Parameter picked : myMethod) 
       { 
        picked.accept(visitor); // This will add the appropriate 
              // swing 
              // component 
       } 

       JFrame myFrame = new JFrame("Visitor pattern"); 
       myFrame.setContentPane(myPanel); 
       myFrame.setVisible(true); 
       myFrame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 
       myFrame.setSize(500, 500); 
      } 
     }); 
    } 
} 

的更多信息。

1

对于您需要创建自定义PlainDocument。例如,对于JTextField只包含年龄值应创建AgeDocument类,它会是这个样子:

import javax.swing.text.Document; 
import javax.swing.text.PlainDocument; 
import javax.swing.text.AttributeSet; 
import javax.swing.text.BadLocationException; 
class AgeDocument extends PlainDocument 
{ 
    @Override 
    public void insertString(int offs, String str, AttributeSet a) throws BadLocationException 
    { 
     /**Write your logic here**/ 
     if (str == null) 
     { 
      return; 
     } 
     char[] arr = str.toCharArray(); 
     for (int i = 0; i < arr.length; i++) 
     { 
      if (!Character.isDigit(arr[i]))//Checking for Non Numeric. 
      { 
       return; 
      } 
      if (Character.getNumericValue(arr[i])==0) 
      { 
       try 
       { 
        int val = Integer.parseInt(getText(0,offs)); 
        if (val == 0) 
        { 
         super.insertString(offs,"", a);//Don't allow to put 0 as age. 
         return; 
        } 
       } 
       catch (Exception ex){return;} 
      } 
     } 
     super.insertString(offs, new String(str), a); 
    } 
} 

,只要你想设置这个AgeDocument属性设置为JTextField对象,你只要写JTextFieldOBject.setDocument(new AgeDocument())

同样,您可以独立创建多个模型。并且可以在代码中的任何位置使用它们。

+0

这可能很有用,谢谢。但在使用这种技术来过滤输入之前,我必须使用适当的组件来初始化视图。我应该在哪里以及如何选择一个'JTextField',一个'JComboBox'或任何其他与'Parameter'类型和条件相关的组件。如果这一切都进入一个大开关'if(param.isInt()&& param.isRange()){createComboBox(); }'与每种类型的情况? – phil 2013-03-19 20:11:27

+0

如果您确定将在给定的输入类型上调用'swing'的组件,那么您可以创建一个'Map',其中'key'作为参数类型,'value'作为'Swing'类的名称'组件'的对象,你想创建相应的键。通过这种方式,您可以使用'Map'的'get(key)'方法轻松找出与给定类型的参数相对应的实际组件。IMO – 2013-03-19 20:36:32