将多个嵌入式javafx JFXPanel管理成swing tabbedpane

时间:2013-01-21 22:11:03

标签: multithreading swing scala thread-safety javafx

我正在使用swing来显示多个javafx Tableview,每个javafx嵌入(感谢JFXPanelTabbedPane

我使用oracle doc中描述的熟知模式,以scala方式:

implicit def fun2Run[T](x: ⇒ T) = new Runnable {
    def run = x
  }

  def myTabbedScene():Scene = {
    val root = new StackPane
    root.getChildren.add(new Label("Hello world!"))
    new Scene(root, 300, 300)
  }

  def initFxPanel(fxPanel: JFXPanel, s: ⇒ Scene) = {
    fxPanel.setScene(s)
  }

  def initSwingGui(panel: PluginPanel) = {
    val fxPanel = new JFXPanel()
   // code to add panel to JPanel
    panel.peer.add(fxPanel)
    Platform runLater initFxPanel(fxPanel,myTabbedScene())
  }

  val jfxSwingPanel = new PluginPanel("wrap 2") {
    var jtemp = new JPanel()
    contents += jtemp
  }

  SwingUtilities invokeLater initSwingGui(jfxSwingPanel)

每次用户打开一个新的swing选项卡(只有场景方法不同)时执行此代码,但我不确定这是在这种情况下管理线程的最佳方法: - /

当我关闭或打开标签时,我的应用程序中存在一些不连贯的状态,并且在显示期间出现错误。

我的用例示例,以及一些问题:

  • 我打开第一个选项卡J1,调用了一个runlater,我的场景在选项卡中显示没有问题。

  • 我打开第二个标签J2,在javafx线程上调用新的runlater,

  • 我切换到标签J1,我的标签中的显示是如何刷新的?向主线程启动隐式runnable操作以使其成为可能? javafx如何识别要刷新的好标签?如果我有一个启动某个动作的按钮,我会在javafx主线程上发起一个runlater()动作来发送?

更新

我找到了一个可以帮助读者的代码来源,您可以revalidate()或/和repaint()包含_contentpane的摇摆面板(此处为jfxPanel}

   SwingUtilities.invokeLater(new Runnable() { 
    public void run() { 
    _contentPane.add(_jfxPanel); 
    _contentPane.revalidate(); 
    _contentPane.repaint(); }});
  • 我关闭第一个标签J1,javafx自动关闭/垃圾javafx资源关联?

我有其他一般性问题:

  • javafx应用程序主线程如何管理此多个runlater()调用 当他们从不同的jfxpanel到达时?

  • 当用户关闭标签时,如何正确关闭资源(不使用exit()平台方法关闭主javafx线程)与我的jfxpanel相关联?如果我销毁JFXPanel,那么用于展示的javafx资源会被解放吗?

  • 使用任务来管理我的线程可以解决我的问题吗?

我的问题可能是天真的,但我开始在gui建设,我有问题了解javafx如何在不同的嵌入式面板上管理场景。

1 个答案:

答案 0 :(得分:3)

  

当javafx应用程序线程从不同的jfxpanel到达时,如何管理这个多个runlater()调用?

来自Platform.runLater javadoc:

  

在JavaFX Application Thread上运行指定的Runnable   未来的未指定时间。这种方法可以从中调用   任何线程,都会将Runnable发布到事件队列然后返回   立即给来电者。 Runnables按顺序执行   他们被张贴了。传递给runLater方法的runnable将是   在任何Runnable传入后续调用之前执行   runLater。

此外:

  

当用户关闭标签时,如何正确关闭执行我的jfxpanel的线程(没有关闭主javafx线程)?

目前还不清楚你指的是哪个主题。通常,在集成JavaFX和Swing时,只需要关注两个线程 - Swing调度线程和JavaFX应用程序线程 - 这两个线程都应该由相应的底层框架管理,您不需要显式关闭。您不需要任何其他线程,除非您尝试执行某些不应在这些线程中执行的操作(例如高度CPU密集型任务或远程I / O) - 这些线程不会出现在示例代码中是这样的。

  

使用任务来管理我的线程可以解决我的问题吗?

除非你特别需要这样的事情,否则这种解决方案可能会使你的情况进一步复杂化而不是改善它。

  

我关闭第一个选项卡J1,javafx自动关闭/垃圾javafx资源关联?

如果你没有保留对相关jfxpanel中任何资源的引用,那么Java虚拟机可以垃圾收集jfxpanel和与之相关的资源 - 这只是标准的Java垃圾收集技术,这里没什么特别的

  

我切换到标签J1,我的标签中的显示是如何刷新的?向主线程启动隐式runnable操作以使其成为可能?

听起来不错(Java术语中的主线程是用于启动Java主要功能的线程,根本不涉及GUI编程)。您可能希望通过Platform.runLater()提交可运行的刷新请求,以便它将在JavaFX应用程序线程上执行。

  

javafx如何识别要刷新的好标签?

每个swing选项卡中都有一个JavaFX JFXPanel,每个swing选项卡都知道它有哪个JFXPanel,因此当您调用Platform.runLater刷新特定面板时,将(最终)引用传递给要使用的JFXPanel。这里有一些伪造的代码,没有任何语言来说明这个概念:

on swing tab change event
  final JFXPanel curPanel = tab.getJFXPanel()
  Platform.runLater() {
    // update curPanel here...
  }
  

如果我有一个启动某个动作的按钮,我会在发送的javafx主线程上启动runlater()动作?

本质上我认为你在这里是正确的,我只是重写你的问题以澄清一些术语 - 让我们说它是一个挥杆按钮,并且在对挥杆按钮执行动作时,你打电话给{{1然后,runLater调用中的代码最终将在JavaFX应用程序线程上执行。


我无法回答的其他问题,因为我在Scala中不够流利,无法提供合理的答案。

老实说,如果你刚刚开始构建GUI,那么我主动提出的建议是使用Java而不是Scala并坚持使用Swing或JavaFX,但不要将它们混合在一起直到你对GUI构建过程非常熟悉 - 否则,在集成过程中可能遇到的陷阱和陷阱太多,很少有人可以帮助你。