Code:
import java.awt.Dimension;
import javax.swing.*;
public class Game extends JFrame {
private static final long serialVersionUID = -7919358146481096788L;
JPanel a = new JPanel();
public static void main(String[] args) {
new Game();
}
private Game() {
setTitle("Insert name of game here");
setLocationRelativeTo(null);
setLayout(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
a.setPreferredSize(new Dimension(600, 600));
add(a);
pack();
setVisible(true);
}
}
So I set the preferred size of the JPanel to 600 by 600 and pack the frame, but the frame's size is still 0 by 0.
Why is this and how do I fix it?
As you said, pack() will try and arrange the window so that every component is resized to its preferredSize.
The problem is that it seems that the layout manager is the one trying to arrange the components and their respective preferredSizes. However, as you set the layout manager as being null, there is no one in charge of that.
Try commenting the setLayout(null) line, and you're gonna see the result. Of course, for a complete window, you're going to have to choose and set a meaningful LayoutManager.
This works fine to me:
import java.awt.Dimension;
import javax.swing.*;
public class Game extends JFrame {
private static final long serialVersionUID = -7919358146481096788L;
JPanel a = new JPanel();
public static void main(String[] args) {
new Game();
}
private Game() {
setTitle("Insert name of game here");
setLocationRelativeTo(null);
//setLayout(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
a.setPreferredSize(new Dimension(600, 600));
add(a);
pack();
setVisible(true);
}
}
pack() queries the preferred size of the parent container over that of the child so you would have to use:
setPreferredSize(new Dimension(600, 600));
Another note is to call
setLocationRelativeTo(null);
after pack() has been called to calculate center coordinates :)
OK, just spotted the null layout there, why not use the default BorderLayout of JFrame?
Your problem is setLayout(null), becase the docs say for pack():
Causes this Window to be sized to fit the preferred size and layouts of its subcomponents
thus with no layout it does not execute correctly.
This seems to work fine for me:
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Game extends JFrame {
JPanel panel = new JPanel();
private void createAndShowGUI() {
setTitle("FrameDemo");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel.setPreferredSize(new Dimension(600, 600));
add(panel);
//setLayout(null); //wont work with this call as pack() resizes according to layout manager
pack();
setLocationRelativeTo(null);
setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Game().createAndShowGUI();
}
});
}
}
Related
package com.gautam.notepad;
import javax.swing.*;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Graphics;
public class main {
public static void main(String[] args) {
panel1 p =new panel1(); // This is the panel1 class object
new App("NOTEPAD",p); // i'm trying to pass panel1 object
}
}
class App extends JFrame {
public App(String title,panel1 panel)
{
this.setTitle(title);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
this.setLocationRelativeTo(null);
this.setSize(800, 640);
this.setLayout(new FlowLayout());
this.add(panel);
this.setResizable(false);
}
}
class panel1 extends JPanel{
public void paintComponent(Graphics g)
{
g.setColor(Color.green);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
}
}
it works fine but in the paintcomponent method it is g.fillRect() method
is not working it is not painting the whole screen only small rectangle is painted in the middle of the screen.what is the problem in this code
You have problem on line this.setLayout(new FlowLayout());, just remove it and it will work. By default it will use BorderLayout which is what you need.
This will work
import javax.swing.*;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
public class NotePad {
public static void main(String[] args) {
App app = new App("NOTEPAD");
app.getContentPane().setBackground(Color.green);
}
}
class App extends JFrame {
public App(String title)
{
this.setTitle(title);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
this.setLocationRelativeTo(null);
this.setSize(800, 640);
this.setLayout(new FlowLayout());
//this.add(panel);
this.setResizable(false);
}
}
The problem has to do with your selected Layout.Have a look at this https://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html#flow to see the different layouts and how to use them.
If you change this.setLayout(new FlowLayout()); to this.setLayout(new BorderLayout()); for instance, it should work
Ok Flowlayout() gets it's own size and it happens that that small size is what you're getting from the flowlayout(), if you want to be still able to use the Flowlayout() and control the dimensions of your green Rectangle than i suggest using the setPreferredSize() method on your panel which will eliminate this problem and will keep your FlowLayout too.
public static void main(String[] args) {
panel1 p =new panel1(); // This is the panel1 class object
Dimension size= new Dimension(800, 640);//here you can add the size you want
p.setPreferredSize(size);
new App("NOTEPAD",p); // i'm trying to pass panel1 object
}
I'm making a GUI for a a custom source server browser with improved filtering.
This is what I have so far.
However, when I resize...
When I resize the window I want the L4D2 'filter panel' to resize to the current maximum width of the container. I also want to be able to add more of these panels in a column (such as box layout provides).
Boxlayout get's the panels to appear in a column, but it doesn't do anything for their widths.
I'm thinking I may need to override the filter panels preferred size methods so that they can retrieve the size of the parent container, but I'm not sure how to do this.
How should I approach this problem?
EDIT: Here's an example program depicting the problem.
import javax.swing.*;
import java.awt.*;
public class guiExampleProblem {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
final MyWindows wnd = new MyWindows("guiExampleProblem");
wnd.setVisible(true);
}
});
}
}
class MyWindows extends JFrame {
public MyWindows(String text) {
super(text);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
JPanel containerPanel1 = new JPanel();
JPanel containerPanel2 = new JPanel();
JPanel containerPanel3 = new JPanel();
containerPanel1.setBackground(Color.BLACK);
containerPanel2.setBackground(Color.RED);
containerPanel3.setBackground(Color.GREEN);
mainPanel.add(containerPanel1);
mainPanel.add(containerPanel2);
mainPanel.add(containerPanel3);
this.add(mainPanel);
pack();
}
}
When the window is resized, I want the panels to expand only along the x-axis, and remain at a constant height on the y-axis, however in the example the panels expand on both the x y axis.
I managed to get the desired functionality by overriding the 'filter panels' getPrefferedSize methods so that they retrieve the parent containers width and use that. Here is the code in the form of an example:
import javax.swing.*;
import java.awt.*;
public class guiExampleProblem {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
final MyWindows wnd = new MyWindows("guiExampleProblem");
wnd.setVisible(true);
}
});
}
}
class MyWindows extends JFrame {
public MyWindows(String text) {
super(text);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new FlowLayout());
JPanel containerPanel1 = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(this.getParent().getWidth(),60);
}
};
JPanel containerPanel2 = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(this.getParent().getWidth(),60);
}
};
JPanel containerPanel3 = new JPanel() {
#Override
public Dimension getPreferredSize() {
return new Dimension(this.getParent().getWidth(),60);
}
};
containerPanel1.setBackground(Color.BLACK);
containerPanel2.setBackground(Color.RED);
containerPanel3.setBackground(Color.GREEN);
mainPanel.add(containerPanel1);
mainPanel.add(containerPanel2);
mainPanel.add(containerPanel3);
this.add(mainPanel);
pack();
}
}
Put the panel (with BoxLayout) that is to stretch in the CENTER of a BorderLayout -- put the panel to the right in the EAST of that BorderLayout. You have given no detail of what else you want this to do, nor any code, but this might be what you want.
--
After your solution: it seems to me that using FlowLayout here is confusing -- it lays out its components one after the other horizontally, and your trick of getting preferred size from the width of the container makes it behave differently. I also avoid getting into layout logic in my application when I can, so I looked for another way to do this and came up with:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
public class guiExampleProblem2
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
final MyWindows2 wnd = new MyWindows2("guiExampleProblem2");
wnd.setVisible(true);
}
});
}
}
class MyWindows2 extends JFrame
{
public MyWindows2(String text)
{
super(text);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel mainPanel = new JPanel();
mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.PAGE_AXIS));
JPanel containerPanel1 = addContainedPanel(Color.BLACK, 60, 60, mainPanel);
JPanel containerPanel2 = addContainedPanel(Color.RED, 60, 60, mainPanel);
JPanel containerPanel3 = addContainedPanel(Color.GREEN, 60, 60, mainPanel);
this.add(mainPanel, BorderLayout.NORTH);
pack();
}
JPanel addContainedPanel(Color color, int width, int height, JPanel container)
{
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(width, height));
panel.setBackground(color);
container.add(panel);
return panel;
}
}
This uses the NORTH portion of a BorderLayout (which is the default layout for a JFrame, by the way) to do the main thing you wanted -- stretch things horizontally. The BoxLayout with a page axis is intended to lay things out top-to-bottom, so I think that's less confusing for the reader. Anyway, it's another way to do it that I think uses the components - including the layout managers - more like they were intended and documented.
Can anybody tell me what is the problem in following program? I want to fit JScrollPane on JtextArea but when I add it then JTextArea is not visible.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class Area extends JFrame
{
private JTextArea ta;
private JTextField tf;
JScrollPane jp;
public Area()
{
super("Text Area");
tf=new JTextField();
tf.setBounds(100,350,300,30);
add(tf);
ta=new JTextArea();
ta.setBounds(100,100,300,200);
jp= new JScrollPane(ta);
add(jp);
setLayout(null);
setSize(500,500);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String...s)
{
new Area();
}
}
I see several problems:
Don't use a null layout; do use a real layout.
The default layout of JFrame is BorderLayout; the default position is CENTER; only one component can occupy a position at a time; the example below uses NORTH & CENTER.
Use the appropriate constructor parameters to size the text components initially.
The scrollbar will appear automatically whenever the scrollpane is smaller than the enclosed component; resize the frame to see the effect.
As shown here, the frame's size is made smaller for effect.
See also Initial Threads.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
/** #see https://stackoverflow.com/a/19215436/230513 */
public class Area extends JFrame {
public Area() {
super("Text Area");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextField tf = new JTextField(12);
add(tf, BorderLayout.NORTH);
JTextArea ta = new JTextArea(24, 12);
JScrollPane jp = new JScrollPane(ta);
add(jp, BorderLayout.CENTER);
pack();
// arbitrary size to make vertical scrollbar appear
setSize(240, 240);
setLocationByPlatform(true);
setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Area();
}
});
}
}
Try this:
public Area()
{
super("Text Area");
tf=new JTextField();
tf.setBounds(100,350,300,30);
add(tf);
ta=new JTextArea();
jp= new JScrollPane(ta);
jp.setBounds(5, 5, 100, 100);
add(jp);
setLayout(null);
setSize(500,500);
setVisible(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
You have to use setBounds on JScrollPane, not on JTextArea
sounds like its added but its not shown because of the policy try this:
jp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
jp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
Could anyone point out where I am going wrong with this java swing gui code. I am trying to add two buttons to a JPanel and then add it into a frame after setting the size but it seems to not be responding to the setSize values passed to it
public Test() {
GridLayout layout = new GridLayout(1, 2);
//this.setLayout(layout);
this.setSize(700, 700);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
buttonPanel = new JPanel();
buttonPanel.setSize(new Dimension(30, 100));
JButton rectButton = new JButton("Rectangle");
JButton ovalButton = new JButton("Oval");
buttonPanel.add(rectButton);
buttonPanel.add(ovalButton);
this.add(buttonPanel);
this.add(new PaintSurface());
this.setVisible(true);
}
This may not answer your immediate question...but...
GridLayout layout = new GridLayout(1, 2);
this.setLayout(layout);
// You're original code...
// Why are you using `BorderLayout.CENTER` on a `GridLayout`
this.add(new PaintSurface(), BorderLayout.CENTER);
You set the layout as a GridLayout, but you are using BorderLayout constraints to apply one of the components??
Also, make sure that there are not calls to Test#pack else where in your code, as this will override the values of setSize
UPDATED (from changes to question)
Remember, the default layout manager for JFrame is BorderLayout, so even though you're calling buttonPanel.setSize, it's likely that it's begin overridden by the layout manager anyway.
I would take a read through A Visual Guide to Layout Managers and Using Layout Managers to find a layout manager that best meets your requirements.
If you can't find a single one, consider using compound components with different layout managers to bring the layout closer to what you want to achieve.
Ok, I'll just give you a solution:
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Cobie extends JFrame{
JButton rectButton = new JButton("Rectangle");
JButton ovalButton = new JButton("Oval");
JPanel buttonPanel = new JPanel();
JPanel paintSurface = new JPanel();
public Cobie(){
setLayout(new GridLayout(2,1));
buttonPanel.setBackground(Color.RED);
paintSurface.setBackground(Color.BLUE);
buttonPanel.add(rectButton);
buttonPanel.add(ovalButton);
add(buttonPanel);
add(paintSurface);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable(){
public void run(){
Cobie c = new Cobie();
c.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
c.setSize(600,400); //Avoid using this method
c.setVisible(true);
}
});
}
}
According to your updated answer, you are not setting your layout on anything.
Anyway, if you use LayoutManager's (which you should), it is pointless to call setSize()/setBounds()/setLocation() since it will be overriden by the LayoutManager (that is actually its job).
And guessing that your Test class extends JFrame, by calling this.add(buttonPanel); this.add(new PaintSurface()); you are adding two components with the same constraint (BorderLayout.CENTER, since BorderLayout is the default LayoutManager of the content pane of the JFrame) to the content pane.
Consider reading the LayoutManager tutorial.
Just for information, although far from perfect, this shows something "working":
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test extends JFrame {
private JPanel buttonPanel;
public class PaintSurface extends JButton {
public PaintSurface() {
super("Paint surface dummy");
}
}
public Test() {
GridLayout layout = new GridLayout(1, 2);
this.setLayout(layout);
this.setSize(700, 700);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
buttonPanel = new JPanel();
buttonPanel.setSize(new Dimension(30, 100));
JButton rectButton = new JButton("Rectangle");
JButton ovalButton = new JButton("Oval");
buttonPanel.add(rectButton);
buttonPanel.add(ovalButton);
this.add(buttonPanel);
this.add(new PaintSurface());
this.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
}
Can someone explain why the following doesn't work as I expect?
Pressing the button 'should' result in the display only containing the (empty) JScrollPane, ie the input field and button should disappear. However they stay until the component is resized...
public static void main(String[] args)
{
JFrame frame = new JFrame("test");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
final JPanel panel = new JPanel();
Container cp = frame.getContentPane();
cp.setLayout(new FlowLayout());
cp.add(new JScrollPane(panel));
Component textField = new JTextField("i am input");
JButton button = new JButton(new AbstractAction("i am pressy")
{
#Override
public void actionPerformed(ActionEvent e)
{
// this is already on the EDT
panel.removeAll();
panel.revalidate();
}
});
panel.setLayout(new FlowLayout());
panel.add(textField);
panel.add(button);
frame.pack();
frame.setVisible(true);
}
Thanks for your help. p.
When updating a visible GUI the code should be:
panel.revalidate();
panel.repaint(); // sometimes needed, this appears to be one of them
The revalidate() method marks components as needing to be laid out, but until something triggers repaint() you won't see any change. Resizing the parent window is one such trigger; switching applications is another. In this previous version, note how setSize() on the panel obviates the need for repaint(). Similarly, this example changes the layout in resetGame().
The article Painting in AWT and Swing goes into more detail.
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.WindowConstants;
/** #see https://stackoverflow.com/questions/5812002 */
public class RevalidateTest {
private static JPanel panel = new JPanel(); // default FlowLayout
private static JTextField text = new JTextField("Text field");
private static JButton clear = new JButton(new AbstractAction("Clear") {
#Override
public void actionPerformed(ActionEvent e) {
panel.removeAll();
panel.add(reset);
panel.revalidate();
panel.repaint();
}
});
private static JButton reset = new JButton(new AbstractAction("Reset") {
#Override
public void actionPerformed(ActionEvent e) {
panel.removeAll();
panel.add(text);
panel.add(clear);
panel.revalidate();
panel.repaint();
}
});
static void createAndShowGUI() {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
panel.add(text);
panel.add(clear);
frame.add(panel); // default BorderLayout center
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
createAndShowGUI();
}
});
}
}
You can execute panel.repaint() as specified in the comment by #Jeremy, however, the UI will still change when you resize the window. The reason being that the removal of the elements from the JPanel will cause the panel to resize. A repaint operation will not cause the panel to resize until the JFrame rechecks its layout (as happens on a window resize).
To make sure that the layout is correctly layed out on a change, you can call frame.validate(). This operation will cause the JFrame to revalidate itself and all child components, which is the same operation that is taking place during a window resize event. To execute this method in your code you would need to change JFrame frame to final, i.e.,
final JFrame frame = new JFrame("test");