Suppose I have a JPanel in a JFrame. When I invoke a method that changes the preferred size of that JPanel, it does not change.
The code looks something like this:
public class SomePanel extends JPanel{
public SomePanel(){
setPreferredSize( new Dimension( 390, 40 ) );
setBackground( Color.BLACK );
}
public void expand(){
setPreferredSize( new Dimension( 390, 200 ) );
}
public static void main( String args[] ){
JFrame frame = new JFrame();
frame.setSize( 450, 500 );
frame.setLayout( new FlowLayout() );
SomePanel somePanel = new SomePanel();
frame.add( somePanel );
frame.setVisible( true );
somePanel.expand();
}
}
Is there something that I have to do first? I have tried so check the size of the JPanel when expand() is invoked. The height of the JPanel before and after setting the preferred size remains at 40.
I have also tried to use a Dimension variable, and that did not work either.
Dimension dimension;
public SomePanel(){
dimension = new Dimension( 390, 40 );
...
}
public expand(){
dimension.setSize( 390, 200 );
setPreferredSize( dimension );
}
Add frame.pack(); after somePanel.expand(); in your main() method. It will be done.
You need to invalidate the container hierarchy to make it re-layout the components.
Simply call invalidate followed by revalidate on the component you have changed.
Here's a small example...
public class TestComponentHierarcy {
public static void main(String[] args) {
new TestComponentHierarcy();
}
public TestComponentHierarcy() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
frame.add(new Test());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class Test extends JPanel {
private Dimension size = new Dimension(10, 10);
public Test() {
setLayout(new GridBagLayout());
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
size.width += 10;
size.height += 10;
invalidate();
revalidate();
}
});
}
#Override
public Dimension getPreferredSize() {
return size;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
}
}
}
+1 to all.
I usually use a combination of:
revalidate() and pack(). (see #GagandeepBali and #StanislavL answer here for more reasoning as to my choice of revalidate()) as for pack() this allows for my JFrame to be sized to fit the contents.
do not call setPreferredSize rather override getPreferredSize of JPanel.
also do not call setSize(..) on JFrame use correct LayoutManager which adjusts to all added components size and than simply call pack() before setting JFrame visible.
And lastly but not stressed enough warp creation and manipulation of Swing components in SwingUtilities.invokeXXX block / Event Dispatch Thread
Here is an example I made:
Basically a JPanel which overrides getPreferredSize and has a method setPanelSize(int w,int h) which changes variables in JPanel instance to return new Dimensions for getPreferredSize. after that I call revalidate() and pack() on JFrame to refelect changes:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test {
public Test() {
initComponents();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Test();
}
});
}
private void initComponents() {
final JFrame frame = new JFrame();
frame.setTitle("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final MyPanel myPanel = new MyPanel();
final JButton changeSizeButton = new JButton("Change size to 300x300");
changeSizeButton.addActionListener(new ActionListener() {
boolean resized = false;
#Override
public void actionPerformed(ActionEvent ae) {
if (resized) {
myPanel.setPanelSize(200, 200);
resized = false;
changeSizeButton.setText("Change size to 300x300");
} else {
myPanel.setPanelSize(300, 300);
resized = true;
changeSizeButton.setText("Change size to 200x200");
}
frame.revalidate();
frame.pack();
}
});
frame.add(myPanel);
frame.add(changeSizeButton, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
}
class MyPanel extends JPanel {
private int width, height;
public MyPanel() {
super(true);
width = 200;
height = 200;
}
#Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
public void setPanelSize(int width, int height) {
this.width = width;
this.height = height;
}
}
Related
How do I put a button on the border that surrounds the frame like this cog:
_"Is the a short example anywhere? "
Yea, here... This very basic. You need to do alot more to it. You'll notice I have to add a MouseMotionListener to the JPanel that acts as the top frame border, because when you remove the decoration from the frame, you're also taking away that functionality. So the MouseMotionListener makes the frame draggable again.
You would also have to implement resizing if you wished. I already implemented the Systemexit()` when you press the image. Test it out. You need to provide your own image.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.LineBorder;
public class UndecoratedExample {
static JFrame frame = new JFrame();
static class MainPanel extends JPanel {
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
}
static class BorderPanel extends JPanel {
JLabel stackLabel;
int pX, pY;
public BorderPanel() {
ImageIcon icon = new ImageIcon(getClass().getResource(
"/resources/stackoverflow1.png"));
stackLabel = new JLabel();
stackLabel.setIcon(icon);
setBackground(Color.black);
setLayout(new FlowLayout(FlowLayout.RIGHT));
add(stackLabel);
stackLabel.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
System.exit(0);
}
});
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent me) {
// Get x,y and store them
pX = me.getX();
pY = me.getY();
}
});
addMouseMotionListener(new MouseAdapter() {
public void mouseDragged(MouseEvent me) {
frame.setLocation(frame.getLocation().x + me.getX() - pX,
frame.getLocation().y + me.getY() - pY);
}
});
}
}
static class OutsidePanel extends JPanel {
public OutsidePanel() {
setLayout(new BorderLayout());
add(new MainPanel(), BorderLayout.CENTER);
add(new BorderPanel(), BorderLayout.PAGE_START);
setBorder(new LineBorder(Color.BLACK, 5));
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.setUndecorated(true);
frame.add(new OutsidePanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
I have a following code ( trying to learn swing and java). I created a ladder using rectangular components using class and placed on the main frame. Everything works okay but if I resize it even slightly, the ShapeManager object (i.e, the ladder) disappears. I don't know what is going on. Any help please.
GUIMain Class:
package mainProg;
import javax.swing.*;
import java.awt.BorderLayout;
import java.awt.event.*;
import java.awt.*;
public class GUIMain {
static JPanel mainPanel;
static JButton[] newButtons;
static ShapeManager newShape;
private static class BtnEvtHandler implements ActionListener {
public void actionPerformed(ActionEvent e) {
//System.exit(0);
JOptionPane.showMessageDialog( null, "WELCOME" );
}
}
private static JButton[] createButtons() {
JButton[] buttonArray= new JButton[2];
buttonArray[0]=new JButton("OK");
buttonArray[1]=new JButton("MOVE");
BtnEvtHandler okButtonHandler= new BtnEvtHandler();
( buttonArray[0]).addActionListener(okButtonHandler);
return buttonArray;
}
private static ShapeManager createShape(int x) {
ShapeManager newContent=new ShapeManager(x);
return newContent;
}
private static JPanel mainContainer() {
JPanel mainPanel= new JPanel();
mainPanel.setSize(400, 400);
return mainPanel;
}
private static void createAndShowGUI() {
JFrame.setDefaultLookAndFeelDecorated(false);
JFrame frame = new JFrame(" DB ");
mainPanel= mainContainer();
mainPanel.setLayout(new BorderLayout(10, 10));
newButtons= createButtons();
newShape= createShape(20);
newButtons[0].setHorizontalAlignment(0);
mainPanel.add(newButtons[0],BorderLayout.PAGE_START);
newButtons[1].setHorizontalAlignment(0);
mainPanel.add(newButtons[1],BorderLayout.PAGE_END);
newShape.setPreferredSize(new Dimension(400, 400));
mainPanel.add(newShape, BorderLayout.LINE_END);
frame.setContentPane(mainPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 600);
frame.setLocation(500,200);
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
ShapeManager Class:
package mainProg;
import javax.swing.JPanel;
import java.awt.*;
#SuppressWarnings("serial")
class ShapeManager extends JPanel {
int rectPos;
ShapeManager(int rectPos) {
setPreferredSize(new Dimension(400,400));
this.rectPos=rectPos;
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
while (rectPos<150) {
g.setColor(Color.BLUE);
g.drawRect(rectPos+10, rectPos+10, 100, 10);
g.fillRect(rectPos+10, rectPos+10, 100, 10);
rectPos=rectPos+10;
}
}
}
You never reset rectangle position, so after the first paint it remains above 150. You need to reset it after you exit your while loop.
Try this:
g.setColor(Color.BLUE);
int position = rectPos;
while (position<150) {
position += 10;
g.drawRect(position, position, 100, 10);
g.fillRect(position, position, 100, 10);
}
can someone take a look at my code below and tell me why, when I change the following two statements, I do not see a change on the rectangle that is painted. So if I change:
g.setColor(Color.black);
g.fillRect(l, w, 100, 100);
The program still prints a black rectangle with the same dimensions and in the same position that I first started with even though I change color to yellow or try to change the dimensions or location. I am BlueJ. The following is my full code:
import java.awt.*;
import javax.swing.*;
public class SwingPaintDemo2 extends JComponent {
public static boolean isWall = true;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
//System.out.println("Created GUI on EDT? "+
//SwingUtilities.isEventDispatchThread());
JFrame f = new JFrame("Swing Paint Demo");
JPanel MyPanel = new JPanel();
MyPanel.setBorder(BorderFactory.createEmptyBorder(1000, 1000, 1000, 1000));
MyPanel.setPreferredSize(new Dimension(250, 200));
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new MyPanel());
f.pack();
f.setVisible(true);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
int l = 10;
int w = 10;
g.setColor(Color.black);
g.fillRect(l, w, 100, 100);
}
}
Any advice would be appreciated.
Your SSCCE doesnt compile where is MyPanel class or did you mean new SwingPaintDemo2()?
On the assumption you meant new SwingPaintDemo2():
The code does work just fine but the JFrame is sized very small:
because you dont give it any size and none of its components have a size as they do not have any components added to them, thus we must make the JComponent return a correct size so when we call pack() our JFrame is sized correctly
Solution
override getPreferredSize() of JComponent to return a width and height which fits all drawings.
Some suggestions though:
Dont extend JComponent rather extend JPanel
Here is an example (your code with above fixes implemented):
import java.awt.*;
import javax.swing.*;
public class SwingPaintDemo2 extends JPanel {
public static boolean isWall = true;
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
//System.out.println("Created GUI on EDT? "+
//SwingUtilities.isEventDispatchThread());
JFrame f = new JFrame("Swing Paint Demo");
JPanel MyPanel = new JPanel();
MyPanel.setBorder(BorderFactory.createEmptyBorder(1000, 1000, 1000, 1000));
MyPanel.setPreferredSize(new Dimension(250, 200));
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(new SwingPaintDemo2());
f.pack();
f.setVisible(true);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
int l = 10;
int w = 10;
g.setColor(Color.black);
g.fillRect(l, w, 100, 100);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(150, 150);
}
}
I'm having this problem where an object that I've drawn isn't appearing in the GUI. I know it's being processed because data is being pushed to a log file. However, the graphic isn't appearing.
Here's some of my code:
public static void main(String[] args)
{
JFrame window = new JFrame();
window.setLayout(new BorderLayout());
window.setVisible(true);
}
There's a button and a few other widgets that I've placed here and there. The center pane (BorderLayout.CENTER) is where my DrawnObject is to be displayed.
// Called when button is pushed/clicked
public static void trigger()
{
DrawnObject shape = new DrawnObject();
window.setLayout(new BorderLayout());
window.getContentPane().add(shape, BorderLayout.CENTER);
window.pack;
}
public class DrawnObject extends JComponent()
{
#Override
public Dimension getMinimumSize()
{
return new Dimension(100, 100);
}
#Override
public Dimension getPreferredSize()
{
return new Dimension(500, 500);
}
#Override
public Dimension getMaximumSize()
{
return new Dimension(700, 700);
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(10, 10, 10, 10);
}
}
I've tried casting the Graphics object as Graphics2D and using the appropriate draw methods, but that hasn't helped.
Try changing the color...
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(10, 10, 10, 10);
The graphics context color is set to the components background color by default
public class PaintTest01 {
public static void main(String[] args) {
new PaintTest01();
}
public PaintTest01() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new DrawPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class DrawPane extends JPanel {
#Override
public Dimension getPreferredSize() {
return new Dimension(30, 30);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.RED);
g.fillRect(10, 10, 10, 10);
}
}
}
UPDATED
From your updated code in your question, it can't compile...
You create a JFrame named window in the constructor, which is a local variable...
public static void main(String[] args)
{
JFrame window = new JFrame();
window.setLayout(new BorderLayout());
window.setVisible(true);
}
Then you try and add the DrawObject to the window...
public static void trigger()
{
DrawnObject shape = new DrawnObject();
window.setLayout(new BorderLayout());
window.getContentPane().add(shape, BorderLayout.CENTER);
window.pack;
}
But because window is undefined, you example can't compile.
The only way that this would compile is if you had a static variable at the class level called window, which in that case, it should be producing a NullPointerException, unless you've initialised that variable
public class MyDrawing {
public static JFrame window = new JFrame();
This would mean you have two frames, one you created in the constructor and one your create as a static level class field. This won't work, because they are different instances
have to return PreferredSize from public class DrawnObject extends JComponent(), otherwise returns Dimension(0, 0);
Top-Level containers have got implemented BorderLayout, then window.add(shape, BorderLayout.CENTER); is proper code line and JComponent should be layed correctly
use pack() instead of invalidate(), this code line doesn't works, to invoke something for container layed by BorderLayout or GridLayout (e.i. ???), nor for container based on JComponent,JComponent havent implemented any LayoutManager in API, have to return PreferredSize
for better help sooner post an SSCCE
Try adding your DrawnObject to the windows content pane, and also don't forget to set a layout. Using a null layout is bad practice (your layout is set to null if you call on invalidate).
window.getContentPane().setLayout(new BorderLayout());
window.getContentPane().add(shape, BorderLayout.CENTER);
window.pack();
window.setVisible(true);
Also, try to skip the invalidate().
I am trying to view a JApplet within a JFrame.
Class: Paint
public void paint(Graphics g) {
g.drawString("hi", 50, 50);
}
public static void main(String args[]) {
JFrame frame = new JFrame("test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setJMenuBar(methodThatReturnsJMenuBar());
JPanel panel = new JPanel(new BorderLayout());
frame.add(panel);
JApplet applet = new Paint();
panel.add(applet, BorderLayout.CENTER);
applet.init();
frame.pack();
frame.setVisible(true);
}
The applet shows up in the Window, but there is no background (it's transparent), and when I click on the Menu, the list is covered. How do I make it so that the Menu list isn't covered, and there is a background?
Edit: When I draw a white rectangle, it fixes the background problem, but the Menu list is still covered.
I would gear my GUI creation towards making a JPanel and then use the JPanel as I desire, either in an JApplet or a JFrame. For e.g.,
import java.awt.*;
import javax.swing.*;
public class MyPanel extends JPanel {
private static final Dimension PREF_SIZE = new Dimension(400, 300);
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString("hi", 50, 50);
}
#Override
public Dimension getPreferredSize() {
return PREF_SIZE;
}
public JMenuBar methodThatReturnsJMenuBar() {
JMenu menu = new JMenu("Menu");
JMenuBar menuBar = new JMenuBar();
menuBar.add(menu);
return menuBar;
}
}
Then to use in an applet:
import javax.swing.JApplet;
public class MyApplet extends JApplet {
public void init() {
try {
javax.swing.SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
createGUI();
}
});
} catch (Exception e) {
System.err.println("createGUI didn't successfully complete");
}
}
private void createGUI() {
getContentPane().add(new MyPanel());
}
}
Or in a JFrame:
import javax.swing.JFrame;
public class MyStandAlone {
private static void createAndShowUI() {
MyPanel myPanel = new MyPanel();
JFrame frame = new JFrame("MyPanel");
frame.getContentPane().add(myPanel);
frame.setJMenuBar(myPanel.methodThatReturnsJMenuBar());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
createAndShowUI();
}
});
}
}