Issue with Dialog Modality in Swing in java 1.6 - java

I have 3 dialog that gets displayed together in my project.
First dialog is modeless with setVisibleOnTop(false).
Second dialog is modeless with setVisibleOnTop(true).
Third dialog is Application Modal with setVisibleOnTop(true).
Now the issue is :
Ideally when there is a dialog "third" opened with APPLICATION_MODAL property then no other JComponent should accept the click. This works fine with java 1.7.
With java 1.6 is I click on dialog "one" then dialog "second" goes at the back of dialog "one". Whereas dialog "third" is still opened.
Now the question is:
Why dialog "one" comes in front when there is an APPLICATION_MODAL dialog (third) opened?
Why second dialog with property setAlwaysOnTop(true) goes at back?
I believe this is a issue with java 1.6. Does anyone know about this?
Is this bug documented somewhere?
Sample Code:
import java.awt.Frame;
import javax.swing.JDialog;
class MyDialog1 extends JDialog {
MyDialog1 ()
{
super();
super.setVisible(false);
setTitle("one");
}
}
class MyDialog2 extends JDialog {
MyDialog2 ()
{
super(null,ModalityType.MODELESS);
setAlwaysOnTop(true);
setTitle("second");
}
}
class MyDialog3 extends JDialog {
MyDialog3 ()
{
super(new Frame(),ModalityType.APPLICATION_MODAL);
setTitle("third");
setAlwaysOnTop(true);
super.setVisible(false);
}
}
public class ModalityIssue {
public static void main(String args[])
{
MyDialog1 d1=new MyDialog1();
d1.setSize(600, 600);
MyDialog2 d2=new MyDialog2();
d2.setSize(500, 500);
MyDialog3 d3=new MyDialog3();
d3.setSize(400, 400);
d1.setVisible(true);
d2.setLocationRelativeTo(d1);
d2.setVisible(true);
d3.setLocationRelativeTo(d2);
d3.setVisible(true);
}
}

dont to use awt components
JFrame ignores alwaysOnTop and modality,
use Initial Thread,
important is code ordering too
you can to use aplication modality (seems like as better, but nobody knows if meets with your requirement/s)
MyDialog1 always flashing (MyDialog2 is painted before MyDialog1, then jumps behing MyDialog2, standard users can't catch that), maybe there aren't any JComponents added to any of Top-Level Containers in the current JVM
for example (Java 1.6.21 / 025 / 031, the same corerctly works in 1.7.04 and 1.8.60 / 66 / win10)
import java.awt.Dialog.ModalityType;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
class MyDialog1 extends JDialog {
public MyDialog1() {
super(null, ModalityType.MODELESS);
setAlwaysOnTop(true);
setTitle("fist");
}
}
class MyDialog2 extends JDialog {
public MyDialog2() {
super(null, ModalityType.MODELESS);
setAlwaysOnTop(true);
setTitle("second");
}
}
public class ModalityIssue {
private JFrame frame = new JFrame();
private MyDialog1 d1 = new MyDialog1();
private MyDialog2 d2 = new MyDialog2();
public ModalityIssue() {
frame.setTitle("third");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
frame.setLocation(100, 100);
frame.setVisible(true);
d1.setSize(400, 300);
d1.setLocation(200, 200);
d1.setVisible(true);
d2.setSize(400, 300);
d2.setLocation(300, 300);
d2.setVisible(true);
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new ModalityIssue();
}
});
}
}

Related

How to hide a JPopupMenu by pressing a button?

