从一个源使用两个GUI

时间:2016-07-21 11:18:49

标签: java swing user-interface code-duplication

我正在开发一个现有项目,我希望简化并使其可用。我有两个GUI,我希望他们只从一个资源提供其他GUI代码。我的意思是gui1.javagui2.java由他们的GUI代码组成。而且,一个是他们共同的部分。我们称之为common.java。有了gui选择部分,我可以满足选择哪个gui(gui1或gui2)。我想将common.java扩展到JFrame,然后将gui1.javagui2.java扩展为common.java。此外,如果有一个GUI的外部部分,我可以使用if条件添加外部部分(正如我所说,我可以确定选择了哪个gui。)例如:

protected void MovementStateControl() {
        try {
            URL url = new URL(NameofMyproject.GetWepIp() + "<MESSAGE><Command_No>4</Command_No></MESSAGE>");
            URLConnection connection = url.openConnection();
            Document doc = parseXML(connection.getInputStream());
            NodeList Settings = doc.getElementsByTagName("SYSTEM_SETTINGS");
            Node MovementSystem = Settings.item(0);
            Element MovementElem = (Element) MovementSystem;
            jLabel7.setText(MovementElem.getElementsByTagName("device_name").item(0).getTextContent());
            SystemGuiSelect.DeviceName = MovementElem.getElementsByTagName("device_name").item(0).getTextContent();
            NameofMyproject.signal_max_level = Integer.parseInt(MovementElem.getElementsByTagName("signal_max_val").item(0).getTextContent());

            /* If gui1 is selected, the part should be done as well. Otherwise, just above part okay. */
            if (gui1) {
                NameofMyproject.signal_min_level = Integer.parseInt(MovementElem.getElementsByTagName("signal_min_val").item(0).getTextContent());
                if (!"EXISTS".equals(MovementElem.getElementsByTagName("polarization_system").item(0).getTextContent())) {
                    jLabel24.setVisible(false);
                    LblPolAngle.setVisible(false);
                    lblPolTarget.setVisible(false);
                    jLabel13.setVisible(false);
                    jTextField3.setVisible(false);
                    jButton16.setVisible(false);
                    jButton8.setText("Tx-Xy");
                    jButton3.setVisible(false);
                    jButton4.setVisible(false);
                    jProgressBar3.setVisible(false);
                    jLabel36.setVisible(false);
                    jLabel37.setVisible(false);
                    jLabel5.setVisible(false);
                    jButton18.setVisible(false);
                } else {
                    jLabel24.setVisible(true);
                    LblPolAngle.setVisible(true);
                    lblPolTarget.setVisible(true);
                    jLabel13.setVisible(true);
                    jTextField3.setVisible(true);
                    jButton16.setVisible(true);
                    jButton8.setText("Tx-Xy-Zu");
                    jButton3.setVisible(true);
                    jButton4.setVisible(true);
                    jProgressBar3.setVisible(true);
                    jLabel36.setVisible(true);
                    jLabel37.setVisible(true);
                    jLabel5.setVisible(true);
                    jButton18.setVisible(true);
                }
            }

        } catch (Exception e) {  }
    }

问题出在这里我希望将常见的GUI部分放入common.java以删除代码重复,因为它有两个相同的GUI代码。当然因为common.java是超类,所以它无法知道其子类的元素。 (无法识别JLabels,JButtons等)即使他们的thread部分相同,我也无法从同一来源提供它们。 GUI已使用NetBeans创建。顺便说一下,我对这个问题的解决方案是添加参数所有方法但是该方法有多少参数呢? (也许我使用vargs)但是,我想知道是否有更有效的解决方案。

3 个答案:

答案 0 :(得分:3)

据我了解,您有两个基本问题需要处理。首先是UI视图与控制逻辑的分离,第二是增加Swing代码中的重用。 我的解决方案是引入 In Process Event Bus ,以便在View和Control之间进行通信,并使用通用布局引入 Extract Components 来自当前UI类的模式,以增加Swing代码中的重用。

使用事件总线从控件分离视图

您需要这个,因为您的视图会有所不同,但您的控制逻辑应保持不变。您需要找到一种方法来告诉您的UI device_name 已更改。我建议使用 事件总线 实现。有些实现已经为您解决了 EventDispatchThread 处理问题。

事件总线分隔 gui2.java 只会对与其包含的视觉元素相关的事件作出反应,并且 < em> gui1.java ,其中包含所有当前已知的字段,将对所有事件做出反应。您的控制器只是发布事件而不知道它是否被某人使用或者只是丢弃了。

Ectract组件以增加Swing代码中的重用

我建议识别用户界面的常见部分,例如标签组,文本字段等,它们在功能上彼此相同(例如,人的姓氏和姓氏)。将它们提取到一个扩展 JPanel 的单独类中,并在需要的地方重用它们。

不要将这些片段直接注册到 EventBus ,或者至少注入他们应该响应的事件名称。否则,您可能无法在一个 JFrame 中使用同一组件的两个实例,因为它们会自动显示相同的值。

我希望这提供了一些从哪里开始重构以及前进的方向。

答案 1 :(得分:2)

正如你所提到的,超类不应该知道它的子类。 不使用继承,而是使用合成

common.java 应该由其专门的容器组成。如果您需要添加新的 gui3,将来会将 common.java gui1.java gui2.java 中解耦.java 你不会破坏任何API,而且很容易创建一个新的 SpecializedGUI.java

enter image description here

答案 2 :(得分:1)

基于您的方法示例,我建议您使用简单的解决方案来解决您的问题 首先,正如吉尔伯特所建议的那样,常见的小部件(文本字段,标签等)必须在抽象的公共类中,如果可能的话,可以放在公共类中(它更简单)。当然,具体gui的具体小部件将在具体类中。 为了便于使用由具体类操作的常用窗口小部件,请在抽象公共类中将字段声明为受保护。

其次,在你的代码片段中,你做了

 if (gui1) { then...

我建议你创建听众,而不是不需要的条件语句(不是父类的角色来了解孩子的家伙)和繁琐(在时间上不可维护)。这些将是您的具体类必须实现的简单接口。
它只是简单地向具体类调度在父类调度事件时采取行动或不采取行动的责任。 为了强制您的具体类实现接口,请使用抽象类Common来实现此接口。 通过这种方式,具体类将无法选择实现它。

这是一个非常简单的例子,有两个guis并说明了所提出的概念:

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public abstract class CommonFrame extends JFrame implements MyFrameListener {

    protected JLabel myLabelForControlMove;
    private JButton btnControlMove;
    private JPanel panel;

    public CommonFrame() {
        panel = new JPanel();
        add(panel);
        myLabelForControlMove = new JLabel("waiting for information...");
        panel.add(myLabelForControlMove);
        btnControlMove = new JButton("click to control move");
        panel.add(btnControlMove);
        setVisible(true);
        pack();


        // call concrete class with no aware which one is used
        onMovementStateCreation();

        btnControlMove.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
            // call concrete class with no aware which one is used
            onMovementStateControl();
            }
        });
    }
}



public interface MyFrameListener {

  void onMovementStateCreation();

  void onMovementStateControl();

}


public class Gui1 extends CommonFrame {

 @Override
 public void onMovementStateCreation() {
   myLabelForControlMove.setText("control starts");
 }

 @Override
 public void onMovementStateControl() {
   myLabelForControlMove.setText("control with state Gui1");
 }

}


public class Gui2 extends CommonFrame {

  @Override
  public void onMovementStateCreation() {
    myLabelForControlMove.setText("control with state Gui2");
  }

  @Override
  public void onMovementStateControl() {
    // does nothing
  }

}