If so someone could explain how to get this to paint and why it isn't painting that would be awesome!!!
public class Main extends JPanel implements Runnable {
public void run() {
System.out.println("g");
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(50, 50, 200, 200);
}
public static void main(String[] args) {
JFrame frame = new JFrame("Physics!");
frame.setSize(500, 500);
frame.setBackground(Color.BLUE);
frame.setVisible(true);
Main physics = new Main();
Thread t = new Thread(physics);
t.start();
}
}
You never add physics to the JFrame
Main physics = new Main();
JFrame frame = new JFrame("Physics!");
frame.add(physics);
Side Note
When painting on JPanel override getPreferredSize() so the panel has a preferred size, then you can just pack() the frame, as you should be doing, instead of setting it's size
#Override
public Dimension getPreferredSize() {
return new Dimension(500, 500);
}
...
frame.pack();
// frame.setSize(500, 500);
Also, paintComponent should be protected not public
Also see Initial Threads for running Swing apps on the Event Dispatch Thread
You have to add the JPanel to the JFrame:
JFrame frame = new JFrame("Physics!");
Main physics = new Main();
Thread t = new Thread(physics);
t.start();
frame.setContentPane(physics); // Add it like this
frame.setSize(500, 500);
frame.setBackground(Color.BLUE);
frame.setVisible(true);
Try putting t.join() in the main method after t.start() .. Your main method should wait for the thread to finish.
Related
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 know this question has been asked a lot, but ive read through about 10 different articles, all reccomending to different things such as "frame = this" nad frame.add(d)" Im not sure why, but none of these have been working. I typed something and the program worked fine, except the Jbuttons wouldnt show up until i clicked on the JFrame a few times. After some tweaking of that code, im back to the start. Now i just get a error:
Exception in thread "main" java.lang.NullPointerException
at Guis.Dynamic_JFrame.<init>(Dynamic_JFrame.java:37)
at Guis.Dynamic_JFrame.main(Dynamic_JFrame.java:46)
Heres my code:
public class Dynamic_JFrame extends JFrame{
static JFrame frame;
Graphics g;
Handler handler = new Handler();
JButton red = new JButton();
JButton green = new JButton();
JButton orange = new JButton();
public Dynamic_JFrame(){
red.setText("RED");
green.setText("GREEN");
orange.setText("orange");
add(green);
add(red);
add(orange);
red.addActionListener(handler);
green.addActionListener(handler);
orange.addActionListener(handler);
frame.setVisible(true);
}
public static void main(String[] args){
Dynamic_JFrame d = new Dynamic_JFrame();
frame = new JFrame("Changing colors");
frame.setPreferredSize(new Dimension(500,500));
frame.setMaximumSize(new Dimension(500,500));
frame.setMinimumSize(new Dimension(500,500));
frame.setLayout(new FlowLayout());
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public class Handler implements ActionListener{
public void actionPerformed(ActionEvent e) {
if(e.getSource()==red){
getContentPane().setBackground(Color.RED);
}
if(e.getSource()==green){
getContentPane().setBackground(Color.GREEN);
}
if(e.getSource()==orange){
getContentPane().setBackground(Color.ORANGE);
}
}
}
}
New code, Minor Changes. Program works as intended except for the buttons not updating until i click where they should be:
JFrame frame;
public Dynamic_JFrame(){
frame = new JFrame();
frame = this;
red.setText("RED");
green.setText("GREEN");
frame.add(green);
frame.add(red);
frame.setVisible(true);
}
public static void main(String[] args){
Dynamic_JFrame d = new Dynamic_JFrame();
d.frame.setPreferredSize(new Dimension(500,500));
d.frame.setMaximumSize(new Dimension(500,500));
d.frame.setMinimumSize(new Dimension(500,500));
d.frame.setLocationRelativeTo(null);
d.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
d.frame.setLayout(new FlowLayout());
}
A number of things...
Firstly, Dynamic_JFrame extends from JFrame so I don't know why you've then gone and create another frame...
Secondly, when Dynamic_JFrame calls frame.setVisible in the constructor, frame is null as it has not being initialised.
From my perspective, the simplest solution would be to extend Dynamic_JFrame from something like JPanel instead and simply add it to an instance of JFrame
For example...
public class Dynamic_JFrame extends JPanel {
static JFrame frame;
// Not sure that this is a good idea...
Graphics g;
//...
public Dynamic_JFrame(){
// Don't use this...
//frame.setVisible(true);
}
public static void main(String[] args){
EventQueue.invokeLater(new Runnable() {
public void run() {
Dynamic_JFrame d = new Dynamic_JFrame();
frame = new JFrame("Changing colors");
frame.setLayout(new FlowLayout());
frame.add(d);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
I am having some trouble with adding a JMenuBar and a JPanel to a JFrame, here is my Main Method:
public static Timer timer = new Timer(100, ActionListener.repaint);
public static void main(String[] args) {
Insets in;
frame.setSize(600, 500);
frame.pack();
in = frame.getInsets();
frame.setSize(600 + (in.left + in.right) - 10, 500 + (in.top + in.bottom) - 10);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
add.addActionListener(new ActionListener());
frame.setJMenuBar(menuBar);
menuBar.add(file);
file.add(add);
file.add(sub);
frame.add(gui);
timer.start();
frame.setVisible(true);
}
The field 'gui' is my JPanel class:
#Override
public void paintComponent(Graphics g) {
}
Here is my repaint Timer:
public static java.awt.event.ActionListener repaint = new java.awt.event.ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
GUI.gui.repaint();
}
};
here is the output:
See how it duplicated the JMenuBar? It does that for anything painted onto that JPanel.
Any solutions?
Any solutions?
Yes. Dont call Thread.sleep in the paintComponent method. In fact dont call Thread.sleep anywhere in a Swing application. For periodic delays use a Swing Timer
I'm trying to play around with JFrame/JPanels repaint(); and so forth, but when I start a thread, and call repaint via run while true, it only spits out a line of System.out.println("as"); which I put in place to check if loop was running.
So the question is:
Why is my drawings disappearing when calling repaint in a loop?
(It seems only a JFrame with the canvas_width/height is showing up, no panels etc.)
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(CANVAS_WIDTH, CANVAS_HEIGHT);
frame.setPreferredSize(new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT));
frame.setVisible(true);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel p = new JPanel(new GridLayout());
frame.getContentPane().add(p);
Something s = new Something();
p.add(s);
p.setBackground(Color.black);
frame.pack();
}
And the something class:
public class Something extends JPanel implements Runnable {
public Something(){
Thread t = new Thread();
t.start();
run();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.cyan);
g.fillRect(0, 0, getWidth()-150, getHeight()-100);
g.setColor(Color.BLACK);
g.fillOval(10, 10, 25, 25);
}
#Override
public void run() {
while(true){
repaint();
System.out.println("as");
try {
Thread.sleep(1);
} catch (InterruptedException e){}
}
}
}
Any help regarding the contentpane is appreciated, since, I'm not sure this is done correctly.
Instead of calling Thread.sleep(n) in your Thread, implement a Swing Timer for repeating tasks. That ensures that repaint() is called on the Event Dispatch Thread.
See Concurrency in Swing for more details.
Also, repainting every 1 millisecond is being very optimistic.
Working SSCCE E.G. (Note this version actually changes the co-ords of the resulting paint operations, just so we know something is happening!
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Something extends JPanel {
static final int CANVAS_WIDTH = 400;
static final int CANVAS_HEIGHT = 100;
private int xDelta = 0;
public Something(){
ActionListener animater = new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
repaint();
}
};
Timer t = new Timer(10,animater);
t.start();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.cyan);
g.fillRect(0, 0, getWidth()-(xDelta--), getHeight()-100);
g.setColor(Color.BLACK);
g.fillOval(xDelta, 10, 25, 25);
if (xDelta<0) {
xDelta = CANVAS_WIDTH;
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(CANVAS_WIDTH, CANVAS_HEIGHT);
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel p = new JPanel(new GridLayout());
frame.getContentPane().add(p);
Something s = new Something();
p.add(s);
p.setBackground(Color.black);
frame.pack();
frame.setResizable(false);
frame.setVisible(true);
}
}
Starting a Runnable in a new Thread is done with java.lang.Thread.Thread( Runnable ) constructor.
Calling a method of a GUI component outside the Swing event loop is not a good practice, use a Swing timer instead.
Your code becomes:
public static void main(String[] args) {
...
new Timer( 40, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
repaint
}
}).start();
...
}
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.