UI2
should be a dialog and not another JFrame
since Swing applications should usually only have a single, top-level container.
You also don't need to do all the hard work yourself of placing GUI components on the screen nor sizing them. You should use layout managers and other, relevant parts of the rich, API – in order to make the JButton
look like an app icon.
More notes after the code.
import java.awt.*;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.Objects;
import javax.imageio.ImageIO;
import javax.swing.*;
public class MainUI {
private JButton button;
private JFrame frame;
private JPanel panel;
private UI2 ui2;
public MainUI() {
frame = new JFrame();
frame.setSize(1000, 700);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
try {
button = new JButton();
Image img = ImageIO.read(Objects.requireNonNull(getClass().getResource("icons8-messages-100.png")));
button.setIcon(new ImageIcon(img));
button.setFocusable(false);
button.setContentAreaFilled(false);
button.setBorderPainted(false);
panel = new JPanel();
panel.add(button);
frame.add(panel);
button.addActionListener(e -> {
if (ui2 == null) {
ui2 = new UI2(frame);
}
ui2.setVisible(true);
});// addActionListener
}
catch (Exception e) {
e.printStackTrace();
}
frame.setVisible(true);
}// End of MainUI
public static void main(String[] args) {
EventQueue.invokeLater(() -> new MainUI());
}
}// Class MainUI
@SuppressWarnings("serial")
class UI2 extends JDialog {
public UI2(JFrame owner) {
super(owner);
setSize(200, 200);
setResizable(false);
setLocationRelativeTo(owner);
addComponentListener(new ComponentAdapter() {
public void componentMoved(ComponentEvent e) {
// This makes the ui2 not go outside the Main UI
int x = getX();
int y = getY();
int width1 = owner.getWidth();
int height1 = owner.getHeight();
int width2 = getWidth();
int height2 = getHeight();
if (x < owner.getX()) {
setLocation(owner.getX(), y);
}
if (y < owner.getY()) {
setLocation(x, owner.getY());
}
if (x + width2 > owner.getX() + width1) {
setLocation(owner.getX() + width1 - width2, y);
}
if (y + height2 > owner.getY() + height1) {
setLocation(x, owner.getY() + height1 - height2);
} // end of if statements
}// componentMoved
});// addComponentListener
}
}// Class UI2
(Below notes are in no particular order.)
- You don't need to create a new
UI2
each time the user clicks the JButton
(in UI1
). Create it once and then just hide it when you close it and show it when you click the JButton
. The default behavior is to hide the JDialog
when it is closed.
- A Swing application does not need to extend
JFrame
(or JPanel
or any other JComponent). A Swing application can extend JComponent
(or subclass thereof) but it does not have to.
- The default layout for [the content pane of]
JFrame
is BorderLayout
so no need to explicitly set this.
- Printing a message, like Something's Wrong, in a
catch
block, might be user-friendly but it won't help you find the cause of the exception
. I nearly always print the stack trace in my catch
blocks.
Screen capture of running app.

However, since you don't want UI2
to move outside of UI1
, an alternative would be to use a JInternalFrame rather than a JDialog
. Here is a demonstration.
(Again, there are notes after the code.)
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.util.Objects;
import javax.imageio.ImageIO;
import javax.swing.DefaultDesktopManager;
import javax.swing.DesktopManager;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JPanel;
public class IframTst {
private JDesktopPane desktopPane;
private JInternalFrame iFrame;
public IframTst() throws IOException {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createButton(), BorderLayout.PAGE_START);
frame.add(createDesktopPane(), BorderLayout.CENTER);
frame.setSize(1000, 700);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createButton() throws IOException {
JPanel panel = new JPanel();
JButton button = new JButton();
Image img = ImageIO.read(Objects.requireNonNull(getClass().getResource("icons8-messages-100.png")));
button.setIcon(new ImageIcon(img));
button.setFocusable(false);
button.setContentAreaFilled(false);
button.setBorderPainted(false);
button.addActionListener(this::showIframe);
panel.add(button);
return panel;
}
private JDesktopPane createDesktopPane() {
desktopPane = new JDesktopPane();
DesktopManager manager = new DefaultDesktopManager() {
private static final long serialVersionUID = -4685522430190278205L;
@Override
public void dragFrame(JComponent f, int newX, int newY) {
setBoundsForFrame(f, newX, newY, f.getWidth(), f.getHeight());
}
@Override
public void setBoundsForFrame(JComponent f,
int newX,
int newY,
int newWidth,
int newHeight) {
Rectangle rect = desktopPane.getVisibleRect();
if (newX < 0) {
newX = 0;
}
if (newX + newWidth > rect.width) {
newX = rect.width - newWidth;
}
if (newY < 0) {
newY = 0;
}
if (newY + newHeight > rect.height) {
newY = rect.height - newHeight;
}
super.setBoundsForFrame(f, newX, newY, newWidth, newHeight);
}
};
desktopPane.setDesktopManager(manager);
return desktopPane;
}
private void showIframe(ActionEvent event) {
if (iFrame == null) {
iFrame = new JInternalFrame(null, false, true, false, false);
iFrame.setDefaultCloseOperation(JInternalFrame.HIDE_ON_CLOSE);
iFrame.setSize(200, 200);
desktopPane.add(iFrame);
}
iFrame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
try {
new IframTst();
}
catch (IOException xIo) {
xIo.printStackTrace();
}
});
}
}
- The
ActionListener
is implemented using method references
- The inspiration for keeping the
JInternalFrame
within the bounds of its parent JDesktopPane
came from
Preventing JInternalFrame from being moved out of a JDesktopPane
(as well as looking at the source code for class DefaultDesktopManager
)
You can also set the initial location of the JInternalFrame
within the JDesktopPane
. Refer to
How do I open a JInternalFrame centered in a JDesktopPane?
How it looks when I run it.
