简体   繁体   English

如何使用另一个类的按钮更改 JLabel?

[英]How to change a JLabel with a button from another class?

I have two classes and a text file database, The JLabel in the first class, let's call it class1 automatically set it self to the number in the database.我有两个类和一个文本文件数据库,第一个类中的JLabel ,我们称之为class1自动将其设置为数据库中的数字。 Now, in class2 I have this little JFrame and a text field and of course a button, the value I put in the text field overwrites the one in the database, but here's the problem.现在,在class2我有这个小JFrame和一个文本字段,当然还有一个按钮,我放在文本字段中的值会覆盖数据库中的值,但问题就在这里。 The label in the first class wont update while running, but if I restart it it will show me the value that I want.第一个类中的标签在运行时不会更新,但是如果我重新启动它,它将显示我想要的值。

How do I update it while the program is running?如何在程序运行时更新它? I've tried to change the label in the buttonActionperformed in the other class but it gives me a NullPointException every time.我试图更改在另一个类中执行的buttonActionperformed中的标签,但它每次都给我一个NullPointException

How do I fix this?我该如何解决?

THE MAIN CLASS ( JUST THE JFRAME )主要类(只是 JFRAME)

package BankrollG;

import java.awt.Graphics;
import javax.swing.JFrame;

public class BGbrain {

    BGbody body = new BGbody();
    JFrame Frame = new JFrame();

    public BGbrain() {
        Frame.setSize(body.width, body.height);
        Frame.setTitle(body.title);
        Frame.setResizable(false);
        Frame.setDefaultCloseOperation(Frame.EXIT_ON_CLOSE);
        Frame.add(body.panel);
        Frame.setLocationRelativeTo(null);
        Frame.setFocusable(true);

        Frame.setVisible(true);
    }

    public static void main(String[] args ) {
        new BGbrain();
    }
}

Then you got the class with the components:然后你得到了包含组件的类:

private JLabel bankroll_label

    public BGbody(){        
        panel.setLayout(null);
        windowComponents();           
    }

    public void windowComponents() {
        // Bankroll database access
        try {
           
            FileReader fr = new FileReader("Bankroll.txt");
            BufferedReader br = new BufferedReader(fr);
            set_bankroll = br.readLine();
                
        } catch(IOException e) {
            System.out.println("FEL MED LÄSNING AV DATABAS /// BGBODY");
        }
    
    }
}

THEN you got the JFrame class that I created with the netbeans function然后你得到了我用 netbeans 函数创建的 JFrame 类

private void AddcurrencyActionPerformed(java.awt.event.ActionEvent evt) {
                    
    String CBR = txt_bankroll.getText();

    try {
        FileWriter fw = new FileWriter("Bankroll.txt");
        PrintWriter pw = new PrintWriter(fw);

        pw.println(CBR);
        pw.close();
    } catch(IOException e) {
        System.out.println("FEL MED INSKRIVNINGEN I DATABASEN");
    }
}         

Now, everything goes as plan, but I can't update my JLabel "bankroll_label" from the button class because it just returns nullpointsexceptions.现在,一切都按计划进行,但我无法从按钮类更新我的 JLabel“bankroll_label”,因为它只返回 nullpointsexceptions。 The data is there, because the JLabel reads from the database but it wont update when changes has been made from the button class.数据在那里,因为 JLabel 从数据库中读取,但在按钮类进行更改时它不会更新。 So a getter setter method wont work because the value IS there but it wont update the JLabel.因此 getter setter 方法将不起作用,因为值在那里,但它不会更新 JLabel。

I hope this made it easier to understand my problem.我希望这能让我更容易理解我的问题。 It's ALOT more code, that dont have to do with this, I hope I simplified it at least some.它有更多的代码,与此无关,我希望我至少简化了一些。

