【问题标题】:How to add border to panel of javafx?如何为javafx面板添加边框?
【发布时间】:2013-06-21 18:11:22
【问题描述】:

我正在开发一个应用程序,我需要一些小部件来包装在面板中。我想在它周围加上一个边框。我是一个 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);

【问题讨论】:

    标签: java javafx-2


    【解决方案1】:

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

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

    这是complete executable sample

    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;
    }
    

    【讨论】:

      【解决方案2】:

      我创建了扩展 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。它给出了以下结果。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-12-29
        • 2017-10-14
        • 2011-09-14
        • 2010-10-11
        • 1970-01-01
        • 2020-03-07
        • 1970-01-01
        相关资源
        最近更新 更多