I have this code and want to repaint my graphic when the Button gets pressed:
public class JDraw extends JFrame {
/**
* Draws a figur in a JFrame.
* The color of it is random and can get changed by a button.
*/
public static JButton okButton = new JButton("change color");
public JDraw(String newTitel) {
super.setTitle(newTitel);
}
//Main method
public static void main(String str[]) {
JDraw window = new JDraw("Graphic");
window.setSize(300, 450);
window.setVisible(true);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.add(okButton, BorderLayout.SOUTH);
okButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//JDraw.repaint(); <-- problem
}
});
}
#Override
public void paint(final Graphics g) {
super.paint(g);
Random rand = new Random();
int r1 = rand.nextInt(255);
int b1 = rand.nextInt(255);
int g1 = rand.nextInt(255);
g.setColor(new Color(r1, g1, b1));
//head
g.drawOval(100, 50, 100, 100);
g.fillOval(100, 50, 100, 100); // filled
//more drawing stuff.....
}
}
However I have no idea how to do it, because I cant do the repaint in my ActionPerfomed.
Error: non-static method repaint() cannot be referenced from a static context
I hope somebody can help. :)
You need to make the following call in your actionPerformed:
window.repaint();
To be able to reference window from within you actionPerformed, you need to make your window variable final:
final JDraw window = ...;
However, if I can suggest a few improvements:
Don't extend JFrame
Don't override paint(Graphics) of JFrame
Instead create a class that extends JComponent or JPanel and set it as the content pane of the JFrame
Instead of overrding paint(Graphics), rather override paintComponent(Graphics)
Your okButton should not be static. Instead move all your code in a non-static method like initUI() and have a code like new JDraw().initUI();
Wrap the code starting your UI in a SwingUtilities.invokeLater(Runnable) so that your UI is properly initiated from the Event Dispatching Thread.
You can't refer to the class JDraw. You should use an object instead. The object in your case is window. So, use:
window.repaint();
It is like saying: Human, walk to the door. Human is the class. You can't tell Human to do something, you need an instance of Human, like Obama or Santa Claus. In your case: you can't tell JDraw to repaint, but the object of type JDraw, i.e.: window.
Related
I have a main class that creates the instance of the JFrame and JPanel and I set the JPanel as public so I can access it from another class to add more things into it (I don't know if this is how it works, that's just my logic).
public class Main {
private JFrame obj;
public Gameplay gamePlay;
public Main() {
obj = new JFrame();
gamePlay = new Gameplay();
}
public void execute() {
//properties of the jframe
obj.setBounds(10, 10, 700, 600);
obj.setTitle("Brick breaker");
obj.setResizable(false);
obj.setVisible(true);
obj.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//add the jpanel inside the jframe
obj.add(gamePlay);
}
public static void main(String[] args) {
Main main = new Main();
main.execute();
}
}
Then, I have another class named Gameplay which extends JPanel. One of the methods inside has to draw things inside the JPanel and add a label when a condition is true.
Note that the commented region at the end where "GAME OVER" is drawn by with graphics g it does work correctly, but I want to put a label instead because I want to use custom font. The label never shows up. All the other things that the method pait() has to paint also work fine.
public void paint(Graphics g) {
//background
g.setColor(Color.black);
g.fillRect(1, 1, 692, 592);
//more code of drawing things
//...
if(ballposY > 570) {
play = false;
ballXdir = 0;
ballYdir = 0;
lblGameOver = new JLabel("GAME OVER");
lblGameOver.setForeground(Color.green);
lblGameOver.setFont(pixels);//custom font
Main main = new Main();
main.gamePlay.add(lblGameOver);
//g.setColor(Color.green);
//g.setFont(new Font("serif", Font.BOLD, 30));
//g.drawString("GAME OVER", 250, 300);
}
g.dispose();
}
You are need to add this line to your code:
lblGameOver.setOpaque(true);
It's will add your BackGroud and make that methode works well
lblGameOver.setForeground(Color.green);
I'd like to draw something in JFrame, so i decided to use below code but although it works truly but i don't want to have any ActionListener.
public class Draw
{
public static void main(String[] args)
{
final JPanel jPanel = new JPanel();
JFrame jFrame = new JFrame("Drawing Window");
JButton jButton = new JButton("draw");
jPanel.add(jButton);
jFrame.add(jPanel);
jFrame.setBounds(0, 0, 500, 500);
// first place
jFrame.setVisible(true);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// second place
jButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
Graphics graphics = jPanel.getGraphics();
graphics.drawLine(0,0,100,100);
graphics.drawOval(0,0,100,100);
}
});
}
}
as you can see i added the below code inside of ActionPerfomed method:
Graphics graphics = jPanel.getGraphics();
graphics.drawLine(0,0,100,100);
graphics.drawOval(0,0,100,100);
now i want to put it in the first place ( the comment place in the code ) but i will get an error, and if i put it in the second place, i will get no error but it does not draw any things.
It seems that it is necessary to put the drawing methods inside actionPerformed, my question is why? and is there any other way?
graphics.drawLine(0,0,100,100);
graphics.drawOval(0,0,100,100);
These statements need to be moved to an overridden paintComponent(Graphics) method of the jPanel.
The getPreferredSize() method of the panel should also be overridden to return a dimension of 500x500, then, instead of:
jFrame.setBounds(0, 0, 500, 500);
Simply call:
jFrame.pack();
One other option for you is to make the method(paintComponent or paint):
public void paintComponent(Graphics graphics){
graphics.drawLine(0,0,100,100);
graphics.drawOval(0,0,100,100);
}
and call the repaint from actionListener as shown..
public void actionPerformed(ActionEvent action){
repaint();
}
If it is usefull for you you can transform it as you want....
I have a class which extends JFrame and creates a window and it needs to call the paint() method which is in a different class. I understand that if they were in the same class, the setVisible(true) would call the paint method, but since they are in different classes, it does not. I have created objects of the Die class (the one painting), but I don't know how to use them to call the paint method.
This is the class which creates the window:
public class Game extends Frame
{
public void window()
{
setTitle("Roll"); // Title of the window
setLocation(100, 100); // Location of the window
setSize(900, 600); // Size of the window
setBackground(Color.lightGray); // Color of the window
setVisible(true); // Make it appear and call paint
}
And for the paint method in the other class called Die, I used:
public void paint(Graphics pane)
If I understand your question you could pass the Die instance into the Game constructor with something like
public class Game extends Frame {
private Die die;
public Game(Die die) {
this.die = die;
}
public void window() {
setTitle("Roll"); // Title of the window
setLocation(100, 100); // Location of the window
setSize(900, 600); // Size of the window
setBackground(Color.lightGray); // Color of the window
setVisible(true); // Make it appear and call paint
die.setVisible(true); // The same
}
}
Then, wherever you call new Game() you add the Die instance argument. This is a fairly common way to implement a callback in Java (and other OOP languages).
I have a button that when pressed calls a changecolor() method in a different class where some drawing is done. The button listener works fine and I see from some logging that the color was in fact changed but my drawing is not updated. This is my current implementation:
(This method is called when a button is clicked)
public void changeWarningLightColor(){
System.out.println("change color method called");
if(warningLights.equals(Color.GREEN)){
warningLights=Color.RED;
System.out.println(warningLights);
repaint();
}
else{
warningLights=Color.GREEN;
repaint();
}
}
and my drawing is created in the same file in the above method as follows:
#Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.drawSomething();
//draw a bunch of lines
}
My question is what is the proper way to call repaint() in order to actually update the drawing? Do I need to somehow call g.repaint() or do something different?
Separate class where the frame is created:
public class MainWindow extends JFrame {
public MainWindow(){
JPanel Window = new JPanel();
JPanel LeftSidePanel = new JPanel();
LeftSidePanel.setLayout(new BorderLayout());
LeftSidePanel.add(new DrawStatus(),BorderLayout.CENTER); //where the drawing is added
Window.setLayout(new BoxLayout(Window,0));
Window.add(LeftSidePanel);
add(Window);
}
public static void main(String[] args) {
//main method for showing the frame we created with the panels, and circles inside it
MainWindow frame = new MainWindow();
frame.setSize((int) (.75*Toolkit.getDefaultToolkit().getScreenSize().getWidth()),(int) (.75*Toolkit.getDefaultToolkit().getScreenSize().getHeight()));
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.setTitle("DVPWS v1.0");
frame.setResizable(false);
MenuBar menu = new MenuBar();
frame.setJMenuBar(menu);
frame.setVisible(true);
}
}
If you are using a Jframe (most likely are) do
yourFrame.repaint();
Optionally
yourPanel.repaint();
In this case you could do
public MainWindow mw = new MainWindow();
mw.repaint();
If that doesnt work(i had a similar problem) than your going to have to make an instance of JFrame instead of extending it.
I am new to Java....I studied that we can add two things on frame... I added button and in response by clicking on button I want rectangle as output....but i don't understand that..Why i am not getting output.....
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class customizedgui5 implements ActionListener {
JButton button;
JFrame frame;
public static void main(String[] args) {
customizedgui5 hi = new customizedgui5();
hi.go();
}
public void go() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton button = new JButton("click me");
button.addActionListener(this);
myclass a = new myclass();
frame.getContentPane().add(button, BorderLayout.CENTER);
frame.getContentPane().add(a, BorderLayout.SOUTH);
frame.setSize(100, 100);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent event) {
frame.repaint();
frame.revalidate();
}
}
class myclass extends JPanel {
public void paintComponent(Graphics g) {
g.setColor(Color.orange);
g.fillRect(20, 50, 100, 100);
}
}
I would start by taking a look at Performing Custom Painting.
The main problem in your code is you are getting NullPointerException when you click the button because the reference of frame is null.
It is null because you've shadowed it in the constructor (basically, declared another variable of the same name within the constructor)...
// I'm null..
JFrame frame;
public void go() {
// Not the same as frame above...
JFrame frame = new JFrame();
You are also going to not see any changes because of a number of reasons...
The myclass panel has no size. With BorderLayout, this won't be "too" much of a problem, but...
You've drawing outside of the visible range of the panel. The rectangle you are painting won't appear because it is being painted outside of the width and height of the panel.
The rectangle will appear before you press the button as paintComponent will be called to update the state of the panel once it's made visible on the screen...
The first thing you need to is provide some kind of size hints to the BorderLayout. Try adding...
#Override
public Dimension getPreferredSize() {
return new Dimension(120, 150);
}
To myclass.
You also don't need to repaint the frame, what you really want to repaint is the instance of myclass. Try updating customizedgui5 so that a becomes a instance variable (like frame...
//...
myclass a;
//...
public void go() {
//...
a = new myclass();
//...
}
public void actionPerformed(ActionEvent event) {
a.repaint();
}
Now, the rectangle will still be shown the moment that the panel is made visible on the screen. Sure you could try setting it invisible, but this will affect the layout of the frame, hiding your component to start with, so, instead, we need some kind of flag we can trip so we know when to paint the rectangle. This is easily achieved by using a simple boolean variable, for example...
class myclass extends JPanel {
private boolean paintRect;
public void setPaintRect(boolean paint) {
paintRect = paint;
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(120, 150);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (paintRect) {
g.setColor(Color.orange);
g.fillRect(20, 50, 100, 100);
}
}
}
Then in you actionPerformed method, you just need to set the flag...
public void actionPerformed(ActionEvent event) {
a.setPaintRect(true);
}
You may also want to take a read through Code Conventions for the Java Programming Language. It will make it easier for people to read your code...
When you click on your button, you're calling the method actionPerformed(ActionEvent event)
Take a look at what you did there. Currently, you repaint and re-validate the frame. If you want to add a rectangle to your frame, you need to do so by adding a new component to the frame that will draw the rectangle.
You could add another instance of your myclass JPanel which paints a rectangle like so:
public void actionPerformed(ActionEvent event) {
frame.getContentPane().add(new myclass(), BorderLayout.NORTH);
frame.repaint();
}
This would add your custom rectangle-drawing panel to the North section of your BorderLayout. If you want to add the rectangle "on top of" your button, you should embed your button within a JPanel, then add the rectangle-drawing panel to that instead of your main JFrame