Two JPanels in JFrame , One under other - java

I've got two panels in my frame, and I would like to set them one under other, and this first should have size like 9/10*screen frame, and this second 1/10.
I've tried with GridLayout (2 rows and one column) but I can't set them specific size.
How should I do that?
ok maybe I will write some my code:
I am writing game - pacman, and in the first panel there is a whole game, and in this second I would like to display player info(like score, name etc.) This first I would like to set on 80% screen, and second on 20%.
What is more my frame should be resizeable and all in it, sa I have to change size of Panels(keeping this 80% to 20%) when size of frame is changing. SO that I wrote this InitComponents().
package pacman;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.Toolkit;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import java.awt.Image;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
public class Pacman extends JFrame implements items
{
Image image;
public Pacman()
{
initComponents();
try {
image = ImageIO.read( Pac.class.getResourceAsStream("/img/Pac02.gif"));
} catch (Exception e) {
System.out.println("Blad prz otwieraniu " + e);
System.exit(0);
}
int screen_width = Toolkit.getDefaultToolkit().getScreenSize().width;
int screen_height = Toolkit.getDefaultToolkit().getScreenSize().height;
this.setLocation(screen_width/3, screen_height/3);
this.setLayout(new BorderLayout());
this.getContentPane().add(panel, BorderLayout.CENTER);
this.getContentPane().add(panel2, BorderLayout.PAGE_END);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setIconImage(image);
setTitle("..::Pacman::..");
setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setPreferredSize(new Dimension(416,438));
this.pack();
setLocationRelativeTo(null);
setVisible(true);
}
private void initComponents() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
int width = e.getComponent().getSize().width;
int height = e.getComponent().getSize().height;
panel.setSize(width, height*8/10) ;
panel2.setSize(width, height*2/10);
}
});
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Pacman();
}
});
}
}

GridLayout is the wrong layout if you want different sized components. As the javadoc states:
The container is divided into equal-sized rectangles, and one
component is placed in each rectangle.
If you've only got JPanels, you might want to consider a JSplitPane - see javadoc or tutorial.
EDIT: Based on your edit/code, a JSplitPane really looks like the solution to your problem. You can then set the divider location after creation using setDividerLocation(double) - see the javadoc - e.g.
JSplitPane split = new JSplitPane(JSplitPane.VERTICAL);
split.setTopComponent(topPanel);
split.setBottomComponent(bottomPanel);
split.setDividerLocation(0.8);
Alternatively, since it's quite hard to suggest a layout without knowing your intentions for the GUI, you should consider taking a look at the Visual Guide to layouts.

Have a look at this output :
And here is the code for that, you are not suppose to use GridLayout when you need to adjust sizes for columns/rows, under such situations comes GridBagLayout to the rescue.
import java.awt.*;
import javax.swing.*;
// http://stackoverflow.com/questions/10968853/two-jpanels-in-jframe-one-under-other
public class GridBagLayoutExample
{
private void displayGUI()
{
JFrame frame = new JFrame("GridBagLayout Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel contentPane = new JPanel();
contentPane.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.anchor = GridBagConstraints.FIRST_LINE_START;
gbc.fill = GridBagConstraints.BOTH;
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 1.0;
gbc.weighty = 0.9;
JPanel topPanel = new JPanel();
topPanel.setOpaque(true);
topPanel.setBackground(Color.WHITE);
contentPane.add(topPanel, gbc);
gbc.weighty = 0.1;
gbc.gridy = 1;
JPanel bottomPanel = new JPanel();
bottomPanel.setOpaque(true);
bottomPanel.setBackground(Color.BLUE);
contentPane.add(bottomPanel, gbc);
frame.setContentPane(contentPane);
frame.setSize(200, 300);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new GridBagLayoutExample().displayGUI();
}
});
}
}

Check out,
Assuming that by under you mean one Jpanel is overlapping another!
http://docs.oracle.com/javase/tutorial/uiswing/components/layeredpane.html
cheers!

You can use border layout
http://docs.oracle.com/javase/tutorial/uiswing/layout/border.html
Set the bigger panel to be CENTER, and the smaller to be PAGE_END. Set the size of the bigger panel, and the smaller panel will use what space is left.

