Home > other >  How to make a non-blocking PrinterJob pageDialog in Java?
How to make a non-blocking PrinterJob pageDialog in Java?

Time:07-28

Below is code to create a simple window with a useless button in it and a PrintingJob that automatically opens a page dialog when the program starts:

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());
  }
}

Current behavior: The page dialog blocks user inputs to the rest of the application - it's not possible to click or move the application window.

Wanted behavior: The page dialog shall not block user inputs to the rest of the application - it shall be possible to click and move the application window.

From what I can see pageDialog() creates a WPageDialog which extends Dialog and is hardcoded to set modal=true, aka it blocks user input to other top-level windows when shown. I essentially want modal=false such that user input to other top-level windows are not blocked by the dialog, but this is not immediately modifiable.

Running the pageDialog in it's own thread does not resolve the issue.

Is there some nifty workaround for this to achieve the wanted behavior?

CodePudding user response:

Here is an example of creating a ServiceDialog explicitly, which doesn't block the origin JFrame (or anything really).

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");
    }
}

Something that probably shouldn't be done. The example at the bottom starts a separate process with jshell running and creates the print dialog. The original gui stays responsive.

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();
    
  }
}    
  • Related