if-statement inside of paintComponent makes it not paint - java

I'm trying to write a solitaire game.
I would like to call repaint() when the game starts and paint the full deck
once only the first time repaint is called, but when I add the if-statement it
no longer paints.
Here is the code with the if-statement:
private void paintInitialDeck(Graphics g, Card card){
card.paintCard(g);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (initialDrawing) {
Card card;
for (int i = 0; i < deck.size(); i++) {
card = deck.get(i);
card.setY((int) (50 + 0.2 * i));
card.setX((int) (250 + 0.2 * i));
paintInitialDeck(g, card);
}
initialDrawing = false;
}
}
It doesn't work, but if I remove the if statement and the initialDrawing = false
then it works.
Problem is, I need the if-statement.
Anyone can help me understand this better?
ps.: initialDrawing is set to true to begin with. Also, it's really the initialDrawing = false
that makes the whole thing not paint.

What's happening is that with initial instantiation of that class with the paintComponent method, the paintComponent method is called once. So the paint will occur once, but after that, not again because the initiaDrawing is set to false after the first call to paintComponent in the initial instantiation. So a call to repaint() within the program would not work, as initialDrawing will be false after the first start up paint process.
I'm not sure if you see the paint occurring when you first start the program, but this is why, it won't allow you to paint again after the program has started.
A possible fix might be to initialize initialDrawing to false so it doesn't initially paint. Then whatever component calls the repaint() method, in the action, first set the inititialDrawing to true, then call repaint(). Disable that component so another call to repaint() cannot be made. (or something of this logical nature).
Here's an example
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
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 DisablePaint extends JPanel {
ImagePanel panel;
JButton button;
boolean intialDraw = false;
public DisablePaint() {
button = new JButton("Paint Once");
setLayout(new BorderLayout());
panel = new ImagePanel();
add(panel, BorderLayout.CENTER);
add(button, BorderLayout.SOUTH);
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
intialDraw = true;
panel.repaint();
button.setEnabled(false);
}
});
}
private class ImagePanel extends JPanel {
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (intialDraw) {
g.setColor(Color.BLUE);
g.fillRect(50, 50, 200, 200);
initialDraw = false;
}
}
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame();
frame.add(new DisablePaint());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
You can see that initialDraw is first set to false, so it won't draw on initial start of program. I then make a call to repaint() in the actionPerformed, but first setting the intialDrawing to true. Then disable the button, not allowing a another initial painting

With the if statement your cards will only ever be drawn on the first call to paintComponent(). After that, the method will only invoke super.paintComponent() which erases any content that had previously been drawn on the component.
Since you don't have a lot of control over when paintComponent() is invoked it might be best to avoid including any behaviour related to it in your application's logic as you've done with the if-statement.
Here's an arbitrary block of code. Try compiling this example and see how many times "Repainted" is printed.
import javax.swing.*;
import java.awt.*;
public class Test {
public static void main(String args[]) {
JFrame frame = new JFrame();
frame.add(new JPanel() {
public void paintComponent(Graphics g)
{
super.paintComponents(g);
System.out.println("Repainted");
}
});
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(200, 200);
frame.setVisible(true);
}
}

The straight-forward solution would be
if (initialDrawing) {
Card card;
for (int i = 0; i < deck.size(); i++) {
card = deck.get(i);
card.setY((int) (50 + 0.2 * i));
card.setX((int) (250 + 0.2 * i));
}
initialDrawing = false;
}
for (Card card : deck) {
card.paintCard(g);
}
This however suggests, that the initialisation should be done elsewhere, maybe in the constructor. In general painting code should do just painting and may be called several times.

Related

Why do the pixels appear to be offset in my JFrame? [duplicate]

