【问题标题】:How to make a non-blocking PrinterJob pageDialog in Java?如何在 Java 中制作非阻塞 PrinterJob pageDialog?
【发布时间】:2022-07-27 19:41:31
【问题描述】:

下面是创建一个简单窗口的代码,其中包含一个无用的按钮和一个在程序启动时自动打开页面对话框的 PrintingJob:

import java.awt.BorderLayout;
import java.awt.print.PrinterJob;
import javax.swing.JButton;
import javax.swing.JFrame;

public class DummyCode {
  public static void main(String[] args) {
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().add(new JButton(\"TEST\"), BorderLayout.CENTER);
    frame.pack();
    frame.setVisible(true);
    PrinterJob pj = PrinterJob.getPrinterJob();
    pj.pageDialog(pj.defaultPage());
  }
}

当前行为:页面对话框阻止用户对应用程序其余部分的输入 - 无法单击或移动应用程序窗口。

想要的行为:页面对话框不应阻止用户对应用程序其余部分的输入 - 应该可以单击和移动应用程序窗口。

从我所看到的pageDialog() 创建了一个WPageDialog,它扩展了Dialog 并被硬编码为设置modal=true,也就是当显示时它会阻止用户输入到其他顶级窗口。我本质上想要 modal=false 这样用户对其他顶级窗口的输入不会被对话框阻止,但这不能立即修改。

在自己的线程中运行页面对话框并不能解决问题。

是否有一些巧妙的解决方法可以实现所需的行为?

  • 令人印象深刻的是对话框是模态的,但它从来没有附加顶级 JFrame/Window。为什么你希望对话框是“非阻塞的”?
  • “对于聪明的工程师来说,最大的陷阱之一就是优化不应该存在的东西。”——埃隆·马斯克
  • @matt 因为应用程序的性质和用途。我不想谈任何细节。
  • 我已更新我的答案以显示如何以非模态方式显示 ServiceDialog。

标签: java swing


【解决方案1】:

这是一个显式创建 ServiceDialog 的示例,它不会阻止原始 JFrame(或任何真正的东西)。

mport sun.print.ServiceDialog;

import javax.print.DocFlavor;
import javax.print.PrintService;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.swing.JButton;
import javax.swing.JFrame;
import java.awt.BorderLayout;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.print.PrinterJob;

public class TestPrint {

    public static void main(String[] args) throws Exception{
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JButton test = new JButton("TEST");
        test.addActionListener(evt -> System.out.println("action!"));

        frame.getContentPane().add(test, BorderLayout.CENTER);
        frame.pack();
        frame.setVisible(true);

        final GraphicsConfiguration gc =
            GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
        PrintService service = PrinterJob.getPrinterJob().getPrintService();
        ServiceDialog log = new ServiceDialog(gc, 500, 500, service, DocFlavor.SERVICE_FORMATTED.PAGEABLE, new HashPrintRequestAttributeSet(), frame);
        log.setModal(false);
        log.setVisible(true);
        System.out.println("waiting");
    }
}

可能不应该做的事情。底部的示例启动了一个运行 jshell 的单独进程并创建了打印对话框。原始 gui 保持响应。

import java.awt.BorderLayout;
import java.awt.print.PrinterJob;
import java.awt.Dialog;
import javax.swing.JButton;
import javax.swing.JFrame;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
public class DummyCode {

    static void drain(Process proc) throws Exception{
        InputStream is = proc.getInputStream();
        InputStreamReader reader = new InputStreamReader( is, "UTF8");
        new Thread( ()->{
            char[] buffer = new char[512];
            try{
                int read = reader.read(buffer, 0, 512);
                while(read >= 0 ){
                    System.out.println( new String(buffer, 0, read ) );
                    read = reader.read(buffer, 0, 512);
                }            
            } catch(IOException e){
                e.printStackTrace();
            } 
        } ).start();     
    }

  public static void main(String[] args) throws Exception{
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JButton test = new JButton("TEST");
    test.addActionListener(evt -> System.out.println("action!"));
    
    frame.getContentPane().add(test, BorderLayout.CENTER);
    frame.pack();
    frame.setVisible(true);
    Process proc = Runtime.getRuntime().exec("/usr/bin/jshell");
    
    drain(proc);
    
    OutputStream os = proc.getOutputStream();
    OutputStreamWriter writer = new OutputStreamWriter( os, "UTF8" );
    writer.write( "import java.awt.print.PrinterJob;\n");
    writer.write( "PrinterJob pj = PrinterJob.getPrinterJob();\n");
    writer.write( "pj.pageDialog(pj.defaultPage());\n");
    writer.flush();
    
  }
}    

【讨论】:

  • 有些事情可能不应该做。呵呵,我同意。我也考虑过这种方法——这是一个很好的尝试!从技术上讲,这可能会解决我的问题,但实际上我怀疑它是否可以使用。我想我会玩弄它,看看它是怎么回事。
  • 哦,现在我明白了,很好的发现!愚蠢的我忽略了您在之前的评论中提到的 ServiceDialog 方法,因为我忽略了“setModal”方法。我试试看,谢谢
猜你喜欢
  • 2021-09-27
  • 2016-08-26
  • 2018-01-04
  • 2014-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多