在VBox内部的TitledPane内包装的单词

时间:2013-12-23 12:32:18

标签: scala javafx javafx-2

我有TitledPanes,其中包含大量文本。 TitledPanes放在VBox内部以垂直放置。但是,当放置在VBox中时,TitlePane的宽度将成为文本的整个宽度,而不是包装文本。如何使TitlePane的宽度是可用区域的宽度,如果有必要包装它的内容?

在这个例子中,文本包装按预期工作,但是没有VBox,所以你不能有多个TitledPane。

package nimrandsLibrary.fantasyCraft.characterBuilder

import javafx.scene.control._
import javafx.scene.layout._
import javafx.scene._

class TiltedTextExample extends javafx.application.Application {
  def start(stage : javafx.stage.Stage) {
    val titledPane = new TitledPane()
    titledPane.setText("Expand me!")
    val label = new Label("Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.")
    label.setWrapText(true)
    titledPane.setContent(label)
    stage.setScene(new Scene(titledPane, 300, 300))
    stage.show()
  }
}

object TiltedTextExample extends App {
  javafx.application.Application.launch(classOf[TiltedTextExample])
}

在此示例中,TitledPane放置在VBox内部,以便可以添加多个TitlePanes并垂直堆叠。令人费解的是,这打破了自动换行的行为。

package nimrandsLibrary.fantasyCraft.characterBuilder

import javafx.scene.control._
import javafx.scene.layout._
import javafx.scene._

class TiltedTextExample extends javafx.application.Application {
  def start(stage : javafx.stage.Stage) {
    val titledPane = new TitledPane()
    titledPane.setText("Expand me!")
    val label = new Label("Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.")
    label.setWrapText(true)
    titledPane.setContent(label)
    val vBox = new VBox()
    vBox.getChildren().add(titledPane)
    stage.setScene(new Scene(vBox, 300, 300))
    stage.show()
  }
}

object TiltedTextExample extends App {
  javafx.application.Application.launch(classOf[TiltedTextExample])
}

2 个答案:

答案 0 :(得分:1)

我必须深入研究(查看JavaFX代码本身),但我找到了一个可行但不理想的解决方案。

问题基本上归结为这样一个事实,即TitledPane没有被编码为支持水平内容偏差(其最小/首选高度是根据其可用宽度计算的)。因此,即使它的内容,Label,支持这个功能,它由TitledPane渲染的mote,它计算它的最小和首选尺寸而不考虑另一个,在这种情况下,Label控件只需要一个显示所需的宽度和高度所有文字都在一行上。

要覆盖此行为,我必须覆盖三个函数,一个是TitledPane本身,一个是TitlePane的默认外观(实际上是TitledPane的维度计算)。首先,我重写getContentBias返回HORIZONTAL。然后,我重写getMinWidth返回0.最后,我更新皮肤的computePrefHeight函数,以便在询问其子项所需的高度时考虑可用的宽度。

以下是代码:

package nimrandsLibrary.fantasyCraft.characterBuilder

import javafx.scene.control._
import javafx.scene.layout._
import javafx.scene._

class TiltedTextExample extends javafx.application.Application {
  private def createTitledPane(title: String) = {
    val titledPane = new HorizontalContentBiasTitledPane()
    titledPane.setText(title)
    val label = new Label("Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.")
    label.setWrapText(true)
    titledPane.setContent(label)
    titledPane.setExpanded(false)
    titledPane
  }

  def start(stage: javafx.stage.Stage) {
    val vBox = new VBox()
    vBox.getChildren().add(createTitledPane("Expand Me #1"))
    vBox.getChildren().add(createTitledPane("Expand Me #2"))
    vBox.getChildren().add(createTitledPane("Expand Me #3"))
    stage.setScene(new Scene(vBox, 300, 300))
    stage.show()
  }
}

object TiltedTextExample extends App {
  javafx.application.Application.launch(classOf[TiltedTextExample])
}

class HorizontalContentBiasTitledPane extends javafx.scene.control.TitledPane {
  override def getContentBias() = javafx.geometry.Orientation.HORIZONTAL

  override def computeMinWidth(height: Double) = 0

  this.setSkin(new com.sun.javafx.scene.control.skin.TitledPaneSkin(this) {
    private val getTransitionMethod = classOf[com.sun.javafx.scene.control.skin.TitledPaneSkin].getDeclaredMethod("getTransition")
    getTransitionMethod.setAccessible(true)

    override protected def computePrefHeight(width: Double) = {
      val contentContainer = getChildren().get(0)
      val titleRegion = getChildren().get(1)
      val headerHeight = Math.max(com.sun.javafx.scene.control.skin.TitledPaneSkin.MIN_HEADER_HEIGHT, snapSize(titleRegion.prefHeight(-1)));
      var contentHeight = 0.0;
      if (getSkinnable().getParent() != null && getSkinnable().getParent().isInstanceOf[com.sun.javafx.scene.control.skin.AccordionSkin]) {
        contentHeight = contentContainer.prefHeight(width);
      } else {
        contentHeight = contentContainer.prefHeight(width) * getTransitionMethod.invoke(this).asInstanceOf[java.lang.Double].toDouble
      }
      headerHeight + snapSize(contentHeight) + snapSpace(getInsets().getTop()) + snapSpace(getInsets().getBottom());
    }
  })
}

这适用于我的用例,但有一些限制,其中一些可以解决,一些不能。

  • 这段代码很脆弱,因为它取决于Java FX的具体实现细节,特别是我必须在TitlePane的默认外观上调用私有方法的部分。我没有看到任何简单的方法来解决这个问题,除了在其enteritety中重新实现TitlePane的默认外观(我认为这并不太难,因为代码可用)。
  • 将TitlePane的minWidth限制为0可能会产生问题。根据用例,可能需要更强大的算法。
  • 同样,硬编码标题窗格对HORIZONTAL的内容偏差并不理想。更强大的解决方案是使用其内容的内容偏差,并根据内容偏差使控件的维度计算工作。

尽管存在局限性,但这段代码似乎对我有用,而且我认为使其更加健壮的修改相当简单。但是,如果任何人有一个不那么激烈的解决方案,或者可以改善我的解决方案,请提供帮助。

答案 1 :(得分:0)

使用文字代替标签。示例如下,

  @Override
  public void start(Stage primaryStage) {
    StackPane root = new StackPane();

    primaryStage.setScene(new Scene(root, 300, 250));

    primaryStage.setTitle("Hello World!");

    VBox vBox = new VBox();
    TitledPane tPane = new TitledPane();
    tPane.setText("expand me");
    tPane.setPrefWidth(root.getWidth());

    Text text = new Text();
    text.setText("Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.  Some really long text here.");
    text.setWrappingWidth(tPane.getPrefWidth());

    tPane.setContent(text);

    vBox.getChildren().add(tPane);

    root.getChildren().add(vBox);

    primaryStage.show();
}

javafx的标题栏将占用其子女的最大宽度。

<强>结果:

enter image description here