Java JPanel上活动图形顶部的JTextFields,线程问题

有没有人试图使用Swing来构建适当的多缓冲渲染环境,并且可以在上面添加Swing用户界面元素?

在这种情况下,我在背景上绘制了一个动画红色矩形。不需要每帧更新背景,因此我将其渲染到BufferedImage上,然后仅重画清除矩形先前位置所需的部分。请参见下面的完整代码,这扩展了以前的线程通过@trashgod给出的例子,在这里。

到目前为止,一切都很好; 动画流畅,CPU使用率低,无闪烁。

然后,我将一个JTextField添加到Jpanel(通过单击屏幕上的任何位置),然后通过在文本框中单击以将其聚焦。现在,在每次光标闪烁时清除矩形的先前位置都会失败,请参见下图。

我很好奇是否有人知道为什么会发生这种情况(摆动不是线程安全的吗?图像被异步绘制吗?)以及朝哪个方向寻找可能的解决方案。

这是在Mac OS 10.5,Java 1.6上

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, 0, width, height);

g1.setColor(Color.green);

g1.drawRect(0, 0, width - 1, height - 1);

g.drawImage(buffer1, 0, 0, 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, 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.y, 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

}

}

回答:

NewTest延伸JPanel; 但由于你并未在对的每次调用中绘制每个像素paintComponent(),因此你需要调用超类的方法并清除旧的绘制:

@Override

protected void paintComponent(Graphics g) {

super.paintComponent(g);

int width = this.getWidth();

int height = this.getHeight();

g.setColor(Color.black);

g.fillRect(0, 0, width, height);

...

}

附录:如你所述,在构造函数中设置背景色无需在中填充面板paintComponent(),而super.paintComponent()允许文本字段正常运行。如你所见,建议的解决方法很脆弱。相反,请简化代码并按要求进行优化。例如,你可能不需要插入,复杂的缓冲区和组件侦听器的复杂性。

附录2:请注意,super.paintComponent()调用UI委托的update()方法,“该方法将用其背景颜色填充指定的组件(如果其opaque属性为true)”。你可以使用它setOpaque(false)来避免这种情况。

动画测试

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 http://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, 0, 0, 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.y, rect.width, 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(), e.getY(), 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, 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);

}

}

}

以上是 Java JPanel上活动图形顶部的JTextFields,线程问题 的全部内容, 来源链接: utcz.com/qa/413971.html

回到顶部