Java 如何复制JButton操作并更改其对底层对象的引用?

Java 如何复制JButton操作并更改其对底层对象的引用?,java,swing,jbutton,jtextfield,Java,Swing,Jbutton,Jtextfield,下面的示例使用JButton、JTextField和JLabel创建JFrame。 按下按钮后,文本字段和标签中的值将递增。 本例还创建了第二个JFrame,它是第一个JFrame的副本。 按钮、文本字段和标签也会被复制 目前的问题是,复制框架上的按钮仍然会更新原始框架上的文本字段和标签。“为什么”是相当明显的,因为代码对文本字段和标签进行了特定的引用 虽然这不是以最好的方式写的,但它是我正在处理的场景的一个很好的例子 目标是,在不进行重大重写的情况下,让复制的按钮操作更新复制的测试字段和标签而

下面的示例使用JButton、JTextField和JLabel创建JFrame。 按下按钮后,文本字段和标签中的值将递增。 本例还创建了第二个JFrame,它是第一个JFrame的副本。 按钮、文本字段和标签也会被复制

目前的问题是,复制框架上的按钮仍然会更新原始框架上的文本字段和标签。“为什么”是相当明显的,因为代码对文本字段和标签进行了特定的引用

虽然这不是以最好的方式写的,但它是我正在处理的场景的一个很好的例子

目标是,在不进行重大重写的情况下,让复制的按钮操作更新复制的测试字段和标签而不是原始字段和标签的侵入性最小的方法是什么

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.JTextField;

class ButtonTextFieldLabel extends JFrame
{
    JButton bnt1 = new JButton("B1");
    JTextField tf1 = new JTextField("1");
    JLabel lbl1 = new JLabel("100");

    public ButtonTextFieldLabel()
      {
          super("Main Frame");
          setLayout(null);

          bnt1.setBounds(50,100,120,40);
          tf1.setBounds(300,100, 80,40);
          lbl1.setBounds(200,100,80,40);
          bnt1.addActionListener(new ListenerHolder(this));

          add(bnt1);
          add(tf1);
          add(lbl1);

          setSize(500,500);
          makeCopy(this);       
          setVisible(true);
      }

    private void makeCopy(ButtonTextFieldLabel originalObj) 
    {
          JFrame copyFrame = new JFrame();
          copyFrame.setTitle("Copy of " + originalObj.getTitle());
          copyFrame.setSize(originalObj.getSize());
          copyFrame.setLocation(originalObj.getX()+100, originalObj.getY()+100);
          copyFrame.setLayout(null);

          JButton copyBnt1 = new JButton();       
          copyBnt1.setBounds(originalObj.bnt1.getBounds());
          copyBnt1.setLabel(originalObj.bnt1.getLabel());
          copyFrame.add(copyBnt1);

          for (ActionListener al : originalObj.bnt1.getActionListeners())
          {
              copyBnt1.addActionListener(al);
          }

          JTextField copyTf1 = new JTextField();
          copyTf1.setBounds(originalObj.tf1.getBounds());
          copyTf1.setText(originalObj.tf1.getText());

          JLabel copyLbl1 = new JLabel();
          copyLbl1.setBounds(originalObj.lbl1.getBounds());
          copyLbl1.setText(originalObj.lbl1.getText());

          copyFrame.add(copyBnt1); 
          copyFrame.add(copyTf1);
          copyFrame.add(copyLbl1);

          copyFrame.setVisible(true);
    }

    public void runThis() 
    {
        tf1.setText(  Integer.toString(Integer.parseInt(tf1.getText())+1)   );
        lbl1.setText(  Integer.toString(Integer.parseInt(lbl1.getText())+1)   );
    }

} 

class ListenerHolder implements  ActionListener
{
    ButtonTextFieldLabel ph;
    public ListenerHolder(ButtonTextFieldLabel ph)
    {
        this.ph = ph;       
    }
    @Override
    public void actionPerformed(ActionEvent arg0) 
    {
        ph.runThis();

    }
}

public class TestBTL
    {
      public static void main(String[] args){
        new ButtonTextFieldLabel();
    }
}

您已经知道问题的原因——您正在复制原始ActionListener,并完成对原始GUI组件的引用。总体解决方案不是复制动作监听器,而是创建GUI来保存和维护自己的唯一状态。一种解决方案是,不要试图通过kludge复制组件,而是创建一个自包含的GUI对象来保存和更新自己的状态。如果需要,可以使用工厂方法创建多个GUI

例如:

import java.awt.Dimension;
import java.awt.event.ActionEvent;

import javax.swing.*;

public class TestBtl2 {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            createAndDisplayFrame("Frame 1").setVisible(true);
            createAndDisplayFrame("Frame 2").setVisible(true);
        });
    }

    // Factory method
    private static JFrame createAndDisplayFrame(String text) {
        BtlPanel btlPanel = new BtlPanel();
        JFrame frame = new JFrame(text);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(btlPanel);
        frame.pack();
        frame.setLocationByPlatform(true);
        return frame;
    }
}

class BtlPanel extends JPanel {
    private int value = 0;
    private JButton button1 = new JButton(new ButtonAction("Button 1"));
    private JLabel label1 = new JLabel("00");
    private JTextField textField1 = new JTextField("00");

    public BtlPanel() {
        textField1.setFocusable(false);
        add(button1);
        add(Box.createHorizontalStrut(20));
        add(label1);
        add(Box.createHorizontalStrut(20));
        add(textField1);

        setPreferredSize(new Dimension(300, 100));
    }

    public void incrementValue() {
        value++;
        String text = String.format("%02d", value);
        label1.setText(text);
        textField1.setText(text);
    }

    private class ButtonAction extends AbstractAction {
        public ButtonAction(String name) {
            super(name);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            incrementValue();
        }
    }

}

附带建议:

  • 虽然空布局和
    setBounds()
    可能会像创建复杂GUI的最简单和最好的方式一样吸引新手,但您创建的GUI越多,在使用它们时遇到的困难就越严重。当GUI调整大小时,它们不会调整您的组件的大小,它们是一个需要增强或维护的皇家女巫,当它们放置在滚动窗格中时会完全失败,当在所有平台或屏幕分辨率与原始分辨率不同的情况下查看时,它们看起来非常糟糕
  • 退房:

请看,谢谢,我实际上遵循了这一点,这很有道理,但如果有十几个不同的JFrame,每个JFrame都有不同数量的按钮、文本字段、标签和工具栏按钮,会怎么样?您会为每个可能的组合创建一个工厂方法吗?@UnhandledException:首先,您的应用程序应该只有一个主应用程序窗口,换句话说,只有一个JFrame,请参阅上面的第二方推荐链接了解原因。其次,我将我的GUI创建转向JPanel的创建(参见上面的代码示例),因为通过这种方式,我可以将我的JPanel放入JFrame、JDialog、另一个JPanel或任何其他可能需要它的位置。第三,你在评论中提出的问题过于宽泛和模糊。通常每个JPanel都独立存在,并且都有一个底层的M-V-C结构。