I'm creating a simple Break Out style game. The main game extends JFrame and I'm adding a JPanel to the frame.
When I was using paint() to draw the game graphics the items sat within the window as expected (i.e by their x, y coordinates).
I've updated the code to use BufferStrategy as I was getting flickering. Since the, the graphics that are rendered are offset by 22px.
This means the Bricks are off the top of the screen!
The code is as follows:
package BreakOut;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
public class Game extends JPanel implements KeyListener{
GameStateManager gsm = new GameStateManager();
BufferStrategy strategy;
public Game() {
//add menu state to GameStateManager
gsm.add(new MenuState(gsm));
createFrame();
while(true)
{
gsm.update();
//repaint();
render();
try{
Thread.sleep(10);
}
catch(InterruptedException e)
{
}
}
}
public void createFrame()
{
JFrame frame = new JFrame("Mini Tennis");
frame.setLayout(new BorderLayout());
this.setPreferredSize(new Dimension(400,400));
frame.add(this);
frame.pack();
frame.setBackground(Color.BLACK);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
addKeyListener(this);
this.setFocusable(true);
frame.createBufferStrategy(2);
strategy = frame.getBufferStrategy();
frame.setVisible(true);
System.out.println(frame.getInsets());
}
public void render()
{
Graphics g = strategy.getDrawGraphics();
super.paint(g);
gsm.render(g);
g.dispose();
strategy.show();
}
public void keyPressed(KeyEvent k) {
switch(gsm.getState())
{
case MAIN_MENU:
if(k.getKeyCode()==KeyEvent.VK_ENTER)
{
//add the PlayState to the Stack and update enum value
gsm.add(new PlayState(gsm, this));
}
break;
case PLAYING:
if(k.getKeyCode()==KeyEvent.VK_P)
{
//add the PlayState to the Stack and update enum value
gsm.add(new PauseState(gsm));
}
break;
case PAUSE:
if(k.getKeyCode()==KeyEvent.VK_P)
{
gsm.pop();
}
break;
case GAME_OVER:
if(k.getKeyCode()==KeyEvent.VK_ENTER)
{
gsm.pop();
}
break;
}
//send input to GameStateManager
gsm.keyPressed(k.getKeyCode());
}
public void keyReleased(KeyEvent k) {
gsm.keyReleased(k.getKeyCode());
}
public void keyTyped(KeyEvent k) {
gsm.keyTyped(k.getKeyCode());
}
public static void main(String[] args) {
new Game();
}
}
When I output System.out.println(frame.getInsets()); I get
java.awt.Insets[top=22,left=0,bottom=0,right=0]
I'm obviously doing something wrong but can't figure out why adding BufferStrategy would create the JPanel to be offset by 22px
Any help would be appreciated :)
Frames have borders and decorations, which is included within the bounds of the frame (they don't get added to the outside), from the looks of things you're using MacOS and the 22pixels to the top is the window title.
Best solution is, don't use the frame as the render surface, instead, use the Game class. This will mean it will need to extend from java.awt.Canvas instead of javax.swing.JPanel and you will need to create the BufferStrategy from it
If you override the Canvas's getPreferredSize method, you can use pack on the frame it will pack the window around this, so the physical frame will be larger then the content, but the content will be the size you would prefer
You will also want to move you main/game loop to separate thread, as this is current in the risk of blocking the Event Dispatching Thread, which could cause you no end of issues (like never getting a key event)

Unable to create a button on top of a rectangle

Here is a piece of code :
import java.awt.Color;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class QuitButton extends JPanel implements ActionListener
{
static JButton button = new JButton("Panic");
Color[] colors = new Color[9];
boolean pressed = false;
public QuitButton()
{
button.addActionListener(this);
colors[0] = Color.RED;
colors[1] = Color.BLUE;
colors[2] = Color.GREEN;
colors[3] = Color.YELLOW;
colors[4] = Color.BLACK;
colors[5] = Color.PINK;
colors[6] = Color.MAGENTA;
colors[7] = Color.ORANGE;
colors[8] = Color.CYAN;
}
#Override
public void actionPerformed(ActionEvent e)
{
pressed = true;
}
public static void main(String args[])
{
JFrame frame = new JFrame("Do NOT Panic!!");
QuitButton qb = new QuitButton();
frame.add(qb);
frame.add(button);
frame.setLayout(new FlowLayout());
frame.setSize(400, 400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
//frame.pack();
button.requestFocus();
qb.gameLoop();
}
public void gameLoop()
{
while (true)
{
repaint();
try
{
Thread.sleep(200);
} catch (Exception e)
{
}
}
}
public void paint(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
if (pressed == false)
{
super.paint(g2d);
g2d.setColor(Color.GRAY);
g2d.fillRect(0, 0, 400, 400);
} else
{
super.paint(g2d);
Random r = new Random();
int min = 0;
int max = 8;
int index = r.nextInt(max - min) + min;
g2d.setColor(colors[index]);
g2d.fillRect(0, 0, 400, 400);
}
}
The purpose of this program: The rectangle should be grey before but when I click the panic button colours should start changing.
Please don't get confused with the name of the class which is QuitButton.
But my rectangle is not occupying the entire window. Instead I am getting a teeny tiny rectangle like this : http://g.recordit.co/xJAMiQu6fM.gif
I think it is because of the layout I am using and I haven't specified anywhere that the button will be on top. Probably that's why they are coming side by side. I am new to GUI creation and thank you for your help.
You seem to be making some guesses on how to do this, which is not a good way to learn to use a library. Your first step should be to check the relevant tutorials on this, most of which will be found here: Swing Info Since this appears to be homework, I'm not going to give you a code solution but rather suggestions on how to improve:
Override paintComponent, not paint since the latter gives double buffering and is less risky (less painting of borders and child component problems)
In your paintComponent override, be sure to call the super's paintComponent method first to clear "dirty" pixels.
Use a Swing Timer, not a while loop for your game loop. This will prevent your while loop from freezing the Swing event thread, a problem that can freeze your program. Google the tutorial as it is quite helpful.
Do your randomization within the ActionListener's code (here likely the ActionListener for your Swing Timer), not within the painting code. The painting code should not change the state of the object but rather should only display the object's state.
FlowLayout will respect a component's preferredSize, and your component's preferred size is 0,0 or close to it. Change this. Best to override public Dimension getPreferredSize() and return a Dimension that matches your Rectangle's size.
Avoid using "magic" numbers, such as for your rectangle's size, and instead use constants or fields.
Call repaint() within your Timer's ActionListener so the JVM knows to paint the component.

Why JFrame fails to display when thread is invoked?

(I've seen the other 2 questions that are similar to mine in title, but they are different and do not provide a solution to my problem.)
Hi,
I have the below code of simple display of lines. I'm declaring a JFrame in the main, then calling on a new instance of the DrawGraph1 class, passing the JFrame as argument.
In the constructor, I'm invoking a thread (EventQueue.invokeLater). The constructor use the JFrame and use it to create some lines and string and whatever)
(Sorry about improper indentation, it has been tweaked a lot)
package test;
import java.awt.*;
import java.awt.geom.*;
import java.text.DateFormatSymbols;
import javax.swing.*;
public class test {
public static void main(String[] args){
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 700);
frame.setVisible(true);
DrawGraph1 obj = new DrawGraph1(frame);
}
}
class DrawGraph1{
DrawGraph1(final JFrame frame){
EventQueue.invokeLater(new Runnable(){
#Override
public void run(){
frame.setTitle("LineDrawing");
frame.add(new JComponent()
{
#Override
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
Line2D line = new Line2D.Double();
int decrement = 0, label = 0;
g2.setColor(Color.red);
g.drawString("Red Line ->> High temperatures", 330, 110);
g2.setColor(Color.green);
g.drawString("Green Line ->> Low temperatures", 330, 130);
} });}});}}
So According to my testing, the program reaches the constructor, passes the frame, and starts the thread, but apparently it stops at the line
frame.add(new JComponent()
With the NetBeans debugger underlining (or something) the add method. I also tried in which I invoke the thread at the main, pass the JFrame to the constructor, jump to it and it also stops at the same statement.
The display is simply the Frame itself with whatever settings prior to the add statement (i.e. in the main settings such as size).
I'm pretty sure it is very silly problem since it worked yesterday, not sure what I changed, but I just gave up.
I just changed the order of these two lines.
frame.setVisible(true);
DrawGraph1 obj = new DrawGraph1(frame);
to
DrawGraph1 obj = new DrawGraph1(frame);
frame.setVisible(true);
and the output:
Primarily, you passed the JFrame to the JPanel. You should create the JPanel, and pass it to the JFrame.
Here are the major changes I made.
All of the Swing GUI creation has to be on the Event Dispatch Thread. This includes the JFrame and the JPanel. I added a Runnable to the main method, and called the EventQueue invokeLater method to start the Swing GUI on the Event Dispatch Thread.
I moved all the JFrame code in the main method, and all of the JPanel drawing code in the DrawGraph1 class paintComponent method. The paintComponent method is for painting only. Do your other processing in other classes and / or other methods.
The JFrame methods have to be called in a specific order. Call the JFrame methods in the same order that I called them in your code.
I added a call to super.paintComponent to your paintComponent method. This maintains the Swing paint chain and clears the drawing panel.
I moved the sizing of the GUI from the JFrame to the JPanel. You're concerned with the size of the drawing panel, not the entire GUI.
Here's the revised code. I renamed the class so that it wouldn't conflict with other code in my testing package. You should change it back.
package com.ggl.testing;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class SimpleJPanelTest {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
#Override
public void run() {
final JFrame frame = new JFrame("Line Drawing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new DrawGraph1());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
};
EventQueue.invokeLater(runnable);
}
}
class DrawGraph1 extends JPanel {
private static final long serialVersionUID = 6733473371292195071L;
public DrawGraph1() {
setPreferredSize(new Dimension(800, 700));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
Line2D line = new Line2D.Double();
int decrement = 0, label = 0;
g2.setColor(Color.red);
g.drawString("Red Line ->> High temperatures", 330, 110);
g2.setColor(Color.green);
g.drawString("Green Line ->> Low temperatures", 330, 130);
}
}

Text Field Deforming on Repaint

I have a pretty simple JFrame (it consists only of one text field and a lot of stuff I paint), though whenever repaint() is called the text field changes. I'm pretty sure it's repaint(), as it happens even when I drag the frame from one monitor to the next as well as whenever I call it in the code.
It starts off fine when I run the program:
However, whenever repaint() is called, this happens:
If I start typing in the field, the rest immediately pops back up and works fine. Ultimately, my end goal is to reset a large portion of my frame to what is painted in paintComponent() while still having the text field visible.
I'm relatively new to Graphics and painting, any help is greatly appreciated!
EDIT
In creating the SSCCE, I discovered the problem with the text field was being caused by the Graphics2D method rotate that was in my paintComponent method. I don't know why it's happening, but I can work around it and consider that problem solved.
Now, I'm having a new problem: my paintComponent method is being called one too many times. Below is a SSCCE of this problem, the order I want things to happen is:
Call to paintComponent()
(when button is pressed) Call to repaint()
(when button is pressed, but after repaint) Call to paintStuff()
That all happens, however afterwards paintComponent is somehow being called, erasing everything painted by paintStuff().
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class tester extends JFrame {
private JPanel contentPane;
private JButton button;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
tester frame = new tester();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public tester() {
setBounds(100, 100, 450, 300);
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
contentPane = new JPanel(){
public void paintComponent(Graphics g1) {
System.out.println("draw rectangle - should be first");
super.paintComponent(g1);
g1.drawRect(50,50,50,50);
}
};
contentPane.setLayout(null);
setContentPane(contentPane);
button = new JButton("Click me!");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println("repaint - should be second");
repaint();
paintStuff(contentPane.getGraphics());
}
});
button.setBounds(10, 11, 95, 20);
contentPane.add(button);
}
public void paintStuff(Graphics g){
System.out.println("draw circle - should be last");
g.drawOval(100,100,10,10);
}
}
paintStuff(contentPane.getGraphics());
No, don't use the getGraphics() method to do painting. To repaint the component you simply use:
contentPane.repaint();
and then you move the drawOval(...) statement to the paintComponent() method.
If you want to draw the oval conditionally then you need to create a Boolean property for your custom painting. Then the code would look something like:
super.paintComponent(g1);
g1.drawRect(50,50,50,50);
if (drawOval)
g1.drawOval(100,100,10,10);
Then in your class you would create a method like:
public void setDrawOval(Boolean drawOval)
{
this.drawOval = drawOval;
repaint();
}
So in the ActionListener you simply use:
contentPane.setDrawOval(true);

