I have the following little program:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class ScrollPanePlay extends JFrame
{
public static void main(String[] args)
{
ScrollPanePlay frame = new ScrollPanePlay();
frame.setVisible(true);
}
public ScrollPanePlay()
{
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
JPanel panel = new JPanel(this);
panel.setLayout(new FlowLayout(FlowLayout.LEFT));
panel.add(new JLabel("one"));
panel.add(new JLabel("two"));
panel.add(new JLabel("three"));
panel.add(new JLabel("four"));
panel.add(new JLabel("five"));
JScrollPane scrollPane = new JScrollPane(panel);
add(panel, BorderLayout.CENTER); // <== add either panel or scrollpane
pack();
}
}
If I add panel, then the labels in the panel wrap when the window is made narrow, as expected for FlowLayout.
If I add the panel to scrollpane and add the scrollpane to the frame, then the labels don't wrap, because the scrollPane is reporting sufficient width (I guess) to hold all the labels, and allows the user to scroll to see them.
I would like the scrolling behavior, but only for vertical - I would like the user to choose the width he wants to see, and have the scrollbar appear only for scrolling vertically. How can I do that?
I tried extending JScrollPane and returning true from getScrollableTracksViewportWidth(), but, as I expected, that doesn't do what I want because it's the frame's width I want things to track, not the viewport. I tried extending JPanel and overriding getWidth to return the width of the frame, but that still left all the labels in a horizontal row, i.e., they quit wrapping. Is there something that will do this without a custom layout manager? Seems to me all we need is programmatic control of the viewport width.
It is a viewport issue. When inside a JScrollPane a JPanel wont resize to fit the JScrollPane size (that is kind of why ScrollPanes exist).
You can use a Scrollable Panel instead of a JPanel and set it to fit the maximum width (in this case it would fit to the JScrollPane).
Something like:
ScrollablePanel panel = new ScrollablePanel( new BorderLayout());
panel.setScrollableWidth( ScrollablePanel.ScrollableSizeHint.FIT );
Check this answer to a little more general answer and for a link to the .class.
Related
To summarize my problem, I am developing an interface for an application in Java. I have run into a problem I haven't previously faced yet.
To create a sort of "navigation bar" i created a thin JPanel at the top of the JFrame. Then I wanted to add a JButton to it to represent the "home" button which leads to the starting content of the application. When I did that and made width as well as height of the Button equal to the height of the Panel, the Button had a little gap of approximately 3 pixels to the top of the Panel. I don't know why that is, there is no other element inside the Panel. I am not using any layout, however i have tried to fix that problem using a FlowLayout but nothing really changed.
Here is the full code for the interface, i marked the menu panel with red color for testing purpose only. How do I get rid of that small gap to the top?
package UserInterface;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Interface {
private JFrame frame;
private JPanel menu;
private JPanel content;
public JButton home;
public Interface() {
Dimension dim = new Dimension(50, 50);
frame = new JFrame();
menu = new JPanel();
content = new JPanel();
frame.setSize(1600, 900);
menu.setSize(1600, 50);
content.setSize(1600, 850);
frame.setTitle("Tierland");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocation(
(int)((Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2) - (frame.getWidth() / 2)),
(int)((Toolkit.getDefaultToolkit().getScreenSize().getHeight() / 2) - (frame.getHeight() / 2))
);
frame.setSize(1600, 900);
menu.setSize(1600, 50);
content.setSize(1600, 850);
menu.setBackground(Color.RED);
home = new JButton();
home.setPreferredSize(dim);
home.setMinimumSize(dim);
home.setMaximumSize(dim);
home.setSize(dim);
frame.add(menu);
frame.add(content);
frame.setVisible(true);
menu.setVisible(true);
content.setVisible(true);
}
}
I am not using any layout,
Yes you are. By default a JPanel uses a FlowLayout.
however i have tried to fix that problem using a FlowLayout but nothing really changed.
That is because the default FlowLayout uses a 5 pixel gap around any component added to the panel.
You should be using:
menu.setLayout( new FlowLayout(...) );
Read the FlowLayout API for the appropriate constructor that will allow you to use 0, for the horizontal and/or vertical gap.
frame.add(menu);
frame.add(content);
Also, by default, the content pane of the frame uses a BorderLayout, so you should be using:
frame.add(menu, BorderLayout.PAGE_START);
frame.add(content, BorderLayout.CENTER);
You should not be attempting to control the size of the button:
//home.setPreferredSize(dim);
//home.setMinimumSize(dim);
//home.setMaximumSize(dim);
Just set the text of the button or add an Icon to the button and the button will determine its own preferred size.
Also, you really should call your "menu" panel a "toolbar" panel. Swing already supports menus and there is a special method to add a menu bar to the frame. Read the section from the Swing tutorial on How to Use Menus for more information.
I am using Miglayout to define a layout for my program. The problem is the JScrollPane prevents the JButton shrinking below its preferred size. The minimum, preferred, and maximum widths for the JButton are set like this, "w 300:600:900" //min:pref:max.
What is the best way to fix this problem?
SSSCE
import java.awt.*;
import javax.swing.*;
import net.miginfocom.swing.MigLayout;
public class ButLay extends JFrame {
private ButLay() {
super("Button Layout");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new MigLayout("", "grow", "grow"));
createPanel();
setSize(800, 200);
setVisible(true);
}
JPanel panel = new JPanel(new MigLayout("", "grow", "grow"));
JScrollPane scroll;
JButton button = new JButton("Button");
private void createPanel() {
panel.add(button, "gapleft 100, align right, w 300:600:900, south");
scroll = new JScrollPane(panel);
getContentPane().add(scroll, "grow");
}
public static void main(String[] args) {
new ButLay();
}
}
The default behaviour of a JScrollPane is to display the component in the scroll pane at its preferred size so that the scrollbars can appear as required.
If you want to change the behaviour then you can try to implement the Scrollable interface on your panel. You might be able to override the getScrollableTracksViewportWidth() method to return true. Now your panel should resize as the viewport of the scrollpane resizes. However using this approach your won't get a scrollbar if you make the viewport too small.
If you want the scrollbar in the above situation, then you may also need to override the getPreferredSize() method to return the minimum size when the preferredSize is greater than the size of the viewport.
You can also check out Scrollable Panel which implements the Scrollable interface for you and allows you to customize the behaviour with some convenience methods.
Don't know if I'm making a rookie mistake, but changing the row parameter when creating a GridLayout for a JPanel in my JFrame, seems to be causing another JPanel to vanish altogether:
Here's the stripped down version of the code:
In the GridBug constructor I set up my layout and put a sub class of JPanel in BorderLayout.CENTER. This does other stuff in my original code, but here just draws a box to show it's being displayed.
Somehow the state of the bottom panel which is added to BorderLayout.PAGE_END causes the center panel to vanish
In particular, changing the GridLayout row parameters to a higher value causes the center panel to vanish, lower values work fine
The code as it is now, does not work on my computer, if I uncomment some of the code to reduce row parameters, or if I don't add the JLabel or subPanels then it works...
I have no idea what I'm doing wrong:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class GridBug extends JFrame{
static class ImagePanel extends JPanel{
#Override
public Dimension getPreferredSize(){
return new Dimension(200,200);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
System.out.println("Painting image panel...");
g.setColor(Color.CYAN);
g.fillRect(0, 0, getWidth(), getHeight());
}
}
public GridBug() {
setLayout(new BorderLayout());
/*PROBLEM CODE HERE*/
//add center image panel - does not appear depending on GridLayout settings in other panels
ImagePanel centerPanel = new ImagePanel();
add(centerPanel , BorderLayout.CENTER);
//add bottom panel
JPanel bottomPanel = new JPanel();
add(bottomPanel, BorderLayout.PAGE_END);
bottomPanel.setLayout(new GridLayout(6,0)); //doesn't work
// bottomPanel.setLayout(new GridLayout(5,0)); //works
JPanel subPanel = new JPanel();
//if I pass more than 4 or so rows as param to gridlayout,
//then imagePanel is not displayed
subPanel.setLayout(new GridLayout(4,0)); //doesn't work
// subPanel.setLayout(new GridLayout(3, 0)); //works
//if I don't add this label - works
JLabel label = new JLabel("A Label:");
subPanel.add(label);
bottomPanel.add(subPanel); //if I don't add the subPanel it works fine
/*END OF PROBLEM CODE?*/
//set window params
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(400,400);
setLocationRelativeTo(null);
setVisible(true);
}
public static final void main(String[] args){
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new GridBug();
}
});
}
}
Not sure the exact result you want, so I didn't even try. But the problem you're facing, is one of the reasons, you want to pack() your frame, and not setSize(). You're constricting the preferred sizes of the component. pack() respects the preferred size of all your components, and should be used, rather than setSize()
bottomPanel.setLayout(new GridLayout(6,0)); //doesn't work..
// with pack(), now it does.
pack();
//setSize(400,400); // if you increase the size it'll work also, but just pack()
You just need to work on the laying out of your components now to get your desired look :)
A more detailed explanation of your problem.
This is how you code currently looks when I set the background. Note: you can already see the setSize() is taking a toll on your top panel's preferred size (200, 200).
The top CYAN is your image panel.
The BLUE is the subPanel with 4 row. With GridLayout, all the rows will be at least the size of it largest component. In this case it's the label. You can see the blue area is 4 times the height of the label (as it should be)
Not the RED, which is the bottomPanel. This has 5 rows. The largest component is the subPanel, so the total size of the bottomPanel is the size of the subPanel x 5, as you can also see. Once you add another row, the top panel gets pushed out.
I'm currently trying to fill a JPanel (using GridLayout) with Buttons. These Buttons should be squares having a set width.
The programm should be able to resize the playing field (n*m buttons). Problem is, the buttons are automatically stretched to completely fill the JScrollpane, completely ignoring the set height and width. Thus making the scrollbars unnecessary.
Here is my code:
Creating the panels:
panel_game = new javax.swing.JPanel();
jScrollPane1 = new javax.swing.JScrollPane(panel_game);
Trying to resize the JPanel: (where x and y are the number of buttons and zoomlvl the size)
panel_game.setLayout(new java.awt.GridLayout(x, y));
panel_game.setBounds(panel_game.getX()+5,panel_game.getY()+5,x*zoomlvl-5,y*zoomlvl);
panel_game.setPreferredSize(new Dimension(x*zoomlvl,y*zoomlvl));
And adding the buttons: (f is my playfield, a 2D-Array)(buttons is a Arraylist, containing my buttons)
for(int i=0; i<f.getSize()[0]*f.getSize()[1];i++){
buttons.add(new JButton());
buttons.get(i).setSize(zoomlvl, zoomlvl);
buttons.get(i).setPreferredSize(new Dimension(zoomlvl,zoomlvl));
panel_game.add(buttons.get(i));
}
I have no clue how I can tell Java to stop resizing my buttons etc. automatically.
Help would be appreciated :)
GridLayout is built to fill the container that uses it with components. If the container holding the buttons is constrained in size, then the buttons will stretch or fill to fill that container as closely as possible. A solution may be to nest layout managers so that this does not occur, but I can't give more specific advice without more code, particularly a minimal example program. Images might help too.
If you want to prevent the "button grid panel" from stretching to fill the whole viewport area of the ScrollPane, you could place this grid panel into another panel (with FlowLayout).
In general, you should either
not set the preferred size of the panel_game OR
not set the preferred size of the buttons
because
when you set the preferred size of the buttons, then the preferred size of the panel will be computed from the preferred sizes of the buttons
when you set the preferred size of the panel, then the size of the buttons will be determined by the size of the panel, respectively
Maybe this is what you want to achieve:
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
public class ScrollButtonGrid
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
int x = 5;
int y = 5;
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(x, y));
for(int i=0; i<x*y;i++){
JButton button = new JButton(String.valueOf(i));
button.setPreferredSize(new Dimension(100,100));
panel.add(button);
}
JPanel container = new JPanel(new FlowLayout(FlowLayout.CENTER, 0,0));
container.add(panel);
JScrollPane scrollPane = new JScrollPane(container);
f.getContentPane().add(scrollPane);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
I have this simple Java Swing test application that show an upper label and under this label a button:
package com.techub.exeute;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import org.jdesktop.application.SingleFrameApplication;
public class Main extends SingleFrameApplication{
public static void main(String[] args) {
Main a = new Main();
a.startup();
}
#Override
protected void startup() {
JFrame frame = new JFrame("FrameDemo");
frame.setMinimumSize(new Dimension(800, 400));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel myLabel = new JLabel("Hello World !!!", SwingConstants.CENTER);
myLabel.setFont(new Font("Serif", Font.BOLD, 22));
myLabel.setBackground(Color.RED);
myLabel.setOpaque(true);
myLabel.setPreferredSize(new Dimension(100, 80));
frame.getContentPane().add(myLabel, BorderLayout.NORTH);
Button myButton = new Button("Click Me !!!");
myButton.setMaximumSize(new Dimension(50, 25));
frame.getContentPane().add(myButton, BorderLayout.CENTER);
//Display the window.
frame.pack();
frame.setVisible(true);
}
}
The button is in the BorderLayout.CENTER position. The problem is that this button occupies all available space in the CENTER position also if I have set the Maximum Size property with a Dimension object.
What am I wrong? What can I do to create a button having specific dimension?
You're currently telling Java to place the button in the center of your BorderLayout. Java then thinks that you want the entire area filled with this button. If you want to place a normal sized button in the center of your BorderLayout, add the button to a new JPanel and place the JPanel inside BorderLayout.CENTER.
Doing this, you're telling Java to fill out BorderLayout.CENTER with your JPanel. The elements that you place inside this JPanel will appear normal, because these elements are not getting "stretched" because of your BorderLayout - the JPanel is.
You fail to realize that it's not only the max/min/preferred sizes of the components that determine the outcome. The LayoutManager has a lot to say in this, and as you noticed, BorderLayout will fill the whole area with the component.
What you can do is create a JPanel, make it use for example FlowLayout and put that JPanel to BorderLayout.CENTER and the JButton to the JPanel.
You are using BorderLayout, North region has JLabel. JButton is put on center. JButton will occupy all the space left as per BorderLayout.
Please find more information about Layout on link : http://docs.oracle.com/javase/tutorial/uiswing/layout/using.html
U are using BorderLayout, button occupy all the left space of the frame.
use setBounds() function .
myButton.setBounds(10,200,100,30);