[英]Get visible state of Node in JavaFX 8
我需要檢測當前是否正在顯示節點。 即如果我的節點在 TabPane 中,我需要知道它是否在選定的選項卡中。
在示例中,我想知道 HBox 何時顯示。Node 的 visibleProperty 和 managedProperty 似乎對我沒有幫助:
public class VisibleTest extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
TabPane tabpane = new TabPane();
tabpane.getTabs().add(new Tab("Tab1", new Label("Label1")));
HBox hbox = new HBox(new Label("Label2"));
hbox.setStyle("-fx-background-color: aquamarine;");
hbox.visibleProperty().addListener((observable, oldValue, newValue) -> {
System.out.println("Hbox visible changed. newValue: " + newValue);
});
hbox.managedProperty().addListener((observable, oldValue, newValue) -> {
System.out.println("Hbox managed changed. newValue: " + newValue);
});
Tab tab2 = new Tab("tab2", hbox);
tabpane.getTabs().add(tab2);
primaryStage.setScene(new Scene(tabpane));
primaryStage.setWidth(600);
primaryStage.setHeight(500);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
我知道,可以在選項卡的selectedProperty
state 上監聽,但這並不能解決我的實際問題。
Node.impl_isTreeVisible()
做我想做的事,但這是 depricated API。
有任何想法嗎?
- - - - - - - - - - - - - - - - - - 更新 - - - - - - - ------
我意識到上面的代碼示例並沒有很好地解釋我想要完成的事情。
下面是一些 Swing 代碼,它演示了我在 JavaFX 中試圖完成的工作。檢測 JComponent/Node 是否可見/顯示,並基於該 state,啟動或停止后台進程。 如果它是 javaFX class,構造函數會是什么樣子。
public class SwingVisible extends JComponent {
String instanceNR;
Thread instanceThread;
boolean doExpensiveStuff = false;
public SwingVisible(String instanceNR) {
this.instanceNR = instanceNR;
this.setLayout(new FlowLayout());
this.add(new JLabel(instanceNR));
instanceThread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (doExpensiveStuff) {
/*
* do expensive stuff.
*/
System.out.println(instanceNR + " is visible " + isVisible());
}
}
}
});
/*
* How to do this in FX?
*/
addComponentListener(new ComponentAdapter() {
@Override
public void componentShown(ComponentEvent e) {
if (!instanceThread.isAlive()) {
instanceThread.start();
}
doExpensiveStuff = true;
}
@Override
public void componentHidden(ComponentEvent e) {
doExpensiveStuff = false;
}
});
}
public static void main(String[] args) {
/*
* This block represents code that is external to my library. End user
* can put instances of SwingVisible in JTabbedPanes, JFrames, JWindows,
* or other JComponents. How many instances there will bee is not in my
* control.
*/
JTabbedPane jtp = new JTabbedPane();
jtp.add("tab1", new SwingVisible("1"));
jtp.add("tab2", new SwingVisible("2"));
jtp.add("tab3", new SwingVisible("3"));
JFrame f = new JFrame("test");
f.setContentPane(jtp);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(300, 300);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
選擇 tab1 時為 Output:
1 可見 true
1 可見 true
1 可見 true
...
選擇 tab2 時為 Output:
2可見真
2可見真
2可見真
...
您可以使用Tab
的selectedProperty
來確定它是否被選中,如果其內容可見,則可以使用擴展名。 它是一個布爾屬性。
我已根據您的初始JavaFX示例將Swing代碼轉換為JavaFX:
public class VisibleTest extends Application {
public class FXVisible extends Tab {
FXVisible(String id) {
super(id, new Label(id));
Timeline thread = new Timeline(
new KeyFrame(Duration.ZERO, e -> {
if (isSelected()) {
// do expensive stuff
System.out.println(id + " is visible");
}
}),
new KeyFrame(Duration.seconds(1))
);
thread.setCycleCount(Timeline.INDEFINITE);
selectedProperty().addListener((selectedProperty, wasSelected, isSelected) -> {
if (isSelected) {
if (thread.getStatus() != Status.RUNNING) {
System.out.println(id + " starting thread");
thread.play();
}
}
// else, it is not selected -> content not shown
});
}
}
@Override
public void start(Stage primaryStage) throws Exception {
TabPane tabpane = new TabPane();
tabpane.getTabs().add(new FXVisible("1"));
tabpane.getTabs().add(new FXVisible("2"));
tabpane.getTabs().add(new FXVisible("3"));
// add as many as you want
primaryStage.setScene(new Scene(tabpane));
primaryStage.setWidth(600);
primaryStage.setHeight(500);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
我用JavaFX Timeline
替換了你的線程。 你的問題不是關於這個話題,所以我不會在這里詳細介紹,盡管它是自我解釋的。
我不明白為什么在Swing示例中你有一個監聽器更改一個布爾值來指示組件是否可見,當你可以直接在線程中調用isVisible()
(請參閱下面的注釋以獲取有關線程的注釋)。 這就是為什么在上面的代碼中我采用了直接檢查isSelected()
的方法,沒有自我聲明的布爾值。 如果你需要恢復你的設計,那就相當簡單了。 只是注意到這一點是為了清晰。
可以使用selectedProperty()
上的更改偵聽器替換ComponentListener
並查詢新值。 只需確保您的示例執行它應該執行的操作:第一次選擇選項卡時,線程/計時器將啟動。 之后,線程/計時器什么都不做。 您可能想要暫停非顯示內容的計算。 再次,只是注意到它,因為它似乎是我的潛在錯誤,否則你很好。
更新的答案。
tab2.getContent().isVisible();
在我看來,我的原始答案是正確的。 如果沒有,您需要以更好的方式提出問題。 您想知道何時hbox可見(意味着您可以在屏幕上看到hbox)。
tabpane.getSelectionModel().selectedItemProperty().addListener((obsVal, oldTab, newTab)->{
System.out.println(newTab.getText());
if(newTab.getText().equals("tab2"))
{
//You can use this code to set the hbox visibility, that way you can force the behavior you are looking for.
hbox.setVisible(true);
System.out.println("hbox is visible!");
}
else
{
//You can use this code to set the hbox visibility, that way you can force the behavior you are looking for.
hbox.setVisible(false);
System.out.println("hbox is not visible!");
}
});
從快速檢查來看,這似乎適用於檢查 window 是否正在顯示以及它所在的選項卡是否正在顯示。 我也檢查過,對於可折疊的帶標題的窗格,它似乎也能按預期工作。
public static boolean detectVisible( Node node )
{
Node current = node;
while( current != null ) {
if( !current.isVisible() ) {
return false;
}
current = current.getParent();
}
Window window = Optional.of( node ).map( Node::getScene ).map( Scene::getWindow ).orElse( null );
if( window == null ) {
return false;
}
if( window instanceof Stage && ( (Stage) window ).isIconified() ) {
return false;
}
return window.isShowing();
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.