简体   繁体   中英

Is there a way to repaint graphics after using super.paint(g)?

so I have a question, lets say I create a rectangle in Java using the paint method, after a 100 ms delay I do super.paint(g), this clears the rectangle previously shown, is there a way to make it re appear?

Thanks!

An example of what I'm talking about is down below, what this program is meant to do is whenever I hold down mouse button 1, it creates a rectangle that goes down and than disapears after mouse button 1 is off. The problem is whenever I hold down mouse button 1 again, the rectangle doesn't appear.

First class:

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;

import javax.swing.JFrame;
import javax.swing.Timer;

public class RecoilHelper extends JFrame {


static Timer rs;
static int recoil = 540;
static boolean clearRectangle = false;

/**
 * Launch the application.
 */
public static void main(String[] args) {
    JNativehookRecoilHelp.main(null);
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                RecoilHelper frame = new RecoilHelper();
                frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

/**
 * Create the application.
 */
public RecoilHelper() {
    initialize();
}

/**
 * Initialize the contents of the frame.
 */
private void initialize() {
    
    setBounds(0, 0, 1920, 1080);
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setUndecorated(true);
    setBackground(new Color(1.0f,1.0f,1.0f,0.0f));
    setAlwaysOnTop(true);
    
    rs = new Timer(10,(ActionEvent e)->{
        repaint();
        
        recoil += 12;
    
    
        if (recoil>600) {
            
            rs.stop();
        }
        
    });

    
}

public void paint(Graphics g) { 
     
    Rectangle r = new Rectangle(960, recoil, 4, 4);
    System.out.println(recoil);
    super.paintComponents(g);
    g.fillRect(
       (int)r.getX(),
       (int)r.getY(),
       (int)r.getWidth(),
       (int)r.getHeight()
    );  
    if (clearRectangle) {
        super.paint(g);
    } 
    
}

}

Second class(tracks mouse button 1 events using JNativehook):

import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;

import org.jnativehook.GlobalScreen;
import org.jnativehook.NativeHookException;
import org.jnativehook.mouse.NativeMouseEvent;
import org.jnativehook.mouse.NativeMouseInputListener;

public class JNativehookRecoilHelp implements NativeMouseInputListener {

@Override
public void nativeMouseClicked(NativeMouseEvent arg0) {
    // TODO Auto-generated method stub

}

@Override
public void nativeMousePressed(NativeMouseEvent arg0) {
    // TODO Auto-generated method stub
    System.out.println("Pressed");
    RecoilHelper.recoil = 540;
    RecoilHelper.rs.start();

}

@Override
public void nativeMouseReleased(NativeMouseEvent arg0) {
    // TODO Auto-generated method stub
    System.out.println("Released");
    RecoilHelper.clearRectangle=true;
    
}

@Override
public void nativeMouseDragged(NativeMouseEvent arg0) {
    // TODO Auto-generated method stub
    
}

@Override
public void nativeMouseMoved(NativeMouseEvent arg0) {
    // TODO Auto-generated method stub
    
}
public static void main(String[] args) {
    GlobalScreen.addNativeMouseListener(new JNativehookRecoilHelp());
    LogManager.getLogManager().reset();

    // Get the logger for "org.jnativehook" and set the level to off.
    Logger logger = Logger.getLogger(GlobalScreen.class.getPackage().getName());
    logger.setLevel(Level.OFF);

    try {
        GlobalScreen.registerNativeHook();
    }
    catch (NativeHookException ex) {
        


        System.exit(1);
    }
}

}

Currently you are attempting to override the paint method of the JFrame, this presents two issues, this first is that a JFrame is a heavyweight component (it has a title bar and a number of associated things that you need to consider) so you may have endless issues, the second issue is that you need to override the paintComponent method of the component that you wish to perform custom painting on.

The solution here is to instead place a JPanel inside the JFrame, and override the paintComponent method of the JPanel.

Below is a working example that creates a new rectangle and adds it to the frame every half second but also keeps the existing rectangles by adding them to a list and drawing each one in the list every time it is repainted.

The main class is simple, and simply adds our CustomJpanel to the JFrame:

public class PaintExample extends JFrame
{
    private CustomJPanel customJpanel;
    
    public PaintExample()
    {
        //Create and add the custom panel to the JFrame
        setPreferredSize(new Dimension(400, 300));
        customJpanel = new CustomJPanel();
        getContentPane().add(customJpanel, java.awt.BorderLayout.CENTER);
        pack();
    }
    
    public static void main(String args[])
    {
        //Show the JFrame:
        java.awt.EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                new PaintExample().setVisible(true);
            }
        });
    }
}

And the custom panel class that does our painting:

public class CustomJPanel extends JPanel
{
    int x = 0;
    int y = 0;
    boolean clearRectangle = true;
    //This is a list that we use to keep track of all the rectangles to draw/update
    ArrayList<Rectangle> rectangleList = new ArrayList<>();
    
    //Start a timer when the panel is created that will update the rectangle location every half second (500ms).
    //In your case you would use your recoil timer instead
    public CustomJPanel(){
        //Create event action
        ActionListener taskPerformer = new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                add a new rectangle in a different location
                x+= 5;
                y+= 5;
                rectangleList.add(new Rectangle(x,y,10,10));
                //Update the panel
                repaint();
            }
        };
        //Create and start a repeating event
        Timer timer = new Timer(500, taskPerformer);
        timer.setRepeats(true);
        timer.start();
    }
    
    //Here is where it all happens:
    @Override
    protected void paintComponent(Graphics g)
    {
        //Call super first to perform normal component painting
        super.paintComponent(g);
        //Now do your custom painting
        if (clearRectangle)
        {
            //Draw each rectangle in the list
            for (Iterator<Rectangle> iterator = rectangleList.iterator(); iterator.hasNext();)
            {
                Rectangle r = iterator.next();
                g.drawRect(r.x, r.y, r.width, r.height);
            }
        }
    }
}

And the window looks like this after a couple so seconds, note how it keeps all previous rectangles: 示例输出

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM