Java – jtextfields: thread problem in activity drawing on JPanel

Has anyone tried to use swing to build an appropriate multi buffer rendering environment on which swing user interface elements can be added?

In this case, I have an animated red rectangle drawn on the background The background doesn't need to be updated every frame, so I render it to bufferedimage and redraw only the part needed to clear the previous position of the rectangle See the complete code below, which extends the example given in @ trashgod in the previous thread here

So far, it's very good; Smooth animation, low CPU usage, no flicker

Then I add a jtextfield to the JPanel (by clicking anywhere on the screen) and by clicking the focus in the text box Clearing the previous position of the rectangle now fails when each cursor flashes, as shown in the figure below

If anyone knows why this happens, I'm curious (swing is not thread safe, images are drawn asynchronously) and where to look for possible solutions

This is in Mac OS 10.5, Java 1.6

JPanel redraw fail http://www.arttech.nl/javaredrawerror.png

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;

public class NewTest extends JPanel implements 
    MouseListener,ActionListener,ComponentListener,Runnable 
{

JFrame f;
Insets insets;
private Timer t = new Timer(20,this);
BufferedImage buffer1;
boolean repaintBuffer1 = true;
int initWidth = 640;
int initHeight = 480;
Rectangle rect;

public static void main(String[] args) {
    EventQueue.invokelater(new Newtest());
}

@Override
public void run() {
    f = new JFrame("NewTest");
    f.addComponentListener(this);
    f.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE);
    f.add(this);
    f.pack();
    f.setLocationRelativeTo(null);
    f.setVisible(true);
    createBuffers();
    insets = f.getInsets();
    t.start();
}

public Newtest() {
    super(true);
    this.setPreferredSize(new Dimension(initWidth,initHeight));
    this.setLayout(null);
    this.addMouseListener(this);
}

void createBuffers() {
    int width = this.getWidth();
    int height = this.getHeight();

    GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    GraphicsDevice gs = ge.getDefaultScreenDevice();
    GraphicsConfiguration gc = gs.getDefaultConfiguration();

    buffer1 = gc.createCompatibleImage(width,height,Transparency.OPAQUE);        

    repaintBuffer1 = true;
}

@Override
protected void paintComponent(Graphics g) {
    int width = this.getWidth();
    int height = this.getHeight();

    if (repaintBuffer1) {
        Graphics g1 = buffer1.getGraphics();
        g1.clearRect(0,width,height);
        g1.setColor(Color.green);
        g1.drawRect(0,width - 1,height - 1);
        g.drawImage(buffer1,null);
        repaintBuffer1 = false;
    }

    double time = 2* Math.PI * (System.currentTimeMillis() % 5000) / 5000.;
    g.setColor(Color.RED);
    if (rect != null) {
        g.drawImage(buffer1,rect.x,rect.y,rect.x + rect.width,rect.y + rect.height,this);
    }
    rect = new Rectangle((int)(Math.sin(time) * width/3 + width/2 - 20),(int)(Math.cos(time) * height/3 + height/2) - 20,40,40);
    g.fillRect(rect.x,rect.width,rect.height);
}

@Override
public void actionPerformed(ActionEvent e) {
    this.repaint();
}

@Override
public void componentHidden(ComponentEvent arg0) {
    // TODO Auto-generated method stub

}

@Override
public void componentMoved(ComponentEvent arg0) {
    // TODO Auto-generated method stub

}

@Override
public void componentResized(ComponentEvent e) {
    int width = e.getComponent().getWidth() - (insets.left + insets.right);
    int height = e.getComponent().getHeight() - (insets.top + insets.bottom);
    this.setSize(width,height);
    createBuffers();
}

@Override
public void componentShown(ComponentEvent arg0) {
    // TODO Auto-generated method stub

}

@Override
public void mouseClicked(MouseEvent e) {
    JTextField field = new JTextField("test");
    field.setBounds(new Rectangle(e.getX(),e.getY(),100,20));
    this.add(field);
    repaintBuffer1 = true;
}

@Override
public void mouseEntered(MouseEvent arg0) {
    // TODO Auto-generated method stub

}

@Override
public void mouseExited(MouseEvent arg0) {
    // TODO Auto-generated method stub

}

