Refresh printers in Java while application is running

后端 未结 4 921
心在旅途
心在旅途 2021-01-18 12:45

As the title says, I would like to refresh the printers that are registered in the settings of the computer while my Java application is running. Normally, I can use P

相关标签:
4条回答
  • 2021-01-18 13:22

    A quick workaround is for CUPS-based systems is:

    System.setProperty("sun.java2d.print.polling", "false");
    

    Warning, this has the side-effect of gradually slowing down calls (e.g. 80ms) to PrintServiceLookup.lookupPrintServices(...).

    Specifically:

    Property sun.java2d.print.polling set to true:

    • <1ms to call PrintServiceLookup.lookupPrintServices(...)

    Property sun.java2d.print.polling set to false:

    • 80ms to call PrintServiceLookup.lookupPrintServices(...)

    Although 80ms is a very short amount of time for most UI, in a high-load scenario this can affect performance.

    Furthemore, this 80ms gradually increases over time. For example, 100,000 calls to PrintServiceLookup.lookupPrintServices(...) gradually increases the delay from 80ms to 1,000ms. Long-running programs may experience a noticeable delay.

    That said, this delay is still prefered over the AppContext workaround, especially on CUPS systems (Linux, Mac). The AppContext provided in other solutions introduces JVM threading issues that eventually cause 2,000ms delays, and at times up to 200,000ms delays (reference: https://github.com/qzind/tray/issues/479)

    Detailed bug report: https://github.com/AdoptOpenJDK/openjdk-build/issues/1212

    0 讨论(0)
  • 2021-01-18 13:33

    I'm not sure what you were expecting. Here's the output for my Windows Vista laptop running Java 7.

    Number of servies found: 3
    --> Available Printer 0: Win32 Printer : PamFax
    --> Available Printer 1: Win32 Printer : Microsoft XPS Document Writer
    --> Available Printer 2: Win32 Printer : CutePDF Writer
    x
    Number of servies found: 3
    --> Available Printer 0: Win32 Printer : PamFax
    --> Available Printer 1: Win32 Printer : Microsoft XPS Document Writer
    --> Available Printer 2: Win32 Printer : CutePDF Writer
    

    Printer services don't change every 5 minutes, even on a shared network.

    Updated based on the comment:

    Your Java application will have to have to be stopped and started to get the updated list of printers.

    I guess I don't understand your environment. In the places I've worked, all of the printers have been defined on the network long before we ever wrote any code. Printer changes were rarely (i mean once a year) made.

    0 讨论(0)
  • 2021-01-18 13:38

    There is no need to restart the application in order to refresh the list of print services.

    Here I found the solution:

    /**
     * Printer list does not necessarily refresh if you change the list of 
     * printers within the O/S; you can run this to refresh if necessary.
     */
    public static void refreshSystemPrinterList() {
        Class<?>[] classes = PrintServiceLookup.class.getDeclaredClasses();
        for (Class<?> clazz : classes) {
            if ("javax.print.PrintServiceLookup$Services".equals(clazz.getName())) {
                // sun.awt.AppContext.getAppContext().remove(clazz);
                // Use reflection to avoid "Access restriction" error message
                try {
                    Class<?> acClass = Class.forName("sun.awt.AppContext");
                    Object appContext = acClass.getMethod("getAppContext").invoke(null);
                    acClass.getMethod("remove", Object.class).invoke(appContext, clazz);
                } catch (Exception e) {
                }
                break;
            }
        }
    }
    

    Basically, the static class PrintServiceLookup.Services maintains the list of print services. So, if you remove this class from the AppContext, you force PrintServiceLookup to create a new instance again. Thus, the list of print services gets refreshed.

    0 讨论(0)
  • 2021-01-18 13:39

    I have encountered the same problem before and after multiple tests, it seems like the printer list is snapshotted at the start of the Java application and can't be refreshed after that using java's lookupPrintServices().

    What I did to solve that problem is call directly the Winspool API using JNA. If you intend to do so, the Winspool API is well documented by Microsoft : Winspool API documentation

    Also, I described a part of my solution to a problem I had a few month ago in this question, it might help you understand JNA and the Winspool API.

    0 讨论(0)
提交回复
热议问题