I'm making a program that has a popup menu with two buttons, one of which should close the popup menu, but I have no idea how to do that and googling hasn't gone too well.
I've tried using popup.hide() but then the menu wouldn't come back, despite doing so when I tried just moving the popup. It also required me to put a SuppressWarning in that case and it took a few seconds for it to close at all. Is there any better way of doing it?
I'm not sure what kind of code is relevant, but here's the relevant buttons and their roles in this(I skipped all the creating the GUI parts that didn't seem relevant, everything looks good and I know that the buttons are working):
package test;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
interface CustomButton {
JButton create();
void react(JPopupMenu popup, JFrame frame);
}
class ErrandsButton implements CustomButton {
private JButton errands = new JButton("Errands");
public JButton create() {
return errands;
}
public void react(JPopupMenu popup, JFrame frame) {
errands.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
popup.show(frame, 120, 65);
}
});
}
}
class Test {
static JFrame frame = new JFrame("List");
static CustomButton errands = new ErrandsButton();
static JButton cancelTask = new JButton("Cancel");
static JPopupMenu popup = new JPopupMenu();
static void cancelTask() {
cancelTask.addActionListener(new ActionListener() {
#SuppressWarnings("deprecation")
public void actionPerformed(ActionEvent e) {
popup.hide();
}
});
}
public static void main(String args[]) {
createInterface();
cancelTask();
errands.react(popup, frame);
}
static void createInterface() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
JPanel popup1 = new JPanel();
JPanel button = new JPanel();
popup1.add(cancelTask);
popup.add(popup1);
frame.add(popup);
button.add(errands.create());
frame.getContentPane().add(BorderLayout.CENTER, button);
frame.setVisible(true);
}
}
Use popup.setVisible(true) and popup.setVisible(false).
frame.add(popup); is the problem. Do not add a JPopupMenu to a Container. Instead, use setComponentPopupMenu.
Alternatively, you could do the work yourself by adding a MouseListener whose mousePressed, mouseReleased and mouseClicked methods call isPopupTrigger and show. (It is vital that you do this in all three of those methods—different platforms have different conditions for showing popup menus.)
But really, using setComponentPopupMenu is easier.

JFileChooser in front of fullscreen Swing application

I know there are some topics relative to this question (mainly this unanswered one and this one which is not handling full screen app).
I basically tried every combination of first topic sample and available methods (requestFocus, requestFocusInWindow, ...) but JFileChooser is always displaying behind the fullscreen app. I tried to change filechooser's parent too (setting it to null, itself or the parent frame) with no more success.
Have anyone a working example of this not-that-much-particular use case? Or is there a workaround to let user select files in a fullscreen app?
Unfortunately I can't say how you realised the implementation of the fullscreen app. But I tried a few things and came up with this:
import java.awt.Color;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Gui extends JFrame {
public Gui() {
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
//this.setSize(java.awt.Toolkit.getDefaultToolkit().getScreenSize());
// Set some charateristics of the frame
this.setExtendedState(Frame.MAXIMIZED_BOTH);
this.setBackground(Color.black);
this.setUndecorated(true);
JButton a = new JButton("PRESS ME!");
a.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
JFileChooser fc = new JFileChooser();
fc.showOpenDialog(getParent());
}
});
this.add(a);
this.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Gui();
}
});
}
}
Pay attention to the fact, that I created a new JFileChooser with the parent of the current JFrame as parameter.
EDIT:
I now even tried to set
java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(new Gui());
and without the
this.setUndecorated(true);
it worked for me (got a nice fullscreen view and the JFileChooser was in the front). I believe the problem with the window decoration is linked to my window manager (I'm using linux with gnome).
Hopefully this solution works for you, if not:
Could you explain a little bit more, how you create the fullscreen app?
I would suggest instead of using using a Popup, just embed the JFileChooser into your application. It doesn't really make sense to have popups in a windowless application (Personally, I don't like popups much anyways).
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class FullScreenApp {
public static void main(String[] args) {
final JFrame frame = new JFrame();
frame.setTitle("Frame");
frame.setSize(800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GraphicsDevice device = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
device.setFullScreenWindow(frame);
device.setDisplayMode(new DisplayMode(800, 600, 32, 60)); // Ugh.
frame.setVisible(true);
final Box panel = Box.createVerticalBox();
JButton btn = new JButton();
btn.setText("Button");
panel.add(btn);
frame.add(panel);
final CustomFileChooser chooser = new CustomFileChooser(panel);
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
chooser.show();
}
});
}
public static class CustomFileChooser extends JFileChooser{
/** Node this chooser should be added to.
* There's likely a better way of doing this,
* but it was convenient for a quick example */
Container parent;
public CustomFileChooser(Container parent){
super();
this.parent = parent;
//Make configurations for your file chooser
setApproveButtonText("Open");
}
#Override
public void approveSelection(){
super.approveSelection();
//Perform accept action here
System.out.println(getSelectedFile().getAbsolutePath());
parent.remove(CustomFileChooser.this);
parent.repaint();
}
#Override
public void cancelSelection(){
super.cancelSelection();
//Perform cancel action here
System.out.println("Canceled");
parent.remove(CustomFileChooser.this);
parent.repaint();
}
#Override
public void show(){
rescanCurrentDirectory();
parent.add(this);
revalidate();
repaint();
}
#Override
public Dimension getMaximumSize(){
//Not necessary - But I felt the chooser should have a maximum size
return new Dimension(500,300);
}
}
}
FullscreenLib
//import
import argha.util.Fullscreen;
//this for JFrame
//true for setting Undecorated on/off
Fullscreen screen = new Fullscreen(this, true);
screen.DoTheWorkFor();
You can use my library for creating fullscreen windows and the problem you are facing hope it solved after that i tested and its working.
Hope it may helped you

