【问题标题】:Calling method in Jframe from external class and thread to set label values从外部类和线程调用 Jframe 中的方法来设置标签值
【发布时间】:2015-03-13 08:24:41
【问题描述】:

我有两个类,一个是 JFrame,另一个是实现可运行的外部类。我想在自己的线程中运行的外部类,直到收到停止命令。我还希望它通过在其类中实现的方法在其自己的线程中在后台更新 JFrame 上的值(或者这就是我认为最优雅的方法)。

我制作了一个简单的程序来说明我想要做什么并表明它不起作用。据我了解,从 EDT 外部调用时,JFrame 的值不会更新。我一直在寻找修复程序,说是在 invokelater() 调用中包含您想要更改文本值的代码部分。但是,这仍然不起作用。我真的陷入了困境,我确信这很简单,我只是不明白为什么这不起作用。

在这个简单的例子中,我在 JFrame 中有一个开始按钮和输出。我实例化我的外部类,并在按下开始按钮时将其作为 JFrame 类中的一个线程启动。该线程在一个外部类中并更新输出,直到达到 5。它通过调用 JFrame 中的一个方法来执行此操作,该方法在输出标签上调用 setText()

JFrame(我会省略自动生成的部分):

package javaapplicationtest;

public class JavaTestForm extends javax.swing.JFrame {

public JavaTestForm() {
    initComponents();
    jtf = new JavaExternClass();
    jtf_thread = new Thread(jtf);
}

/* Method I use outside of this class to update output label */
public void setLabel(int in) {
    final int inf = in;
    System.out.println("Setting output to " + in);

    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            output.setText(Integer.toString(inf));
        }
    });
}

/* Start button is pressed */
private void startActionPerformed(java.awt.event.ActionEvent evt)   {                                      
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            jtf_thread.start();
        }
    });
}   

/* Main entry */
public static void main(String args[]) {
    /* Create and display the form */
    java.awt.EventQueue.invokeLater(new Runnable() {
        public void run() {
            new JavaTestForm().setVisible(true);
        }
    });
}

/* External class */
private JavaExternClass jtf;
private Thread jtf_thread;

我的外部类:

package javaapplicationtest;

import java.util.logging.Level;
import java.util.logging.Logger;

public class JavaExternClass implements Runnable {    
    public void run() {
        gui = new JavaTestForm();
        for (int i = 0; i < 4; i++) {
            gui.setLabel(i); // Call method to set form output
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ex) {
                Logger.getLogger(JavaTestForm.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    private JavaTestForm gui;
}

【问题讨论】:

  • "(我将省略自动生成的部分):" 为了尽快获得更好的帮助,请发布MCVE(最小完整可验证示例)或SSCCE(简短,自包含,正确的例子)。 Thread.sleep(1000); 不要在 Swing/AWT GUI 中使用它。而是使用 Swing TimerTimer (actionPerformed(..)) 内的操作会自动在 EDT 上执行。
  • 读了你的简历后,我明白你为什么提到 SSCCE 和 MCVE。
  • 我编写了 SSCCE 并帮助创建了 MCVE,原因与我经常链接到它们的原因相同(并且写了很多)。因为准备 MCVE/SSCCE 既是一种很好的调试技术,也是一种与他人交流问题的方式。目前,我正在使用 2 位代码,其中一个包含一个“钢琴键盘”,允许用户选择一种乐器,单击一个键并听到该乐器在该音调下的声音。但我试图增加加载和播放 MIDI 曲调并显示正在播放的键并遇到问题的能力。所以我创建了一个 MCVE 来测试..
  • .. 想法。它根本没有 GUI(因为 GUI 与问题无关),只专注于播放 MIDI 序列,同时尝试检测音符开/关控制代码(这是我尚未设法解决的问题)。

标签: java multithreading swing jframe thread-synchronization


【解决方案1】:

当创建JavaExternClass 的新实例时,您正在创建一个新实例JavaTestForm...这还没有以StackOverflowException 结束,目前我无法理解,但“其他”问题也就是说,JavaExternClass 中的JavaTestForm 实例与main 中创建的实例无关,实际上是屏幕上的 UI。

您应该将JavaTestForm 的引用传递给它,而不是让JavaExternClass 创建JavaTestForm 的新实例...

public class JavaExternClass implements Runnable {   
    private JavaTestForm gui;
    public JavaExternClass(JavaTestForm gui) {
        this.gui = gui;

现在,当涉及到这些事情时,我是一团糟,但是,我不想将类传递给其他类,这些类具有接收者不应该知道或无法访问的其他功能,什么都没有更糟糕的是,有些课程会删除所有组件!

相反,我会创建一个interface,它描述了JavaExternClass 想要在JavaTestForm 上执行和实现此类的操作,从而只公开JavaExternClass 期望的功能,而不是其他任何东西。

您可能还想看看Concurrency in SwingInitial Threads

【讨论】:

  • 我会检查这些引用,但在这种情况下,正如你所指出的,这只是糟糕代码的一个很好的例子,以及对基本 oo 原则/语义的误用/误解。我在这方面工作太多了,我想我的脑子坏了。
  • 您对 Andrew Thompson 对我最初的问题的评论有什么意见吗?我更喜欢这个实现而不是使用Timers(这些类有少数,它们与外部设备执行相当复杂的通信/操作)。但是我对Java比较陌生,所以我也不是很清楚。
  • 如果您打算定期修改 UI 的状态,那么是的,Swing Timer 会是更好的选择,因为它会在事件的上下文中执行它的滴答回调调度线程。但是,如果您需要等待一些信息/执行长时间运行的过程,那么 SwingWorker 可能会更好,它允许您在 EDT 之外执行操作,但支持通过 @987654340 将更新同步回 EDT @/process 方法...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-30
  • 1970-01-01
相关资源
最近更新 更多