Related

Drawing graphics on a panel

I am trying to draw graphics on panels, but I am not sure how I would go about doing that.
I have tried creating a class that extends the JPanel and overrided paintComponent, and some other methods, but nothing gets rendered at all.
Here is my code:
edit:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Lesson1 extends JFrame {
private static final long serialVersionUID = -198253288329146091L;
private JPanel contentPane;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Lesson1 frame = new Lesson1();
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public Lesson1() {
contentPane = new JPanel();
setContentPane(contentPane);
JPanel panel = new JPanel() {
private static final long serialVersionUID = -5974584127539186578L;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillRect(0, 0, 500, 500);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
};
contentPane.add(panel);
JPanel panel_1 = new JPanel() {
private static final long serialVersionUID = 123456789L;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.PINK);
g.fillRect(0, 0, 200, 200);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
};
panel.setLayout(new BorderLayout());
panel_1.setLayout(new BorderLayout());
panel.add(panel_1);
}
}
I am not sure what I am doing wrong here, but I have tried everything I could. Thanks!
Mistake #1
contentPane.setLayout(null);
and
panel.setLayout(null);
Before you do anything else, you need to learn and understand what the layout managers actually do and why null layouts are naive and not recommended (especially when you're just learning).
Start by taking the time to go through Laying Out Components Within a Container
Remove contentPane.setLayout(null); and change panel.setLayout(null); to panel.setLayout(new BorderLayout()); and you will see an immediate change.
In fact, you really don't need panel, as the default contentPane of a JFrame is already setup to use BorderLayout.
This means you can get rid of panel.setBounds(73, 52, 231, 143);
Mistake #2
Okay, this is more of an oversight, but, when you start customising components, you need to provide sizing hints, which allows the layout managers to make decisions about how best to layout your component in relationship to other components and based on it's own internal rules.
To this end, you should, at the very least, override the getPreferredSize method (avoid the setXxxSize methods as these can lead to unexpected results if used incorrectly)
Add...
#Override
public Dimension getPreferredSize() {
return new Dimension(1001, 1001);
}
to panel_1
This now means you can do something more like...
Lesson1 frame = new Lesson1();
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
and the window will pack it self around the component (and be centred on the screen) and you can get rid of setBounds(100, 100, 450, 300);
Alright, anyways I tried but have no luck making it so I can set panels in a specific position :/
Layout management in a GUI environment is part science, part voodoo, part black magic
Pixel perfect positioning is an illusion in modern UI development. There are so many factors which go into determining "how" a component should be positioned on a single platform, let along across multiple platforms, you'd spend the rest of your live constantly adding "hacks" to account for the infinite number of possible edge case.
This is why any decent UI framework abstracts the concept, Swing uses the layout manager API for this purpose, iOS (and MacOS) use Auto layout, etc...
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Lesson1 {
/**
* Launch the application.
*/
public static void main(String[] args) {
new Lesson1();
}
public Lesson1() {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.NORTHWEST;
add(new RectPane(), gbc);
gbc.gridx = 2;
gbc.anchor = GridBagConstraints.NORTHEAST;
add(new RectPane(), gbc);
gbc.gridx = 1;
gbc.gridy = 1;
gbc.anchor = GridBagConstraints.CENTER;
gbc.weightx = 1;
gbc.weighty = 1;
add(new RectPane(), gbc);
gbc.weightx = 0;
gbc.weighty = 0;
gbc.gridx = 0;
gbc.gridy = 2;
gbc.anchor = GridBagConstraints.SOUTHWEST;
add(new RectPane(), gbc);
gbc.gridx = 2;
gbc.anchor = GridBagConstraints.SOUTHEAST;
add(new RectPane(), gbc);
}
// This is just to demonstrate how the layout works when the avaliable
// space is larger then the desired space, you don't need this
// and should get rid of it and just let the layout manager calculate
// it's desired size based on it's content
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
}
public class RectPane extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.GREEN);
g.fillRect(0, 0, 100, 100);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 100);
}
}
}
Understand, GridBagLayout IS the most complex layout manager in the standard API, but it is the most flexible. You're also not confined to a single layout manager, you can use compound layouts to create very advanced interfaces

