Make Java Swing Modal Dialog Behave Like Mac OSX Dialogs - java

I am writing a small app that requires a ProgressBar to appear centred under the frame's TitleBar as is often seen in Mac OSX apps. I have two problems:
1. I have managed the positioning but I had to hard code the parent Frame's TitleBar height. Is there a 'soft' way to get the TitleBar's height?
In the Dialog's constructor:
Dimension dimensionParentFrame = parent.getSize();
Dimension dimensionDialog = getSize();
int x = parent.getX() + ((dimensionParentFrame.width - dimensionDialog.width)/2);
setLocation(x, parent.getY() + 22); // TODO HARD CODE WARNING TITLE HEIGHT
2. Even though the Dialog is modal, I can still click on the parent Frame and move it. How can I make the Dialog 'stick' to the parent Frame? That is, when the parent Frame is moved the Dialog moves with it as if attached.
Any help/pointers would be much appreciated.
Here is the code:
import javax.swing.JFrame;
import javax.swing.JButton;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class ModalDialogDemoFrame extends JFrame
{
ModalDialogDemoFrame modalDialogDemo;
public ModalDialogDemoFrame()
{
modalDialogDemo = this;
setBounds(100, 100, 400, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton buttonDialog = new JButton("Open Dialog");
buttonDialog.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
// Create a Modal Dialog with this Frame as Parent.
ModalDialog modalDialog = new ModalDialog(modalDialogDemo, true);
modalDialog.setVisible(true);
}
});
getContentPane().add(buttonDialog, BorderLayout.CENTER);
}
/**
* #param args
*/
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
ModalDialogDemoFrame window = new ModalDialogDemoFrame();
window.setVisible(true);
}
catch (Exception e)
{
e.printStackTrace();
}
}
});
}
}
import java.awt.Dimension;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JButton;
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class ModalDialog extends JDialog
{
public ModalDialog(JFrame parent, boolean modal)
{
super(parent, modal);
Dimension dimensionParentFrame = parent.getSize();
setSize(new Dimension((parent == null) ? 300 : dimensionParentFrame.width / 2, 75));
Dimension dimensionDialog = getSize();
int x = parent.getX() + ((dimensionParentFrame.width - dimensionDialog.width)/2);
setLocation(x, parent.getY() + parent.getInsets().top);
setUndecorated(true);
setModal(modal);
setModalityType(ModalityType.APPLICATION_MODAL);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
JButton buttonClose = new JButton("Close");
buttonClose.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
dispose();
}
});
getContentPane().add(buttonClose, BorderLayout.CENTER);
}
}

int titleBarHeight = frame.getInsets().top;
Even though the Dialog is modal, I can still click on the parent Frame and move it.
Then you are doing something wrong because this should NOT happen.
Post your SSCCE that demonstrates the problem.

Related

JFrame doesn't appear unless method invoked in main

