Override paint(graphics g) Java - java

I have a little issue with my GUI in NetBeans. I draw images (dots) when a user clics in a JPanel at the mouse clic location. This part works just fine. I store each image locations in two different ArrayList that contains the X location and Y location. Now what I want to do is to delete the latest image drawn in the Panel after a button is clicked. So what I did is remove the last index of both ArrayList, and then call repaint() to draw all the images from the locations in both X and Y ArrayList (code below).
What is weird is that I need to resize the GUI (put it in full screen or just change its' size) in order for the drawn images to show up again in the JPanel otherwise, the panel remains empty.
Here's the parts of code that are affected :
public void paint(Graphics g) {
super.paint(g);
for(int i=0;i<=listePointsX.size()-1;i++) {
try{
BufferedImage icon = ImageIO.read(getClass().getResourceAsStream("/myimage.png"));
Graphics graphe = jPanel1.getGraphics();
graphe.setColor(Color.BLACK);
graphe.drawImage(icon, this.listePointsX.get(i),this.listePointsY.get(i), rootPane);
}catch(Exception e1){
}
}
private void jButtonUndoActionPerformed(java.awt.event.ActionEvent evt) {
if(listePointsX.size()>0){
int lastObject= listePointsX.size();
listePointsX.remove(lastObject-1);
listePointsY.remove(lastObject-1);
jPanel1.repaint();
}
else{
}
}
Any idea what I need to do to some kind of "refresh" the whole thing? Am I doing something wrong? Tried searching about that but did not find anyting...

Graphics graphe = jPanel1.getGraphics(); is NOT how painting should work, instead, you should have overriden the panel's paintComponent method and painted the points within in.
See Painting in AWT and Swing and Performing Custom Painting for more details about how painting works in Swing
Instead, your panel should be doing ALL the work, managing the points in the ArrayList and painting them. You parent component "might" have the ability to add or remove points if that meets your design requirements, but the core responsibility remains with the panel.
Avoid performing any long running or block operations within the paint methods, they should run as fast as possible. Since the image never changes, you should simply load once (either when the class is constructed or when you first need the image) and keep using the same reference.

Alright it worked just fine now. I had to do it the way you told me up here. I created a new class that extends jPanel (below). Then in my main Form, had to create an object of this class. Whenever a user makes a click, it will call this Drawing class object and add an item to the ArrayList (this object manages everything regarding created points... It looks like this :
public class MyDrawingClass extends JPanel {
ArrayList<Integer> arrayListPointX = new ArrayList<>();
ArrayList<Integer> arrayListPointY = new ArrayList<>();
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
try{
BufferedImage icon = ImageIO.read(getClass().getResourceAsStream("/images/dot.png"));
g.setColor(Color.BLACK);
if(arrayListPointX.size()<=0){
...
}
else{
for(int i=0;i<listePointsX.size();i++){
g.setColor(Color.BLACK);
g.drawImage(icon, listePointsX.get(i), listePointsY.get(i), rootPane);
}
}
}catch(Exception e){
...
}
}
So if I want to "undo", let's say my object of "MyDrawingClass" is called "draw". I can do : draw.arrayListPointX.remove(draw.arrayListPointX.size()-1); and call repaint(); to display remaining points.
Thanks for your tips appreciate it ! :)

Related

Cant draw a shape to a specific panel in a NetBeans GUI

I'm trying to make a simple application to draw shapes to a panel in a jFrame. The GUI is a NetBeans generated jFrame. The application has three panels. the first two hold button groups to select the shape and a color. There's a button to draw the shape to the third panel once the selections are made.
What the GUI looks like
Unfortunately I'm having no love and can't make it work. For now I just want to get the button to draw a shape then I'll add the button functionality. Here's the code I have so far.
private void btnDrawShapeActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
Draw shape = new Draw();
pnlDrawPad.add(shape); //pnlDrawPad is the name of the jPanel
shape.drawing();
}
import javax.swing.*;
import java.awt.*;
public class Draw extends JPanel{
public Draw(){
super();
}
public void drawing(){
repaint();
}
//#Override <-- gives error "method does not override or implement a method from a supertype"
public void paintCompnent(Graphics g){
super.paintComponent(g);
g.setColor(Color.RED);
g.drawString("Hello World!",40,30);
}
}
When I click the "Draw Shape" button nothing happens. I've been searching for a couple days now and am not finding the answer. Actually, its making me more confused as to what to do.
How to deal with this?
Don't keep creating new panels for each shape.
Instead you need a single panel with an ArrayList of objects you want to paint. Then you customize the paintComponent(...) method of the panel to iterate through all the objects in the panel and paint them.
So you button will just add another object to the ArrayList and then invoke repaint() on the panel.
Check out Custom Painting Approaches. The DrawOnComponent example shows how to paint a Rectangle objects from an ArrayList to get you started.
I found that with NetBeans you don't need to Override the paintComponents() method. Since all the GUI stuff is done when you design it, you merely need to add the drawings to the panel or what ever you need to do. I found you that by declaring and instantiating a 2D graphics object then drawing it to the place you want.
private void btnDrawShapeActionPerformed(java.awt.event.ActionEvent evt) {
int centerX;
int centerY;
Graphics2D drawFx = (Graphics2D)pnlDrawPad.getGraphics();
drawFx.setColor(Color.ORANGE);
centerX = (int)(458*Math.random());
centerY = (int)(440*Math.random());
drawFx.fillOval(centerX-50, centerY-50, 100, 100);
drawFx.dispose();
}
Worked like a charm so now every time I push the draw shape button it draws a shape to the panel in a different location every time. I've since put in the radio button functionality to change shape color and fill and added a button to clear the screen.
Not sure if this is the ideal way to do it but for this stupid simple little program it works well enough and I'm done stressing over it.

Java - Add new image to Jframe using JComponent on click

I created a Jframe using netbeans drag-n-drop designer. After asking here , I can make the color changing works after changing the color of some item from recList and paint(g) on a new thread of my Draw class.
Now I want to add another JComponent like DrawCar that will add the car image to the Jframe. I want this new JComponent because I don't want to re-render the "car" if the squares in the background change color.
So I created the DrawCar with paint() method like below:
public void paint(Graphics g) {
//This to make the (0,0) at the bottom-left not top-left as default.
Graphics2D g2 = (Graphics2D)g;
AffineTransform at = g2.getTransform();
at.translate(0, getHeight());
at.scale(1, -1);
g2.setTransform(at);
//Below is to draw the car
try {
image = ImageIO.read(new File("car.png"));
} catch (IOException ex) {
Logger.getLogger(Car.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
g.drawImage(image, 245, 0, null);
}
If I put these code to render the car in the paint() method of Draw class, it works, so no problem with this code!
In the Container (the class with the GUI) class, I have a button handler. I want the car appear when I click that button, so I tried to add to the event handler with
private void starter_btnActionPerformed(java.awt.event.ActionEvent evt) {
Thread reDraw = new Thread(new Runnable() {
#Override
public void run() {
//draw1 below is the instance of "Draw" class
//draw1.paint2(draw1.getGraphics()); //This code works with repainting the square with new color as mentioned before
DrawCar draw2 = new DrawCar();
repaint();
revalidate();
}
});
reDraw.start();
}
but it won't work, I don't know what I missed here. Maybe some ways to add the DrawCar to the current JFrame?
Thank you for your time!
EDIT:
I just make a simple project to make it clear. I created a JFrame named Test and drop in it a button that will show the picture when I click on it. It's all auto-generated codes.
Now I create a new class call MyClass
public class MyClass extends JComponent{
private BufferedImage image;
MyClass(){
try {
image = ImageIO.read(new File("D://pic.jpg"));
} catch (IOException ex) {
Logger.getLogger(this.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(image, 50, 50, null);
}
}
And in the Test, the event handler of the button is like this:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
// TODO add your handling code here:
MyClass mc = new MyClass();
add(mc);
repaint();
revalidate();
}
I clicked it and nothing happens. The picture is supposed to shows up on click. How do I make it happens? Thank you
EDIT 2:
This is the image of what I want to achieve, it's the little green car on the bottom, it should appears only when I click "Start!"
I see quite a few general problems with your code, including:
Never override the paint method, but rather a JPanel or JComponent's paintComponent method.
Almost always call the super's method.
Never read in a file from within a painting method.
Your code flagrantly violates Swing threading rules -- most all Swing calls should be made on the Swing event thread, not off of it as you're doing.
Better to create and post your Minimal, Complete, and Verifiable example or sscce as this way we can run your actually functioning code.
As for your specific problem, you're creating a DrawCar component instance, but you never appear to add it to your GUI, and so it will never show since it is never part of a top-level window such as a JFrame or JApplet or JDialog.
re comments:
Just though paint() and paintComponent() are the same, just one calls another...
No they're not. The paint(...) method is the more "primitive" of the two as it's based in the old AWT code base. It does not automatically do double buffering (unlike paintComponent) and is responsible for painting the component, the component's borders, and any child components held by the component. For the latter reason, you want to avoid overriding it since if you mess it up, you risk mispainting more than just the component.
Back to my problem, I make it like this DrawCar draw2 = new DrawCar(); add(draw2); draw2.setVisible(true); revalidate(); repaint(); I don't know if I missed the "prefix" before add, the code is auto-generated so I can't find any JFrame frame = new JFrame(); to make frame.add(draw2) like others do with their code Any chance that we will find some logical problem?
You've got major structural problems as your new DrawCar class again is nowhere to be seen in the main GUI.
So I'm guessing that your main GUI already has a DrawCar component held within it, and that you're goal is to get this to draw a car on button push (you never say!). If so, then why not have the DrawCar hold a JPanel and simply set its Icon with your image. Myself, I'd read the image in at program start up, and also flip it at at that time, if that were my goal.
Again, if you're still having problems, then isolate the problem down to the smallest compilable runnable code, your mcve and let us test it.

Drawn graphics flicker and then disappear when resizing window

The goal here is that I can click a color and shape, then two points on the figuresPanel. That colored shape is filled in on the figuresPanel, and I can add shapes on top of each other etc. I also need the current date to be displayed in the corner of the figuresPanel, on top of all the painted shapes. I am able to create shapes (though they always cover the date) no problem, but whenever I resize or minimize the window, all the painted shapes disappear. I've tried implementing quite a few different methods from Graphics (update, paint, redraw, etc.) and haven't found one that corrects this issue. I thought paintComponent() would take care of all that, but apparently not. Feel free to point out anything that could be implemented in a better way, always happy to learn something new.
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
drawFigures();
figuresPanel.add(dateLabel, c);
}
#Override
public Dimension getPreferredSize() {
return (new Dimension(800, 600));
}
private void addFigure(Figure figure) {
figureList.add(figure);
listArea.append(figure.toString() + "\n");
figure.fill(getGraphics());
}
private void drawFigures() {
for (Figure f : figureList) {
f.fill(getGraphics());
}
}
I would suggest a few things that might help you.
In your method drawFigures() instead of using getGraphics(), why don't you pass the instance of Graphics in paintComponentMethod as a parameter to the method and use it to draw the object. This will make sure that you are drawing on the same instance of the Graphics that you are using to paint.
In your method addFigure(Figure figure) I would suggest you remove the line figure.fill(getGraphics());, to draw the object completely. Instead in your mouseClicked(MouseEvent event) method after your switch statement insert:
revalidate();
repaint();
This should actually take care of the drawing of the objects are done exactly on the same Graphics object that is being used to display the components.
I hope that this shall be helpful.

How do i clear the panel after drawing Graphics objects on it?

I have a panel in which i draw a number of graphics objects on using the paintComponent method and the Graphics methods to draw.
I need to create a button, that you click and then it clears the panel.
example :
JButton clear = new JButton("Clear");
public void actionPerformed(ActionEvent e){
if(e.getSource()==clear){
//button code here
}
}
What i need is the code that goes inside that IF statement.
The paintComponent method will get called everytime a repaint is called and this method draw what you write in it everytime.If you want to clear a screen of object then you must remove the object(a button for example) from the panel/frame on the button click function.
It is not a good practice to write logic code in the paintComponent method with boolean etc.
Do something like this:
private boolean clear = false;
public void paintComponent(Graphics g) {
super.paintComponent(g);
if(clear)
return;
}
// all your graphics here
}
public void actionPerformed(ActionEvent e){
if(e.getSource()==clearButton){
clear = true;
repaint();
}
}
Don't forget to change back the clear flag, at some point of the program, when you want to allow drawing.
Check out Custom Painting Approaches for the two common ways of doing custom painting:
paint objects contained in a List, in which case you would clear the List
paint onto a BufferedImage, in which case you would clear the BufferedImage
The examples code shows how "Clear" would be done in both cases.

Painting new panel on top of another one

I have a program where the base panel is just drawing the background (trees, water, etc), and i have a player and other objects moving around the screen. I don't want to call repaint() on the whole thing because it slows me down because it repaints the whole thing. When I try to add a new panel on top that will be repainted a lot and handle moving objects, nothing happens in my code. This is what I have in the constructor for the first
public GamePanel()
{ //some code
top = TopPanel();
top.setSize(this.getSize());
add(top);
//some more code
}
and then in the class for the toppanel
public TopPanel()
{
}
public void paintComponent(Graphics g)
{
i.drawItem(//);
player.draw(//fields);
}
And no matter what I do, I can't get anything to show up on the panel when i run it.
My general approach when rendering a complex but static 'background' with other things painted on top is to draw the background to a BufferedImage and simply redraw the image before painting the dynamic parts.

Categories