GridBagLayout centering components

I have been trying for a while to make this work.
I have looked at many tutorials and examples on-line, nothing seems to help.
The combo box and the label are both centered right under each other in the middle of the frame.
I know that there needs to be a GridBagConstraints and you need to set the gbc every time you add a new component.
I am doing that so I am not sure why it's not working.
Also why would it be in the center?
Shouldn't it be in the top left if anything?
public class Application {
ArrayList listOfTickers = new ArrayList();
JFrame frame;
JPanel panel;
JLabel jLabel;
GridBagLayout layout;
GridBagConstraints gbc;
JComboBox comboBox;
Application(ArrayList listOfTickers) throws BadLocationException {
this.listOfTickers = listOfTickers;
setLabels();
setComboBox(listOfTickers);
setFrameAndPanel();
addComponents();
closeFrame();
}
private void addComponents() {
addobjects(jLabel, panel, layout, gbc, 1, 3, 4, 2);
addobjects(comboBox, panel, layout, gbc, 3, 0, 2, 1);
}
private void setLabels() {
jLabel = new JLabel("test");
}
private void closeFrame() {
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
private void setComboBox(ArrayList listOfTickers) throws BadLocationException {
comboBox = new JComboBox(listOfTickers.toArray());
comboBox.addActionListener(e -> {
String ticker = comboBox.getSelectedItem().toString();
});
}
private void setFrameAndPanel() {
frame = new JFrame("JFrame Example");
panel = new JPanel();
layout = new GridBagLayout();
panel.setLayout(layout);
frame.getContentPane().setLayout(layout);
gbc = new GridBagConstraints();
frame.add(panel);
frame.setSize(600, 600);
}
public void addobjects(Component component, Container panel, GridBagLayout layout, GridBagConstraints gbc, int gridx, int gridy, int gridwidth, int gridheight) {
gbc.gridx = gridx;
gbc.gridy = gridy;
gbc.gridwidth = gridwidth;
gbc.gridheight = gridheight;
layout.setConstraints(component, gbc);
panel.add(component, gbc);
}
}
Also why would it be in the center? Shouldnt it be in the top left if anything?
No, this is how GridBagLayout works, GridBagLayout will layout it's components around the centre of the container. You can play around with the weightx/y properties to change how much of the remaining space is allocated to a given cell.
I would also recommend avoid gridwidth and gridheight until you have a better understanding of what these do, as they are effecting the position of your components
The following will move the components to the top/left point of the container...
private void addComponents() {
gbc.gridx = 1;
gbc.gridy = 3;
gbc.weighty = 1;
gbc.anchor = GridBagConstraints.NORTHWEST;
panel.add(jLabel, gbc);
gbc.gridx = 3;
gbc.gridy = 0;
gbc.anchor = GridBagConstraints.WEST;
gbc.weightx = 1;
gbc.weighty = 0;
panel.add(comboBox, gbc);
}
Although, since you're applying a GridBagLayout to the JFrame itself, I'd be tempted to change the weightx/y and anchor properties for the panel itself when you add it to the frame, it will make it much simpler
so if I wanted to let say build a calculator with positioning the buttons in specific areas, essentially transforming the entire panel into one big grid and plotting my containers inside that grid what would be the best layout to use and how would I do that?
That depends ultimately on what you want the UI to look like. If all you want is for all the buttons to evenly occupy the available space, the maybe GridLayout would be a better choice...
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class Application {
public static void main(String[] args) {
new Application();
}
public Application() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridLayout(4, 3));
String labels[] = new String[] {"7", "8", "9", "4", "5", "6", "1", "2", "3", "", "0", ""};
for (String label : labels) {
if (label.trim().isEmpty()) {
add(new JLabel());
} else {
add(new JButton(label));
}
}
}
}
}
Note, I had to allow for two empty spaces around the 0 button, this is a requirement of GridLayout, as you don't get control over which cells the components actually appear, they are simply laid out in a linear fashion.
However, if you would prefer something that looks more like most calculators, then you'll need GridBagLayout...
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Application {
public static void main(String[] args) {
new Application();
}
public Application() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
String labels[][] = new String[][]{{"7", "8", "9"}, {"4", "5", "6"}, {"1", "2", "3"}};
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridy = 0;
for (String[] row : labels) {
gbc.gridx = 0;
for (String col : row) {
add(new JButton(col), gbc);
gbc.gridx++;
}
gbc.gridy++;
}
gbc.gridx = 0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridwidth = 3;
add(new JButton("0"), gbc);
}
}
}
Needs drive musts, you need to decide on the need of flexibility over uniformity (in this case). GridBagLayout is very powerful and flexible, but with it comes complexity.
Note: I could have done the second layout using two panels and two GridLayouts as well - which is an important concept, you're not stuck to a single layout manager, you can use multiple panels, each using different layout managers and "compound" them together to produce a rich interface
If you're going to be doing much UI building, it would greatly benefit you to download the Netbeans IDE and learn to use its GUI builder. It's an excellent GUI builder, and the visual feedback you get as you tweak layout parameters is incredibly helpful for getting the hang of UI building, and especially for getting the hang of how the various GridBagLayout parameters work. It's much more efficient for experimentation than a "write-run-tweak-rerun" loop.
Manually writing UI code is my least favorite thing. Don't inflict it on yourself if possible!