I have a class which create a JFrame with an image but everytime I create the class and run the method to instantiate it, it doesn't appear. However, I have noticed that if I was to create the exact same class and run the same method in the main then the frame appears.
This is most of the code from the class with the JFrame that I am trying to create:
JFrame myFrame= new JFrame();
public void CreateFrame()
{
JLabel background=new JLabel(new ImageIcon("image.jpg"));
myFrame.add(background);
background.setLayout(new FlowLayout());
myFrame.setLayout(new GridLayout(1,1));
myFrame.setSize(360,250);
myFrame.setUndecorated(true);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
myFrame.setLocation((dim.width/2-170), dim.height/2-125);
myFrame.pack();
myFrame.setVisible(true);
}
If I run the code
MyClass mc = new MyClass();
mc.CreateFrame();
in a method in another class it doesn't come up. However, if I run the exact same code in a main method, it works.
For example, this doesn't work:
Example 1
public class otherClass extends JFrame
{
public void MethodA()
{
MyClass mc = new MyClass();
mc.CreateFrame();
}
public static void main(String[] args)
{
otherClass oc = new otherClass();
oc.MethodA();
}
}
but this does work
Example 2
public class otherClass extends JFrame
{
public void MethodA()
{
//CODE
}
public static void main(String[] args)
{
otherClass oc = new otherClass();
oc.MethodA();
MyClass mc = new MyClass();
mc.CreateFrame();
}
}
Can anyone see where I'm going wrong? Sorry if a stupid mistake, I'm still getting to grips with Java.
Thanks
EDIT
import javax.swing.ImageIcon;
import javax.swing.JWindow;
import javax.swing.JLabel;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import javax.imageio.ImageIO;
import java.util.Timer;
import java.util.Date;
import javax.swing.JFrame;
public class MyClass
{
JFrame homeFrame = new JFrame();
public void createFrame()
{
JLabel background=new JLabel(new ImageIcon("images.jpg"));
myFrame.add(background);
background.setLayout(new FlowLayout());
myFrame.setLayout(new GridLayout(1,1));
myFrame.setSize(360,250);
myFrame.setUndecorated(true);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
myFrame.setLocation((dim.width/2-170), dim.height/2-125);
myFrame.setAlwaysOnTop(true);
myFrame.pack();
myFrame.setVisible(true);
durationOfTime();
}
public void durationOfTime()
{
MainProgram mp = new MainProgram();
long startTime = System.currentTimeMillis();
long elapsedTime = 0L;
int count =0;
while (elapsedTime < 2*1000)
{
if(count==0)
{
mp.launchInitiation();
}
count+=1;
elapsedTime = (new Date()).getTime() - startTime;
}
myFrame.setVisible(false);
mp.homeFrame.setVisible(true);
}
public static void main(String[] args)
{
MyClass mc = new MyClass();
mc.createFrame();
}
}
Full code from class with JFrame trying to make. I am trying to use this JFrame as a splash screen but whatever class I call
MyClass mc = new MyClass();
mc.createFrame();
from, it just doesn't appear. Two seconds do pass by before my main GUI appears up but this method is supposed to be called in a login type frame. However, I have tested it with a blank JFrame / GUI to appear upon button click also and it still doesn't appear.
EDIT2
I also previously tried this SplashScreen example by # http://examples.oreilly.com/jswing2/code/ch08/SplashScreen.java but I couldn't get it to work (same problem, appears when called from main but not when called from action listener)
import java.awt.*;
import javax.swing.*;
public class SplashScreen extends JWindow {
private int duration;
public SplashScreen(int d) {
duration = d;
}
// A simple little method to show a title screen in the center
// of the screen for the amount of time given in the constructor
public void showSplash() {
JPanel content = (JPanel)getContentPane();
content.setBackground(Color.white);
// Set the window's bounds, centering the window
int width = 450;
int height =115;
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
int x = (screen.width-width)/2;
int y = (screen.height-height)/2;
setBounds(x,y,width,height);
// Build the splash screen
JLabel label = new JLabel(new ImageIcon("oreilly.gif"));
JLabel copyrt = new JLabel
("Copyright 2002, O'Reilly & Associates", JLabel.CENTER);
copyrt.setFont(new Font("Sans-Serif", Font.BOLD, 12));
content.add(label, BorderLayout.CENTER);
content.add(copyrt, BorderLayout.SOUTH);
Color oraRed = new Color(156, 20, 20, 255);
content.setBorder(BorderFactory.createLineBorder(oraRed, 10));
// Display it
setVisible(true);
// Wait a little while, maybe while loading resources
ClassToLoad ctl = new ClassToLoad();
try {
Thread.sleep(duration);
ctl.initiate();
} catch (Exception e) {}
setVisible(false);
}
public void showSplashAndExit() {
showSplash();
System.exit(0);
}
public static void main(String[] args) {
// Throw a nice little title page up on the screen first
SplashScreen splash = new SplashScreen(10000);
// Normally, we'd call splash.showSplash() and get on with the program.
// But, since this is only a test...
splash.showSplashAndExit();
}
}
I added the code in the lines with ClassToLoad and this SplashScreen is called on an action listener, what happens is the program waits the 2 seconds that I tell it to, no frame appears, and then the main class that I wanted to load while the splash screen is visible loads. I tried this method first but this didn't work which lead to me using the code listed above this edit
EDIT 3
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TestFrame extends JFrame implements ActionListener
{
JPanel thePanel = new JPanel(null); //layout
JButton button = new JButton();
public void startGUI()
{
this.setLayout(new GridLayout(1,1));
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
CREATEMYPANEL();
this.add(thePanel);
this.setTitle("NO_TITLE_SET");
this.setSize(400,400);
this.setVisible(true);
this.setResizable(true);
}
public void CREATEMYPANEL()
{
button.setLocation(242,151);
button.setSize(100,50);
button.addActionListener(this);
button.setText("button");
thePanel.add(button);
}
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==button)
{
System.out.println("button has been pressed ");
SplashScreen splash = new SplashScreen(1000);
splash.showSplash();
}
}
public static void main(String[] args )
{
TestFrame tf = new TestFrame();
tf.startGUI();
}
}
An example of where I call splash screen from. Still doesn't work. Also, just a note that the image I am loading is a local image
Apologies for bad question formatting
Your code works for me except for some details I noticed:
You're calling setSize(...) and then calling pack(). Probably your image isn't being loaded and thus your JFrame has a size of 0, 0. (And thus it looks like it never appears). .pack() and .setSize(...) are mutually exclusive.
You're setting the JLabel's layout manager to FlowLayout but never adding anything to it. (You can safely remove it)
I see you're importing java.util.Timer if you want to dispose the JFrame after 2 seconds, then you should be using a javax.swing.Timer instead. Otherwise you could get problems related to threading.
Also don't forget to place your program on the Event Dispatch Thread (EDT) as Swing is not thread safe
Following above recommendations you can have this code:
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.MalformedURLException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class SplashscreenSample {
private JFrame myFrame;
private JLabel background;
private Timer timer;
public void createFrame() {
timer = new Timer(2000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
myFrame.dispose();
#SuppressWarnings("serial")
JFrame frame = new JFrame(getClass().getSimpleName()) {
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
};
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
timer.stop();
}
});
myFrame = new JFrame(getClass().getSimpleName());
try {
background = new JLabel(new ImageIcon(new URL("http://cdn.bulbagarden.net/upload/thumb/6/6b/175Togepi.png/250px-175Togepi.png")));
} catch (MalformedURLException e) {
e.printStackTrace();
}
myFrame.add(background);
timer.setInitialDelay(2000);
timer.start();
myFrame.setLayout(new GridLayout(1, 1));
myFrame.setUndecorated(true);
myFrame.setAlwaysOnTop(true);
myFrame.pack();
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
myFrame.setLocation((dim.width/2-170), dim.height/2-125);
myFrame.setVisible(true);
myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new SplashscreenSample().createFrame());
}
}
Or you can use the Splashscreen class...
For example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Toolkit;
import java.net.MalformedURLException;
import java.net.URL;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JWindow;
public class SplashScreen extends JWindow {
private int duration;
public SplashScreen(int d) {
duration = d;
}
// A simple little method to show a title screen in the center
// of the screen for the amount of time given in the constructor
public void showSplash() {
ImageIcon icon = null;
try {
icon = new ImageIcon(new URL("http://www.cqsisu.com/data/wallpapers/5/718448.gif"));
} catch (MalformedURLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
JPanel content = (JPanel) getContentPane();
content.setBackground(Color.white);
// Set the window's bounds, centering the window
int width = icon.getIconWidth();
int height = icon.getIconHeight();
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
int x = (screen.width - width) / 2;
int y = (screen.height - height) / 2;
setBounds(x, y, width, height);
// Build the splash screen
JLabel label = new JLabel(icon);
JLabel copyrt = new JLabel("Copyright 2002, O'Reilly & Associates", JLabel.CENTER);
copyrt.setFont(new Font("Sans-Serif", Font.BOLD, 12));
content.add(label, BorderLayout.CENTER);
content.add(copyrt, BorderLayout.SOUTH);
Color oraRed = new Color(156, 20, 20, 255);
content.setBorder(BorderFactory.createLineBorder(oraRed, 10));
// Display it
setVisible(true);
// Wait a little while, maybe while loading resources
loadResources();
setVisible(false);
}
public void loadResources() {
TestFrame tf = new TestFrame();
try {
Thread.sleep(duration);
tf.startGUI();
} catch (Exception e) {
}
}
public static void main(String[] args) {
SplashScreen splash = new SplashScreen(10000);
splash.showSplash();
}
}
Try creating and setting the frame visible in a constructor of the class.
Could it be that while your program is counting
while (elapsedTime < 2*1000)
{
if(count==0)
{
mp.launchInitiation();
}
count+=1;
elapsedTime = (new Date()).getTime() - startTime;
}
it is blocking for said 2 seconds and waiting for this method to finish, return back to the create method and then just finish that one?
it seems this could be a better comment, but i need 50 rep for some reason to comment.

unable to close JOptionPane properly in chain order

I am displaying a JOptionPane suppose A on a button click from JFrame, and again displaying another JOptionPane suppose B on a button click from JOptionPane A, and I have a button on JOptionPane B suppoce button1, on the click event of button1, I am using code JOptionPane.getRootFrame().dispose() for closing the JOptionPane B, but it closes both A and B, please help me how can close only B but not A.
here is my sample code
i want second JOptionPane must be open
import java.awt.Dimension;
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.JOptionPane;
import javax.swing.JPanel;
public class SampleCode extends JFrame {
public SampleCode() {
setSize(new Dimension(500, 500));
setLocation(450, 150);
but1 = new JButton("Click me");
add(but1);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
but1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
but1Function();
}
});
}
public static void main(String args[]) {
new SampleCode();
}
void but1Function() {
JPanel panel1 = new JPanel();
JButton but2 = new JButton("Open new dialog");
panel1.add(but2);
but2.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JPanel pan2 = new JPanel();
JButton but3 = new JButton("click me to close");
pan2.add(but3);
but3.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JOptionPane.getRootFrame().dispose();
}
});
JOptionPane.showMessageDialog(null, pan2);
}
});
JOptionPane jp = new JOptionPane(panel1, JOptionPane.CLOSED_OPTION,
JOptionPane.DEFAULT_OPTION, null, new Object[] {}, null);
JDialog dialog = jp.createDialog(null, "This one must be remain open");
dialog.setLocation(500, 200);
dialog.setSize(new Dimension(345, 200));
dialog.setVisible(true);
}
JButton but1;
}
You don't want to get the root frame nor dispose of it. You want to get the window that is displaying the JOptionPane, a Window that should be a modal JDialog. So instead, use SwingUtilities.getWindowAncestor(someComponentInJOptionPane), and call dispose() on that Window if you want to programmatically dispose of your JOPtionPane.
import java.awt.Component;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class OptionPaneFun {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#SuppressWarnings("serial")
public void run() {
final JPanel panel1 = new JPanel();
panel1.add(new JButton(new AbstractAction("Show new option pane") {
{
putValue(MNEMONIC_KEY, KeyEvent.VK_S);
}
#Override
public void actionPerformed(ActionEvent e1) {
final JPanel panel2= new JPanel();
panel2.add(new JButton(new AbstractAction("Dispose of this option pane") {
{
putValue(MNEMONIC_KEY, KeyEvent.VK_D);
}
#Override
public void actionPerformed(ActionEvent e2) {
Component comp = (Component) e2.getSource();
Window win = SwingUtilities.getWindowAncestor(comp);
if (win != null) {
win.dispose();
}
}
}));
JOptionPane.showMessageDialog(panel1, panel2);
}
}));
JOptionPane.showMessageDialog(null, panel1);
}
});
}
}
The static method "getRootFrame()" returns your root frame which is the only one and it's the same for both your components (A and B). What you need to do - you have to put two frames in your root frame (call them frameA and frameB) and put paneA to frameA and paneB to frameB. Instead of calling this static method just invoke frameB.dispose() on reference frameB which you already have.
Try to add
panel.validiate();
After the dispose command. I had the same problem once and it helped a lot when I used this trick.
Basically when you add this command, it is telling the frame to validate or actually do it.
Read the oracle docs for more info.

