假设我的JPanel
名为内容,其paintComponent(g)
被覆盖。这个面板通常非常快速地绘制,但有时候(澄清:用户生成的图形对象可以有数千个点,这会减慢渲染速度。它需要是这个方式,这不是我的问题的一部分)由于其中的所有图形内容可能需要一秒钟重新绘制。
我想在鼠标位置附近绘制一个点,但我想快速更新,而不是每次移动鼠标时都不需要重新绘制内容。
我试图将它画在玻璃窗格上,如下所示:
class LabelGlassPane extends JComponent {
public LabelGlassPane(JApplet frame) {
this.frame = frame;
}
public JApplet frame;
public void paintComponent(Graphics g) {
if(ell != null){
g2.setColor(Vars.overDot);
g2.fill(ell); //this is an ellipse field that was created in the mouesmoved() listener
}
}
}
我的问题是,即使我现在只在移动鼠标时更新此玻璃窗格,但当我在其上调用repaint()
时,它会重新绘制applet中的所有其他组件。
如果不对下面的组件进行绘画,我如何在这个玻璃窗格上绘画(或者有另一种绘画方式)?
感谢。
编辑:这是一个简单的例子。移动鼠标时jp不应该更新,但它是。
public class Glasspanetest extends JApplet implements Runnable{
public void init() {
setLayout(new BorderLayout());
GraphicsPanel jp = new GraphicsPanel();
add(jp, BorderLayout.CENTER);
glass = new LabelGlassPane(this);
this.setGlassPane(glass);
glass.setVisible(true);
}
class GraphicsPanel extends JPanel{
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.red);
g.fillOval(50, 50, 50, 50);
System.err.println("Painting bottom panel");
}
}
public LabelGlassPane glass = null;
public Ellipse2D.Double ell = null;
class LabelGlassPane extends JComponent {
public LabelGlassPane(JApplet frame) {
this.frame = frame;
this.addMouseMotionListener(new MoveInfoListener());
}
public JApplet frame;
public void paintComponent(Graphics g) {
//g.setColor(Color.red);
//Container root = frame.getRootPane();
// g.setColor(new Color(255,100,100,100));
// g.fillRect(100, 100, 500, 500);
if(ell != null){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.black);
g2.fill(ell);
System.out.println("Painted glass pane");
}
//rPaint(root,g);
}
}
public class MoveInfoListener implements MouseMotionListener{
public void mouseMoved(MouseEvent e) {
ell = new Ellipse2D.Double(e.getX()-3, e.getY()-3, 6, 6);
glass.repaint();
}
public void mouseDragged(MouseEvent arg0) {}
}
public void run() {}
}
答案 0 :(得分:1)
问题在于,Swing无法知道它应该只重新绘制LabelGlassPane
的一小部分,可能只展示您GraphicsPanel
的一小部分内容。
这是因为您在组件中执行自定义绘制,尽管您只绘制了面板的一小块区域,但您也可以在整个面板上进行绘制。
现在,为什么每次重新绘制GraphicsPanel
时,LabelGlassPane
都会重新粉饰,这是因为LabelGlassPane
不是不透明的,这意味着,为了正确显示没有涂漆的区域,它需要在玻璃板下“涂抹”任何东西。
这两个方面的组合迫使Swing在每次调用重绘时都完全绘制两个面板。
但是有办法避免这种糟糕的组合。为此,您需要通过以下方式使您的绘画方法更加巧妙:
Graphics
的剪辑与您计划绘制的区域相交时才进行重绘。如果没有交叉点,那么您可以跳过绘制操作。小型演示代码显示:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Ellipse2D.Double;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Glasspanetest extends JFrame {
public JFrame init() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
GraphicsPanel jp = new GraphicsPanel();
add(jp, BorderLayout.CENTER);
LabelGlassPane glass = new LabelGlassPane();
this.setGlassPane(glass);
glass.setVisible(true);
setSize(400, 400);
return this;
}
class GraphicsPanel extends JPanel {
private Shape oval = new Ellipse2D.Double(50, 50, 50, 50);
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (g.getClip().intersects(oval.getBounds2D())) {
g.setColor(Color.red);
((Graphics2D) g).fill(oval);
System.out.println("Painting bottom panel");
}
}
}
public Ellipse2D.Double ell = null;
class LabelGlassPane extends JComponent {
public LabelGlassPane() {
this.addMouseMotionListener(new MoveInfoListener());
}
public class MoveInfoListener implements MouseMotionListener {
@Override
public void mouseMoved(MouseEvent e) {
Ellipse2D.Double oldEll = ell;
ell = new Ellipse2D.Double(e.getX() - 3, e.getY() - 3, 6, 6);
LabelGlassPane.this.repaint(oldEll, ell);
}
@Override
public void mouseDragged(MouseEvent arg0) {
}
}
public void repaint(Double oldEll, Double ell) {
Rectangle rect = ell.getBounds();
if (oldEll != null) {
rect = rect.union(oldEll.getBounds());
}
// repaint(rect);
repaint();
}
@Override
public void paintComponent(Graphics g) {
// g.setColor(Color.red);
// Container root = frame.getRootPane();
// g.setColor(new Color(255,100,100,100));
// g.fillRect(100, 100, 500, 500);
if (ell != null) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setColor(Color.black);
g2.fill(ell);
System.out.println("Painted glass pane");
}
// rPaint(root,g);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new Glasspanetest().init().setVisible(true);
}
});
}
}
注意:这不是我最喜欢的应用程序方法,但它会起作用。不幸的是,我没有完整的应用程序图片来提供替代方法。