I am learning how to use Swing and found myself quite difficult task.
What I am trying to accomplish: I want to have panel (call it menu panel) on the left side (let's say 100px width) and the second panel (call it content panel), which takes the rest of available place.
In menu panel there are 3 buttons. When I press on of them, to the right side of menu panel (over content panel) second menu panel (submenu) should appear (and it should start in the middle of button which was pressed).
It may be hard to understand, so I've created simple draft:
I tried JLayeredPane but there were problems with resizing window (elements in Layered Pane didn't resize).
JLayeredPane
miss implementations for LayoutManager
, you have to setPreferredSize
or setBounds
manually for sizing/place JComponents
,
there is one possible workaround you can add ComponentListener
to the JFrame
, then on componentResized(ComponentEvent e)
you can resize/replace JComponent(s)
to the desired Bounds
for example
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class LayeredPaneWithOverlap {
private JTextArea textArea = new JTextArea(2, 10);
private JPanel textPanel = new JPanel(new BorderLayout());
private JTable table = new JTable(30, 5);
private JScrollPane scroll = new JScrollPane(table);
private JLayeredPane layer = new JLayeredPane();
private JFrame frame = new JFrame("Frame with resiziable JLayeredPane");
public void makeUI() {
textArea.setBorder(new LineBorder(Color.DARK_GRAY));
textArea.setText("Frame with resiziable JLayeredPane");
textPanel.setOpaque(false);
textPanel.add(textArea, BorderLayout.NORTH);
Font font = textArea.getFont();
FontMetrics fontMetrics = textArea.getFontMetrics(font);
int h = fontMetrics.getHeight() + frame.getInsets().top +
textPanel.getInsets().top + textArea.getInsets().top
+ textArea.getInsets().bottom;
scroll.setBounds(0, h, 400, 300);
layer.add(textPanel, new Integer(2));
layer.add(scroll, new Integer(1));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 400);
frame.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
resizeAll();
}
});
}
});
frame.setLocationRelativeTo(null);
frame.add(layer);
resizeAll();
frame.setVisible(true);
}
void resizeAll() {
Insets insets = frame.getInsets();
int w = frame.getWidth() - insets.left - insets.right;
int h = frame.getHeight() - insets.top - insets.bottom;
textPanel.setSize(w, h);
scroll.setSize(w, h - scroll.getY());
layer.revalidate();
layer.repaint();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new LayeredPaneWithOverlap().makeUI();
}
});
}
}
You can set a layoutmanager for the layered pane, javax.swing.OverlayLayout uses the full available space and allows resizing.
JLayeredPane layer = new JLayeredPane();
layer.setLayout(new OverlayLayout(layer));
You probably don't want the submenu to occupy the fullspace. To avoid it you can override its get…size-methods. Or you can add a second LayeredPane (for it's transperancy and it's layoutmanager), set a normal BoxLayout and use a spacer.
JPanel normalContents = new JPanel();
layer.add(normalContents, JLayeredPane.DEFAULT_LAYER);
JLayeredPane subMenuAuxiliaryLayer = new JLayeredPane()
subMenuAuxiliaryLayer.setLayout(new BoxLayout(subMenuAuxiliaryLayer, BoxLayout.LINE_AXIS));
layer.add(subMenuAuxiliaryLayer, JLayeredPane.PALETTE_LAYER);
JPanel submenuContents = new JPanel();
subMenuAuliliaryLayer.add(submenuContents);
subMenuAuxiliaryLayer.add(Box.createHorizontalGlue());
contentPanel.setLayout(null); // Absolute positioning of children.
@Override
public void actionPerformed(ActionEvent evt) {
final JButton btn = (JButton) evt.getSource();
final int buttonY = btn.getY(); // Must be final for usage in new Runnable object.
SwingUtilities.invokeLater(new Runnable() { // Return fast from event handling.
@Override
public void run() {
JPanel child = new JPanel();
child.setBackground(Color.RED); // So we'll see it.
child.setBounds(0, buttonY, 100, 300);
contentPanel.removeAll(); // Clear content panel of prior additions.
contentPanel.add(child); // Add a new panel.
contentPanel.repaint(10L);
}
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With