Experimenting with layered panes here and I'm having a problem. I have two JPanels. I'm adding them both to a JLayeredPane - panel1 is big enough to take up the whole space, while panel2 is smaller and centered using FlowLayout. The problem is that with JLayeredPane, the background next to panel2 seems to be painted white when I add it. Here's a picture to illustrate. panel1 is blue, panel2 is red:
As you can see, the bottom part of the panel1 is still painted, but for some reason the sides are just white. The panel2 is 700 pixels wide and centered, while the frame is 800 pixels wide, so it's definitely not a problem with that. Here's the entire class:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
public class Errortest extends JFrame {
public static void main(String[] args) {
//Creating frame and setting the JLayeredPane as contentpane
Errortest frame = new Errortest();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLayeredPane pane = new JLayeredPane();
pane.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0));
pane.setPreferredSize(new Dimension(800,600));
frame.setContentPane(pane);
frame.pack();
//Creating panels
JPanel panel1 = new JPanel();
panel1.setPreferredSize(new Dimension(800,600));
panel1.setBackground(Color.BLUE);
JPanel panel2 = new JPanel();
panel2.setPreferredSize(new Dimension(700,500));
panel2.setBackground(Color.RED);
pane.add(panel1, new Integer(0));
pane.add(panel2, new Integer(1));
frame.setVisible(true);
}
}
Hopefully that wasn't too confusing. From what I can tell, the white background comes from the JFrame itself, since when I do frame.setBackground(Color.YELLOW); it turns yellow.
If you add a component to a JLayeredPane, it's like adding it to a null layout using container: you must fully specify the component's size and position.
import java.awt.*;
import javax.swing.*;
public class ErrorTest extends JFrame {
public static void main(String[] args) {
// Creating frame and setting the JLayeredPane as contentpane
ErrorTest frame = new ErrorTest();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent pane = new JLayeredPane();
//pane.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 0)); // Take out FlowLayout
pane.setPreferredSize(new Dimension(800, 600));
frame.setContentPane(pane);
// Creating panels
JPanel panel1 = new JPanel();
panel1.setBackground(Color.BLUE);
panel1.setBounds(0, 0, 800, 600); // <<<---- Set Bounds
JPanel panel2 = new JPanel();
panel2.setBackground(Color.RED);
panel2.setBounds(50, 0, 700, 500); // <<---- Set Bounds
pane.add(panel1, new Integer(1));
pane.add(panel2, new Integer(2));
frame.pack();
frame.setVisible(true);
}
}
I believe I found out what the problem is. Has to do with the answer here:
JLayeredPane not respecting layers
You need a layout manager which understands the Z-Axis. The default layout managers don't understand the Z-Axis of the JLayeredPane.
So it's the FlowLayout that's messing me up. I'll just use absolute positioning for my project and use setBounds() to make sure the red panel ends up in the middle. Otherwise I'd have to look into custom layout managers I suppose.
Related
I'm working on a Swing GUI using the JLayeredPane. The JFrame has a JLayeredPane which contains two JPanels. Later I want to display some components in the JPanels, I cut this part of the code to make it shorter for you.
How do I resize the JFrame to the sizes of the JPanels? frame.pack() does not work and without the line setting the preferred size the GUI will show with minimal size.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
public class TestGUI {
private JFrame frame;
private JLayeredPane layeredPane;
private JPanel panelBottom;
private JPanel panelTop;
private MainMenuBar menuBar;
public TestGUI() {
// panel bottom:
panelBottom = new JPanel();
panelBottom.setSize(1000, 500);
panelBottom.setBackground(new Color(0, 100, 0, 100));
panelBottom.setLayout(new GridBagLayout());
// panel top:
panelTop = new JPanel();
panelTop.setSize(950, 450);
panelTop.setBackground(new Color(0, 0, 100, 100));
panelTop.setLayout(new GridBagLayout());
// layered pane:
layeredPane = new JLayeredPane();
layeredPane.add(panelBottom, 1);
layeredPane.add(panelTop, 0);
// frame building:
frame = new JFrame();
menuBar = new MainMenuBar();
frame.setJMenuBar(menuBar);
frame.setLayout(new BorderLayout());
frame.setPreferredSize(new Dimension(1100, 600)); // <-- Without this the GUI will be very small
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(layeredPane, BorderLayout.CENTER);
frame.pack(); // <-- does not work!
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
new TestGUI();
}
}
EDIT: I could just change the preferred size line to fit the biggest JPanel, but i ask the question because I want the JFrame to resize depending on the size of the JPanels dynamically.
As suggested in How to Use Layered Panes: Laying Out Components in a Layered Pane, "Although a layered pane has no layout manager by default, you can still assign a layout manager to the layered pane." Use OverlayLayout, seen here, for overlapping panels.
Alternatively, use JInternalFrame, which does allow you to pack() the internal frames individually, as shown here and here.
I am having issues where the background color of my inner panel is not being set (or not being shown) when inside my JTabbedPane
I have the following structure:
JPanel BorderLayout:
JTabbedPane (BorderLayout.Center):
JPanel Default
..
When I add the inner JPanel to the borderLayout at BorderLayout.CENTER instead of the JTabbedPane then I can see the background color, however if my inner panel is in the tabbed pane and tabbed pane is added to the center then the background color is default and seems to be overriding it.
panel1.setBackground(Color.WHITE);
JTabbedPane tabbedPane = new JTabbedPane();
tabbedPane.add(panel1);
//add tabbed pane to panel with borderlayout
//Background color of this panel is also set previously
add(tabbedPane, BorderLayout.CENTER);
What about making desired components transparent?
package javaapplication31;
import java.awt.EventQueue;
import javax.swing.*;
import java.awt.Color;
import java.awt.Dimension;
public class JavaApplication31
{
public static void main(String[] args)
{
Runnable r = new Runnable()
{
#Override
public void run()
{
//let's make all TabbedPanes transparent by default
UIManager.put("TabbedPane.contentOpaque", false);
JFrame frame = new JFrame();
JPanel parentPanel = new JPanel();
parentPanel.setBackground(Color.WHITE);
frame.add(parentPanel);
JTabbedPane tp = new JTabbedPane();
parentPanel.add(tp);
//Make transparent panel
JPanel panelTransparent = new JPanel();
panelTransparent.setOpaque(false); // this makes panel transparent
panelTransparent.setPreferredSize(new Dimension(200, 200));
tp.addTab("Transparent", panelTransparent);
//Make panel (by default panel is opaque)
JPanel panelOpaque = new JPanel();
tp.addTab("Opaque", panelOpaque);
frame.setPreferredSize(new Dimension(300, 300));
frame.pack();
frame.setVisible(true);
}
};
EventQueue.invokeLater(r);
}
}
I am trying to add multiple panels to another panel. I want them to be on top of each other so I'm using JLayeredPane. I've added a button to each one. Two buttons should appear when it works.
import java.awt.Color;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
public class PanelTest {
public static void main(String[] args) {
JFrame frame = new JFrame();
JPanel mainPanel = new JPanel();
JPanel panel1 = new JPanel();
JPanel panel2 = new JPanel();
JLayeredPane layers = new JLayeredPane();
mainPanel.add(layers);
panel2.setOpaque(false);
panel1.setOpaque(false);
panel1.setVisible(true);
panel2.setVisible(true);
panel1.add(new JButton("1111111111"));
panel2.add(new JButton("2"));
frame.setContentPane(mainPanel);
layers.add(panel1, new Integer(2));
layers.add(panel2, new Integer(3));
frame.setVisible(true);
frame.setSize(500, 500);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
Only the grey background of the mainPanel is visible. What am I doing wrong?
When adding a component to a JLayeredPane, you're essentially adding the component to a null layout using container. This means that you must fully specify both the component's size and its position, often solving both with a setBounds(...) call. Call this on panel1 and panel2, for example:
panel1.setBounds(10, 10, 100, 100);
panel2.setBounds(70, 70, 100, 100);
Edit:
setting bounds didn't make any difference
Setting the size (bounds) is required but you still have an additional problem.
You are adding the JLayeredPane to a JPanel which uses a FlowLayout. By default a FlowLayout respects the preferred size of the component added to it. Since JLayeredPane uses a null layout its preferred size is (0, 0) so there is nothing to paint.
Two solutions:
You don't need the JPanel, just use: frame.setContentPane(layers);
If you really want to use the panel then you need to change the layout manager: JPanel mainPanel = new JPanel( new BorderLayout());
As described in the title. I've got two JPanels one on top of the other using a BorderLayout().
import java.awt.*;
import javax.swing.*;
public class myForm(){
public static void main(String[] args) {
JFrame myFrame = new JFrame("SingSong");
myFrame.setLocation(100,100);
myFrame.setSize(new Dimension(1024,800));
myFrame.setLayout(new BorderLayout());
JPanel jp = new JPanel();
jp.setBackground(new Color(0x00FF00FF));
JPanel jp2 = new JPanel(new BorderLayout());
jp2.setBackground(new Color(0x00000000));
jp.setPreferredSize(new Dimension(100,400));
jp2.setPreferredSize(new Dimension(100,400));
jp2.setLocation(0, 512);
myFrame.add(jp2, BorderLayout.SOUTH);
myFrame.add(jp, BorderLayout.NORTH);
}
}
They each take up half, but how can I go about setting it so that they always take up half the JFrame each, even when resized?
(P.S. I normally use better variable names, I just whipped up that as an SSCCE)
Try the GridLayout
JFrame myFrame = new JFrame("SingSong");
myFrame.setLocation(100, 100);
myFrame.setSize(new Dimension(1024, 800));
GridLayout layout = new GridLayout(2, 1);
myFrame.setLayout(layout);
JPanel jp = new JPanel();
jp.setBackground(new Color(0x00FF00FF));
JPanel jp2 = new JPanel(new BorderLayout());
jp2.setBackground(new Color(0x00000000));
myFrame.add(jp);
myFrame.add(jp2);
myFrame.setVisible(true);
when you setPreferredSize, the layout manager will make it so that both the panels are always 400 pixels tall. If you want the panels to always be half of the height of the frame, then don't set the preferred size. If that doesn't work, then you could always try setting the panels' height to (myFrame.getSize().height) / 2 which will be half the height of the frame.
I have the following layout:
The red, blue and green parts are JPanel. In the red part I have four JLabel. Now if I resize the JFrame, the title labels always stay in the center. But I would prefer if they are evenly distributed horizontaly in the red part. Which layout should I use for that?
Use a GridLayout(1, 0) for the top JPanel. The two numbers means 1 row and variable number of columns. If you are using JLabels, this will be sufficient, especially if you set the JLabels alignment constant to SwingConstants.CENTER. If you are using components that fill the grid slots, such as JButtons, then you may need to use other variants of the GridLayout constructor, such as GridLayout(1, 0, ?, 0) Where the ? is a number that tells the GridLayout how much horizontal separation there should be between slots.
The overall GUI would use a BorderLayout of course.
For more and better information on this, please check out Lesson: Laying Out Components Within a Container and A Visual Guide to Layout Managers
For example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.*;
public class LayoutEg {
private static void createAndShowGui() {
String[] labelStrings = {"One", "Two", "Three", "Four"};
JPanel topPanel = new JPanel(new GridLayout(1, 0));
for (String labelString : labelStrings) {
// create labels and center the text
topPanel.add(new JLabel(labelString, SwingConstants.CENTER));
}
topPanel.setBackground(Color.red);
JPanel centerPanel = new JPanel();
centerPanel.setBackground(Color.blue);
// setting preferred size for demonstration purposes only
centerPanel.setPreferredSize(new Dimension(700, 400));
JPanel bottomPanel = new JPanel();
bottomPanel.setBackground(Color.green);
// main panel uses BorderLayout
JPanel mainPanel = new JPanel(new BorderLayout());
mainPanel.add(centerPanel, BorderLayout.CENTER);
mainPanel.add(topPanel, BorderLayout.PAGE_START);
mainPanel.add(bottomPanel, BorderLayout.PAGE_END);
JFrame frame = new JFrame("LayoutEg");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Use a BorderLayout for the frame's content pane, and use a GridLayout with 1 row and four columns for the title panel.
See http://docs.oracle.com/javase/tutorial/uiswing/layout/border.html and http://docs.oracle.com/javase/tutorial/uiswing/layout/grid.html for tutorials.
If you don't want the same width assigned to each label, but in fact want the same space between every label, you may also use a BoxLayout, and add a glue between each label (and between the border of the panel and the label:
p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
p.add(Box.createHorizontalGlue());
p.add(new JLabel("Label"));
p.add(Box.createHorizontalGlue());
p.add(new JLabel("Long Label"));
p.add(Box.createHorizontalGlue());
p.add(new JLabel("Very long Label"));
p.add(Box.createHorizontalGlue());
p.add(new JLabel("Extremely long Label"));
p.add(Box.createHorizontalGlue());
Use a BorderLayout for the main frame and use the NORTH, CENTER and SOUTH places.
To create empty space like in the bottom panel, use Box.createVerticalStrut(size).
Use BoxLayout to place the labels packed in a row.
Finally use GridBagLayout to center a panel in another Panel.
Here is a short example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Prototype extends JFrame {
public Prototype() {
JPanel labelPanel = new JPanel();
labelPanel.setLayout(new BoxLayout(labelPanel, BoxLayout.LINE_AXIS));
labelPanel.add(new JLabel("First"));
labelPanel.add(Box.createHorizontalStrut(10));
labelPanel.add(new JLabel("Second"));
labelPanel.setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
labelPanel.setOpaque(false);
JPanel bottomPanel = new JPanel();
bottomPanel.add(Box.createVerticalStrut(15));
bottomPanel.setBackground(Color.GREEN);
JPanel centerPanel = new JPanel();
centerPanel.add(Box.createRigidArea(new Dimension(200, 300)));
centerPanel.setBackground(Color.BLUE);
JPanel northPanel = new JPanel(new GridBagLayout());
northPanel.add(labelPanel);
northPanel.setBackground(Color.RED);
JPanel panel = new JPanel(new BorderLayout());
panel.add(northPanel, BorderLayout.NORTH);
panel.add(centerPanel, BorderLayout.CENTER);
panel.add(bottomPanel, BorderLayout.SOUTH);
add(panel);
pack();
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args) {
new Prototype();
}
}
Use a MigLayout.
No, seriously, I used to go crazy trying to get Java layouts working. Then I started maintaining some software that uses MigLayouts, and after a week or so I could do anything I wanted. There is an excellent cheat sheet that looks pretty intimidating, but it's incredibly helpful.
With a MigLayout, to have evenly spread labels in a JPanel you would:
// the "fillx" means that the layout will expand to take up all available horizontal space
JPanel panel = new JPanel(new Miglayout("fillx"));
// the "growx" means that the component will expand to take up all available horizontal space
add(new JLabel("Work items"), "growx");
add(new JLabel("Change set"), "growx");
add(new JLabel("Files"), "growx");
add(new JLabel("Source code"), "growx");
gridLayout, put the labels into the grid layout and set rows to 1 and columns to 4 (1 row for each Label)
http://www.javabeginner.com/java-swing/java-gridlayout-class-example
GridBagLayout is one approach. Set the weightx value to 1.0.
For labels to be distributed evenly horizantally - in the red panel - use BoxLayout with X_AXIS direction and put 'glue' between each label - More here -
http://docs.oracle.com/javase/tutorial/uiswing/layout/box.html