2015-10-02 9 views
0

我有一個在SceneBuilder中構建的FXML類,它是通過FXMLLoader與其關聯的控制器加載的。我已經在小部件的父面板上放置了一個帶有僞類的樣式類。 ToggleButton的樣式很好,但兩個標籤都沒有。CSS未級聯到標籤(JavaFX)

作爲一個測試,我試着直接給CSS類之一的標籤。行爲很有趣;它會在初始更改時採用,但在僞類更改時沒有更新文本顏色。

以下是從生產代碼中刪除的SCCEE。所有文件都直接在類路徑上。

CustomButton.fxml:

<?xml version="1.0" encoding="UTF-8"?> 

<?import javafx.scene.text.*?> 
<?import javafx.scene.layout.*?> 
<?import java.lang.*?> 
<?import javafx.scene.control.*?> 

<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="70.0" prefWidth="70.0" styleClass="custom-button" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="CustomButtonController"> 
    <children> 
     <ToggleButton fx:id="selectionToggle" mnemonicParsing="false" prefHeight="70.0" prefWidth="70.0" /> 
     <Label fx:id="dateLabel" alignment="TOP_LEFT" contentDisplay="TOP" layoutX="5.0" layoutY="5.0" mouseTransparent="true" prefHeight="25.0" prefWidth="60.0" styleClass="custom-button" text="Date" wrapText="true" /> 
     <Label fx:id="eventLabel" alignment="BOTTOM_LEFT" contentDisplay="BOTTOM" layoutX="5.0" layoutY="40.0" mouseTransparent="true" prefHeight="25.0" prefWidth="60.0" text="Event" wrapText="true" /> 
    </children> 
</Pane> 

CustomButtonController.java:

/** 
* Sample Skeleton for 'CustomButton.fxml' Controller Class 
*/ 

import java.net.URL; 
import java.util.ResourceBundle; 

import javafx.css.PseudoClass; 
import javafx.event.ActionEvent; 
import javafx.event.EventHandler; 
import javafx.fxml.FXML; 
import javafx.scene.Parent; 
import javafx.scene.control.Label; 
import javafx.scene.control.ToggleButton; 

public class CustomButtonController { 
    @FXML // ResourceBundle that was given to the FXMLLoader 
    private ResourceBundle resources; 
    @FXML // URL location of the FXML file that was given to the FXMLLoader 
    private URL location; 
    @FXML // fx:id="dateLabel" 
    private Label dateLabel; // Value injected by FXMLLoader 
    @FXML // fx:id="selectionToggle" 
    private ToggleButton selectionToggle; // Value injected by FXMLLoader 
    @FXML // fx:id="eventLabel" 
    private Label eventLabel; // Value injected by FXMLLoader 


    private Parent m_parent; 


    @FXML // This method is called by the FXMLLoader when initialization is complete 
    void initialize() { 
     assert dateLabel != null : "fx:id=\"dateLabel\" was not injected: check your FXML file 'CustomButton.fxml'."; 
     assert selectionToggle != null : "fx:id=\"selectionToggle\" was not injected: check your FXML file 'CustomButton.fxml'."; 
     assert eventLabel != null : "fx:id=\"eventLabel\" was not injected: check your FXML file 'CustomButton.fxml'."; 
    } 

    public void setParent(Parent parent) { 
     m_parent = parent; 

     selectionToggle.setOnAction(new EventHandler<ActionEvent>() { 
      @Override 
      public void handle(ActionEvent event) { 
       m_parent.pseudoClassStateChanged(PseudoClass.getPseudoClass("state2"), selectionToggle.isSelected()); 
       m_parent.applyCss(); 
      } 
     }); 
    } 
} 

Main.java:

import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.SwingUtilities; 

import javafx.application.Platform; 
import javafx.embed.swing.JFXPanel; 
import javafx.scene.Parent; 
import javafx.scene.Scene; 

public class Main implements Runnable { 

    @Override 
    public void run() { 
     JFrame frame = new JFrame("Test Frame"); 
     frame.setSize(800, 600); 

     JPanel panel = new JPanel(); 
     frame.setContentPane(panel); 

     FXMLLoader loader = new FXMLLoader(getClass().getResource("/CustomButton.fxml")); 
     Parent parent = loader.load(); 

     String cssString = getClass().getResource("/CustomButton.css").toExternalForm(); 
     parent.getStylesheets().add(cssString); 

     CustomButtonController cont = loader.<CustomButtonController>getController(); 
     cont.setParent(parent); 

     JFXPanel jfxPanel = new JFXPanel(); 
     jfxPanel.setScene(new Scene(parent)); 

     panel.add(jfxPanel); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       new JFXPanel(); 
       Platform.runLater(new Main()); 
      } 
     }); 
    } 
} 

