Monday Apr 05, 2010

JavaFX - Modal Dialog


How to implement "Modal Dialog" in JavaFX ? Before going into details of implementation, lets first have a look at common requirement for "Modal Dialog".. It must block..

  • Mouse Events beyond the modal dialog
  • Key Events beyond the modal dialog
  • Execution of current Thread until dialog is disposed

JavaSE 6 allows to specify various types of modality as in ModalityType. We will try to implement behavior some where between Application and Document Modal :)

<script src="http://dl.javafx.com/1.2/dtfx.js"></script><script src="http://javafxdemos.googlecode.com/hg/resource/ModalDialog/ModalDialog.js"></script>


To launch click on above image or
Use of "Block EDT" may lead to deadlock and freeze application

Blocking Mouse Events is very easy, we just need to place a Rectangle whose width and height spans the entire Scene. Then set Node.blocksMouse attribute to true.

Key Events can be restricted if we could ensure that none of nodes other than child of Modal-Dialog receives focus. One way to achieve this is to disable default focus traversal. Get a list of all focus-traversable nodes in the dialog. We can set Node.focusTraversable attribute to false. Now add key-listeners to all nodes. Since focus traversal is disabled, the node will receive TAB key events. When the node receives TAB key event we can explicitly move the request to next node by invoking Node.requestFocus. Request focus for previous node for Shift + TAB key event. Please refer to FocusCycleRoot.fx for more information.

Now comes the interesting part - block execution of current thread - But JavaFX is executed on Event Dispatch Thread - EventQueue.isDispatchThread() will return true. So we cannot block this thread, as it will freeze the user interface. Assuming that the underline Toolkit of JavaFX is built on top of AWT Toolkit, we can use AWT APIs to get around this situation. Before blocking the current thread, we can push a new EventQueue instance into System-Event-Queue, so as to create an alternate path for dispatching events. After disposing the modal dialog, we can restore the original event queue using pop. Please refer to EventQueueUtils.java for more information.

Above solution is not stable enough and also not future proof. It assume that Toolkit is AWT and we have access to EventQueue (For which we need to sign the Applet), also the API may not be compatible with other profiles. In addition to this, pop API has tendency to create deadlock, there were attempts to fix this in various releases, but still doesn't provide stable behavior (especially when called from JavaFX).

So we may have to revisit the requirement - "block execution of current thread". Instead we can write the program in such a way that the display of MessageBox will be the last statement in current execution block. Thus we don't have to block the thread. Then MessageBox can handle redirection to other blocks of code by invoking functions. Thus MessageBox will act like a decision box. This approach will work with most cases and can emulate the "block thread" behavior. Also you don't have to sign the application. Please refer to MessageBox.fx for more information.

Also JFXtras has built in Dialog implementation which supports modality. Please refer to JFXtras for more information.

Please try it out and let me know feedback..


<script type="text/javascript">var dzone_style = '2';</script> <script language="javascript" src="http://javafxdemos.googlecode.com/hg/resource/ModalDialog/zoneit.js"></script>

Monday Dec 21, 2009

JavaFX - Custom "Window"


AWT/Swing provides various top level windows such as Window, Frame, Dialog. javafx.stage.Stage is roughly the equivalent for Frame. We can instantiate and show multiple instance of Stage, or we may use Swing windows. But still it may not be convenient and will impact the look and feel of application (especially when deployed as Applet in Browser).

It may not be possible to emulate all features provided by Frame/Dialog (especially Modal-Dialog), but we may implement a CustomNode which has some basic look and functionality. Here is an attempt..

<script src="http://dl.javafx.com/1.2/dtfx.js"></script> <script src="/rakeshmenonp/resource/JavaFXWindow/JavaFXWindow.js"></script>


To launch click on above image or

Try it out and let me know feedback..


<script type="text/javascript">var dzone_style = '2';</script> <script language="javascript" src="/rakeshmenonp/resource/JavaFXWindow/zoneit.js"></script>

Wednesday Apr 29, 2009

JavaFX - Always On Top


Stage is the top level container in JavaFX. It provides attributes such as fullScreen, iconified, opacity, style, icons, resizable, title which loosely maps to corresponding methods in java.awt.Frame.

But it doesn't provide any functionality to create Dialog behavior (modal, no task bar icon etc) and also support for setAlwaysOnTop. These two features are required to get the actual Widget feel. As of now the Stage shows a taskbar icon for each application.

So here is a workaround.. Create an instance of AWTEventListener. Add the same to default AWT Toolkit so as to listen to all ComponentEvent. This will receive an event when Stage (Frame) resized and shown. Get the instance of Frame from this event. Retrieve the content of the Frame and add it to new instance of Dialog. Dispose the Frame. Now set various attributes of Dialog such as modality, always-on-top and make this Dialog visible. Now the content of Frame will be shown in Dialog! :) We may also apply translucency, shaped windows etc to newly created dialog using AWT APIs.

A simple implementation of above approach is provided in FXDialogUtils. This class must be instantiated before Stage is shown so that it can listen to all events. Example, the code can be embedded in Calendar sample as shown below. That is just adding one line to existing application.


FXDialogUtils { };

Stage {
    
    x: bind stageX with inverse
    y: bind stageY with inverse
    width: fxCalendar.width
    height: fxCalendar.height
    title: "Calendar"

If you just want to change some attributes of Frame, you may directly obtain the Frame instance using Frame.getFrames(). This will return an array of Frame instance. We can get find the frame instance of specified Stage using its title. We can modify various Window or Frame properties using this instance.

We may also directly obtain the instance of AWT Window equivalent of Stage using some JavaFX internal APIs, but that may not be compatible across releases. But yes, that is another way of doing it

Now you can launch the Calendar as real widget

Yes, its a hack! Keep exploring other possibilities!

<script type="text/javascript">var dzone_url = "http://blogs.sun.com/rakeshmenonp/entry/javafx_always_on_top";</script> <script type="text/javascript">var dzone_style = '2';</script> <script language="javascript" src="http://widgets.dzone.com/widgets/zoneit.js"></script>

About


The views expressed on this blog are my own and do not necessarily reflect that of my organization

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today