@Override
public void mousePressed(MouseEvent arg0) {
    // TODO Auto-generated method stub

}

@Override
public void mouseReleased(MouseEvent arg0) {
    // TODO Auto-generated method stub

}
}

Solution

Newtest extends JPanel; However, because each pixel will not be drawn every time paintcomponent() is called, you need to call the superclass method and erase the old graphics:

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    int width = this.getWidth();
    int height = this.getHeight();
    g.setColor(Color.black);
    g.fillRect(0,height);
    ...
}

Appendix: as you said, setting the background color in the constructor eliminates the need to fill the panel in paintcomponent(), and super Paintcomponent() allows text fields to function properly As you can see, the proposed solution is fragile Instead, simplify the code and optimize it For example, you may not need complex plug - ins, additional buffers, and component listeners

Appendix 2: Please note that super Paintcomponent() calls the update() method of the UI delegate, "it will fill the specified component with its background color (if its opaque attribute is true)" You can use setopaque (false) to exclude this

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.Transparency;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.Timer;

/** @see https://stackoverflow.com/questions/3256941 */
public class AnimationTest extends JPanel implements ActionListener {

    private static final int WIDE = 640;
    private static final int HIGH = 480;
    private static final int RADIUS = 25;
    private static final int FRAMES = 24;
    private final Timer timer = new Timer(20,this);
    private final Rectangle rect = new Rectangle();
    private BufferedImage background;
    private int index;
    private long totalTime;
    private long averageTime;
    private int frameCount;

    public static void main(String[] args) {
        EventQueue.invokelater(new Runnable() {

            @Override
            public void run() {
                new Animationtest().create();
            }
        });
    }

    private void create() {
        JFrame f = new JFrame("AnimationTest");
        f.setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE);
        f.add(this);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
        timer.start();
    }

    public Animationtest() {
        super(true);
        this.setOpaque(false);
        this.setPreferredSize(new Dimension(WIDE,HIGH));
        this.addMouseListener(new MouseHandler());
        this.addComponentListener(new ComponentHandler());
    }

    @Override
    protected void paintComponent(Graphics g) {
        long start = System.nanoTime();
        super.paintComponent(g);
        int w = this.getWidth();
        int h = this.getHeight();
        g.drawImage(background,this);
        double theta = 2 * Math.PI * index++ / 64;
        g.setColor(Color.blue);
        rect.setRect(
            (int) (Math.sin(theta) * w / 3 + w / 2 - RADIUS),(int) (Math.cos(theta) * h / 3 + h / 2 - RADIUS),2 * RADIUS,2 * RADIUS);
        g.fillOval(rect.x,rect.height);
        g.setColor(Color.white);
        if (frameCount == FRAMES) {
            averageTime = totalTime / FRAMES;
            totalTime = 0; frameCount = 0;
        } else {
            totalTime += System.nanoTime() - start;
            frameCount++;
        }
        String s = String.format("%1$5.3f",averageTime / 1000000d);
        g.drawString(s,5,16);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        this.repaint();
    }

    private class MouseHandler extends MouseAdapter {

        @Override
        public void mousePressed(MouseEvent e) {
            super.mousePressed(e);
            JTextField field = new JTextField("test");
            Dimension d = field.getPreferredSize();
            field.setBounds(e.getX(),d.width,d.height);
            add(field);
        }
    }

    private class ComponentHandler extends ComponentAdapter {

        private final GraphicsEnvironment ge =
            GraphicsEnvironment.getLocalGraphicsEnvironment();
        private final GraphicsConfiguration gc =
            ge.getDefaultScreenDevice().getDefaultConfiguration();
        private final Random r = new Random();

        @Override
        public void componentResized(ComponentEvent e) {
            super.componentResized(e);
            int w = getWidth();
            int h = getHeight();
            background = gc.createCompatibleImage(w,h,Transparency.OPAQUE);
            Graphics2D g = background.createGraphics();
            g.clearRect(0,w,h);
            g.setColor(Color.green.darker());
            for (int i = 0; i < 128; i++) {
                g.drawLine(w / 2,h / 2,r.nextInt(w),r.nextInt(h));
            }
            g.dispose();
            System.out.println("Resized to " + w + " x " + h);
        }
    }
}
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>