Monday, May 30, 2022

Hardware aspects of the Java desktop module

The JVM is a portable architecture for writing programs. This portability ensures that Java programs can be run on virtually any processor. While it is true that the JVM bytecode can be run on virtually on any processor, it is certainly not the case that every CPU comes with the same user interface devices like monitors, speakers, printers, mouses, keyboards, etc. Nor can we assume that there aren't subtle differences between monitors and graphics devices, like in how they render colours.

Programmable computers have the property that they can be universalised and the JVM achieved this, but other hardware devices are a different story. The former is achieved by the JVM while the later is dealt with by Java SE. The Java SE desktop API lets you deal with subtle differences between computer setups, like single versus multiple monitors, different colour models, and various other subtle differences.

There is one more point which just as important. Processors today are not designed with developers in mind. Why bother when no one targets any one processor in particular. The Java virtual machine (JVM) makes your computer into a developer friendly platform, aside from giving you portability. There is never a downside to running your code on a JVM because it is always better then your actual processor and with extremely advanced optimizations any speed differences are negligible.

The JVM easily is the best piece of software ever developed. It completely solves portability issues between CPUs. Portability questions for graphical user interfaces are a different story though. There is an issue now of portability between desktop and mobile applications. One wonders if there will ever be a solution to this problem.

Far too often the solution to mobile-desktop portability issues is to create a mobile interface and give it to desktop users then call it a day. Perhaps developers just need to do a little bit of extra work to make programs work differently on mobile devices and desktop devices. We will see how Java SE lets you get started in handling GUI hardware.

Graphics devices:

The Java SE API has direct support for handling graphics devices with the GraphicsDevice class as well as multiple graphics devices with GraphicsEnvironment. To get the graphics devices from the local graphics environment use getScreenDevices as demonstrated below. This also lets you print the screen bounds of each device.
(let [env (GraphicsEnvironment/getLocalGraphicsEnvironment)
      devices (.getScreenDevices env)]
  (doseq [device devices]
    (prn (.getBounds (.getDefaultConfiguration device)))))
The graphics device class supports direct access to hardware resources on the Java platform. Aside from this, the Java 2D API has everything you need to basically create graphics on the Java platform. It includes support for geometry, compositing, painting and stroking, transformations, clipping, rendering hints, fonts, text layouts, colors, image creation, image drawing, image processing,

The basic way you interact with 2D graphical devices using Java SE is using the Graphics2D class. Graphics2D has all the relevant methods for applying the different parts of the Java 2D API. You can even use it to create images using BufferedImage and its create graphics method. On the other hand, the image processing operations like ConvolveOp operate directly on images.

You can even directly operate on images on the bit level by handling its sample model, data buffer, and color model yourself. Most data in a buffered image is stored in its data buffer, which is an array which stores pixel data in some manner. In most applications it probably sufficise to use the Graphics2D API directly instead of doing primitive operations on color data.

Printers

The java.awt.print package is part of the Java printing API. It presents quite a simple interface to printing. It is also based upon the Java 2D graphics API. There are two classes that enable printing: Printable and Pageable. The former is used to print a bunch of pages with similar page formats while the later can be used to define pages with a variety of different formats. The formats are defined by the page format class.

Typically you can enable printing by subclassing Printable and overriding the print method, which takes in a Graphics as well as a page format and a page number. Then you can interact with the printer using the Graphics object and the Java 2D API. In fact, a printer is just another type of graphics device. Aside from these components, the PrinterJob does the actual job of sending the printable or pageable object to the printer.

The Java print service extension lets you specifically look up all available printers using the PrintServiceLookup class. It has a static method lookupPrintServices that gets all print services available on your systems. The javax print extensions also supports print attribute sets and the ability to select printers that support those attributes.
(let [services (PrintServiceLookup/lookupPrintServices nil nil)]
  (prn (count services))
The Java print service is comparatively a much richer API then the simpler java.awt.print package. The later suffices unless you need advanced control over print handling, events, and attributes. When you need advanced control use the former API.

Audio

Not all computers, even ones with graphical user interface capabilities support sound. But for those that do, you can use them using the Java sound API in the Java desktop module. The Java sound API supports the AU, AIFF, and WAV file formats as part of its sampled audio component.

In addition, it has support for MIDI (music instrument device interface) which can be used to synthesis sounds from music. With the MidiDevice interface, the Java sound API has direct support for MIDI devices.

Input devices

The MouseInfo class in the AWT package allows you to get direct information about the mouse used on the system:
(prn (str "Number of buttons: " (MouseInfo/getNumberOfButtons)))
(prn (str "Mouse location: " (.getLocation (MouseInfo/getPointerInfo))))
The main thing that the Java SE package needs to do to support input devices rather they are the keyboard or the mouse is event handling. This is provided in the java.awt.event package. This allows you to establish listeners that react to keyboard and mouse clicks, which can be used to create interactive programs. Input devices are not that interesting by themselves, so they need to be used in conjunction with other devices.

The overall desktop experience

Swing builds on many of the previously mentioned components like the 2D graphics API and the event handling system to provide the user with a unified user experience. It also builds on the AWT Container/Component model and its layout management system. In many ways it is the singular highlight of the entire Java desktop module.

Swing is not the definitive solution for creating graphical user interface applications. However, it is standard, battle tested, well supported, and good enough for some of the best desktop applications today like IntelliJ, NetBeans, and Protege. If you use Swing it can be the basis of your applications too.

Notes
These icons are part of the Oxygen Icon Set. All rights to these respect icons belong to their respective owners. They are included here for educative purposes.

No comments:

Post a Comment