gpt4 book ai didi

java - 从SwingUtilities.InvokeLater调用中获取返回值?

转载 作者:行者123 更新时间:2023-12-01 12:36:26 25 4
gpt4 key购买 nike

在我的Java应用程序中,主JTabbedPane上有一个JFrame,带有许多JPanel选项卡。在选项卡中,我有一个功能

public void newStatus(final String arg)
{
Runnable sendMsg = new Runnable()
{
@Override
public void run()
{
mainView.newStatusLine(arg);
}
};
SwingUtilities.invokeLater(sendMsg);
}

此函数调用 JFrame mainView主函数将一些文本写入 JTextPane中。我的问题是,这不允许我从主 JFrame获得返回值。我想做类似的事情
public InfoObj getInfo()
{
Runnable sendMsg = new Runnable()
{
@Override
public void run()
{
return mainView.getInfo();
}
};
SwingUtilities.invokeLater(sendMsg);
}

但是我不确定如何使这项工作。我已经尝试并遵循了我的IDE消息,以查看是否可以使它正常工作,但是我无法覆盖 Runnable.Run以返回某些内容。

有什么机制可以做这样的事情吗?

编辑:对于HoverCraftFullOfEels,整个问题是在 JPanels自身之间以及在主要 JFrameJPanel之间进行对话。在某个时候, JPanel想要告诉主要 JFrame做某事,或者它可能想要从中获取一些数据。但是据我所知,我不能仅将 this的引用传递给 JFrameJPanel并使用它来调用公共(public)函数或读取其中的任何公共(public)字段。

有时我不想通过生成的线程在EDT上执行此操作。一些 JPanel产生了线程,我想将 JPanel的引用传递给主 JFrame,以便它可以调用其中的函数来告诉用户有关线程在做什么的信息。

最佳答案

看来您的应用程序数据已全部绑定(bind)到用户界面对象中。如果您可以在EDT上完成所有操作,那么您就可以了。您可以在需要彼此信息的对象之间进行直接调用。由于所有这些都在EDT上,因此它实际上是单线程的,并且没有争用条件或死锁。但是,这可能会导致UI代码的各个部分之间过于紧密地耦合在一起。在这种情况下,您可以使用评论者建议的某种观察者或监听器模式。在单线程,事件驱动的环境(如AWT/Swing)中,这种方法可以很好地工作。

但是然后您说您可能想从EDT之外的其他线程执行此操作。那改变了一切。

(顺便说一句,这是使人们考虑将您的所有应用程序数据绑定(bind)在UI对象内部的方法,这是一种反模式。这使得从UI子系统外部获取这些数据非常困难。 )

您可以添加观察者模式,但是有一些限制。 UI拥有数据,因此只有EDT可以更改数据并将事件触发给观察者。观察者列表需要以线程安全的方式进行维护。大概观察者会希望响应事件而更新数据结构。这些数据结构必须是线程安全的,因为可以从EDT和其他线程访问它们。这种方法是可行的,但是您必须考虑哪些线程正在调用哪些方法,以及哪些数据结构必须是线程安全的。

假设您不想走这条路线,让我们回到原始问题,该问题是关于如何从invokeLater返回内容。这样做可以让您将数据保留在UI中,同时允许其他线程在需要时从UI中获取数据。可以通过一些间接操作来实现,从而实现。不过,它确实有风险。

这是代码。可以从“其他”(非EDT)线程中调用。

InfoObj getInfo() {
RunnableFuture<InfoObj> rf = new FutureTask<>(() -> getInfoObjOnEDT());
SwingUtilities.invokeLater(rf);
try {
return rf.get();
} catch (InterruptedException|ExecutionException ex) {
ex.printStackTrace(); // really, you can do better than this
}
}

这里的窍门是 RunnableFutureRunnableFuture的接口(interface)。这很有用,因为 invokeLater仅接受 Runnable,但是 Future可以返回值。更具体地说, Future可以捕获一个线程中返回的值并将其存储,直到另一个线程想要获取它为止。 FutureTaskRunnableFuture的方便,现成的实现,它带有 Callable参数,该函数可以返回值。

基本上,我们创建一个 FutureTask并将其传递给将在EDT上运行的一些代码( Callable,在此示例中为lambda表达式)。这将收集我们想要的信息并将其返回。然后,我们使用 invokeLater将其发布到EDT。当另一个线程需要数据时,它可以立即调用 get(),也可以卡在 Future上,以后再调用 get()Future.get()引发了一些您必须处理的已检查异常,这带来了一点不便。

这是如何运作的?如果EDT首先运行 Callable,则返回值将存储在 Future中,直到其他线程在其上调用 get()。如果另一个线程首先调用 get(),它将被阻塞,直到该值可用为止。

还有摩擦。精明的读者会认识到这与 invokeAndWait()具有相同的风险,即,如果您不小心,则可以使系统死锁。发生这种情况的原因是,调用 get()的线程可能会阻止等待EDT处理 invokeLater发布的事件。如果EDT由于某种原因被阻塞(也许正在等待另一个线程持有的东西),则结果将导致死锁。避免这种情况的方法是,在调用可能阻止等待EDT的内容时要格外小心。一个好的通用规则是,在调用这些阻止方法之一时不要持有任何锁。

有关如何使自己陷入 invokeAndWaitinvokeLater(FutureTask)麻烦的示例,请参阅 this questionmy answer

如果您的其他线程与UI数据结构完全分离,则此技术应该非常有效。

关于java - 从SwingUtilities.InvokeLater调用中获取返回值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25635428/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com