Disable non-SWT window while SWT dialog showing - java

I'm mixing SWT with a non-SWT window (formerly an AWT window but I'm now using a native GLFW window). When I call fileDialog.show(), I would like the file dialog to get the full application context, where it is drawn on top of the existing non-SWT window, and the non-SWT window cannot be clicked. i.e., the same behavior as when using AWT with an AWT FileDialog.
However, when I show the SWT FileDialog, it still allows me to click the other window and bring that window to front.
Here's how I set up my app. I'm using LWJGL 3 (via LibGDX), which in turn creates a native window through a GLFW binding. And this is part of the reason I'm using SWT...GLFW does not support AWT or Swing.
public static void main (String[] arg) {
//...
new Lwjgl3Application(app, config); //starts an OpenGL loop in a native GLFW window
prepareSWT();
}
static void prepareSWT (){
swtThread = new Thread(new Runnable (){
#Override
public void run() {
swtDisplay = new Display();
swtShell = new Shell(swtDisplay);
while (!swtDisplay.isDisposed()) {
if (!swtDisplay.readAndDispatch())
swtDisplay.sleep();
}
swtDisplay.dispose();
}
});
swtThread.start();
}
public static void showSWTFileChooserDialog (final FileChooserResult fileChooserResult){
swtDisplay.asyncExec(new Runnable() {
#Override
public void run() {
final org.eclipse.swt.widgets.FileDialog fileChooser =
new org.eclipse.swt.widgets.FileDialog(swtShell, SWT.OPEN);
fileChooser.open();
String filename = fileChooser.getFileName();
if (filename == null || filename.equals("")){
fileChooserResult.file = null;
} else {
fileChooserResult.file = new File(fileChooser.getFilterPath(), filename);
}
fileChooserResult.ready = true;
}
});
}
I'm at a loss for how to get the FileDialog to be forced on top of the non-SWT window.

Setting the SWT.SYSTEM_MODAL style on the Shell will block input to all applications' windows on the system.
http://help.eclipse.org/luna/topic/org.eclipse.platform.doc.isv/reference/api/org/eclipse/swt/SWT.html#SYSTEM_MODAL

Related

Create modal dialog from scratch

I'm trying to create my own implementation for an overlay dialog that opens up when the user clicks a button. The code you see below works perfectly fine but is not that pretty. I'm searching for an implementation where I don't have to create a Thread for each dialog I create. Is there any way to acchieve this?
I've been browsing through various Java source files like JOptionPane and JDialog to figure out what they do in order to block the thread until the user closes the dialog, but I didn't manage to understand it. Additionally I tried various code snippets including the EventQueue like for example EventQueue.invokeLater or EventQueue.invokeAndWait.
// MainViewController.java
#FXML
private void handleServerButton(ActionEvent evt){
Thread t = new Thread(() -> {
if (serverD.showDialog(overlay) == Dialog.OK_OPTION){
System.out.println("OK");
} else {
System.out.println("ABORT");
}
});
t.start();
}
// Dialog.java
public int showDialog(Pane parent) {
latch = new CountDownLatch(1);
this.result.set(NONE);
approveButton.setDefaultButton(true);
abortButton.setCancelButton(true);
container.setVisible(true);
parent.setVisible(true);
try {
latch.await();
} catch (InterruptedException ex){ }
approveButton.setDefaultButton(false);
abortButton.setCancelButton(false);
container.setVisible(false);
parent.setVisible(false);
return result.get();
}
#Override
public void changed(ObservableValue<? extends Integer> observable, Integer oldValue, Integer newValue) {
if (newValue != NONE)
latch.countDown();
}
This is what it looks like (please note: the overlay dialog is not a window itself but rather a pane within the main window):
Final Result
Look at the Alert and Dialog documentation. Both provide functionality similar to what you want, and both can be customised if they don't quite match your use case.
Quick example:
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setTitle("title");
alert.setContent("content");
...
// More customisation available, read the docs
alert.show();. // Or showAndWait()
I solved the problem by deriving a Dialog class from Stage and implementing the logic there. The only thing that is left, is to extract the values from the controls of the view controller. But I already noticed that the dialog is passed as a Window through the ActionEvent - so that should be a minor issue.
public class Dialog extends Stage {
public static int OK_OPTION = 0;
public static int ABORT_OPTION = -1;
private int result;
public Dialog(Scene parent, String url) throws IOException{
super(StageStyle.TRANSPARENT);
Parent root = FXMLLoader.load(getClass().getResource(url));
Scene scene = new Scene(root);
if (System.getProperty("os.name").equals("Mac OS X")){
root.setStyle("-fx-background-radius: 0 0 3px 3px;");
}
scene.setFill(Color.TRANSPARENT);
setScene(scene);
initOwner(parent.getWindow());
double titlebar = parent.getWindow().getHeight() - parent.getHeight();
setX(parent.getWindow().getX());
setY(parent.getWindow().getY() + titlebar + 50);
}
public int showDialog(){
showAndWait();
return result;
}
}