Java: Using graphics component within an ActionListener

I have two separate class and driver files, and in the class file I create the paint method:
public void paint(Graphics g){
g.drawLine(......
....
//along with all of my other draw commands
}
Further down in the code, I create a JButton and within this button's action listener I don't know how to use a Graphics object to create more graphics in the JFrame. Should I be adding something to my driver to make this happen, or is there a way to use these graphics within my action listener? Thank you, and any help is appreciated.
You need to draw everything within the paint method. The actionPerformed should only change the state of something already in the paint method, and then call repaint. For example
boolean drawHello = true;
boolean drawWorld = false;
protected void paintComponent(Graphics g) {
super.paintCompoent(g);
if (drawHello)
g.drawString("Hello", 50, 50);
if (drawWorld)
g.drawString("World", 10, 10);
}
Then in your actionPerformed, you can change the state of drawWorld to true and call repaint().
public void actionPerformed(ActionEvent e) {
drawWorld = true;
repaint();
}
So as you can see, everything should be drawn in the paintComponent method. You can just hide and paint renderings, and make them "visible" from a action command. You should already have predefined what could posibly be drawn. Then just change the state of it rendering
And as #MadPrgrammer pointed out, you should not be painting on top-level containers like JFrame. Instead paint on a custom JPanel or JComponent and override the paintComponent method, instead of JFrame and paint
Here's an example where I draw a new square every time the button is pressed. If look at the code, you will see that in the paintComponent method, I loop through a list of Squares and draw them, and in the actionPerformed all I do is add a new Square to the List and call repaint()
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class AddSquares {
private int R = 0;
private int G = 0;
private int B = 0;
private int xLoc = 0;
private int yLoc = 0;
List<Square> squares = new ArrayList<>();
private JButton addSquare = new JButton("Add Square");
private RectsPanel panel = new RectsPanel();
public AddSquares() {
addSquare.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
Color color = new Color(R, G, B);
squares.add(new Square(xLoc, yLoc, color));
panel.repaint();
R += 10;
G += 20;
B += 30;
xLoc += 20;
yLoc += 20;
}
});
JFrame frame = new JFrame("Draw Squares");
frame.add(panel, BorderLayout.CENTER);
frame.add(addSquare, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
private class RectsPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Square square : squares) {
square.drawSquare(g);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(250, 250);
}
}
private class Square {
int x = 0;
int y = 0;
Color color;
public Square(int x, int y, Color color) {
this.x = x;
this.y = y;
this.color = color;
}
public void drawSquare(Graphics g) {
g.setColor(color);
g.fillRect(x, y, 75 ,75);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
AddSquares addSquares = new AddSquares();
}
});
}
}
It's difficult to be 100%, but it would seem as you don't understand how custom painting is performed in Swing.
Start by taking a look at Performing Custom Painting and Painting in AWT and Swing.
Essentially, painting is arranged by the Repaint Manager, which decides what and when something should be painted. It then calls (through a chain of methods) the paint method of the components it thinks need to be updated, passing it a reference to a Graphics context that should be used to actually paint on.
Basically, when ever your paint method is called, you should create paint the current state of your painting.
You should avoid overriding paint and instead use paintComponent from classes the extend JComponent
Your question is a little on the vague side as to what you are actually wondering about but generally speaking:
We don't override paint in Swing, we override paintComponent.
If you are already aware of this, you may be overriding paint because you are doing it on a JFrame and you found that JFrame does not have a paintComponent method. You shouldn't override paint on a JFrame. Instead, create a JPanel or something to put inside the frame and override paintComponent on the panel.
Question about the ActionListener.
It sounds like you are wanting to do painting outside of paintComponent in which case probably the best way is to do painting to a separate Image. Then you paint the Image on to the panel in paintComponent. You can also put an Image in a JLabel as an ImageIcon. Here is a very simple drawing program using MouseListener that demonstrates this (taken from here):
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
class PaintAnyTime {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new PaintAnyTime();
}
});
}
final BufferedImage image = (
new BufferedImage(500, 500, BufferedImage.TYPE_INT_ARGB)
);
final JFrame frame = new JFrame();
final JLabel label = new JLabel(new ImageIcon(image));
final MouseAdapter drawer = new MouseAdapter() {
Graphics2D g2D;
#Override
public void mousePressed(MouseEvent me) {
g2D = image.createGraphics();
g2D.setColor(Color.BLACK);
}
#Override
public void mouseDragged(MouseEvent me) {
g2D.fillRect(me.getX(), me.getY(), 3, 3);
label.repaint();
}
#Override
public void mouseReleased(MouseEvent me) {
g2D.dispose();
g2D = null;
}
};
PaintAnyTime() {
label.setPreferredSize(
new Dimension(image.getWidth(), image.getHeight())
);
label.addMouseListener(drawer);
label.addMouseMotionListener(drawer);
frame.add(label);
frame.pack();
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
#MadProgrammer has already linked to the articles that I was going to link to.

Categories