Your question is a specific example of a basic problem in programming in Java -- how to transfer information between classes.您的问题是 Java 编程中一个基本问题的具体示例——如何在类之间传输信息。 There are several ways to do this, one of the most elegant being giving to use a "model" class that holds your program's logic code and key data, having one class change the model's state by changing a text String that it holds.有几种方法可以做到这一点,最优雅的方法之一是使用一个“模型”类来保存程序的逻辑代码和关键数据,让一个类通过更改它保存的文本字符串来更改模型的状态。 Then using a listener or observer pattern, have the model notify the other class that it has been changed so the other class can extract the new information, its new String from the model.然后使用侦听器或观察者模式,让模型通知另一个类它已被更改,以便另一个类可以从模型中提取新信息,即它的新字符串。 While this is likely the best solution, it may be a bit of overkill and likely is above your current level of coding, so for you, I'm not going to recommend this.虽然这可能是最好的解决方案,但它可能有点矫枉过正,并且可能高于您当前的编码水平,因此对于您来说,我不会推荐这个。

Instead, I'm going to recommend a simpler less elegant solution, that you instead have one class call a setter method of the other to push the new String into it.相反,我将推荐一种更简单的不太优雅的解决方案,您可以让一个类调用另一个类的 setter 方法来新 String送到其中。

One problem we have as volunteer answerers here is that your question is hard to answer because it lacks critical code, making it hard for us to guess why your code is misbehaving, why specifically you're running into a NullPointerException (or NPE) when you try to run it.我们作为志愿者回答者遇到的一个问题是,您的问题很难回答,因为它缺少关键代码,这使我们很难猜测为什么您的代码行为不端,特别是为什么当您遇到 NullPointerException(或 NPE)时尝试运行它。 So all I can do is guess, but guess I will try nevertheless.所以我所能做的就是猜测,但我想我还是会尝试。

For simplicity's sake, let's call one class the, the one that holds the JLabel, the LabelClass and the other class the ButtonTextFieldClass .为简单起见,我们将一个类称为 ,该类包含 JLabel、 LabelClass ,另一个类为ButtonTextFieldClass

One possible reason is that you've got a NullPointerException is because your ButtonTextFieldClass may have a LabelClass variable, but never initialized the variable, something like so:一个可能的原因是您有 NullPointerException 是因为您的ButtonTextFieldClass可能有一个LabelClass变量,但从未初始化该变量,如下所示:

// this guy is null because it is never initialized
private LabelClass labelClass; 

A simple solution could be to try to initialize it like so:一个简单的解决方案可能是尝试像这样初始化它:

private LabelClass labelClass = new LabelClass();

But this won't work because while it does create and assign a LabelClass instance, it's likely not the LabelClass instance that is visualized in the running GUI.但这不会起作用,因为虽然它确实创建并分配了一个 LabelClass 实例,但它可能不是在运行的 GUI 中可视化的 LabelClass 实例。

A better solution is to give the ButtonTextFieldClass a setter method that allows other classes to set the ButtonTextFieldClass with the proper LabelClass instance.更好的解决方案是给ButtonTextFieldClass setter方法,它允许其他类设置ButtonTextFieldClass用适当的LabelClass实例。

eg,例如,

public void setLabelClass(LabelClass labelClass) {
   this.labelClass = labelClass;
}

This way the code that sets up both classes can pass the visualized LabelClass to the first class, and it can call methods on it.这样,设置两个类的代码就可以将可视化的 LabelClass 传递给第一个类,并且可以调用其上的方法。

A simple example of LabelClass could look like so: LabelClass 的一个简单示例如下所示:

class LabelClass extends JPanel {
   private JLabel label = new JLabel("");

   public LabelClass() {
      setBorder(BorderFactory.createTitledBorder("Label Panel"));
      add(label);
   }

   public void setLabelText(String text) {
      label.setText(text);
   }
}

I have it extend JPanel because this way it gives me the freedom of placing it into a JFrame or JDialog or other JPanel as I see fit.我让它扩展了 JPanel,因为这样我就可以自由地将它放入 JFrame 或 JDialog 或我认为合适的其他 JPanel 中。 Note that I've made the JLabel private and have given the class a public setter method, setLabelText(String text) , that allows outside classes the ability to set the JLabel's text.请注意,我已将 JLabel 设为私有,并为该类提供了一个公共 setter 方法setLabelText(String text) ,该方法允许外部类能够设置 JLabel 的文本。

