ixmal

10 posts

Window size vs Scene size


The javafx.scene.Scene class is responsible for rendering JavaFX 2.0 content. A scene can be placed into various containers, for example, javafx.stage.Stage orjavafx.embed.swing.JFXPanel. The size of a container may be or may not be equal to the size of the scene attached to it. In some cases you might want to specify the content size, e.g. when showing a confirmation dialog: the size of the window doesn't really matter, because its only purpose is to show visual content. In other cases, however, you might need to explicitly set a window size: imagine a floating palette panel that should be aligned with the main stage.

Let's examine some common scenarios.

1. Window width and height are known

Use the width and height properties of thejavafx.stage.Window class:
    Screen screen = Screen.getPrimary();
    rectangle2D bounds = screen.getVisualBounds();
    stage.setX(0);
    stage.setY(0);
    stage.setWidth(bounds.getWidth() / 2);
    stage.setHeight(bounds.getHeight() / 2);
    stage.setScene(scene);
    stage.setVisible(true);

2. Content dimensions are known

Just leave your window's width and heightunassigned and set the size of the scene instead:
    Scene scene = new Scene(root, 320, 240);
    stage.setScene(scene);
    stage.setVisible(true);

Scene width and height can be hardcoded as shown in the previous example, or they can calculated based on the scene's content:
    Scene scene = new Scene(root);
    root.getChildren().add(new Button("I'm a JavaFX button"));
    stage.setScene(scene);
    stage.setVisible(true);

As a result, the window size exactly fits the size of the button:



3. Using the default platform width and height

Sometimes you don't want to specify window size at all. Although it's quite tricky in JavaFX 2.0, you still can implement it. You should neight explicitly set window width and height properties, nor place any content into your scene before the window is shown: 
    BorderPane pane = new BorderPane();
    Scene scene = new Scene(pane);
    stage.setScene(scene);
    stage.setVisible(true);
    // After the stage is shown, populate the scene
    pane.setCenter(new WebView(new WebEngine("http://weblogs.java.net")));

More hints


Some hints you might find useful:

  • Window and content dimensions can be combined together. For example, you can set window width explicitly and calculate its height based on the scene's height.
  • Window location conforms to the same rules as a window size: you can either set its x and y coordinates, or place some content and let JavaFX center your window in the screen, or let the native platform place the window to default location.
  • javafx.embed.swing.JFXPanel as a scene container also inherits its size and forwards it to Swing. Therefore, if your layout manager respects components' preferred sizes, the JFXPanel component will be sized to fit JavaFX content in it.

JavaFX 2.0 Beta is out on May 26, 2011. There are many blogs posted about it already, http://fxexperience.com/ is the primary one, and I don't want to post yet another overview of what features are available. Instead, I would like to take a deeper tour into one particular component called JFXPanel

What is JFXPanel?


JavaFX 1.x provided a way to insert existing Swing components into FX scenes. It was neither declared a feature, nor it was supported perfectly. With the introduction of Prism, a new graphics stack for FX, which is completely untied from AWT and Swing, the embedding has become just impossible. However, it makes much more sense to use FX content in Swing, because there are so many existing Swing applications and so many exciting FX features. The good news is that using FX in Swing is now possible and, which is more important, officially supported via public API:javafx.embed.swing.JFXPanel.

Sample code


JFXPanel JavaDoc includes a short template how it should be used. Here it is:
 
     public class Test {

         private static void initAndShowGUI() {
             // This method is invoked on Swing thread
             JFrame frame = new JFrame("FX");
             final JFXPanel fxPanel = new JFXPanel();
             frame.add(fxPanel);
             frame.setVisible(true);

             Platform.runLater(new Runnable() {
                 @Override
                 public void run() {
                     initFX(fxPanel);
                 }
             });
         }

         private static void initFX(JFXPanel fxPanel) {
             // This method is invoked on JavaFX thread
             Scene scene = createScene();
             fxPanel.setScene(scene);
         }

         public static void main(String[] args) {
             SwingUtilities.invokeLater(new Runnable() {
                 @Override
                 public void run() {
                     initAndShowGUI();
                 }
             });
         }
    }

Let's examine this sample. The main() method uses a standard pattern to move initialization to Event Dispatch Thread usingSwingUtilities.invokeLater(). JFXPanel creation is not interesting as well: it's a regular JComponent and therefore must be created on EDT only. If no FX content is attached to the panel, it's painted as a rectangle filled with a default background color, which is probably not what we need, so let's move to the most important part.

