Historically, developers of native applications usually enjoy greater flexibility in developing UI applications, but the price of doing so is to limit the application to a specific platform. In many cases, this flexibility is not as important as getting a richer UI experience and tight desktop integration. Traditionally, cross-platform UI toolboxes such as Swing SWT QT and wxWidgets tend to passively deal with well-known dilemmas. What should I do when only some target platforms support the required functions? In this case, the missing function of simulation may only lead you to another path.
Irregular and transparent windows are the best example of the limitations of cross-platform UI toolbox. If the specific target platform does not support this feature, there is nothing to do on that platform. This function may be added to the toolbox as a powerful parameter, but the Swing developer community has long believed that the main target platform will provide these functions soon. In fact, Windows has been providing these functions since Windo. Ws (see the SetWindowRgn documentation on MSDN) already supports irregular windows. The matching function in X has been available since (see X non-rectangular window shape extension library PDF document). On OS X, you can only set the transparent background color on JFrame.
So far, there are three main options for Swing applications interested in cross-platform transparent and irregular windows.
In the first chapter of Swing Hacks, Joshua Marinacci and Chris Adamson reviewed the method of using java awt Robot to capture the desktop before displaying the target window.
Use JNI to package the native API of the target platform, and use JNA library developed by Timothy Wall, which was released in 2006. Timothy published a blog about the transparency of irregular windows and letter masks.
The main problem of the first method is the use of robot humans. Even if you have access to screen shots, you must complete them before displaying the window. In addition, how to keep the desktop synchronized in the background? Assuming that the YouTube video being played in the background is different from the events generated by the window (resizing and moving), AWT does not provide any way to register listeners in the redrawing of any intersecting window, although Chris and Joshua provide a solution of taking snapshots at least every second, which is not enough to cover the background video playback, and the window needs to be hidden before each snapshot, which may lead to visible flicker.
The use of JNI and JNA leads to a significant improvement in visual fidelity. Pure JNI will bring about a sharp drop in overhead. You must bind each related API of the target platform and bind this library. JNA will share the burden for you. It binds the host libraries and provides a class loader that can extract and load them at runtime. It supports Linux OS X Windows Solaris and FreeBSD.
Consumer JRE Java SE Update N, commonly known as consumer JRE, is the result of Sun's efforts. In order to reconfigure Java as a feasible way to develop rich desktop applications, the list of new functions and major improvements in Consumer JRE is quite extensive, and the release statement of particularly shiny gems is hidden in one of the latest week's construction codes. Bugs in the Ming Dynasty were simply given the title of supporting irregular/transparent windows, but the possibility of implementing new functions of the core JDK is of far-reaching significance to Swing developers. The rest of this article will show several examples of how to realize this function and how to realize it.
Before further study, it is very important. Because the Consumer JRE is officially considered as a minor update to the stable JDK version, it is public * * * You can't add any new API (class methods, etc.). ) into a package, such as java awt or javax swing. All APIs discussed in this article appear in the new sun awt AWTUtilities class, which is not part of the officially supported API. Its position in Java SE is most likely to change. Between now and the final release of Consumer JRE, the signature method may change slightly, so when this change happens, please be prepared to change your own code.
AWTUtilities class I will first discuss sun's AWTUtilities class. Please refer to the transparent and irregular windows blog entry in the core Java. First, let's start with the simple window in the figure.
Figure a window with controls
To make the window transparent, you can use the awt utility setwindowopacity (window float) method, as shown in the figure.
This is the same window, but the opacity is 20%.
To make the window irregular, you can use the awt utility setWindowsShape (windowshape) method as shown in the figure.
The picture shows the same window, but it is cut by an ellipse.
As you can see from the picture, the irregular windows don't look very good, the edges of the windows are serrated, and the overall impression is not very clean. In order to get a better visual effect of irregular windows, we must use the AWT utility SetWindowOpaque (Window Boolean) API and use flexible clipping to draw the window background, which is flexible in the subsequent Swing windows. The blog entry explains cropping and transparency per pixel. For the upper left corner and the upper right corner of the window, this entry adopts Chris Campbell's flexible cropping tutorial and Romain Guy's reflection tutorial, including Sebastien Petrucci's improved diagram, which shows the flexible cropping window with transparency per pixel.
The picture shows the flexible clipping and transparent window of each pixel.
Now that we have these APIs, what shall we do? It is certainly curious to explore their possibilities, and we will look at several different examples of mixing.
Tooltips make application tooltips transparent. Lightweight tooltips can easily achieve this goal because they are drawn as part of the top-level window of Swing (please refer to the glass pane and lightweight pop-up menu items for details about lightweight pop-up menus), but once tooltips become heavyweight and break the window binding, you must continue to use robots or JNI/JNA. Now let's see how to use the AWTUtilities API to accomplish this task.
Javax swing PopupFactory is a factory that creates pop-up menus. Tooltips are just an example of the pop-up function. Other examples include combo box drop-down list and menu popupfactory setsharedinstance API, which can be used to set a custom pop-up factory. This is what we want to do. The current popup factory is used to create all application popup windows. We will install a custom opacity factory on all tooltips.
The implementation of the core pop-up factory is quite complicated. First, try to create a lightweight pop-up window. When it is necessary to create a heavyweight window, the system should manage the cache so as to reuse the previously created pop-up window. The implementation process will create a new heavyweight pop-up window to run on a relatively new laptop. Different solutions did not show any outstanding performance breakthrough. Let's start with a custom pop-up factory.
The public class TranslucentPopupFactory extends popupfactory {@ override public popup get popup (component owner component contents int x int y). Throwing illegargumentexception {///A more complete implementation will cache and reuse // popups and return a new Translucent Pop (Owner Contents X Y)}} The implementation of Translucent Pop is very simple. The constructor creates a new JWindow and sets the opacity of the tooltip to a custom border that provides drag-and-drop shadows from the Looks project.
Translucent popup (component owner component contents int ownery rx int ownery) {//Create a new heavyweight window this popupWindow = new JWindow() // Mark popup sun awt utilities set window opacity (popup window (contents instance of jtooltop)) with partial opacity? F f) // Determine the popup window set location (ownerx ownery)//Add the contents to the popup window get content pane () Add (contents borderlayout center) Contents invalid (). Jcomponent parent = (jcomponent) Coents get parent ()//Set shadow border parent set border (new shadow popup border ())} Now we need to rewrite the show () method of popup to mark the whole popup window as transparent, which requires that every pixel of the shadow border should be dragged and dropped transparently.
@ override public void show () {this popup window set visible (true) this popup window pack ()//Mark the window as non-opaque, so that//Shadow border pixels adopt pixel-by-pixel//translucent sun awt utility set window opaque (this popup window is false)} hide () method just hides and processes the popup window.
@ override public void hide () {this popup window set visible (false) this popup window remove all () this popup window dispose ()} To install this popup window, just call.
The diagram of PopupFactory Set Shared Instance (New TranslucentPopupFactory ()) shows an example framework with transparent tooltips. Note that the visual consistency between tooltips (transparency and drop shadow borders) spans the Swing frame and extends to the background Eclipse window.
Now let's do the same animation. How about the color becomes lighter when the tooltip is displayed and lighter when it is hidden? Once you are familiar with the AWTUtilities API, it is not difficult to realize the code of the show () method given below.
@ override public void show () {if (this to fade) {//Mark the pop-up window with% opacity this curropacity = sun awt utilities set window opacity (popup window f)} This popup window set visible (true) This popup window pack ()//Marks the window as non-opaque. So that//the pixels of the shadow border show translucency per pixel. Sun awt awt utilities set window opacity (this popup window false) if (this to fade) {// Here fadeintimer = newtimer (new action listener () {public void action performed =) {sun awt utilities set window opacity (popup window curropacity/f). //Solution bug should call//popup window repair () but this will not redraw//panel popup window get content pane () repair ()} else {curropacity = fadeintimer stop ()}) This fade in timer set repeats (true) This fade in timer start ()}} At this point, we mark the pop-up window with 0% opacity, and then we start to repeat the timer five times, increasing the opacity of the window by% each time and redrawing it. Finally, we stop the timer, and the final visual effect is a smooth fade-in and fade-out sequence of the tooltip appearance, which lasts about several milliseconds.
The hide () method is very similar.
@ override public void hide () {if (this to fade) {//Cancel fade-in if if (this fade intimer is running ()) this fade intimer stop ()// Start to fade out this fade outtimer = new timer (new action listener () {public void action performed (action event e) {curropacity = if (curropacity > =) {sun awt awt utilities set window opacity (popup window curropacity/f)//Solution bug should call//popup window repair () but will not be redrawn// panel popup window getcontent pane()repaint()} else { fade out timer stop()popup window set visible(false)popup window remove all() popup window dispose()curr opacity = } })this fade out timer set repeats(true)this fade out timer start()} else { popup window set visible(false) Popup window then increases the opacity from% to%, instead of hiding the window immediately (so that the fade-in sequence is twice as large as the fade-in sequence), and then hides and processes the pop-up window. Note that these two methods refer to the Boolean toFade variable, which is set to true on the tooltip. Other types of pop-up windows (menu combo box drop-down list) have no gradient animation.
Video Reflection Now let's do something more exciting. In Romain Guy's blog entry redrawing manager demonstration (chapter), the Swing component that provides reflection function is displayed. How about extracting a test application from his book Dirty Rich Client co-authored with Chet Haase? The display component of the book provides real-time reflection of QuickTime movies and reflection outside the window binding.
First of all, there should be a screenshot of the reflection box in practical application. The picture shows that Swing frame with regular shape (using embedded QuickTime player) is playing Get a Mac advertisement, accompanied by transparent real-time reflection covering the desktop.
Image of QuickTime movie
This implementation reuses several building blocks of Romain and extends them beyond the framework. It also has a redraw manager (for more information about the redraw manager, please refer to the verification overlay using the redraw manager) to keep the contents of the main frame synchronized with the reflection window. It also needs to register component listeners and window listeners on the main frame to ensure that the visibility position and size of the reflection window are synchronized with the main window. In addition, there is a custom pane for drawing its contents to the off-screen buffer. The off-screen buffer is used to draw reflections in the main frame and reflection window.
Let's take a look at the main class of the code, which is the JReflectionFrame constructor that extends JFrame. We created a reflection window and added a non-double-buffered and transparent panel. We also rewrote the paintComponent () of the panel to draw the reflection of the main frame content. After initializing the position and size of the reflection frame, we installed a custom redraw manager.
public JReflectionFrame(String title){ super(title)reflection = new j window()reflection panel = new JPanel() {@ override protected void paint component (graphics g) {//Draw the reflection paint reflection (g) of the main window}}/Mark the panel as non-double buffered and non-opaque// Make it translucent reflection panel set doublebuffered (false) reflection panel set paque (false) reflection set layout (new borderlayout ()). Reflection a DD (Reflection Panel Borderlayout Center)//See the following for registering listeners ...//Initialize the reflection size and reflection setVisible(tr ue) // Install a custom redrawing manager to force redrawing//When something in the main window//The following are listeners to keep the reflection window synchronized with the main frame.
this addcomponent listener(new component adapter(){ @ Override public void ponent hidden(component event e){ reflection set visible(false)} @ override public void pond moved (component event e) {//Update reflection set location (getx () gety ()+getheight ()) {// Update reflection size and position reflection set size (getwidth () getheight ()) reflection set location (getx () gety ()+getheight ())} @ Override public void ponent showed(component event e){ 0 { sun awt AWTUtilities setwindow opaque(Reflection false)} }) This add window listener (new window adapter () {@ override public void window activated (windowevent e) {//forces the reflection set of the display reflection window to always be Sontop (true) and the reflection set to always be Sontop (false)}) redrawing manager is quite simple. It forces the entire root pane of the main frame to be redrawn, and then updates the reflection window, which can optimize the synchronization of the reflection in the update area, which is sufficient for the purpose of the sample application.
Private class ReflectionRepaintManager extends RepaintManager {@ override public void adddirtyregistion (jcomponent c int x int y int w int h). {windowwi n = SwingUtilities getwindowancestor (c) if (win instance of jreflectionframe) {//Mark the entire root pane jrootpane RP = ((jreflectionframe) win) to be redrawn. Getrootpane () super adddirtyregistion (RP RP getwidth () RP getheight ())//Solution to the error, reflection repaint() // should be called, but reflectionPanel repaint will not be re-displayed.
Lishi Xinzhi/Article/program/Java/hx/20 13 1 1/25650