CustomButton.css:

.custom-button:state2 { 
    -fx-base: cyan; 
    -fx-text-fill: red; 
    -fx-fill: yellow; 
    -fx-stroke: purple; 
} 

.custom-button { 
    -fx-base: green; 
    -fx-text-fill: blue; 
} 

結果(頂部是未選擇的,底部被選擇):

Result

注意,切換按鈕服從-fx基,日期標籤(其直接具有添加到它的CSS類)服從-fx -text-fill的初始顏色,但不會在選擇時更新),並且事件Label不會從CSS中獲取任何內容。

+0

是利用必要的僞類的?一個Node可以有任意多的樣式類,所以爲什麼不在CSS中使用像'.custom-button.state2'這樣的選擇器(句點代替冒號)呢? – VGR

+1

@VGR通常,僞類對於這種功能來說非常方便,因爲您不必擔心檢查您不會多次添加同一類。 –

+0

@James_D我不確定我會關注。無論是使用樣式類還是僞類,在將控件返回到正常狀態時,代碼仍然必須將其刪除。而在最糟糕的情況下,多次添加樣式類別不會有任何後果(除少量內存泄漏外)。我錯過了什麼? – VGR

回答

1

FXML將樣式類custom-button應用於窗格(fxml的根)和dateLabel。因此,從CSS樣式類persepctive層次結構看起來像

 
.custom-button 
    .toggle-button.button.labeled 
    .label.labeled.custom-button 
    .label.labeled 

從你的聽衆,選定了切換按鈕時,您設置根窗格的state2僞類。所以選擇時,層次結構看起來像

 
.custom-button:state2 
    .toggle-button.button.labeled 
    .label.labeled.custom-button 
    .label.labeled 
  • 僞類狀態不通過場景圖繼承。所以state2僞類狀態不會傳播到子節點。從查找到的顏色are propagated to the child nodes
  • 值, 的-fx-base這樣的值(這是一個查找到的顏色)被傳播 從父節點到子節點。
  • 屬性通常不會被繼承。有幾個specific exceptions,其中不包括-fx-text-fill

所以你描述的行爲是正常的給出你的代碼。該dateLabel得到一個藍色的文本填充,因爲它具有custom-button樣式類和-fx-text-fill: blue;直接應用到樣式類。在選擇按鈕時,沒有得到-fx-text-fill: red;,因爲它不具備僞類state2集(僅根元素有僞類)。fx-base的值應用於根節點,並且由於它是通過場景圖傳播的查找顏色。

你可以嘗試像

.custom-button { 
    -fx-base: green ; 
} 
.custom-button:state2 { 
    -fx-base: cyan ; 
} 
.custom-button .labeled { 
    -fx-text-fill: blue ; 
} 
.custom-button:state2 .labeled { 
    -fx-text-fill: red ; 
} 

得到你正在尋找的效果。

+0

請注意,樣式類應用於包含按鈕和兩個標籤的父窗格,並且將僞類IS傳播到按鈕(但不是通常的僞類或樣式類的事件標籤) 。查看-fx-base的結果。 – Ironcache

+0

我錯過了'自定義按鈕'也在根節點上聲明。相應地更新答案。 '-fx-base'的值傳播是因爲它是一種查找顏色,而不是因爲僞類狀態被傳播。 –

+0

好的,我明白你對僞類的看法。非常感謝你的澄清,這是一個很大的幫助。如果我理解正確,我注意到的行爲發生是因爲-fx-base是查找的顏色,但-fx-text-fill不是(因此爲什麼按鈕基礎正在更新,但事件標籤是不是)?爲什麼會出現這種情況,並且有什麼方法可以在將來驗證某種東西是查找顏色還是不是東西? – Ironcache

1

最後,我使用「inherit」來確保我的標籤從自定義父類中讀取-fx-text-fill。得到的CSS低於:

CustomButton.css:

.custom-button:state2 { 
    -fx-base: white; 
    -fx-text-fill: red; 
} 

.custom-button { 
    -fx-base: black; 
    -fx-text-fill: cyan; 
} 

.label { 
    -fx-text-fill: inherit; 
} 

它也通過定義查找顏色來完成。

CustomButton.css:

.custom-button:state2 { 
    -fx-base: white; 
    -labelColor: red; 
} 

.custom-button { 
    -fx-base: black; 
    -labelColor: cyan; 
} 

.label { 
    -fx-text-fill: -labelColor; 
}