How to create a modal JDialog on top of another modal JDialog

I have a modal settings dialog which is a JDialog. In this settings window I placed some components including a button to yet another modal settings dialog which is also a JDialog. I made them JDialogs because that is the only way I know of to make a modal dialog.
The problem is this: when I create the main settings dialog I have to construct the JDialog either without a parent Frame or with a parent Frame. Since my main window is a JFrame, I can just pass that to the main settings dialog constructor. But when I want to create the second modal settings dialog which should have the main settings dialog as a parent, I can't find a way to get the (J)Frame of the JDialog. I do want to pass that main settings dialog as a parent so that the second settings dialog centers on it when it is shown. Let's assume the second settings dialog has no constructor for passing a location, just the constructors of the JDialog.
Is there a way to get the (J)Frame of a JDialog?
Is there a design flaw in my setup and should I have used something else for these settings dialogs? (And if so, how should I make these alternative settings dialogs modal?)
Thank you for your help,
Erik
UPDATE:
Thank you all for your answers. They led me to understand that apparently it's not absolutely necessary to have an owner for a JDialog. I thought this was needed for the dialog to be able to disable the owner until the dialog is closed, but apparently the modality is independent of the owner. I also noticed that even with an owner the dialog still doesn't center on the owner, so now my code is like:
public class CustomDialog extends JDialog {
public CustomDialog(String title) {
setModal(true);
setResizable(false);
setTitle(title);
buildGUI();
}
public Result showDialog(Window parent) {
setLocationRelativeTo(parent);
setVisible(true);
return getResult();
}
}
This also allows for modal dialogs in modal dialogs.
Thanks for all your help!
Not sure what exactly you have as a problem, but here is an example on how you can have multiple modal dialogs:
import java.awt.BorderLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TestDialog {
protected static void initUI() {
JPanel pane = newPane("Label in frame");
JFrame frame = new JFrame("Title");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(pane);
frame.pack();
frame.setVisible(true);
}
public static JPanel newPane(String labelText) {
JPanel pane = new JPanel(new BorderLayout());
pane.add(newLabel(labelText));
pane.add(newButton("Open dialog"), BorderLayout.SOUTH);
return pane;
}
private static JButton newButton(String label) {
final JButton button = new JButton(label);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Window parentWindow = SwingUtilities.windowForComponent(button);
JDialog dialog = new JDialog(parentWindow);
dialog.setLocationRelativeTo(button);
dialog.setModal(true);
dialog.add(newPane("Label in dialog"));
dialog.pack();
dialog.setVisible(true);
}
});
return button;
}
private static JLabel newLabel(String label) {
JLabel l = new JLabel(label);
l.setFont(l.getFont().deriveFont(24.0f));
return l;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
initUI();
}
});
}
}
1.please read The New Modality API in Java SE 6
2.Is there a way to get the (J)Frame of a JDialog?
Window ancestor = SwingUtilities.getWindowAncestor(this);
or
Window ancestor = (Window) this.getTopLevelAncestor();
It is now 2021 and so about 8.5 years after the question was posted, but back in 2012 and still in these days by far and away the easiest solution is to simply create the JDialog with a Dialog as owner. Java has 5 constructors with a Dialog owner to offer, next to 5 similar ones with a Frame owner and 5 with a Window owner.
The issue that the OP was probably faced with was the default template for a JDialog in Netbeans or some other IDE. Netbeans (12.2) offers this as a template for a new JDialog Form...:
public class NewJDialog extends javax.swing.JDialog {
/**
* Creates new form NewJDialog
*/
public NewJDialog(java.awt.Frame parent, boolean modal) {
super(parent, modal);
initComponents();
}
You can simply change the signature of the constructor to use a Dialog as owner instead of the default option of a Frame:
public class NewJDialog extends javax.swing.JDialog {
/**
* Creates new form NewJDialog
*/
public NewJDialog(java.awt.Dialog parent, boolean modal) {
super(parent, modal);
initComponents();
}
And away you go.

Iconified JFrame showing behind modal JDialog on win 7 taskbar click

I originally developed the following code on Win XP. When you click the program icon in the XP taskbar, the parent frame remains iconified and the JDialog returns to focus, which is the behavior I want. However, when clicking the program's taskbar icon on Win 7, the parent JFrame changes its state back to Normal and shows behind the app-modal JDialog. I've tried overriding the JFrame's setExtendedState() method to intercept the frame's state change with no luck.
Is there a workaround for this, or is there a flaw my logic I need to address?
import java.awt.*;
import javax.swing.JDialog;
import javax.swing.JFrame;
public class TestLogin extends JFrame {
public TestLogin() {
this.setSize(300, 300);
iconify(this);
setLocationRelativeTo(null);
this.setTitle("I'm a Frame!");
this.setVisible(true);
LoginScreen login = new LoginScreen(this);
}
public static void main(String [] args) {
TestLogin frame = new TestLogin();
}
public static void iconify(Frame frame) {
int state = frame.getExtendedState();
// Set the iconified bit
state |= Frame.ICONIFIED;
// Iconify the frame
frame.setExtendedState(state);
}
public static void deiconify(Frame frame) {
int state = frame.getExtendedState();
// Clear the iconified bit
state &= ~Frame.ICONIFIED;
// Deiconify the frame
frame.setExtendedState(state);
}
public class LoginScreen extends JDialog {
private JFrame root;
public LoginScreen(JFrame root) {
super(root);
this.root = root;
setLocationRelativeTo(null);
this.setTitle("I'm a Dialog!");
setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
this.setSize(200, 200);
setVisible(true);
}
}
}
It looks like a bug in the java paradigm of "write once, run anywhere". If that is to include windows 7, then you might contact oracle and fill a bug report.
Regards,
Stéphane

How I can selected by default an InternalFrame on a JDesktopPane?

I have a JFrame with the JDesktopPane and inside the JDesktopPane, I launch with the constructor a JInternalFrame.
(Its a app like the authentification users, with the textbox user and textbox pass)
I lauch the internal like this:
MyInternalFrame internalF = new MyInternalFrame();
desktopPane.add(internalF);
I try with:
internalF.setVisible(true);
internalF.setSelected(true);
desktopPane.getDesktopManager().activateFrame(internal);
desktopPane.setSelectedFrame(internal);
How I can lauch the JInternalFrame and Its selected by default?
When I run the aplication, internalframe is like in background, Its not selected, Its not focused.
Have a look at the How To Use Internal Frames java tutorial. It gives a nice example and uses the following;
protected void createFrame() {
MyInternalFrame frame = new MyInternalFrame();
frame.setVisible(true);
desktop.add(frame);
try {
frame.setSelected(true);
} catch (java.beans.PropertyVetoException e) {}
}
You can make the internal frame visible AFTER the desktop is created and the main frame is visible. In that case the frame will be selected by default.
So, one example of what you can do:
Create main frame
Create desktop
Create internal frame but don't make it visible
Start thread that sets visible to true on the internal frame, but the thread can wait until the desktop is shown
Make the main frame visible
In the thread call internalFrame.setVisible(true) and exit from the thread.
In such case the internal frame will appear on the desktop and it will be selected as you want it.
You might think of other solution without using threads, but writing handlers to the main frame's events. In any case, to make the internal frame visible after it shows, you have to show it AFTER desktop with main frame is displayed.
Here is the example, that you can use:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.HeadlessException;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
public class Main extends JFrame {
private static final long serialVersionUID = 1L;
private Internal internalFrame;
public Main() throws HeadlessException {
super("Internal Frame Test");
setBounds(10, 10, 600, 400);
setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setLayout(new BorderLayout());
add(createDesktop(), BorderLayout.CENTER);
addWindowListener(new WindowAdapter() {
public void windowOpened(WindowEvent e) {
internalFrame.setVisible(true);
}
});
setVisible(true);
}
private Component createDesktop() {
JDesktopPane d = new JDesktopPane();
internalFrame = new Internal("first");
d.add(internalFrame);
return d;
}
public static class Internal extends JInternalFrame {
private static final long serialVersionUID = 1L;
public Internal(String title) {
super(title);
setBounds(10, 10, 300, 100);
}
}
public static void main(String[] a) {
new Main();
}
}

Categories

Resources