Duplication child JFrame on click

I have a window, which is the main window in my app and it contains buttons. On clicking on one of them, a child JFrame appears and if I click again another frame appears and this can be continuous depending on how many clicks are made. What I want, is when I click on the JButton once only one frame should open and since this frame is open no other similar frames can be opened upon clicking on the button for the second time until the first child frame is closed.
This can be done by opening a Modal dialog box instead of a jFrame. See How to Use Modality in Dialogs for more information.
Here is a simple example from A Simple Modal Dialog:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Point;
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;
public class AboutDialog extends JDialog implements ActionListener {
public AboutDialog(JFrame parent, String title, String message) {
super(parent, title, true);
if (parent != null) {
Dimension parentSize = parent.getSize();
Point p = parent.getLocation();
setLocation(p.x + parentSize.width / 4, p.y + parentSize.height / 4);
}
JPanel messagePane = new JPanel();
messagePane.add(new JLabel(message));
getContentPane().add(messagePane);
JPanel buttonPane = new JPanel();
JButton button = new JButton("OK");
buttonPane.add(button);
button.addActionListener(this);
getContentPane().add(buttonPane, BorderLayout.SOUTH);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
pack();
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
setVisible(false);
dispose();
}
public static void main(String[] a) {
AboutDialog dlg = new AboutDialog(new JFrame(), "title", "message");
}
}