MenuShortcut KeyEvent not working

The code below is a testable class that should print out some text when control+A has been pushed on the keyboard, and will also display an image in the system tray. This is all dependent on the system tray being supported by your operating system.
My issue is that the text is not being printed out when I push control+A, it is only printed when I press the item in the system tray.
/**
*
* #author Tyluur
* #since Aug 23, 2013
*/
public class Testable {
public static void main(String... args) {
registerTrayItems();
}
private static void registerTrayItems() {
if (SystemTray.isSupported()) {
SystemTray tray = SystemTray.getSystemTray();
TrayIcon icon = null;
MenuShortcut shortcut = new MenuShortcut(KeyEvent.VK_A);
MenuItem menuItem = new MenuItem("Toggle", shortcut);
menuItem.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.err.println("The action has been called!");
}
});
PopupMenu popup = new PopupMenu();
popup.add(menuItem);
try {
icon = new TrayIcon(new ImageIcon(new URL("http://i.imgur.com/xQoz2TN.png")).getImage(), "Typer", popup);
tray.add(icon);
} catch (MalformedURLException | AWTException e) {
e.printStackTrace();
}
}
}
}
The reason your code is not working is because Java is not 'globally' listening for your key event, but only when the menu has your focus and is shown.
This is also the reason why there is no possibility to write a pure Java keylogger. Java only allows you to capture window-directed messages.
A workaround would be to implement one of these options:
Use JNI/JNA/whatever native wrapper to access global key hooking
Use an invisible window, always being on top and not shown in the system tray that captures the events. I would not suggest using this one as it may either not work like a charm or annoys your user.
The top approach is not a hard one but will require you to use native access and therefor your application becomes platform-specific.
Good luck!
From the API, it looks like you should try this constructor for the MenuItem()
MenuShortcut shortcut = new MenuShortcut(KeyEvent.VK_A, false);
as the default is to require that the Shift key be pressed too.

Closing A JOptionPane Programmatically

I am working on a project in which I would like to close a generic JOptionPane programmatically (by not physically clicking on any buttons). When a timer expires, I would like to close any possible JOptionPane that may be open and kick the user back to the login screen of my program. I can kick the user back just fine, but the JOptionPane remains unless I physically click a button on it.
I have looked on many sites with no such luck. A doClick() method call on the "Red X" of the JOptionPane does not seem possible, and using JOptionpane.getRootFrame().dispose() does not work.
Technically, you can loop through all windows of the application, check is they are of type JDialog and have a child of type JOptionPane, and dispose the dialog if so:
Action showOptionPane = new AbstractAction("show me pane!") {
#Override
public void actionPerformed(ActionEvent e) {
createCloseTimer(3).start();
JOptionPane.showMessageDialog((Component) e.getSource(), "nothing to do!");
}
private Timer createCloseTimer(int seconds) {
ActionListener close = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Window[] windows = Window.getWindows();
for (Window window : windows) {
if (window instanceof JDialog) {
JDialog dialog = (JDialog) window;
if (dialog.getContentPane().getComponentCount() == 1
&& dialog.getContentPane().getComponent(0) instanceof JOptionPane){
dialog.dispose();
}
}
}
}
};
Timer t = new Timer(seconds * 1000, close);
t.setRepeats(false);
return t;
}
};
This code gotten from
https://amp.reddit.com/r/javahelp/comments/36dv3t/how_to_close_this_joptionpane_using_code/ seems to be the best approach to me. It involves Instantiating the JOptionPane class rather that using the static helper methods to do it for you. The benefit is you have a JOptionPane object that you can dispose when you want to close the dialog.
JOptionPane jop = new JOptionPane();
jop.setMessageType(JOptionPane.PLAIN_MESSAGE);
jop.setMessage("Hello World");
JDialog dialog = jop.createDialog(null, "Message");
// Set a 2 second timer
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(2000);
} catch (Exception e) {
}
dialog.dispose();
}
}).start();
dialog.setVisible(true);

Swing window doesn't appear after getting input from Console

