- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
假设我有一个名为 content 的 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
}
}
}
我的问题是,即使我现在仅在移动鼠标时更新此玻璃 Pane ,但当我对其调用 repaint()
时,它会重新绘制小程序中的所有其他组件。
如何在不绘制下面的组件的情况下在该玻璃板上绘制(或使用其他绘制方式)?
谢谢。
编辑:这是一个简单的例子。当鼠标移动时,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() {}
}
最佳答案
问题是 Swing 无法知道它应该只重绘 LabelGlassPane
的一小部分,并且可能重绘 GraphicsPanel
的一小部分或不重绘。
这是因为您在组件中执行自定义绘制,并且虽然您只绘制面板的一小部分区域,但您也可以很好地绘制整个面板。
现在,至于为什么每次重新绘制 LabelGlassPane
时,GraphicsPanel
都会重新绘制,这是因为 LabelGlassPane
不是不透明的,这意味着,为了正确显示未绘制的区域,它需要绘制玻璃板“下方”的所有内容。
这两个方面的结合迫使 Swing 在每次调用 repaint 时都完全绘制两个面板。
但是有一些方法可以避免这种糟糕的组合。为此,您需要通过以下方式使您的绘画方法更加巧妙:
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);
}
});
}
}
注意:这不是我最喜欢的应用程序方法,但它会起作用。不幸的是,我没有您的应用程序的完整情况,因此无法提供替代方法。
关于java - 在玻璃板上喷漆,无需重新喷漆其他部件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25298319/
我是一名优秀的程序员,十分优秀!