无法将 CSS 应用于 MouseEvent 上以编程方式创建的窗格
Trouble applying CSS to programatically created Pane on MouseEvent
我有一个堆栈窗格,当鼠标进入时,我创建一个窗格,在其中粘贴一些文本,并在鼠标附近显示它。
StatisticsController.java
stackPane.setOnMouseEntered(event -> {
Pane pane = new Pane();
Text text = new Text("Example Text");
//Add the text to the pane and set it near the mouse
pane.getChildren().add(text);
pane.setLayoutY(event.getSceneY() - 50);
pane.setLayoutX(event.getSceneX() - 100);
//add the style class to give it a blueBG background
pane.getStyleClass().add("blueBG");
// add it too our root
getRoot().getChildren().add(pane);
});
正如您在下面看到的,当我在 stackPane 上滚动时出现 Pane 和文本(图像中的黑色圆圈和问号)。
但是它没有我要找的蓝色背景。
我觉得奇怪的是,如果我没有将它添加到根,而是将它添加到现有的 Vbox,它的样式正确(这里我滚动相同的 stackPane):
所以:
//Styles Correctly
getInfoBox().getChildren().add(pane);
// Adds but does not style
getRoot().getChildren().add(pane);
一些可能值得注意的事情:
1)getInfoBox() 是静态的getter。我有多个控制器,它们扩展了一个 MasterController,它具有静态实例变量到所有控制器都希望能够访问的东西——比如 infoBox,以显示信息。
2) 根是在 Main class:
中创建的 BorderPane
Main.java
//Create the root
BorderPane root = new BorderPane();
// I've cut it out to save space but this repeats 4 times to set
//an .fxml file for the top, left, right and bottom of the borderPane ///
FXMLLoader headerLoader = new FXMLLoader(getClass().getResource("/view/header.fxml"));
Parent headerRoot = headerLoader.load();
root.setTop(headerRoot);
//------------------------------------------//
//Set the static reference in the MasterController
MasterController.setRoot(root);
Scene scene = new Scene(root,1366,768);
primaryStage.setScene(scene);
primaryStage.show();
3) css 文件都是使用 Scene Builder 在 .fxml 文件中声明的。顶部、底部、左侧、右侧的 .fxml 文件都具有相同的 css (main.css)。按钮上加载的 statistic.fxml 也单击到中心(您可以在图像中看到)
建议:会不会是因为CSS不是为Scene或BorderPane本身定义的,它只适用于添加到borderPane部分的节点?如果是这样,我将如何让输入 Scene/Stage 使用相同的 css,这是否会否定将 css 添加到每个 .fxml?
编辑:
将此代码添加到主程序以将 CSS 应用到场景时:
Scene scene = new Scene(root,1366,768);
scene.getStylesheets().add(getClass().getResource("/css/main.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
我明白了:
所以文本的 CSS 现在可以使用了,但窗格不行?我不知道为什么会这样。
// ---- 繁殖 -- //
Main.java
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
BorderPane bp = new BorderPane();
MasterController.setRoot(bp);
Parent left = FXMLLoader.load(getClass().getResource("left.fxml"));
Parent right = FXMLLoader.load(getClass().getResource("right.fxml"));
bp.setLeft(left);
bp.setRight(right);
Scene scene = new Scene(bp, 600, 400);
scene.getStylesheets().add(getClass().getResource("main.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
MasterController.java
package sample;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
public class MasterController {
private static VBox rightBox;
private static BorderPane root;
public static VBox getRightBox() {
return rightBox;
}
public static void setRightBox(VBox rightBox) {
MasterController.rightBox = rightBox;
}
public static BorderPane getRoot() {
return root;
}
public static void setRoot(BorderPane root) {
MasterController.root = root;
}
}
LeftController.java
package sample;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import java.io.IOException;
public class LeftController extends MasterController {
@FXML
public void loadCenter(ActionEvent event) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("center.fxml"));
Parent center = loader.load();
getRoot().setCenter(center);
} catch (IOException e){
e.printStackTrace();
}
}
}
CenterController.java
package sample;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
public class CenterController extends MasterController {
@FXML
private VBox center;
public void initialize() {
Platform.runLater(this::build);
}
public void build() {
center.getChildren().add(new Text("loaded"));
StackPane stackPane = new StackPane();
Text text = new Text("ROLL OVER");
stackPane.getChildren().add(text);
center.getChildren().add(stackPane);
stackPane.setOnMouseEntered(event -> {
getRightBox().getChildren().clear();
Pane pane1 = new Pane();
Text exampleText1 = new Text("Example Text");
pane1.getStyleClass().add("blueBG");
Pane pane2 = new Pane();
Text exampleText2 = new Text("Example Text");
pane2.getStyleClass().add("blueBG");
pane1.getChildren().add(exampleText1);
pane2.getChildren().add(exampleText2);
pane1.setLayoutY(event.getSceneY() + 40);
pane1.setLayoutX(event.getSceneX() - 40);
getRoot().getChildren().add(pane1);
getRightBox().getChildren().add(pane2);
});
}
}
RightController.java
包装样品;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.layout.VBox;
public class RightController extends MasterController {
@FXML
private VBox rightBox;
public void initialize() {
setRightBox(rightBox);
}
}
left.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.LeftController">
<children>
<Button mnemonicParsing="false" onAction="#loadCenter" prefHeight="38.0" prefWidth="200.0" text="Click me to load center" />
</children>
</VBox>
center.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import javafx.scene.layout.*?>
<VBox fx:id="center" alignment="TOP_CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="200.0" stylesheets="@main.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.CenterController">
<children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Center" />
</children>
</VBox>
right.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import javafx.scene.layout.*?>
<VBox fx:id="rightBox" alignment="TOP_CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="200.0" stylesheets="@main.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.RightController">
<children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Right Box" />
</children>
</VBox>
main.css
.blueBG {
-fx-background-color: aqua;
}
您应该得到以下结果。您可以看到窗格在添加到右侧时样式正确,但添加到根时则不是。
BorderPane
仅将布局应用于 center
、left
、right
、top
和 bottom
子级。然而,在布局过程中设置 Region
大小的布局(或根场景中的场景)的父级(或不设置,就像在本例中一样)。
结果是样式应用于 Pane
,但 Pane
的大小保持 0
。您可以通过添加
来验证这一点
pane1.resize(100, 100);
到事件处理程序以设置窗格的大小。
您需要使用不同类型的布局作为父级布局以使 pane1
的大小变为非空或自行调整大小。
我有一个堆栈窗格,当鼠标进入时,我创建一个窗格,在其中粘贴一些文本,并在鼠标附近显示它。
StatisticsController.java
stackPane.setOnMouseEntered(event -> {
Pane pane = new Pane();
Text text = new Text("Example Text");
//Add the text to the pane and set it near the mouse
pane.getChildren().add(text);
pane.setLayoutY(event.getSceneY() - 50);
pane.setLayoutX(event.getSceneX() - 100);
//add the style class to give it a blueBG background
pane.getStyleClass().add("blueBG");
// add it too our root
getRoot().getChildren().add(pane);
});
正如您在下面看到的,当我在 stackPane 上滚动时出现 Pane 和文本(图像中的黑色圆圈和问号)。
但是它没有我要找的蓝色背景。
我觉得奇怪的是,如果我没有将它添加到根,而是将它添加到现有的 Vbox,它的样式正确(这里我滚动相同的 stackPane):
所以:
//Styles Correctly
getInfoBox().getChildren().add(pane);
// Adds but does not style
getRoot().getChildren().add(pane);
一些可能值得注意的事情:
1)getInfoBox() 是静态的getter。我有多个控制器,它们扩展了一个 MasterController,它具有静态实例变量到所有控制器都希望能够访问的东西——比如 infoBox,以显示信息。
2) 根是在 Main class:
中创建的 BorderPaneMain.java
//Create the root
BorderPane root = new BorderPane();
// I've cut it out to save space but this repeats 4 times to set
//an .fxml file for the top, left, right and bottom of the borderPane ///
FXMLLoader headerLoader = new FXMLLoader(getClass().getResource("/view/header.fxml"));
Parent headerRoot = headerLoader.load();
root.setTop(headerRoot);
//------------------------------------------//
//Set the static reference in the MasterController
MasterController.setRoot(root);
Scene scene = new Scene(root,1366,768);
primaryStage.setScene(scene);
primaryStage.show();
3) css 文件都是使用 Scene Builder 在 .fxml 文件中声明的。顶部、底部、左侧、右侧的 .fxml 文件都具有相同的 css (main.css)。按钮上加载的 statistic.fxml 也单击到中心(您可以在图像中看到)
建议:会不会是因为CSS不是为Scene或BorderPane本身定义的,它只适用于添加到borderPane部分的节点?如果是这样,我将如何让输入 Scene/Stage 使用相同的 css,这是否会否定将 css 添加到每个 .fxml?
编辑:
将此代码添加到主程序以将 CSS 应用到场景时:
Scene scene = new Scene(root,1366,768);
scene.getStylesheets().add(getClass().getResource("/css/main.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
我明白了:
所以文本的 CSS 现在可以使用了,但窗格不行?我不知道为什么会这样。
// ---- 繁殖 -- //
Main.java
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
BorderPane bp = new BorderPane();
MasterController.setRoot(bp);
Parent left = FXMLLoader.load(getClass().getResource("left.fxml"));
Parent right = FXMLLoader.load(getClass().getResource("right.fxml"));
bp.setLeft(left);
bp.setRight(right);
Scene scene = new Scene(bp, 600, 400);
scene.getStylesheets().add(getClass().getResource("main.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
MasterController.java
package sample;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
public class MasterController {
private static VBox rightBox;
private static BorderPane root;
public static VBox getRightBox() {
return rightBox;
}
public static void setRightBox(VBox rightBox) {
MasterController.rightBox = rightBox;
}
public static BorderPane getRoot() {
return root;
}
public static void setRoot(BorderPane root) {
MasterController.root = root;
}
}
LeftController.java
package sample;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import java.io.IOException;
public class LeftController extends MasterController {
@FXML
public void loadCenter(ActionEvent event) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("center.fxml"));
Parent center = loader.load();
getRoot().setCenter(center);
} catch (IOException e){
e.printStackTrace();
}
}
}
CenterController.java
package sample;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
public class CenterController extends MasterController {
@FXML
private VBox center;
public void initialize() {
Platform.runLater(this::build);
}
public void build() {
center.getChildren().add(new Text("loaded"));
StackPane stackPane = new StackPane();
Text text = new Text("ROLL OVER");
stackPane.getChildren().add(text);
center.getChildren().add(stackPane);
stackPane.setOnMouseEntered(event -> {
getRightBox().getChildren().clear();
Pane pane1 = new Pane();
Text exampleText1 = new Text("Example Text");
pane1.getStyleClass().add("blueBG");
Pane pane2 = new Pane();
Text exampleText2 = new Text("Example Text");
pane2.getStyleClass().add("blueBG");
pane1.getChildren().add(exampleText1);
pane2.getChildren().add(exampleText2);
pane1.setLayoutY(event.getSceneY() + 40);
pane1.setLayoutX(event.getSceneX() - 40);
getRoot().getChildren().add(pane1);
getRightBox().getChildren().add(pane2);
});
}
}
RightController.java 包装样品;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.scene.layout.VBox;
public class RightController extends MasterController {
@FXML
private VBox rightBox;
public void initialize() {
setRightBox(rightBox);
}
}
left.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.LeftController">
<children>
<Button mnemonicParsing="false" onAction="#loadCenter" prefHeight="38.0" prefWidth="200.0" text="Click me to load center" />
</children>
</VBox>
center.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import javafx.scene.layout.*?>
<VBox fx:id="center" alignment="TOP_CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="200.0" stylesheets="@main.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.CenterController">
<children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Center" />
</children>
</VBox>
right.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import javafx.scene.layout.*?>
<VBox fx:id="rightBox" alignment="TOP_CENTER" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="200.0" stylesheets="@main.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.RightController">
<children>
<Text strokeType="OUTSIDE" strokeWidth="0.0" text="Right Box" />
</children>
</VBox>
main.css
.blueBG {
-fx-background-color: aqua;
}
您应该得到以下结果。您可以看到窗格在添加到右侧时样式正确,但添加到根时则不是。
BorderPane
仅将布局应用于 center
、left
、right
、top
和 bottom
子级。然而,在布局过程中设置 Region
大小的布局(或根场景中的场景)的父级(或不设置,就像在本例中一样)。
结果是样式应用于 Pane
,但 Pane
的大小保持 0
。您可以通过添加
pane1.resize(100, 100);
到事件处理程序以设置窗格的大小。
您需要使用不同类型的布局作为父级布局以使 pane1
的大小变为非空或自行调整大小。