I have a simple swing window in order to load files.
This appear in the class analyzedLoad, in a function analyzedloads()
JFileChooser fc = new JFileChooser();
JFrame frame = new JFrame();
int returnVal = fc.showOpenDialog(frame);
frame.dispose();
if (returnVal == JFileChooser.APPROVE_OPTION) {
Where I apply the function without get an input from the user, all fine. But where I get an input from the user, in this way:
int al= 0;
Scanner in = new Scanner(System.in);
System.out.println("for choose file, press 1; for save, press 2");
al= in.nextInt();
if (al== 1){
analyzedLoad.analyzedloads(); // A static function which open the swing window
The window doesn't appear, and the process continue to run, without doing anything.
Thanks.
Becaue "a scanning operation may block waiting for input," I suspect you're blocking the event dispatch thread. Instead use a File Chooser to obtain a file reference.
Try adding a second mywindow.setVisible(true) after the console operation.
You might want to try to declaring the analyzeLoad variable as final and do something like so:
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
analyzedLoad.analyzedloads();
}
}
or since the method is static:
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
YourClass.analyzedloads();
}
}
That being said, without more code we can only speculate.

What technology to use to write systray front-end to webapp?

we have an internal webapplication running on tomcat, build on Spring. The webapplication front-end is build with Flex.
I would like to create a cross-platform systray application that allows to go the home page of the application and displays alerts when certain things happen in the server.
What would you think is the best technology for:
The systray itself? Java Swing?
Communication between the server and the systray? Webservice? RSS feed? Spring remoting? JMX Notifications?
regards,
Wim
If you want to stay with Java you have two options:
Use Swing/AWT. Make sure you are using Java 6 and above (you can install it with your application), since it has support for system tray (from the API):
TrayIcon trayIcon = null;
if (SystemTray.isSupported()) {
// get the SystemTray instance
SystemTray tray = SystemTray.getSystemTray();
// load an image
Image image = Toolkit.getDefaultToolkit.getImage("");
// create a action listener to listen for default action executed on
// the tray icon
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
// execute default action of the application
// ...
}
};
// create a popup menu
PopupMenu popup = new PopupMenu();
// create menu item for the default action
MenuItem defaultItem = new MenuItem("");
defaultItem.addActionListener(listener);
popup.add(defaultItem);
// / ... add other items
// construct a TrayIcon
trayIcon = new TrayIcon(image, "Tray Demo", popup);
// set the TrayIcon properties
trayIcon.addActionListener(listener);
// ...
// add the tray image
try {
tray.add(trayIcon);
} catch (AWTException e) {
System.err.println(e);
}
// ...
} else {
// disable tray option in your application or
// perform other actions
// ...
}
// ...
// some time later
// the application state has changed - update the image
if (trayIcon != null) {
trayIcon.setImage(updatedImage);
}
// ...
Use SWT/JFace. Here is an example (taken from here):
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
Image image = new Image(display, 16, 16);
final Tray tray = display.getSystemTray();
if (tray == null) {
System.out.println("The system tray is not available");
} else {
final TrayItem item = new TrayItem(tray, SWT.NONE);
item.setToolTipText("SWT TrayItem");
item.addListener(SWT.Show, new Listener() {
public void handleEvent(Event event) {
System.out.println("show");
}
});
item.addListener(SWT.Hide, new Listener() {
public void handleEvent(Event event) {
System.out.println("hide");
}
});
item.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
System.out.println("selection");
}
});
item.addListener(SWT.DefaultSelection, new Listener() {
public void handleEvent(Event event) {
System.out.println("default selection");
}
});
final Menu menu = new Menu(shell, SWT.POP_UP);
for (int i = 0; i < 8; i++) {
MenuItem mi = new MenuItem(menu, SWT.PUSH);
mi.setText("Item" + i);
mi.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
System.out.println("selection " + event.widget);
}
});
if (i == 0)
menu.setDefaultItem(mi);
}
item.addListener(SWT.MenuDetect, new Listener() {
public void handleEvent(Event event) {
menu.setVisible(true);
}
});
item.setImage(image);
}
shell.setBounds(50, 50, 300, 200);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
image.dispose();
display.dispose();
}
With Adobe AIR and BlazeDS or LCDS you can easily build this type of application.
I would go for FreePascal. It compiles natively to windows / mac / linux and because of this you do not depend on any other framework (.net, java, air) to be installed. Just one single executable and that's it.
I agree with James: if you have an investment and know-how in Flex, it makes sense to extend that with Air.
As for the payload - if you simply need to 'pop up' notifications from time to time, RSS is the way to go. Otherwise, roll you own XML REST-like service, since it's easy to set up and will give you flexibility in the long run.

Categories