Gluon Glisten框架View首次显示时lookup调用失败问题
Gluon Charm Glisten框架View首次加载时Lookup操作失效问题
问题表现
- 非首页View首次触发
onShown生命周期事件时,调用节点lookup/lookupAll方法查询样式类匹配节点会返回空集合 - 离开该View后再次进入时,相同的lookup逻辑可正常返回目标节点
- 若将该View设置为应用
HOME_VIEW,首次触发onShown事件时lookup可正常执行
最小复现代码
主应用类 MyApplication.java
import static com.gluonhq.charm.glisten.application.AppManager.*; import javafx.application.Application; import javafx.stage.Stage; import com.gluonhq.charm.glisten.application.AppManager; import com.gpsdemo.view.View1; import com.gpsdemo.view.View2; public class MyApplication extends Application { AppManager appManager = AppManager.initialize(); public static final String VIEW1 = HOME_VIEW; public static final String VIEW2 = "View2"; @Override public void init() { appManager.addViewFactory(VIEW1, View1::get); appManager.addViewFactory(VIEW2, View2::get); } @Override public void start(Stage stage) throws Exception { appManager.start(stage); if (com.gluonhq.attach.util.Platform.isDesktop()) { stage.setHeight(600); stage.setWidth(360); stage.centerOnScreen(); } } public static void main(String args[]) { launch(args); } }
首页视图 View1.java
import javafx.scene.control.Label; import com.gluonhq.charm.glisten.control.AppBar; import com.gluonhq.charm.glisten.mvc.View; import com.gluonhq.charm.glisten.visual.MaterialDesignIcon; import com.gpsdemo.MyApplication; public class View1 extends View { private static View1 INSTANCE; public static View1 get() { return INSTANCE != null ? INSTANCE : (INSTANCE = new View1()); } private View1() { setCenter(new Label("Nothing to see here")); } @Override protected void updateAppBar(AppBar appBar) { appBar.setTitleText("View1"); var optionsButton = MaterialDesignIcon.MENU.button(e -> getAppManager().switchView(MyApplication.VIEW2)); appBar.getActionItems().add(optionsButton); } }
测试问题视图 View2.java
import java.util.Set; import javafx.beans.property.SimpleDoubleProperty; import javafx.scene.Node; import com.gluonhq.charm.glisten.control.AppBar; import com.gluonhq.charm.glisten.control.SettingsPane; import com.gluonhq.charm.glisten.control.settings.DefaultOption; import com.gluonhq.charm.glisten.mvc.View; import com.gluonhq.charm.glisten.visual.MaterialDesignIcon; public class View2 extends View { private static View2 INSTANCE; public static View2 get() { return INSTANCE != null ? INSTANCE : (INSTANCE = new View2()); } private View2() { var settingsPane = new SettingsPane(); var option = new DefaultOption<>("Title", "Description", "Category", new SimpleDoubleProperty(), true); settingsPane.getOptions().add(option); setCenter(settingsPane); setOnShown(e -> { System.out.println("On shown"); Set<Node> lookup = settingsPane.lookupAll(".secondary-graphic"); System.out.println(lookup); }); } @Override protected void updateAppBar(AppBar appBar) { appBar.setTitleText("View2"); var backButton = MaterialDesignIcon.ARROW_BACK.button(e -> getAppManager().switchToPreviousView().get()); appBar.setNavIcon(backButton); } }
复现流程
- 启动应用,默认加载展示
View1 - 点击View1顶部AppBar的菜单按钮切换到
View2,首次进入时控制台输出如下:
On shown []
此时lookupAll(".secondary-graphic")返回空集合,查询失败
3. 点击View2顶部的返回按钮回到View1,再次切换进入View2,控制台输出如下:
On shown [HBox@2c8d8a10[styleClass=secondary-graphic]]
此时lookup操作可正常获取到样式类匹配的目标节点
环境信息
<javafx-maven-plugin-version>0.0.8</javafx-maven-plugin-version> <gluonfx-maven-plugin-version>1.0.14</gluonfx-maven-plugin-version> <java-version>17</java-version> <javafx-version>18.0.1</javafx-version> <charm-version>6.1.0</charm-version>
解决方案
问题本质是onShown事件触发时,非首页加载的View内部复杂控件(如SettingsPane)还未完成皮肤加载、CSS应用和布局渲染,内部子节点尚未挂载到场景图上,直接执行lookup自然无法获取结果。
将lookup逻辑放入Platform.runLater()中执行,延迟到JavaFX下一次渲染脉冲完成、所有节点挂载完毕后再查询,即可保证首次进入View时lookup正常返回结果,修改View2的onShown回调代码如下:
setOnShown(e -> { System.out.println("On shown"); // 延迟到场景完成布局渲染后执行查询 javafx.application.Platform.runLater(() -> { Set<Node> lookup = settingsPane.lookupAll(".secondary-graphic"); System.out.println(lookup); // 此处编写节点后续配置逻辑 }); });
该方案兼容所有View加载场景,无需修改框架源码,可稳定解决首次加载时lookup失效的问题。
内容的提问来源于stack exchange,提问作者user1803551
相关产品推荐
相关产品推荐

