【问题标题】:How to lock Parent Window in JavaFx when Jasper Report is visible in popup当 Jasper Report 在弹出窗口中可见时如何在 JavaFx 中锁定父窗口
【发布时间】:2019-10-27 16:51:39
【问题描述】:

为了在 JavaFX 11 中创建 Jasper 报告,我使用的是动态报告。当我单击按钮 Jasper Report 打开并在弹出窗口中可见时。但是我可以根据需要多次单击该按钮,并且报告将打开这些次数。但是一旦jasper报告可见,我想锁定父窗口,以便只有在关闭弹出窗口后才能访问父窗口。正如question 中所解释的,我们可以在父窗口和子窗口中实现同样的事情,但我想用 Parent 实现类似的事情,因为我的舞台和孩子是 Jasper 窗口。下面提到了相同的代码:-

JavaFxJasperReportsDemo.java

package demo;

import java.util.ArrayList;
import java.util.List;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import net.sf.dynamicreports.jasper.builder.JasperReportBuilder;
import net.sf.dynamicreports.report.builder.DynamicReports;
import net.sf.dynamicreports.report.builder.column.Columns;
import net.sf.dynamicreports.report.builder.component.Components;
import net.sf.dynamicreports.report.builder.datatype.DataTypes;
import net.sf.dynamicreports.report.constant.HorizontalTextAlignment;
import net.sf.dynamicreports.report.exception.DRException;

public class JavaFxJasperReportsDemo extends Application{

    @FXML
    private StackPane stackPane;

    public void start(Stage stage) throws Exception{

        try{
            Parent root = FXMLLoader.load(getClass().getResource("/FXMLJavaFXJasperReportsDemo.fxml"));
            Scene scene = new Scene(root);
            stage.setScene(scene);
            stage.setTitle("Java FX Demo");
            stage.show();
            stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
                public void handle(WindowEvent arg0) {
                    Platform.exit();
                }
            });
        }
        catch (Exception e){
            throw e;
        }
    }

    @FXML
    public void loadReport(ActionEvent event) {
        JasperReportBuilder report = DynamicReports.report();
        List<DemoPOJO> lstDemoPOJOs=new ArrayList<DemoPOJO>();
        DemoPOJO demoPOJO=new DemoPOJO();
        demoPOJO.setName("ABC");
        demoPOJO.setCity("Delhi");
        lstDemoPOJOs.add(demoPOJO);
        demoPOJO = new DemoPOJO();
        demoPOJO.setName("XYZ");
        demoPOJO.setCity("Agra");
        lstDemoPOJOs.add(demoPOJO);
        report
        .columns(
                Columns.columnRowNumberColumn("S No"),
                Columns.column("Name", "name", DataTypes.stringType()),
                Columns.column("Address", "city", DataTypes.stringType())
                ).title(
                        Components.text("Demo Java Fx Jasper Reports").
                        setHorizontalTextAlignment(HorizontalTextAlignment.CENTER))
        .pageFooter(Components.pageXofY())
        .setDataSource(lstDemoPOJOs);
        try {
            report.show(false);
        } catch (DRException e) {
            e.printStackTrace();
        }

    }

    public static void main(String[] args){
        try{
            launch(args);
        }
        catch (Exception e){
            e.printStackTrace();
        }
    }
}

【问题讨论】:

  • 您可以使用像 github.com/mgrecol/JasperViewerFx 这样的 JavaFx 查看器。比设置Modality.WINDOW_MODAL
  • @Raw 您能否展示一个示例以及如何在现有 JavaFx 项目中使用 JasperViewerFx。是否有任何 maven 依赖项或相同的任何外部 jar 文件
  • 您可以下载源代码并将它们添加到您的项目中,只需更改JRViewerFx-&gt;start() 函数。添加primaryStage.initOwner(owner); primaryStage.initModality(Modality.WINDOW_MODAL);

标签: javafx jasper-reports


【解决方案1】:

到目前为止,我还没有基于父窗口“可达性”的解决方案。但我可以为您提供一个替代解决方案,不允许用户多次单击。这个想法是在您按下按钮后立即禁用场景的根节点,并仅在报告窗口关闭时启用它。不确定这是否符合您的目的。

reportButton.setOnAction(e -> {
    // Get root node of the scene
    Node sceneRoot = ((Node)e.getTarget()).getScene().getRoot();

    // First things first, disable it !!
    sceneRoot.setDisable(true);

    // Your actual method for showing report
    loadReport(e);
    
    // Get all current AWT windows.
    java.awt.Window[] windows = java.awt.Window.getWindows();

    // Get the recently added window (your report window) and add a close listener.
    windows[windows.length-1].addWindowListener(new java.awt.event.WindowAdapter() {
        public void windowClosing(java.awt.event.WindowEvent evt) {
            // When the window is closed, enable your root node.
            sceneRoot.setDisable(false);
        }
    });
});

注意:JasperReportBuilder 的 JasperViewer 的内部实现是一个 JFrame。

[更新]

完整的工作演示如下:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import net.sf.dynamicreports.jasper.builder.JasperReportBuilder;
import net.sf.dynamicreports.report.builder.DynamicReports;
import net.sf.dynamicreports.report.builder.column.Columns;
import net.sf.dynamicreports.report.builder.component.Components;
import net.sf.dynamicreports.report.builder.datatype.DataTypes;
import net.sf.dynamicreports.report.constant.HorizontalAlignment;
import net.sf.dynamicreports.report.exception.DRException;

