java Box.glue not working as expected - java

I am writing a class where I want to be able to add an unknown number of panels to another JPanel in a vertical BoxLayout. theses panels each consist of a label as a title and another panel. I want the panels that are added to all be located at the top of the panel (in this case Gui) so I added vertical glue at the bottom. I had everything working as expected until I needed to redo some of the code in order to place the main panel (represented by gui) in a scrollpane. for the sake of simplicity I was able to duplicate my problem in the following code. when run you will notice that the glue does not take the empty space but it is rather divided between the other panels. I have set a size for the jframe rather then used .pack() to illustrate the point.
public class Gui extends JFrame {
public Gui() {
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.PAGE_AXIS));
getContentPane().add(new Panel());
getContentPane().add(new Panel());
getContentPane().add(new Panel());
getContentPane().add(new Panel());
getContentPane().add(Box.createVerticalGlue());
}
public class Panel extends JPanel{
public Panel(){
this.setLayout(new BorderLayout());
this.add(new JLabel("Title"), BorderLayout.NORTH);
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
this.add(panel);
panel.add(new JButton("button"));
}
}
public static void main (String[] args){
Gui g = new Gui();
g.setSize(240, 320);
g.setLocationRelativeTo(null);
g.setVisible(true);
g.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}

If you invoke this.setBorder(BorderFactory.createLineBorder(Color.BLACK)) within the Panel class and panel.setBorder(BorderFactory.createLineBorder(Color.RED)) on the nested JPanel, you'll see that there is no "empty space" between those components.
EDIT
By replacing the layout manager of Panel with BoxLayout, you'll get the following -
To be honest, you'll just need to play around with your layout managers. I recommend you read Laying Out Components Within a Container before you proceed any further with Swing.

Related

Problems with BorderLayout() in Java

I've tried a lot of different ways, but I will explain two and what was happening (no error messages or anything, just not showing up like they should or just not showing up at all):
First, I created a JPanel called layout and set it as a BorderLayout. Here is a snippet of how I made it look:
JPanel layout = new JPanel();
layout.setLayout(new BorderLayout());
colorChoice = new JLabel("Choose your color: ");
layout.add(colorChoice, BorderLayout.NORTH);
colorBox = new JComboBox(fireworkColors);
colorBox.addActionListener(this);
layout.add(colorBox, BorderLayout.NORTH);
In this scenario what happens is they don't show up at all. It just continues on with whatever else I added.
So then I just tried setLayout(new BorderLayout()); Here is a snippet of that code:
setLayout(new BorderLayout());
colorChoice = new JLabel("Choose your color: ");
add(colorChoice, BorderLayout.NORTH);
colorBox = new JComboBox(fireworkColors);
colorBox.addActionListener(this);
add(colorBox, BorderLayout.NORTH);
In this scenario they are added, however, the width takes up the entire width of the frame and the textfield (not shown in the snippet) takes up basically everything else.
Here is what I have tried:
setPreferredSize() & setSize()
Is there something else that I am missing? Thank you.
I also should note that this is a separate class and there is no main in this class. I only say this because I've extended JPanel instead of JFrame. I've seen some people extend JFrame and use JFrame, but I haven't tried it yet.
You created a JPanel, but didn't add it to any container. It won't be visible until it is added to something (a JFrame, or another panel that is in a frame somewhere up the hierarhcy)
You added two components to the same position in the BorderLayout. The last one added is the one that will occupy that position.
Update:
You do not need to extend JFrame. I never do, instead I always extend JPanel. This makes my custom components more flexible: they can be added in another panel, or they can be added to a frame.
So, to demonstrate the problem I will make an entire, small, program:
public class BadGui
{
public static void main(String[] argv)
{
final JFrame frame = new JFrame("Hello World");
final JPanel panel = new JPanel();
panel.add(new JLabel("Hello"), BorderLayout.NORTH);
panel.add(new JLabel("World"), BorderLayout.SOUTH);
frame.setVisible(true);
}
}
In this program I created a panel, but did not add it to anything so it never becomes visible.
In the next program I will fix it by adding the panel to the frame.
public class FixedGui
{
public static void main(String[] argv)
{
final JFrame frame = new JFrame("Hello World");
final JPanel panel = new JPanel();
panel.add(new JLabel("Hello"), BorderLayout.NORTH);
panel.add(new JLabel("World"), BorderLayout.SOUTH);
frame.getContentPane().add(panel);
frame.setVisible(true);
}
}
Note that in both of these, when I added something to the panel, I chose different layout parameters (one label I put in 'North' and the other in 'South').
Here is an example of a JPanel with a BorderLayout that adds a JPanel with a button and label to the "North"
public class Frames extends JFrame
{
public Frames()
{
JPanel homePanel = new JPanel(new BorderLayout());
JPanel northContainerPanel = new JPanel(new FlowLayout());
JButton yourBtn = new JButton("I Do Nothing");
JLabel yourLabel = new JLabel("I Say Stuff");
homePanel.add(northContainerPanel, BorderLayout.NORTH);
northContainerPanel.add(yourBtn);
northContainerPanel.add(yourLabel);
add(homePanel);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setLocationRelativeTo(null);
setExtendedState(JFrame.MAXIMIZED_BOTH);
setTitle("Cool Stuff");
pack();
setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(Frames::new);
}
}
The below suggestion is assuming that your extending JFrame.
Testing
First of all, without seeing everything, theres always a numerous amount of things you can try.
First off, after you load everything, try adding this in (Again, assuming your extending JFrame:
revalidate();
repaint();
I add this into my own Swing projects all the time, as it refreshes and checks to see that everything is on the frame.
If that doesn't work, make sure that all your JComponent's are added to your JPanel, and ONLY your JPanel is on your JFrame. Your JFrame cannot sort everything out; the JPanel does that.
JPanel window = new JPanel();
JButton button = new JButton("Press me");
add(window);
window.add(button); // Notice how it's the JPanel that holds my components.
One thing though, you still add your JMenu's and what-not through your JFrame, not your JPanel.

JAVA JScrollPane not showing up

I have a JPanel with scrollbar and i want to add a lot of JLabels to it. But the scrollbar doesnt work . I can not use the scrollbar and even after the panel is full it doesn't scroll . Here is my code :
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class Scroll {
public static void main(String[] args) {
JPanel panel = new JPanel(new GridLayout(0,1));
JPanel p = new JPanel(new BorderLayout());
JScrollPane scroll = new JScrollPane(panel);
scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
p.add(scroll, BorderLayout.NORTH);
JButton but = new JButton("OK");
p.add(but, BorderLayout.SOUTH);
but.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
panel.add(new JLabel("Some random text"));
scroll.revalidate();
p.repaint();p.revalidate();
}
});
JFrame frame = new JFrame();
frame.setSize(800,200);
frame.setVisible(true);
frame.add(p);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
}
}
Your problem seems to lie with your layout managers. I think BorderLayout behaves strangely when you don't use the BorderLayout.CENTER position. I changed the line
p.add(scroll, BorderLayout.NORTH);
to
p.add(scroll, BorderLayout.CENTER);
Then, to make the text appear from the top instead of centering, I changed the layout manager for the panel component to a BoxLayout. From:
JPanel panel = new JPanel(new GridLayout(0, 1));
to
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
This seems to have given me the functionality you want. Let me know if this fixes your issues or not!
As already suggested, you should probably use JList or JTable to implement your use case.
Regarding the issue, this is because all BorderLayout constraints except of CENTER will expand to as much space as their components occupy, even if that means that they will expand out of the screen bounds (in your case the NORTH section expands to the south after each button click).
To solve this, explicitly specify the preferred size for the components which can grow indefinitely if you add them to a non-central panel section with BorderLayout:
scroll.setPreferredSize(new Dimension(-1, 100));
I use -1 for the width here to indicate that it is not important (I could use any other value), since it will be ignored by the layout manager anyway (with BorderLayout.NORTH the component is stretched horizontally to take all the available horizontal space).

