I try to buid JPanels in a separate class to invoke them separately and add different items on it. Please can you tell me what i am doing wrong?
MyFrame.java
import javax.swing.*;
import java.awt.*;
public class MyFrame extends JFrame {
public static void main(String[] args) {
MyFrame frame = new MyFrame();
frame.setVisible(true);
}
public MyFrame() {
setTitle("MyFrame");
setSize(300, 200);
setLocationRelativeTo(null);
setDefaultCloseOperation(EXIT_ON_CLOSE);
MyPanel panel = new MyPanel();
JButton testButton = new JButton("Test");
panel.add(testButton);
}
}
MyPanel.java
import javax.swing.*;
import java.awt.*;
class MyPanel extends JPanel {
public MyPanel() {
this.setOpaque(true);
this.setVisible(true);
}
}
You're not adding your panel variable to your JFrame's contentPane.
Add:
public MyFrame() {
setTitle("MyFrame");
// setSize(300, 200); // let's avoid this
setDefaultCloseOperation(EXIT_ON_CLOSE);
MyPanel panel = new MyPanel();
JButton testButton = new JButton("Test");
panel.add(testButton);
add(panel); // *** here
pack(); // this tells the layout managers to do their thing
setLocationRelativeTo(null);
setVisible(true);
}
As a side note:
public MyPanel() {
this.setOpaque(true);
this.setVisible(true);
}
JPanels are opaque and visible by default, so your method calls within the MyPanel constructor do nothing useful.
Side note 2: I rarely if ever extend JFrame or any other top level window (with the exception of JApplet if I'm forced to use one of these), since I rarely change the innate behavior of the window. Better I think to create my top level windows (i.e., my JFrames) when needed.
Side note 3: Always strive to start your Swing GUI's on the Swing event thread. So do...
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
MyFrame frame = new MyFrame();
frame.setVisible(true);
}
});
}
Edit
You ask:
You wrote lets avoid setting the size.. can you tell me how i can pack it but set a minimum frame size?
I like to override the JPanel's getPreferredSize() method, and have it return a Dimension that makes sense.
For example, you could do something like this to be sure that your GUI is at lest PREF_W by PREF_H in size:
import java.awt.Dimension;
import javax.swing.*;
public class ShowGetPreferredSize extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
#Override
public Dimension getPreferredSize() {
Dimension superSize = super.getPreferredSize();
if (isPreferredSizeSet()) {
return superSize;
}
int w = Math.max(superSize.width, PREF_W);
int h = Math.max(superSize.height, PREF_H);
return new Dimension(w, h);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("ShowGetPreferredSize");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(new ShowGetPreferredSize());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Related
So I am trying to learn how to use card layout and in this sample code I would like to change the size of the frame to a certain size but using setSize does not work.
the following also does not work in the when added to createAndShowGui() function
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
frame.setPreferredSize(new Dimension(500,200));
import java.awt.CardLayout;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class MainGui2 extends JPanel {
private CardLayout cardLayout = new CardLayout();
private WelcomePanel welcomePanel = new WelcomePanel(this);
private HomePanel homePanel = new HomePanel();
public MainGui2() {
setLayout(cardLayout);
add(welcomePanel, WelcomePanel.NAME);
add(homePanel, HomePanel.NAME);
}
public void showCard(String name) {
cardLayout.show(this, name);
}
private static void createAndShowGui() {
MainGui2 mainPanel = new MainGui2();
JFrame frame = new JFrame("MainGui2");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
//frame.pack();
frame.setSize(550, 300);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class WelcomePanel extends JPanel {
public static final String NAME = "welcome panel";
private MainGui2 mainGui2;
public WelcomePanel(final MainGui2 mainGui2) {
this.mainGui2 = mainGui2;
add(new JLabel(NAME));
add(new JButton(new AbstractAction("Logon") {
#Override
public void actionPerformed(ActionEvent e) {
mainGui2.showCard(HomePanel.NAME);
}
}));
}
}
class HomePanel extends JPanel {
public static final String NAME = "home panel";
public HomePanel() {
add(new JLabel(NAME));
}
}
I would like to change the size of the frame to a certain size
Don't try to hard code frame sizes.
If you want extra space around the panels then in the constructor of your MainGui2 class you can add:
setBorder( new EmptyBorder(50, 50, 50, 50) );
This will adjust the preferred size of the panel and this size will now be taken into account when the pack() method is used.
Can anyone tell me why the rectangle is not showing up on the frame?
I only see a button on the frame. Please help.
I tried to using the paint method for drawing the rectangle.
Should I use paintComponent() or just paint()?
public class GUI2 {
public static void main(String[] args) {
JFrame frame = new JFrame("Game");
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500, 500);
frame.setLocation(500, 200);
JPanel panel = new JPanel();
frame.add(panel);
JButton button = new JButton("YO");
panel.add(button);
button.addActionListener(new Action());
frame.paint(null);
}
public void paint(Graphics g) {
g.drawRect(250, 250, 200, 100);
}
static class Action implements ActionListener {
public void actionPerformed(ActionEvent e) {
}
}
}
You shouldn't have to explicitly call paint
get rid of the paint method
Make an Inner JPanel class
Yes override paintComponent in the JPanel class
Call super.paintComponent in the paintComponent method.
Add the class JPanel to the JFrame
Don't do everything inside the main, as you'll find out, that static will cause a problem for you. Do everything inside a constructor
Run the program from the EDT SwingUtilitites.invokeLater().
Make the button a global variable so it can be accessed from the ActionListener
setVisible should be the last thing you do, after adding all the component.
When adding multiple components the JFrame you will want to use the BorderLayout positions, or set the layout to the JFrame to something else besides BorderLayout
Override getPrefferedSize in your JPanel when painting, so the JPanel has a respected preferred size.
Don't set the size of the JFrame just call pack();
Here is a refactor of your code
Also see Creating GUI with Swing | Graphics2D | Performing Custom Paintin for further details.
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class GUI2 {
JButton button = new JButton("YO");
public GUI2() {
button.addActionListener(new Action());
JFrame frame = new JFrame("Game");
frame.add(new DrawPanel(), BorderLayout.CENTER);
frame.add(button, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private class DrawPanel extends JPanel {
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(250, 250, 200, 100);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new GUI2();
}
});
}
static class Action implements ActionListener {
public void actionPerformed(ActionEvent e) {
}
}
}
I can tell you why you'll get a NullPointerException
You've not overridden any paint method of any displayable component
You've not passed a valid Graphics context to you paint method, but I would discourage this any way
You should make use of the #Override annotation which would have prevented the class from compiling. Use it when you think you're overriding a method of a parent class, it will tell you when you're wrong
Start by taking a look at Performing Custom Painting and then take a look at Painting in AWT and Swing for more details about how painting is actually done in Swing
Here is working example of your code:
package test;
import javax.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.image.ImageObserver;
import java.awt.*;
import java.text.AttributedCharacterIterator;
public class GUI2 extends JPanel{
JButton button;
JFrame frame;
public GUI2() {
button = new JButton("YO");
//panel = new JPanel();
frame = new JFrame();
//panel = new JPanel();
this.add(button);
frame.add(this);
//button.addActionListener(new Action());
// this.paint(null);
frame.setSize(500, 500);
frame.setLocation(500, 200);
frame.setVisible(true);
}
public void paint(Graphics g) {
g.setColor(Color.red);
g.drawRect(250, 250, 200, 100);
}
public static void main(String[] args) {
GUI2 test = new GUI2();
}
}
I have removed some statements but you can add them later
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);
}
I made a 840 by 400 frame and added a text field. By default, the java app shrinked only to the size of the text field. I want it fixed to the respective size.
I tried setResizable(false), setExtendedState(), setBounds() with no avail.
Best to use a JPanel as your contentPane or add it to the contentPane, and to override its getPreferredSize() method and then usepack()` on the JFrame. For example:
import java.awt.Dimension;
import javax.swing.*;
#SuppressWarnings("serial")
public class MyPanel extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = 300;
public MyPanel() {
//...
}
#Override
public Dimension getPreferredSize() {
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
MyPanel myPanel = new MyPanel();
JFrame frame = new JFrame("My GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(myPanel);
frame.setResizable(false);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
One advantage of this is that other classes cannot change MyPanel's size via setSize(...) or setPreferredSize(...).
Try
setPreferredSize(new Dimension(840,400));
If you named your frame you can do
name.setPreferredSize(new Dimension(840,400));
In the following example program, if you set useBorderlayout to true, the paintComponent method is never called - why?!
import javax.swing.*;
import java.awt.*;
public class PaintComponentTest extends JPanel {
private final boolean useBorderLayout;
public PaintComponentTest(boolean useBorderLayout){
this.useBorderLayout = useBorderLayout;
initialiseComponents();
}
public void initialiseComponents(){
setOpaque(true);
setBackground(Color.RED);
if(useBorderLayout){
//this appears to be the offending line:
setLayout(new BorderLayout());
}
final JPanel panel = new JPanel();
panel.setOpaque(true);
panel.setBackground(Color.GREEN);
add(panel, BorderLayout.CENTER);
}
#Override
public void paintComponent(Graphics g){
System.out.println("PaintComponentTest.paintComponent");
super.paintComponent(g);
}
public static void main(String [] args){
final boolean useBorderLayout = (args.length == 1 && Boolean.parseBoolean(args[0]));
System.out.println("Running with"+(useBorderLayout?"":"out")+" BorderLayout as layout manager...");
SwingUtilities.invokeLater(new Runnable(){
public void run(){
final JFrame frame = new JFrame("BorderLayout/PaintComponent test");
frame.setPreferredSize(new Dimension(200, 200));
frame.getContentPane().setLayout(new BorderLayout());
final PaintComponentTest componentTest = new PaintComponentTest(useBorderLayout);
frame.getContentPane().add(componentTest);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
});
}
}
Because it doesn't need to. The PaintComponentTest class is a JPanel that has one green JPanel as content. When the BorderLayout is set, the green panel takes up all the space in panel and the PaintComponent method is not needed.
Add this method to your code and you should see it happen:
#Override
public void paintChildren(Graphics g){
System.out.println("PaintComponentTest.paintChildren");
super.paintChildren(g);
}
Because the nested panel covers all the component. Damaged region (to be repainted) is past to the children because the child bounds cover all the damaged region.