Java: Overlay an Image with Transparent JButton

So I'm creating a GUI that represents a vending machine. I'm just running into some problems trying to get the layout to work the way I want it. My thought was to insert an image into a JLabel, and then overlay that image with transparent JButtons in specific locations so that when you click on the image in certain locations, it will trigger the JButton. I haven't gotten to the transparency yet as I'm currently stuck on how to get the JButtons precisely where they need to be.
I've tried setLocation and setBounds with no luck. Any help on how to exactly position the jbuttons over the possible vending machine choices would be great.
import javax.swing.*;
import javax.imageio.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.io.*;
public class vendMachine extends JFrame
{
//Frame Dimensions
private static final int FRAME_HEIGHT = 800;
private static final int FRAME_WIDTH = 800;
private JPanel totalGUI, imagePanel, coinPanel;
public vendMachine()
{
createComponents();
setSize(FRAME_WIDTH, FRAME_HEIGHT);
setTitle("Vending Machine");
}
private void createComponents()
{
try
{
BufferedImage machineImg = ImageIO.read(new File("images/pepsivend.jpg"));
JLabel machineImgLabel = new JLabel(new ImageIcon(machineImg));
machineImgLabel.setLayout(new FlowLayout());
JButton test = new JButton("TEST BUTTON");
machineImgLabel.add(test);
//test.setBounds(0,0,0,0);
ImageIcon pennyIcon = new ImageIcon("images/coins/penny.jpg");
JButton pennyButton = new JButton(pennyIcon);
ImageIcon nickelIcon = new ImageIcon("images/coins/nickel.jpg");
JButton nickelButton = new JButton(nickelIcon);
ImageIcon dimeIcon = new ImageIcon("images/coins/dime.jpg");
JButton dimeButton = new JButton(dimeIcon);
ImageIcon quarterIcon = new ImageIcon("images/coins/quarter.jpg");
JButton quarterButton = new JButton(quarterIcon);
coinPanel = new JPanel();
coinPanel.setLayout(new GridLayout(4,1));
coinPanel.add(pennyButton);
coinPanel.add(nickelButton);
coinPanel.add(dimeButton);
coinPanel.add(quarterButton);
totalGUI = new JPanel();
totalGUI.setLayout(new BorderLayout());
totalGUI.add(machineImgLabel, BorderLayout.CENTER);
totalGUI.add(coinPanel, BorderLayout.EAST);
}
catch (IOException e)
{
e.printStackTrace();
}
add(totalGUI);
}
}
In the above Image I would like some help on how to get the test button, to overlay on top of the pepsi selection. From there I can go about making it transparent and removing the borders and text.
Edited to add: none of the buttons do anything yet. Simply trying to get the layout going before adding in anything else
It's unclear as to what your actually problem, however, I'll start with the layout...
No single layout will ever do everything you want, some times, you'll need to use multiple layouts and compound them. This example uses a BorderLayout and a GridBagLayout to set up the basic layout...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new VendingMachinePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class VendingMachinePane extends JPanel {
public VendingMachinePane() {
setLayout(new BorderLayout());
JLabel label = new JLabel("Cover");
// Demonstration purpose only
label.setPreferredSize(new Dimension(200, 400));
label.setOpaque(true);
label.setBackground(Color.BLUE);
add(label);
JPanel optionsPane = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.anchor = GridBagConstraints.NORTH;
optionsPane.setBackground(Color.DARK_GRAY);
optionsPane.add(new JLabel("Coin Slot"), gbc);
optionsPane.add(makeButton("Pepsi"), gbc);
optionsPane.add(makeButton("Diet Pepsi"), gbc);
optionsPane.add(makeButton("Slice"), gbc);
optionsPane.add(makeButton("Dr Pepper"), gbc);
optionsPane.add(makeButton("Lipton"), gbc);
optionsPane.add(makeButton("Mountain Dew"), gbc);
optionsPane.add(makeButton("Schweppes"), gbc);
gbc.weighty = 1;
optionsPane.add(makeButton("Pepsi"), gbc);
add(optionsPane, BorderLayout.LINE_END);
}
protected JButton makeButton(String text) {
JButton btn = new JButton(text);
btn.setBorderPainted(false);
btn.setContentAreaFilled(false);
btn.setMargin(new Insets(4, 4, 4, 4));
btn.setOpaque(false);
return btn;
}
}
}
As to your "overlay buttons" issue, to me, that doesn't make sense, since a JButton has a icon property, why not just use a JButton to start with?
You make buttons transparent simply by changing their borderPainted contentAreaFilled and opaque properties
// You can pass a `Icon` instead of a `String` to the constructor
JButton btn = new JButton(text);
btn.setBorderPainted(false);
btn.setContentAreaFilled(false);
btn.setMargin(new Insets(4, 4, 4, 4));
btn.setOpaque(false);
Don't forget to setup an ActionListener ;)
Updated, based on the updated requirements...
You Could...
Break the image down in segments, making each element it's own image and simply applying those to the buttons, using a similar approach above
You Could...
Map hot spots on the image, and using a MouseListener monitor where the mouseClicked events occur - you do lose the advantage of keyboard input though
You Could...
Map out the hot spots of the image and using a GridBagLayout or custom layout manager, map the buttons onto the image.