JavaFX 2.0 has its own threading model, which is described, for example, here: http://weblogs.java.net/blog/opinali/archive/2011/05/28/javafx-20-beta-first-impressions. Yes, JavaFX 2.0 is a multi-threaded library, but application developers should only care about one thread called "JavaFX Application Thread". This is the thread where all events are handled, all animations are performed and all scenegraph nodes should be created and mutated. To run your code on this thread,Platform.runLater() should be used, and we see this call in our code.

JFXPanel is a container for an FX scene. In a regular JavaFX application, developers create Scene objects and attach them to top-level windows with Stage.setScene() calls. JFXPanel provides exactly the same API: its setScene() method should be used to attach a Scene. This method is designed carefully, so it can be used both from EDT and FX application thread.

Events and painting

Fine, we've just created an FX scene and attached it to a JFXPanel. What's next? How can I paint FX content in my JFXPanel? How input events are handled? If you ask questions like these, I have a good news: you don't need to bother about all that! Input events are forwarded from Swing to FX automatically and then can be handled using exactly the same API as any other FX events. When FX content is changed, it's painted into Swing automatically. What you do need to care about is threading: every time you need to operate with Swing components, SwingUtilities.invokeLater() is your friend, while Platform.runLater() is the way to work with FX objects. That's it!

JFXPanel can also calculate its preferred size based on FX content. If you create the scene with
 
    Scene scene = new Scene(parent, 200, 200);

or
 
    Scene scene = new Scene(group);
    group.getChildren().add(new Rectangle(50, 50, 150, 150));

the panel preferred size will be 200 x 200 pixels. Of course, your app will benefit from this only if the layout manager used respects component's preferred sizes.

Ah, yes, there's one more JFXPanel feature to mention. It's completely lightweight. What does it mean? See the screenshot where transparent JFXPanel is placed over Swing button:


Recently, I got a new desktop, and the first thing I started with was building JDK. Approximately at the same time I got an image of a new operating system by Microsoft (beta version) and started testing it. So, the natural idea was to combine these efforts. Unluckily, I decided to install the 64-bi ]]>
Windows 7 installation went successfully, without any problems, cygwin didn't bring any unpleasant surprises as well. The next step was to install the compiler - VS 2008 Express Edition, the only available at the moment a Visual Studio product that, nevertheless, is not supported by JDK yet. I selected the 7.0a version as the Platform SDK, which also was provided by Windows 7.

Just a minor reservation: I set the environment variable INSANE to yes while building the system. This variable enables ignoring some non-critical building bugs that inevitably appear on non-supported platforms. For the other typical cases, I wouldn't modify the default value of INSANE (no or undefined).

So, the building started. A few seconds of waiting and:

windows i586 1.7.0-internal build started

Ooops? What's up? I wanted the 64-bit building! For some reasons JDK considered my desktop 32-bit, therefore, I had to force 64-bit by specifying ARCH_DATA_MODEL=64.

Restart. This time the building process lasted a little bit longer:

