问题
Thank you for your help. I've been trying to create a ribbon responsive layout like the one in Word, where the items resize one after another, and so far I haven't had much luck with it.
custom_control.fxml
<fx:root type="javafx.scene.layout.VBox" fx:id="dis" minHeight="-1.0" minWidth="-1.0" prefWidth="350.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2">
<GridPane fx:id="grid">
<children>
<Button text="Button" GridPane.columnIndex="0" GridPane.rowIndex="0" />
<RadioButton text="RadioButton" GridPane.columnIndex="1" GridPane.rowIndex="0" />
<Button onAction="#doSomething" text="Click Me" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<ComboBox GridPane.columnIndex="0" GridPane.rowIndex="1" />
<Slider GridPane.columnIndex="0" GridPane.rowIndex="2" />
<CheckBox text="CheckBox" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<TextField fx:id="textField" prefWidth="200.0" GridPane.columnIndex="0" GridPane.rowIndex="3" />
<MenuButton fx:id="mb" mnemonicParsing="false" text="" GridPane.columnIndex="1" GridPane.rowIndex="3">
<items>
<MenuItem mnemonicParsing="false" text="Action 1" />
<MenuItem mnemonicParsing="false" text="Action 2" />
</items>
</MenuButton>
</children>
<columnConstraints>
<ColumnConstraints hgrow="NEVER" maxWidth="+Infinity" minWidth="10.0" percentWidth="60.0" prefWidth="100.0" />
<ColumnConstraints hgrow="NEVER" maxWidth="+Infinity" minWidth="10.0" percentWidth="40.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
</GridPane>
</fx:root>
CustomController.java
public class CustomController extends VBox {
/**
* Initializes the controller class.
*/
@FXML private TextField textField;
@FXML private VBox dis;
@FXML private GridPane grid;
//dis.prefWidthProperty().bind(grid.widthProperty());
public CustomController() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("custom_control.fxml"));
fxmlLoader.setRoot(this);
fxmlLoader.setController(this);
try {
fxmlLoader.load();
} catch (IOException exception) {
throw new RuntimeException(exception);
}
}
public String getText() {
return textProperty().get();
}
public void setText(String value) {
textProperty().set(value);
}
public StringProperty textProperty() {
return textField.textProperty();
}
public void adaptWidth(double width) {
/*textField.textProperty().addListener((observable, oldValue, newValue) -> {
System.out.println("textfield changed from " + oldValue + " to " + newValue);
});*/
}
@FXML
protected void doSomething() {
System.out.println("The button was clicked!");
}
}
**RibbonJavaFX.java**
public class RibbonJavaFX extends Application {
@Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
HBox start = new HBox();
CustomController rib1= new CustomController();
rib1.setText("Ribbon 1");
CustomController rib2 = new CustomController();
rib2.setText("Ribbon 2");
CustomController rib3 = new CustomController();
rib3.setText("Ribbon 3");
start.getChildren().add(rib1);
start.getChildren().add(rib2);
start.getChildren().add(rib3);
rib3.prefWidthProperty().bind(rib2.widthProperty());
rib2.prefWidthProperty().bind(rib1.widthProperty());
Scene scene = new Scene(start,1800,400);
stage.setScene(scene);
//scene.getStylesheets().add(getClass().getResource("custom_control.css").toExternalForm());
stage.setTitle("Custom Control");
stage.setWidth(300);
stage.setHeight(200);
stage.show();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
So this is how my work looks so far. I've been trying to bind the 3 controllers together, but since it has to be made dynamic and for future use, because all controllers are the same, so they have to adapt to each other. My goal is to make them resize one after another, like the Word toolbar. Can somebody please help me with this? I don't expect a full answer, a hint is maybe all I need.
回答1:
Updated answer!
This answer uses a SplitPane
and an HBox
to accomplish the task. It grows the approapitate StackPane
depending the position of the SplitPane's
divider and the direction the divider is moving. You should be able to make a custom control using these ideas.
Main
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/**
*
* @author blj0011
*/
public class JavaFXApplication232 extends Application
{
@Override
public void start(Stage stage) throws Exception
{
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* @param args the command line arguments
*/
public static void main(String[] args)
{
launch(args);
}
}
Controller
import java.net.URL;
import java.util.ResourceBundle;
import java.util.concurrent.atomic.AtomicBoolean;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.SplitPane;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
/**
*
* @author blj0011
*/
public class FXMLDocumentController implements Initializable
{
@FXML
HBox hBox;
@FXML
SplitPane splitPane;
@FXML
AnchorPane anchorPane2;
@FXML
StackPane sp1, sp2, sp3, sp4;
double orgX, orgY;
double PANE_MIN_WIDTH = 0;
double PANE_STARTING_WIDTH = 200;
double PANES_TOTAL_WIDTH = 800;
AtomicBoolean initialMove = new AtomicBoolean(true);
@Override
public void initialize(URL url, ResourceBundle rb)
{
SplitPane.Divider divider = splitPane.getDividers().get(0);
divider.positionProperty().addListener((obs, oldValue, newValue) -> {
//System.out.println("oldValue: " + oldValue.doubleValue() + " newValue: " + newValue);
//System.out.println(anchorPane2.getWidth() + " :: " + (PANES_TOTAL_WIDTH - 2 * PANE_STARTING_WIDTH));
if (newValue.doubleValue() > oldValue.doubleValue() && !initialMove.get()) {
if (anchorPane2.getWidth() <= PANES_TOTAL_WIDTH && anchorPane2.getWidth() > PANES_TOTAL_WIDTH - PANE_STARTING_WIDTH) {
sp1.setMinWidth(PANE_MIN_WIDTH);
sp1.setMaxWidth(anchorPane2.getWidth() - (PANES_TOTAL_WIDTH - PANE_STARTING_WIDTH));
}
else if (anchorPane2.getWidth() <= (PANES_TOTAL_WIDTH - PANE_STARTING_WIDTH) && anchorPane2.getWidth() > (PANES_TOTAL_WIDTH - 2 * PANE_STARTING_WIDTH)) {
sp2.setMinWidth(PANE_MIN_WIDTH);
sp2.setMaxWidth(anchorPane2.getWidth() - (PANES_TOTAL_WIDTH - 2 * PANE_STARTING_WIDTH));
}
else if (anchorPane2.getWidth() <= (PANES_TOTAL_WIDTH - 2 * PANE_STARTING_WIDTH) && anchorPane2.getWidth() > (PANES_TOTAL_WIDTH - 3 * PANE_STARTING_WIDTH)) {
sp3.setMinWidth(PANE_MIN_WIDTH);
sp3.setMaxWidth(anchorPane2.getWidth() - (PANES_TOTAL_WIDTH - 3 * PANE_STARTING_WIDTH));
}
}
else if (newValue.doubleValue() < oldValue.doubleValue()) {
if (anchorPane2.getWidth() < (PANES_TOTAL_WIDTH - 3 * PANE_STARTING_WIDTH)) {
sp4.setMaxWidth(PANE_STARTING_WIDTH);
sp4.setMinWidth(anchorPane2.getWidth());
}
else if (anchorPane2.getWidth() < (PANES_TOTAL_WIDTH - 2 * PANE_STARTING_WIDTH) && anchorPane2.getWidth() >= (PANES_TOTAL_WIDTH - 3 * PANE_STARTING_WIDTH)) {
sp3.setMaxWidth(PANE_STARTING_WIDTH);
sp3.setMinWidth(anchorPane2.getWidth() - PANE_STARTING_WIDTH);
}
else if (anchorPane2.getWidth() < (PANES_TOTAL_WIDTH - PANE_STARTING_WIDTH) && anchorPane2.getWidth() >= (PANES_TOTAL_WIDTH - 2 * PANE_STARTING_WIDTH)) {
sp2.setMaxWidth(PANE_STARTING_WIDTH);
sp2.setMinWidth(anchorPane2.getWidth() - 2 * PANE_STARTING_WIDTH);
}
else if (anchorPane2.getWidth() <= PANES_TOTAL_WIDTH && anchorPane2.getWidth() >= (PANES_TOTAL_WIDTH - PANE_STARTING_WIDTH)) {
sp1.setMaxWidth(PANE_STARTING_WIDTH);
sp1.setMinWidth(anchorPane2.getWidth() - 3 * PANE_STARTING_WIDTH);
}
}
initialMove.set(false);//Used becase of the first pass, the AnchorPane's width = 0
});
}
}
FXML
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.SplitPane?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<SplitPane fx:id="splitPane" dividerPositions="0.0" prefHeight="160.0" prefWidth="808.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication232.FXMLDocumentController">
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" />
<AnchorPane fx:id="anchorPane2" maxWidth="1.7976931348623157E308" minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="800.0">
<children>
<HBox fx:id="hBox" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="203.0" prefWidth="800.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<StackPane fx:id="sp1" maxWidth="200.0" minWidth="0.0" prefWidth="200.0" style="-fx-background-color: green;" />
<StackPane fx:id="sp2" maxWidth="200.0" minWidth="200.0" prefWidth="200.0" style="-fx-background-color: blue;" />
<StackPane fx:id="sp3" maxWidth="200.0" minWidth="200.0" prefWidth="200.0" style="-fx-background-color: yellow;" />
<StackPane fx:id="sp4" maxWidth="200.0" minWidth="200.0" prefWidth="200.0" style="-fx-background-color: brown;" />
</children>
</HBox>
</children>
</AnchorPane>
</items>
</SplitPane>
来源:https://stackoverflow.com/questions/51602566/javafx-dynamic-resizing