Why isn't mouselistener working?

Here's the code. It prints out the mouse location when it's in the panel but not the JTextArea. I added the mouse listener to the text area as well? The problem is that the coordinates are not consistent throughout the JFrame. Is there a way to just have one mouselistener that covers the entire jframe?
Is there a way to disable the mouse listener in the textarea?
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
public class test extends JFrame {
public test(){
setPreferredSize(new Dimension(600,400));
JPanel p = new JPanel();
p.setBackground(Color.blue);
p.setPreferredSize(new Dimension(600,200));
JTextArea t = new JTextArea();
t.setPreferredSize(new Dimension(600,200));
add(p,BorderLayout.NORTH);
add(t,BorderLayout.SOUTH);
pack();
MouseInput m = new MouseInput();
addMouseMotionListener(m);
t.addMouseMotionListener(m);
setVisible(true);
}
public static void main(String[] args){
new test();
}
public class MouseInput implements MouseMotionListener{
#Override
public void mouseDragged(MouseEvent e) {
}
#Override
public void mouseMoved(MouseEvent e) {
int mx = e.getX();
int my = e.getY();
System.out.println(mx + "," + my);
}
}
}
Think of your mouse events like rain. They fall from the top of your component hierarchy down until something stops them.
Once stopped, they will no long notify other listeners lower in the hierarchy.
In you program you have and JPanel and JTextField sitting on top of another component (the content pane) sitting on a JLayeredPane sitting on top of the frame. Any one of these may be consuming the mouse event.
Try adding the MouseInput to your JPanel, p instead
Updated
This is an example of a global mouse listener (as suggested by #Hovercraft Full Of Eels, it WILL get hammered, as every mouse event will pass through it.
It also demonstrates how to translate a mouse point from it's local context to another context.
import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.AWTEventListener;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class GloablMouseListener {
public static void main(String[] args) {
new GloablMouseListener();
}
public GloablMouseListener() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new BorderLayout());
JPanel panel = new JPanel();
panel.setBackground(Color.BLUE);
JTextArea ta = new JTextArea(10, 20);
add(panel, BorderLayout.NORTH);
add(new JScrollPane(ta), BorderLayout.SOUTH);
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
#Override
public void eventDispatched(AWTEvent event) {
if (event instanceof MouseEvent) {
MouseEvent e = (MouseEvent) event;
System.out.println("Local point = " + e.getPoint());
Point p = e.getPoint();
Window window = SwingUtilities.getWindowAncestor(e.getComponent());
if (window != e.getSource() && window != null) {
p = SwingUtilities.convertPoint(e.getComponent(), e.getPoint(), window);
}
System.out.println("Global point = " + p);
}
}
}, AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
The JTextArea has its own MouseListener/MouseMotionListener that grabs the mouse information before any underlying class with a MouseListener or motion listener can.
This may be fixable by using an AWTEventListener, but I have not tried this myself yet.
Edit
OK, I have tried this as a for instance:
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
#SuppressWarnings("serial")
public class Test2 extends JPanel {
JTextArea textarea = new JTextArea(15, 60);
public Test2() {
JPanel topPanel = new JPanel();
topPanel.setBackground(Color.blue);
setLayout(new GridLayout(0, 1));
add(topPanel);
add(new JScrollPane(textarea));
addMouseMotionListener(new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
int x = e.getX();
int y = e.getY();
System.out.printf("%20s [%03d, %03d]%n", "From MouseAdapter:", x, y);
}
});
long eventMask = AWTEvent.MOUSE_MOTION_EVENT_MASK;
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
#Override
public void eventDispatched(AWTEvent awtEvent) {
MouseEvent mouseEvent = (MouseEvent) awtEvent;
Component component = (Component) awtEvent.getSource();
Point location = component.getLocationOnScreen();
Point test2Location = Test2.this.getLocationOnScreen();
// Normalized to find the mouse location relative to the main JPanel,
// the Test2 "this" JPanel.
int x = mouseEvent.getX() + location.x - test2Location.x;
int y = mouseEvent.getY() + location.y - test2Location.y;
System.out.printf("%20s [%03d, %03d]%n", "From AWTEvent:", x, y);
}
}, eventMask );
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Test2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new Test2());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Try adding a MouseListener to your application's GlassPane.
See these following link. It includes a Java Web Start demo of something similar to what you want to do.
How to Use Root Panes