How to set size of a JSlider?

I have searched the web for a solution to this problem and didn't find anything that worked.
I have a vertical JSlider inside a JPanel that uses GridBagLayout and a GridBagConstraints for positioning the objects on the panel.
Currently I have the following code:
gbc.gridy = 1;
add(button1,gbc);
gbc.gridy = 2;
add(button2,gbc);
gbc.gridy = 3;
add(slider,gbc);
The objects are positioned vertically along the panel.
The slider always appears in the same size (length). Tried to use setPreferredSize - didn't work. Tried to use gridheight in order to have to slider cross two rows - didn't work either. Tried to change the actual min and max values of the slider, didn't help.
Shouldn't GridBagLayout respect preferred size?
EDIT: Also tried creating anoter JPanel inside the main JPanel, set it's layout to FlowLayout, BoxLayout or GridLayout, and add the slider to it. Didn't change a thing. Very weird.
Any ideas?
Use a different layout manager (or put the slider in a nested JPanel with a different layout manager), that will stretch the JSlider. In the example I use BorderLayout
import java.awt.BorderLayout;
import java.awt.GridLayout;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
public class DifferentSizeSlider extends JPanel{
public DifferentSizeSlider() {
JPanel topPanel = new JPanel(new BorderLayout());
topPanel.add(new JSlider());
JPanel bottomPanel = new JPanel(new GridLayout(1, 2));
bottomPanel.add(new JSlider());
bottomPanel.add(new JPanel());
setLayout(new GridLayout(2, 1));
add(topPanel);
add(bottomPanel);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
JOptionPane.showMessageDialog(null, new DifferentSizeSlider());
}
});
}
}
EDIT with your code example
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
public class DifferentSizeSlider extends JPanel{
public DifferentSizeSlider() {
JPanel topPanel = new JPanel(new BorderLayout());
topPanel.setPreferredSize(new Dimension(400, 50));
topPanel.add(new JSlider());
JButton jbtOne = new JButton("Button");
JButton jbtTwo = new JButton("Button");
GridBagConstraints gbc = new GridBagConstraints();
setLayout(new GridBagLayout());
gbc.gridy = 0;
add(jbtOne,gbc);
gbc.gridy = 1;
add(jbtTwo,gbc);
gbc.gridy = 2;
add(topPanel, gbc);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
JOptionPane.showMessageDialog(null, new DifferentSizeSlider());
}
});
}
}
To change the size of a swing component you use the setPrefferedSize() method
setPreferredSize(new Dimension(300, 80));
You may have to use a separate panel with a flowLayout for the slider then add that panel to the . Some layout managers may not take the preferred size.