How to add a ScrollBar at the bottom of the JPanel when using GridLayout?

Hello i wanted to know how to add a ScrollBar at the bottom of a JPanel if i use GridLayout in my desktop app, as far as i know GridLayout only accept as parameter quantity of colums, rows and the horizontal and vertical gap. So how can i add a scroll bar and use it to see the information that's in the JPanel?
Put the JPanel with GridLayout into a JScrollPane. E.G. as seen with the two column GridLayout that displays the labels added to the nested layout example.
If you want the JSrollBar to scroll the JPanel with the gridlayout, then put the grid layout into a scrollpane (remember to extend the scrollable interface)
Read this page of the tutorial to learn how to.
IF you want to use the events from the JScrollBar to change the visible area of your panel then put the panel inside another panel with a JScrollbar on the bottom.
This is an example with a green panel and a scrollbar at the bottom
public class Window extends JFrame {
public Window() {
setPreferredSize(new Dimension(500, 500));
setMinimumSize(new Dimension(500, 500));
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(100, 100));
panel.setBackground(Color.GREEN);
getContentPane().add(panel, BorderLayout.CENTER);
JScrollBar scrollBar = new JScrollBar(JScrollBar.HORIZONTAL);
scrollBar.setMinimum(0);
scrollBar.setMaximum(100);
scrollBar.setBlockIncrement(30);
scrollBar.addAdjustmentListener(new AdjustmentListener() {
#Override
public void adjustmentValueChanged(AdjustmentEvent e) {
System.out.println("Adjustment changed");
}
});
getContentPane().add(scrollBar, BorderLayout.SOUTH);
setVisible(true);
}
public static void main(String[] args) {
new Window();
}
}

Best layout for frame