Java tabbed panes within internal frame

I am trying to get an internal frame to contain tabbed panes. However, my code does not seem to be loading the panes into the internal frame. I have my code in the java files, called InternalFrame.java and TabbedPaneSample.java. The code for both files is included below. Can anyone show me how to fix the code below so that it loads the tabbed panes when I run InternalFrame.java?
Here is my code:
The code for InternalFrame.java is:
package test;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLayeredPane;
public class InternalFrame extends JFrame {
JButton openButton;
JLayeredPane desktop;
JInternalFrame internalFrame;
TabbedPaneSample myTabbedPaneSample = new TabbedPaneSample();
public InternalFrame() {
super("Click button to open internal frame with two panels.");
setSize(500, 400);
openButton = new JButton("Open");
Panel p = new Panel();
p.add(openButton);
add(p, BorderLayout.SOUTH);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
openButton.addActionListener(new OpenListener());
desktop = new JDesktopPane();
desktop.setOpaque(true);
add(desktop, BorderLayout.CENTER);
}
class OpenListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if ((internalFrame == null) || (internalFrame.isClosed())) {
internalFrame = new JInternalFrame("Internal Frame", true, true, true, true);
internalFrame.setBounds(50, 50, 200, 100);
internalFrame.add(myTabbedPaneSample, BorderLayout.CENTER);
internalFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
internalFrame.pack();
internalFrame.setMinimumSize(new Dimension(300, 300));
desktop.add(internalFrame, new Integer(1));
internalFrame.setVisible(true);
}
}
}
public static void main(String args[]) {
InternalFrame myInternalFrame = new InternalFrame();
myInternalFrame.setVisible(true);
}
}
And the code for TabbedPaneSample.java is:
package test;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
public class TabbedPaneSample extends JTabbedPane {
private JTabbedPane tabbedPane = new JTabbedPane();
private ImageIcon closeImage = new ImageIcon("C:/test/shipIcon.gif");
private Dimension closeButtonSize;
private int tabCounter = 0;
public TabbedPaneSample() {
closeButtonSize = new Dimension(closeImage.getIconWidth() + 2, closeImage.getIconHeight() + 2);
}
public void add() {
final JPanel content = new JPanel();
JPanel tab = new JPanel();
tab.setOpaque(false);
JLabel tabLabel = new JLabel("Tab " + (++tabCounter));
JButton tabCloseButton = new JButton(closeImage);
tabCloseButton.setPreferredSize(closeButtonSize);
tabCloseButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int closeTabNumber = tabbedPane.indexOfComponent(content);
tabbedPane.removeTabAt(closeTabNumber);
}
});
tab.add(tabLabel, BorderLayout.WEST);
tab.add(tabCloseButton, BorderLayout.EAST);
this.addTab(null, content);
this.setTabComponentAt(this.getTabCount() - 1, tab);
}
public static void main(String[] args) {
TabbedPaneSample main = new TabbedPaneSample();
main.add();
main.add();
}
}
Here's one approach, shown below. A more flexible approach using Action is referenced here.
Addendum: Reviewing your code, you should let the various layout managers and component preferred sizes do more of the work, as shown. In particular, this.setPreferredSize() is done for demonstration purposes. In a real application, you would restore user size and location preferences.
package overflow;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
/** #see https://stackoverflow.com/posts/6514889 */
public class InternalFrame extends JFrame {
JButton openButton;
JLayeredPane desktop;
JInternalFrame internalFrame;
public InternalFrame() {
super("Click button to open internal frame with two tabs.");
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setPreferredSize(new Dimension(400, 400));
openButton = new JButton("Open");
JPanel p = new JPanel();
p.add(openButton);
this.add(p, BorderLayout.SOUTH);
openButton.addActionListener(new OpenListener());
desktop = new JDesktopPane();
this.add(desktop, BorderLayout.CENTER);
this.pack();
this.setLocationRelativeTo(null);
}
class OpenListener implements ActionListener {
private static final int DELTA = 40;
private int offset = DELTA;
public void actionPerformed(ActionEvent e) {
internalFrame = new JInternalFrame(
"Internal Frame", true, true, true, true);
internalFrame.setLocation(offset, offset);
offset += DELTA;
internalFrame.add(createTabbedPane());
desktop.add(internalFrame);
internalFrame.pack();
internalFrame.setVisible(true);
}
}
private JTabbedPane createTabbedPane() {
JTabbedPane jtp = new JTabbedPane();
createTab(jtp, "One");
createTab(jtp, "Two");
return jtp;
}
private void createTab(JTabbedPane jtp, String s) {
jtp.add(s, new JLabel("TabbedPane " + s, JLabel.CENTER));
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
InternalFrame myInternalFrame = new InternalFrame();
myInternalFrame.setVisible(true);
}
});
}
}
First of all, I think Finally, I think you shouldn't use desktop.add(internalFrame, new Integer(1)) but rather desktop.add(internalFrame) instead, the reason is that JDesktopPane uses its layers (it is a JLayeredPane subclass) internally, and I don't think you should play with layers yourself.
Then, following this problem I had once with JInternalFrame, I would advise you call pack() after adding the internal frame to the desktop pane.
Hence, you should try with your OpenListener class looking like this:
class OpenListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
if ((internalFrame == null) || (internalFrame.isClosed())) {
internalFrame = new JInternalFrame("Internal Frame", true, true, true, true);
internalFrame.setBounds(50, 50, 200, 100);
internalFrame.add(myTabbedPaneSample, BorderLayout.CENTER);
internalFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// internalFrame.pack();
internalFrame.setMinimumSize(new Dimension(300, 300));
// desktop.add(internalFrame, new Integer(1));
desktop.add(internalFrame);
internalFrame.pack();
internalFrame.setVisible(true);
}
}
}
Besides, I also agree with trashgod comments on Action of course and the simplifying rework he has done on your snippet.
I preferred to create in my Main Frame class (which extends JFrame) the following function:
private void showIntFrame(Class intFrameClass) {
JInternalFrame targetFrame = null;
int xoff = 0, yoff = 0;
for(JInternalFrame jif : jdp.getAllFrames()) {
if(jif.getClass().equals(intFrameClass))
targetFrame = jif;
if(jif.getLocation().x > xoff)
xoff = jif.getLocation().x;
if(jif.getLocation().y > yoff)
yoff = jif.getLocation().y;
}
if(targetFrame == null) {
try {
Constructor<JInternalFrame> c = intFrameClass.getConstructor(MainFrame.class);
targetFrame = c.newInstance(MainFrame.this);
} catch (Exception ex) {
System.err.println("Exception in MainFrame.showIntFrame() while creating new JInternalFrame instance. " + ex.getLocalizedMessage());
ex.printStackTrace();
return;
}
jdp.add(targetFrame);
targetFrame.setLocation(xoff + 30, yoff + 30);
}
targetFrame.setVisible(true);
try {
targetFrame.setSelected(true);
} catch (PropertyVetoException ex) {
System.err.println("PropertyVetoException in MainFrame.showIntFrame() while activating JInternalFrame instance. " + ex.getLocalizedMessage());
}
}
Here jdp is instance of JDesktopPane, which previously was set as ContentPane of my main JFrame.
Because my programs often contain numbers of different classes, inherited from JInternalFrame, it is easier to call this function from event handlers to show new subclass of JInternalFrame.
Every subclass of JInternalFrame in my programs have one constructor with one parameter - MainFrame (main JFrame).

Categories

Resources