C:/PROGRA~2/MICROS~1.0/VC/bin/X86_AM~1/cl -O1 -Zi -nologo -MD /D _STATIC_CPPLIB -Fdc:/work/ie-build-64/tmp/java/hpi/windows_ threads/obj64/linker_md.pdb -Fmc:/work/ie-build-64/tmp/java/hpi/windows_threads/obj64/linker_md.map -wd4800 -Wp64 -W3 -DWIN32 -DIAL -D_LITTLE_ENDIAN -D_X86_ -Dx86 -DWIN32_LEAN_AND_MEAN -I. -Ic:/work/ie-build-64/tmp/java/hpi/windows_threads/CClassHeader s -I../../../../src/windows/javavm/export -I../../../../src/share/javavm/export -I../../../../src/windows/hpi/include -I../../.. /../src/windows/hpi/export -I../../../../src/share/hpi/include -I../../../../src/share/hpi/export -c -Foc:/work/ie-build-64/t mp/java/hpi/windows_threads/obj64/linker_md.obj ../../../../src/windows/hpi/src/linker_md.c
cl : Command line warning D9035 : option 'Wp64' has been deprecated and will be removed in a future release
linker_md.c
C:\PROGRA~1\MICROS~1\Windows\v6.1\INCLUDE\winnt.h(128) : fatal error C1189: #error : "No Target Architecture"
make[3]: *** [c:/work/ie-build-64/tmp/java/hpi/windows_threads/obj64/linker_md.obj] Error 2
make[3]: Leaving directory `/cygdrive/c/work/ws/ie/make/java/hpi/windows'
make[2]: *** [all] Error 1
make[2]: Leaving directory `/cygdrive/c/work/ws/ie/make/java/hpi'
make[1]: *** [all] Error 1
make[1]: Leaving directory `/cygdrive/c/work/ws/ie/make/java'
make: *** [all] Error 1

What? Wait a minute... Why -D_X86_ and -Dx86? There is something wrong... I started exploring the whole log and discovered the following:

build windows ia64 1.7.0-internal started

But "ia64" is the Itanium architecture, not what I intended to build. Interesting, can I build JDK on Itanium? I'd better leave it to someone else to test. :) The wrong architecture problem was resolved by specifying the PROCESSOR_IDENTIFIER variable to AMD64 (this issue has been already resolved in the very latest JDK builds). Restarted again:

C:/PROGRA~2/MICROS~1.0/VC/bin/X86_AM~1/link -dll -out:c:/work/ie-build-64/tmp/java/verify/obj64/verify.dll \ -map:c:/work/ie-build-64/tmp/java/verify/obj64/verify.map \ -nologo /opt:REF /incremental:no /manifest /debug /LIBPATH:c:/work/devtools/dxsdk9/Lib/x64 @c:/work/ie-build-64/tmp/java/verify/obj64/verify.lcf c:/work/ie-build-64/lib/jvm.lib
LINK : fatal error LNK1104: cannot open file 'c:/work/ie-build-64/lib/jvm.lib'
make[2]: *** [c:/work/ie-build-64/bin/verify.dll] Error 80
make[2]: Leaving directory `/cygdrive/c/work/ws/ie/make/java/verify'
make[1]: *** [all] Error 1
make[1]: Leaving directory `/cygdrive/c/work/ws/ie/make/java'
make: *** [all] Error 1

There is something wrong with the lib/jvm.lib file in the build directory. Is this file on the disk? It is... Well, but what is in this file? Aha, "access denied" on a preview attempt. Now I see why the linker doesn't find this file. But what is still unclear to me, why this file has such strange security permissions.

Frankly speaking, I almost stuck on this step... After one and a half day I found a brief, just a few pages, description of the CYGWIN variable. And - what a miracle! - it helped. I set its value to nontsec and made all files created by cygwin obtain permissions according to the NTFS model, not POSIX. It is stated that I might encounter the same problem on Vista as well, or may be even on XP or 2000 when using NTFS. I didn't try building on Vista, but it works fine on XP.

The next restart revealed the absence of the msvcr90.dll file in the system directory C:\Windows\System32. Unfortunately, I cannot provide the exact log for this error: for some reasons subsequent builds do not crash on this step. However, I can suggest the solution: you need to set up the following environment variable:

ALT_MSVCRNN_DLL_PATH=/redist/amd64/Microsoft.VC90.CRT

One and a half hour more - why building on Windows takes so much time? - and, voila, JDK is done. It's time to relax a little, to test, for instance, to run some demos.

$ bin/java -showversion -jar demo/jfc/Java2D/Java2Demo.jar

Error occurred during initialization of VM
java/lang/NoClassDefFoundError: java/lang/Object

Well... It's not time for relaxing yet... Having thought I decided that it is because of the wrong HotSpot version I used for building. I used Visual Studio 2008 while the promoted build for HotSpot is built by using Visual Studio 2003. Therefore, let's build the virtual machine.

I have to admit that after building JDK and setting all the required variable, the process of HotSpot building went surprisingly well. Several errors related to the data structure redefinition and appeared in a new version of Platform SKD had been fixed, so all I had to do was just to get them from the hotspot space. After the build is complete, you need to take jvm.dll for server, in case of 64-bit implementation, or client with server, in case of 32-bit implementation, and copy it to the bin directory of the built JDK.

Finally, a couple of words about 32 bits. The following is a to-do list for the successful building procedure:

  • 1a. Set ARCH_DATA_MODEL=32
    or
  • 1b. Set PROCESSOR_IDENTIFIER=x86
  • 2. Set ALT_MSVCRNN_DLL_PATH=/redist/x86/Microsoft.VC90.CRT
  • 3. Use 32-bit promoted JDK build as a bootstrap.
  • 4. Add 32-bit versions of the compiler, linker, and other utilities to PATH. They are located in/bin/x86_amd64 and


My special thanks to Kelly for his help and advice.

In the last blog posting I introduced a new component called JWebPane that renders HTML content in Java applications. Today I'd like to discuss the details of the practical use of this component. Let me start with typical use cases.

 

1. HTML Rendering

Since the necessity of employing this component in GUI applications appeared a long time ago, each solution, even simple rendering of web pages, is greatly appreciated. Moreover, in spite of the fact that the importance of interactivity is rising steeply, the correct rendering of up-to-date web content still remains a crucial requirement for an HTML component. It's worth mentioning that JWebPane copes with this task successfully along with the help of WebKit, one of the most advanced web engines.

 

2. Load event notifications

Let's move on to more interesting items. The load control of web pages and its resources is another highly demanded function required by many users. For this purpose JWebPane provides the following events: page loading start, external resource loading start, loading progress, loading stop or error, page loading finish, and resources loading finish. The exact set of events is not finalized yet, and new event types will appear soon.

 

3. Navigation

Sometimes using the HTML component is limited to one document, however, the HTML format itself implies tie-up and cross linking of documents. Navigation control, such as Back, Forward, Get URL and other commands, is naturally provided by JWebPane. The navigation function is closely related to transfers from one page to another. This is quite a controversial point: on the one hand, the application should maintain the history, but on the other hand, the component possesses information about which web sites were visited during the current session. That's why JWebPane provides the basic tools for history maintenance as well as the ability to retrieve history from the application.

 

4. Chrome

I always wondered where did the "chrome" term come from :-) This term is used to specify the HTML component environment, which is usually a browser window. Chrome typically includes support of the following elements: status bar, window title and icon, tooltips, window size, the component itself, and others. JWebPane, as an HTML component, doesn't have built-in support of these controls, however, it provides an API to implement those in the application.

 

5. What next?

Undoubtedly, the list of the JWebPane features is incomplete. I'm going to tell you more about the coolest ones, for example, how to create new windows or how to work with JavaScript. Additionally, we would like developers that are ready to use JWebPane share their ideas and visions. After all, they indeed define what kind of features should the convenient and handy HTML component have. Don't they?

Recently, at the JavaOne conference, Sun has introduced several new JavaFX related technologies and products. The Scene Graph and WebKit session was one of the technical sessions to present such advanced technologies:

Inside The JavaFX

Description of the problem


When the java.awt.SystemTray class was first introduced in JDK 6.0, there was only one method to check if the system tray and tray icons can be used: isSupported(). The value returned by this method is constant for the given desktop/environment, for example, on Windows platform it always return true.

Another thing that can help the developers with the system tray isAWTException thrown by SystemTray.add(TrayIcon icon) method. According to the JavaDoc for this method, this exception is thrown "if the desktop system tray is missing". One of the common cases when the system tray is missing is when the notification area applet is removed from the GNOME desktop manually by user.

Recently I have faced another problem, on Windows. There are several projects that make possible to install a Java application as a Windows NT/2K/XP service. Some of such Java applications may interact with the user using SystemTray andTrayIcons. Here the problem lies: Windows services may start before any user is logged in, so no taskbar and system tray are present.

Introducing isAvailable method


Obviously, the isSupported() method is not enough. Developers should be able to detect not only whether Java supports the system tray on the given platform, but also whether the system tray is currently present and tray icons can be added into it.

The most probable name for the new method will beisAvailable. Additionally, it may be useful to have another method in the SystemTray class that works the following way: if the system tray is available, adds the given tray icon into it, if not - waits until the tray becomes available and then adds the icon. AWTException is not required for this case.

Introducing a new property


There is another problem to be resolved to make the using of tray icons easier. Consider an application like an instant messenger that is run as an icon in the system tray, without any other visible window. If the system tray is removed or made unavailable this application may lose some of its functionality.

Alternatively, using a property that changes its value when the system tray becomes available/unavailable, enables an application to listen for that property change and behave correspondingly. For example, an application can show some toplevel window.

There is already a property called 'trayIcons' in theSystemTray class. The new property will be accessible as a parameter of thejava.beans.PropertyChangeListener interface instance by using the same methods: addPropertyChangeListenerand removePropertyChangeListener.

What's the problem?


In Java™ 2 SE 5.0 and previous releases a single method injava.awt.Frame class enables developers to specify an icon for the frame: setIconImage(Image image). This image had an arbitrary size and it was scaled to represent frame's icon in a different locations.

Let's assume that application is running on Windows platform. Icon that was set to the frame is used in several places: on the frame's title bar, on the button on the system taskbar, in the window list when switching to another application by pressing Alt-Tab. The taskbar icon usually has a 16x16 pixels size, the title bar icon size varies depending on the user settings, window list uses a 32x32 sized icons. Thus, if we specify an image of 16x16 pixels size, it will look fine in a taskbar and ugly when switching to another application. The 32x32 pixels image has the similiar problems.

More icons


In the Mustang release the following new method is introduced to the java.awt.Window class:setIconImages(List<? extends Image> icons). Using this method you can supply as many images as you need to represent window's icon.

How does it work? Every time either the system or window manager needs an icon for Java window, it examines the list of specified images and searches for the image of the most appropriate size. Exact definition for this 'most appropriate' size is platform-dependent.

Dialogs icons


You may have already noticed that the new method is added to thejava.awt.Window class, not to thejava.awt.Frame class. In particular, this fact means that you can now set an icon for Java dialogs as well as for frames. This feature is extremely important for parentless dialogs introduced in earlier Mustang builds.

If no icon is set for a dialog, it inherits the icon from its parent window. If a parent is null - that means the dialog is parentless - the platform-default icon is used. If a parent is not-null and no icon was explicitly set for the dialog, then the icon is inherited from the parent window.

When will this API be available?


The answer is: it is already available, since Mustang b85 build was released at the end of May. However, some minor improvements are planned for the next Mustang builds.

Desktop API vs Runtime.exec()


I'm often asked why is that new class,java.awt.Desktop, is introduced. They state all the required actions can be performed with the call to one ofRuntime.exec() methods:
    Desktop.getDesktop().open(new File(filename));
is close to
    Runtime.getRuntime().exec("start " + filename);
So I decided to write a couple of words about this issue to answer the most of such questions at once:)

The difference is...


The problem with the "start" invocation is that it only works on the Windows platform. It will fail on the Mac, Linux, and Solaris platforms. With the Desktop API, you can be guaranteed that it will start an application on all platforms.

There are also lots of other handy features in the new API, such as open, edit, print, and two special actions - browse and mail - that launch separate processes.

See java.awt.Desktop JavaDoc for details.

What's the problem?


Tray icons introduced in Mustang have several properties and methods corresponding to image for the icon, tooltip text, popup menu and ability to show some message to the user. Let's inspect the popup menu more closely.

Popup menu used in tray icons must be an instance ofjava.awt.PopupMenu. This class represents a menu and allows to insert or delete simple menu items and separators. You cannot change its appearance or even provide an image for particular menu item.

Use JPopupMenu instead


There is another class to create popup menus provided by Swing:javax.swing.JPoupMenu. As all Swing components this class can be customized in any way and makes use of the current Look&Feel. Here is a short illustrating example how it can be used:

First, create a tray icon with a null popup since we're going to use our own one:

    TrayIcon trayIcon = new TrayIcon(someImage, "Tooltip", null);
Then, create a custom JPopupMenu:

    JPopupMenu jpopup = new JPopupMenu();

    JMenuItem javaCupMI = new JMenuItem("Example", new ImageIcon("javacup.gif"));
    jpopup.add(javaCupMI);

    jpopup.addSeparator();

    JMenuItem exitMI = new JMenuItem("Exit");
    jpopup.add(exitMI);
At last, show the popup menu when user clicks a right mouse button on the tray icon:

    trayIcon.addMouseListener(new MouseAdapter() {
        public void mouseReleased(MouseEvent e) {
            if (e.isPopupTrigger()) {
                jpopup.setLocation(e.getX(), e.getY());
                jpopup.setInvoker(jpopup);
                jpopup.setVisible(true);
            }
        }
    });

And enjoy the result:
http://weblogs.java.net/blog/ixmal/jpopupmenu/ss.jpg

Magic?


You may probably ask me: "What is that magic line 'jpopup.setInvoker(jpopup);' for?" The answer is not as simple as quiestion is, though.

JavaDoc for JPopupMenu.setInvoker() method says that invoker is the component in which the popup menu menu is to be displayed. This property can be set to null, but it leads to popup menu to operate incorrectly.

Setting popup's invoker to itself has some side-effect too. Usually, if you dispose all the windows in your application, Java exits automatically. If you show JPopupMenu with self invoker, it won't, so the only way to terminate the whole application is to call to System.exit().

Both of these issues are well known to Swing team and will be corrected before the Mustang final release. See 6421284and 6400183for details.

Toolkit

java.awt.Toolkit is an abstract superclass of all actual implementations of the Abstract Window Toolkit (AWT). Subclasses of java.awt.Toolkit are used to bind various components to particular native resources.

You may have noticed that many of the methods injava.awt.Toolkit,java.awt.GraphicsEnvironment and other classes require the availability of display, keyboard and mouse. You may easily find such methods as they throwjava.awt.HeadlessException in headless mode.

What is that headless mode?

Headless mode

Headless mode is a system configuration in which graphic adapter, keyboard or mouse are lacking. For example, mainframes or dedicated servers do not support a display, keyboard or mouse. On the other hand, such environments possess a substantial computing power, which can be used for the non-visual features realization.

All the AWT components with the exception of Canvasand Panel can not be operated in Headless mode. These include: applets, buttons, checkboxes, choices, dialogs, file dialogs, frames, labels, lists, menus, menubars, popup menus, page and print dialogs, scrollbars, scrollpanes, text components, windows, and their descendants. Such heavyweight components require a native "peer" at the operating system level, which cannot be guaranteed on "headless" machines.

Here is a brief list of what is available in Headless mode:

    * lightweight components: canvas, panels, Swing components (with the exception of JApplet, JDialog, JFrame and JWindow)
    * fonts and font metrics
    * colors
    * images
    * printing usingjava.awt.PrintJob, java.awt.print.* andjavax.print.*
    * audio beep

Headless mode setup

To set up the Headless mode you should set the appropriate system property using System.setProperty() method. Property name is "java.awt.headless" and possible values are "true" or "false". Note, that this property shoult be set before the toolkit is initialized with Toolkit.getDefaultToolkit()method.

To check up the availability of the Headless mode you should useGraphicsEnvironment.isHeadless() method. This method checks the "java.awt.headless" property: if it equals to "true", it is assumed that java.awt.HeadlessException will be thrown from all the methods that are dependent on a display, keyboard, or mouse. This method *does not check*hardware configuration of the system, so it is possible to run the application in the Headless mode on a usual desktop.
 

Operating in the Headless mode

Canvas

Following code represents a blank rectangular area onto which we can paint. To create a new canvas component usejava.awt.Canvas class:
    Canvas c = new Canvas()
    {
        public void paint(Graphics g)
        {
            Rectangle r = getBounds();
            g.drawLine(0, 0, r.width - 1, r.height - 1);
            g.drawLine(0, r.height - 1, r.width - 1, 0);
        }
    }

Fonts

This code illustrates how to set font using Font class for drawing a text string. The Graphics object is used to render this string:
    public void paint(Graphics g)
    {
        g.setFont(new Font("Arial", Font.ITALIC, 12));
        g.drawString("Test", 32, 8);
    }

Colors

This code shows how to set color with the specified red, green, and blue values for drawing a filled rectangle. The Graphics object is used to render this line:
    public void paint(Graphics g)
    {
        g.setColor(new Color(255, 127, 0));
        g.fillRect(0, 0, 32, 24);
    } 

Images

In following example the read method of the javax.imageio.ImageIO class decodes the grapefruit.jpg file and returns a result as a Buffered Image:
    Image i = null;
    try
    {
        File f = new File("grapefruit.jpg");
        i = ImageIO.read(f);
    }
    catch (Exception z)
    {
        z.printStackTrace(System.err);
    }

Printing

This code illustrates how print a prepared canvas enabling to define the printer as a default surface for the paint method:
    PrinterJob pj = PrinterJob.getPrinterJob();
    pj.setPrintable(new Printable()
    {
        public int print(Graphics g, PageFormat pf, int pageIndex)
        {
            if (pageIndex > 0)
            {
                return Printable.NO_SUCH_PAGE;
            }
            ((Graphics2D)g).translate(pf.getImageableX(), pf.getImageableY());
            // paint canvas
            c.paint(g);
            return Printable.PAGE_EXISTS;
        }
    });
--> 

Example

All the capabilities described above are represented in the integrated HeadlessBasics example. There are some comments in the source code to better understang Headless mode basics.

Compile the source code using javac compiler. Download grapefruit.jpgimage and put it to the directory where the HeadlessBasics class is located and then run the example with `java HeadlessBasics`. You can run it without any display, keyboard or mouse in the system, for example, using a remote console.

Filter Blog

By date: