11

我正在开发一个应用程序,我需要一些小部件来包装在面板内。我想在它周围加上一个边框。我是一个 swt 程序员,在复合中我可以通过 swt.border 来放置边框。但是如何在 JavaFX 中做到这一点。对此的任何帮助表示赞赏。

代码:

Label Center=new Label();
Center.setText("Center Frequency");

GridPane.setConstraints(Center, 0, 0);
tb1[i].getChildren().add(Center);
TextField text=new TextField();
GridPane.setConstraints(text, 1, 0);
tb1[i].getChildren().add(text);

Label chiprate=new Label();
chiprate.setText("Chiprate");

GridPane.setConstraints(chiprate, 0, 1);
tb1[i].getChildren().add(chiprate);
TextField chip=new TextField();
GridPane.setConstraints(chip, 1, 1);
tb1[i].getChildren().add(chip);

Label frequency=new Label();
frequency.setText("Frequency deviation");

GridPane.setConstraints(frequency, 0, 2);
tb1[i].getChildren().add(frequency);
TextField frequencydeviation=new TextField();
GridPane.setConstraints(frequencydeviation, 1, 2);
tb1[i].getChildren().add(frequencydeviation);

Label outputLabel=new Label();
outputLabel.setText("Output Power");

GridPane.setConstraints(outputLabel, 0, 3);
tb1[i].getChildren().add(outputLabel);
TextField output=new TextField();
GridPane.setConstraints(output, 1, 3);
tb1[i].getChildren().add(output);
4

2 回答 2

22

我创建了BorderedTitledPane一个在内容周围放置标题边框的类。

如果您不需要标题,则在事物周围放置边框会更容易 - 只需在区域(例如)上设置css 边框参数。-fx-border-color: black;

这是一个完整的可执行示例

带边框的标题窗格

import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;

/** Places content in a bordered pane with a title. */
public class BorderedTitledPane extends StackPane {
  private StringProperty title = new SimpleStringProperty();
  private ObjectProperty<Node> graphic = new SimpleObjectProperty<>();
  private ObjectProperty<Node> content = new SimpleObjectProperty<>();
  private ObjectProperty<Pos>  titleAlignment = new SimpleObjectProperty<>();
  // todo other than TOP_LEFT other alignments aren't really supported correctly, due to translation fudge for indentation of the title label in css => best to implement layoutChildren and handle layout there.
  // todo work out how to make content the default node for fxml so you don't need to write a <content></content> tag.

  public BorderedTitledPane() {
    this("", null);
  }

  public BorderedTitledPane(String titleString, Node contentNode) {
    final Label titleLabel = new Label();
    titleLabel.textProperty().bind(Bindings.concat(title, " "));
    titleLabel.getStyleClass().add("bordered-titled-title");
    titleLabel.graphicProperty().bind(graphic);

    titleAlignment.addListener(new InvalidationListener() {
      @Override
      public void invalidated(Observable observable) {
        StackPane.setAlignment(titleLabel, titleAlignment.get());
      }
    });

    final StackPane contentPane = new StackPane();

    getStyleClass().add("bordered-titled-border");
    getChildren().addAll(titleLabel, contentPane);

    content.addListener(new InvalidationListener() {
      @Override
      public void invalidated(Observable observable) {
        if (content.get() == null) {
          contentPane.getChildren().clear();
        } else {
          if (!content.get().getStyleClass().contains("bordered-titled-content")) {
            content.get().getStyleClass().add("bordered-titled-content");  // todo would be nice to remove this style class when it is no longer required.
          }
          contentPane.getChildren().setAll(content.get());
        }
      }
    });

    titleAlignment.set(Pos.TOP_LEFT);
    this.title.set(titleString);
    this.content.set(contentNode);
  }

  public String getTitle() {
    return title.get();
  }

  public StringProperty getTitleStringProperty() {
    return title;
  }

  public void setTitle(String title) {
    this.title.set(title);
  }

  public Pos getTitleAlignment() {
    return titleAlignment.get();
  }

  public ObjectProperty<Pos> titleAlignmentProperty() {
    return titleAlignment;
  }

  public void setTitleAlignment(Pos titleAlignment) {
    this.titleAlignment.set(titleAlignment);
  }

  public Node getContent() {
    return content.get();
  }

  public ObjectProperty<Node> contentProperty() {
    return content;
  }

  public void setContent(Node content) {
    this.content.set(content);
  }

  public Node getGraphic() {
    return graphic.get();
  }

  public ObjectProperty<Node> graphicProperty() {
    return graphic;
  }

  public void setGraphic(Node graphic) {
    this.graphic.set(graphic);
  }
}

相关的 CSS。

.bordered-titled-title {
  -fx-translate-x:  8;
  -fx-translate-y: -10;
  -fx-padding: 0 0 0 4;
  -fx-background-color: -fx-background;
}

.bordered-titled-border {
  -fx-content-display: top;
  -fx-border-insets: 2 0 0 0;
  -fx-border-color: -fx-text-box-border;
  -fx-border-width: 2;
}

.bordered-titled-content {
  -fx-padding: 18 5 5 5;
}
于 2013-06-25T05:22:43.893 回答
0

我创建了扩展 StackPane 的 TitledBorderedPane 类。我使用 Shape 对象来创建 Rectangle 和 Text。该类包含一个包含内容的容器 StackPane 对象。以下代码是不言自明的。

import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.shape.Shape;
import javafx.scene.text.Text;

public class TitledBorderedPane extends StackPane{

    private final StackPane container;

    private final Group shapeGroup = new Group();
    private final Rectangle rect;
    private final Rectangle rectRemove;
    private final Text title;

    public TitledBorderedPane(String titleText) {
        
        container = new StackPane();

        //Rectangle to create border
        //Initial size of the rectangle is not important 
        //as it is set with action listener.
        rect = new Rectangle(0, 0, 200, 200);
        rect.setStroke(Color.BLACK);
        rect.setFill(null);
        rect.setStrokeWidth(1);
        rect.setArcWidth(10.0);
        rect.setArcHeight(10.0);

        //Border title text               
        title = new Text(20.0, 4.0, titleText);        

        //Rectangle to remove part of the border to fit the text
        rectRemove = new Rectangle(15, -2, title.getBoundsInLocal().getWidth() + 10, 5);

        //Set padding of the container, so the content of the container 
        //does not overlap the border
        container.setPadding(new Insets(title.getBoundsInLocal().getHeight() + 5));

        super.getChildren().addAll(shapeGroup, container);

        //Add action listeners to width and height properties 
        widthProperty().addListener(
                (observable, oldvalue, newvalue) -> {
                    rect.setWidth((double)newvalue - title.getBoundsInLocal().getHeight());
                    setShape();
                }
        );
        heightProperty().addListener(
                (observable, oldvalue, newvalue) -> {
                    rect.setHeight((double)newvalue - title.getBoundsInLocal().getHeight());
                    setShape();
                }
        );

        //The style should not be used here. I have used it only for the example.
        setStyle("-fx-background-color: rgba(0, 100, 100, 0.5); -fx-background-radius: 0;");
    }

    private void setShape() {        
        Shape shape = Shape.subtract(rect, rectRemove);
        shape.setSmooth(true);
        shapeGroup.getChildren().clear();
        shapeGroup.getChildren().addAll(shape, title);
    }

    /**
     * Returns ObservableList of the container pane
     *
     * @return
     */
    @Override
    public ObservableList<Node> getChildren() {
        return container.getChildren();
    }

}

该类可以用作普通的 StackPane。它给出了以下结果。

TitledBorderedPane 显示两个实例

于 2022-01-06T20:57:54.633 回答