What kind of layout should I use to create a page Like this:
It should be resizable
It has two main panels Right and Left?
Extra space will be given to the 'Main Text' text area, and extra height will be given to the button panel while centering them.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
public class EndOfLineButtonLayout {
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
// the GUI as seen by the user (without frame)
JPanel gui = new JPanel(new BorderLayout());
gui.setBorder(new EmptyBorder(2, 3, 2, 3));
JPanel textPanel = new JPanel(new BorderLayout(5,5));
textPanel.add(new JScrollPane(new JTextArea("Top Text",3,20)),
BorderLayout.PAGE_START);
textPanel.add(new JScrollPane(new JTextArea("Main Text",10,10)));
gui.add(textPanel, BorderLayout.CENTER);
JPanel buttonCenter = new JPanel(new GridBagLayout());
buttonCenter.setBorder(new EmptyBorder(5,5,5,5));
JPanel buttonPanel = new JPanel(new GridLayout(0,1,5,5));
for (int ii=1; ii<6; ii++) {
buttonPanel.add(new JButton("Button " + ii));
}
// a component added to a GBL with no constraint will be centered
buttonCenter.add(buttonPanel);
gui.add(buttonCenter, BorderLayout.LINE_END);
JFrame f = new JFrame("Demo");
f.add(gui);
// Ensures JVM closes after frame(s) closed and
// all non-daemon threads are finished
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// See http://stackoverflow.com/a/7143398/418556 for demo.
f.setLocationByPlatform(true);
// ensures the frame is the minimum size it needs to be
// in order display the components within it
f.pack();
// should be done last, to avoid flickering, moving,
// resizing artifacts.
f.setVisible(true);
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
SwingUtilities.invokeLater(r);
}
}
You can use gridbag layout, try using netbeans, I have tried it and found really usefull.
Once you create it with netbeans you can use the same and build infact any kind of layout.
best of luck with other solutions.
p.s. border layout is perfect for your requirement, but I mentioned this just in case you would like to do lot more .
I would use BorderLayout.
Create Three JPanels and add them to a JFrame as follows:
public class YourClass extends JFrame{
//code here
this.setLayout(new BorderLayout());
this.add(TopPanel, BorderLayout.NORTH);
this.add(RightPanel, BorderLayout.EAST);
this.add(MainPanel, BorderLayout.CENTER);
this.pack();
this.setVisible(true);
The two main panels would be placed inside a main JPanel using a BorderLayout. The left panel would be placed using BorderLayout.CENTER, and the right panel would be placed using BorderLayout.LINE_END.
The left panel would use a BoxLayout, Y axis to separate the two JPanels within the left panel.
The right buttons panel would use a GridBagLayout. This sizes the buttons the same and allows you to use Insets to add some spacing to the buttons.
The buttons would be spaced from the top to the bottom of the right buttons panel. If you want all the buttons towards the top of the right buttons panel, you would put the right buttons panel inside of another JPanel using a FlowLayout.

Swing: Start second JPanel, when the first JPanel is clicked

I'm writing a simple java game and I'm facing this problem:
My different layouts are in different JPanels (1 JPanel for the welcoming page, where I have to press 'start game' and another one with the actuall functionallity)
I start the game from a JFrame
import javax.swing.JFrame;
public class RType extends JFrame {
public RType() {
add(new Welcome());//first panel
add(new Board());//panel with the game
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(100, 100);
setResizable(false);
setVisible(true);
}
public static void main(String[] args) {
new RType();
}
}
obviuosly, this launches the second panel right after the first, and I cant see the first one.
I've tried some stuff, trying to invoke the second panel in the main method, when the first panel is clicked that way:
RType rt=new RType();
rt.add(new Board()); //in this case add(new Board()); is removed from constructor
but it's doing nothing.
how can I solve it?
As #nachokk has said, you should be using a CardLayout instead. It lets you do things like tabs in a browser, but you don't need to make the tabs visible for your game if you don't want to. You make your welcome "card" visible at first, then when the user clicks you switch to the Board "card".
I don't recommend to add directly to the JFrame components, instead use another container as JPanel . JFrame default layout is BorderLayout, when you add in the way you are adding it always put in the center.
Make something like this:
JFrame frame = new JFrame();
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new CardLayout());
mainPanel.add(new Welcome(), "Welcome");
mainPanel.add(new Board(),"Board");
frame.add(mainPanel);
Here is a tutorial How to use CardLayout
on first panel of welcome add a button, and apply actionperformed like
JButton myButton = new JButton("Add Component ");
myButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
frame.remove(welcome);
frame.add(Board, BorderLayout.CENTER);
frame.revalidate();
frame.repaint();
}
});
By default, both panels will fill up the entire Frame's area. To fix this, you will need to use another layout, such as a GridLayout to structure the areas in which the panels will take up the Frame's area.
You can also go with no layout to hard code the pixel values of where you want the panels to fit in your frame.
EDIT: Based on what you're looking to do, the CardLayout is probably what you'll want to use for your Frame's layout.

Categories