import java.util.ArrayList;
import java.util.List;

public class JavaFxJasperReportsDemo extends Application {

    @FXML
    private StackPane stackPane;

    public void start(Stage stage) throws Exception {

        try {
            StackPane root = new StackPane();
            ContextMenu cm = new ContextMenu();
            cm.getItems().addAll(new MenuItem("Test1"), new MenuItem("Test2"));
            Button reportButton = new Button("Report");
            reportButton.setContextMenu(cm);
            reportButton.setOnAction(e -> {
                // Get root node of the scene
                Node sceneRoot = ((Node) e.getTarget()).getScene().getRoot();

                // First things first, disable it !!
                sceneRoot.setDisable(true);

                // Your actual method for showing report
                loadReport(e);

                // Get all current AWT windows.
                java.awt.Window[] windows = java.awt.Window.getWindows();

                // Get the recently added window (your report window) and add a listener.
                windows[windows.length - 1].addWindowListener(new java.awt.event.WindowAdapter() {
                    public void windowClosing(java.awt.event.WindowEvent evt) {
                        // When the window is closed, enable your root node.
                        sceneRoot.setDisable(false);
                    }
                });
            });
            root.getChildren().add(reportButton);
            Scene scene = new Scene(root, 200, 200);
            stage.setScene(scene);
            stage.setTitle("Java FX Demo");
            stage.show();
            stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
                public void handle(WindowEvent arg0) {
                    Platform.exit();
                }
            });


        } catch (Exception e) {
            throw e;
        }
    }

    @FXML
    public void loadReport(ActionEvent event) {
        JasperReportBuilder report = DynamicReports.report();
        List<DemoPOJO> lstDemoPOJOs = new ArrayList<DemoPOJO>();
        DemoPOJO demoPOJO = new DemoPOJO();
        demoPOJO.setName("ABC");
        demoPOJO.setCity("City 1");
        lstDemoPOJOs.add(demoPOJO);
        demoPOJO = new DemoPOJO();
        demoPOJO.setName("XYZ");
        demoPOJO.setCity("City 2");
        lstDemoPOJOs.add(demoPOJO);
        report
                .columns(
                        Columns.columnRowNumberColumn("S No"),
                        Columns.column("Name", "name", DataTypes.stringType()),
                        Columns.column("Address", "city", DataTypes.stringType())
                ).title(
                Components.text("Demo Java Fx Jasper Reports").
                        setHorizontalAlignment(HorizontalAlignment.CENTER))
                //.pageFooter(Components.pageXofY())
                .setDataSource(lstDemoPOJOs);
        try {
            report.show(false);
        } catch (DRException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        try {
            launch(args);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

【讨论】:

  • 如果父窗口有上下文菜单,即使在执行 sceneRoot.setDisable(false); 之后,上下文菜单在打开时仍将保持禁用状态。
  • @RenojJoseph,我尝试设置 ContextMenu 并检查,看起来它按预期工作?或者我错过了什么。用我正在工作的演示更新了答案。你能告诉我 ContextMenu 的设置方式和位置吗?
  • 如果动作的来源是一个按钮,一切都很好。但就我而言,我的窗口有一个按钮和一个带有上下文菜单的表格视图。单击按钮时,整个表格将显示在 jasper 查看器中。关闭碧玉查看器后,如果我打开表格视图的上下文菜单,它将毫无问题地处于活动状态。单击时,我的表视图上下文菜单将在 jasper 查看器中打开所选行的详细信息(例如发票)。在这种情况下,如果我在关闭 jasper 查看器后重新打开上下文菜单,上下文菜单将被禁用。
  • 我稍微修改了您的代码,以便禁用所有打开的窗口,jasper 查看器应始终位于顶部,并将修改后的代码发布为下面的答案。
  • @RenojJoseph,我对你提到的工作流程有点不清楚。我的第一直觉是它不应该与这个实现有任何联系。话虽如此,如果您能提供用例的完整工作示例,我们可以进行调查。
【解决方案2】:

这是 Sai Dandem 发布的内容的修改代码。它将禁用所有打开的 javafx 窗口,并且 jasper 查看器将始终位于顶部。当 jasper 查看器关闭时,所有窗口都将启用。

public class MakeJasperViewerAsModalWindow {

    public MakeJasperViewerAsModalWindow(JasperViewer jasperViewer) {

        jasperViewer.setAlwaysOnTop(true);

        final java.awt.Window[] windows = java.awt.Window.getWindows();
        final List<Window> windowsfx = Window.getWindows();
        windowsfx.stream().forEach(o -> {

            o.getScene().getRoot().setDisable(true);
        });

        windows[windows.length - 1].addWindowListener(new java.awt.event.WindowAdapter() {

            @Override
            public void windowClosing(java.awt.event.WindowEvent evt) {

                windowsfx.stream().forEach(o -> {

                    o.getScene().getRoot().setDisable(false);
                });
            }
        });
    }
}

可以用作new MakeJasperViewerAsModalWindow(jasperViewer);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-01
    • 2019-03-18
    • 2017-06-30
    • 1970-01-01
    • 2012-09-20
    • 2013-06-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多