Floating JPanel above a JPanel with BorderLayout

I have a JPanel called pnlMain with a layout set to BorderLayout. Inside the panel are three JPanel added to PAGE_START, CENTER, and PAGE_END. Now, my requirement is if the Settings button is clicked, it will display a transparent JPanel above pnlMain. This transparent panel will then contain an opaque, smaller, centered panel, that will contain the settings stuff.
I know I can do this using JLayeredPane, but looking at the tutorial it says that you can only put components of different depth using absolute positioning which I'm aware is highly discouraged.
Is there some other way to do this without using absolute positioning?
You can use the glass pane of the parent frame, which will allow you to add components to it that will appear to overlaid over the main content.
Basically, I would, create a JPanel and set it to be transparent (setOpaque(false)). I would set it's layout manager to something like GridBagLayout (as it will use the preferred size of the child component and center it automatically within it's parent container).
Onto this panel I would then add the Settings panel.
Finally, I would set the parent frame's glass pane to the first (backing) pane and make it visible.
frame.getRootPane().setGlassPane(backingPane); // Or similar
Take a look at How to use Root Panes
Updated
If you can't use the glass pane of the top level frame yourself, then you need to fake it.
This example basically uses a JLayeredPane backed by a GridBagLayout
If you add a MouseListener and KeyListener to the background pane you can consume events going to the child components.
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class FloatingPane {
public static void main(String[] args) {
new FloatingPane();
}
public FloatingPane() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
final WorkPane workPane = new WorkPane();
JButton settings = new JButton("Settings");
settings.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
workPane.toggleSettings();
}
});
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(workPane);
frame.add(settings, BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class WorkPane extends JLayeredPane {
private final BackingPane backingPane;
public WorkPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 1;
gbc.gridy = 0;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.fill = GridBagConstraints.BOTH;
add(createLabel("Center", Color.BLUE), gbc);
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 0;
gbc.weighty = 0;
gbc.fill = GridBagConstraints.VERTICAL;
add(createLabel("Left", Color.RED), gbc);
gbc.gridx = 2;
add(createLabel("Right", Color.GREEN), gbc);
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 1;
gbc.weighty = 1;
gbc.gridheight = GridBagConstraints.REMAINDER;
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.BOTH;
backingPane = new BackingPane();
backingPane.add(new SettingsPane());
backingPane.setVisible(false);
add(backingPane, gbc);
setLayer(backingPane, DEFAULT_LAYER + 1);
}
public void toggleSettings() {
backingPane.setVisible(!backingPane.isVisible());
}
protected JLabel createLabel(String text, Color bg) {
JLabel label = new JLabel(text);
label.setHorizontalAlignment(JLabel.CENTER);
label.setOpaque(true);
label.setBackground(bg);
return label;
}
}
public class BackingPane extends JPanel {
public BackingPane() {
setLayout(new GridBagLayout());
setOpaque(false);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(new Color(128, 128, 128, 192));
g.fillRect(0, 0, getWidth(), getHeight());
}
}
public class SettingsPane extends JPanel {
public SettingsPane() {
setBorder(new EmptyBorder(10, 10, 10, 10));
add(new JLabel("Settings"));
}
}
}
Another solution might be to fake the entire glass pane by taking a snap shot of the current panel and using a CardLayout, flip to the settings pane, using the snap shot as the backgound image for the settings pane (which can could then apply effects to like gray scaling and bluring)

Categories

Resources