The ButtonTextFieldClass could look something like: ButtonTextFieldClass 可能类似于:

class ButtonTextFieldClass extends JPanel {
   private JTextField textField = new JTextField(10);
   private JButton button = new JButton(new ButtonAction("Send Text"));
   private LabelClass labelClass;

   public ButtonTextFieldClass() {
      setBorder(BorderFactory.createTitledBorder("Button TextField Panel"));
      add(textField);
      add(button);
   }

   // here we allow other classes to set instances of our LabelClass  
   public void setLabelClass(LabelClass labelClass) {
      this.labelClass = labelClass;
   }

   // ....

I've also given the button an AbstractAction in place of an ActionListener since it is like a super ActionListener on steroids.我还给按钮一个 AbstractAction 代替 ActionListener,因为它就像类固醇上的超级 ActionListener。 Inside of it, I'd get the text from the JTextField and then call the LabelClass's setter method (if the variable is not null) to set the label's text:在其中,我会从 JTextField 获取文本,然后调用 LabelClass 的 setter 方法(如果变量不为 null)来设置标签的文本:

  public void actionPerformed(ActionEvent e) {
     String text = textField.getText(); 
     if (labelClass != null) {
        labelClass.setLabelText(text);
     }
  }

Then to set everything up, in another class I'd create instances of both LabelClass and ButtonTextFieldClass , and then "hook them up" by calling the setter method:然后要设置所有内容,在另一个类中,我将创建LabelClassButtonTextFieldClass实例,然后通过调用 setter 方法“将它们连接起来”:

  LabelClass labelClass = new LabelClass();
  ButtonTextFieldClass buttonTextFieldClass = new ButtonTextFieldClass();
  buttonTextFieldClass.setLabelClass(labelClass); // set our reference

The whole thing could look like so:整个事情可能看起来像这样:

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;

public class TransferData {

   private static void createAndShowGui() {
      LabelClass labelClass = new LabelClass();
      ButtonTextFieldClass buttonTextFieldClass = new ButtonTextFieldClass();
      buttonTextFieldClass.setLabelClass(labelClass); // set our reference

      JPanel mainPanel = new JPanel(new GridLayout(0, 1));
      mainPanel.add(buttonTextFieldClass);
      mainPanel.add(labelClass);

      JFrame frame = new JFrame("TransferData");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }
}

class LabelClass extends JPanel {
   private JLabel label = new JLabel("");

   public LabelClass() {
      setBorder(BorderFactory.createTitledBorder("Label Panel"));
      add(label);
   }

   public void setLabelText(String text) {
      label.setText(text);
   }
}

class ButtonTextFieldClass extends JPanel {
   private JTextField textField = new JTextField(10);
   private JButton button = new JButton(new ButtonAction("Send Text"));

   // one possible solution -- give this class a variable 
   // of the LabelClass -- but don't initialize the variable 
   // here, but rather do it in a setter
   private LabelClass labelClass;

   public ButtonTextFieldClass() {
      setBorder(BorderFactory.createTitledBorder("Button TextField Panel"));
      add(textField);
      add(button);
   }

   // here we allow other classes to set instances of our LabelClass  
   public void setLabelClass(LabelClass labelClass) {
      this.labelClass = labelClass;
   }

   // an AbstractAction is like a "super" ActionListener
   private class ButtonAction extends AbstractAction {
      public ButtonAction(String name) {
         super(name); // set the button's text and actionCommand
         int mnemonic = (int) name.charAt(0); // get first char
         putValue(MNEMONIC_KEY, mnemonic); // set mnemonic
      }

      @Override
      public void actionPerformed(ActionEvent e) {
         String text = textField.getText(); 
         if (labelClass != null) {
            labelClass.setLabelText(text);
         }
      }
   }
}

For simplicity's sake, I've displayed both JPanels within the same GUI, but it could work just as well if one JPanel were in one JFrame and the other within a JDialog.为简单起见,我在同一个 GUI 中显示了两个 JPanel,但如果一个 JPanel 在一个 JFrame 中而另一个在 JDialog 中,它也可以正常工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM