我有一個擴展JPanel的類(下面),該面板位於JScrollPane中。它監聽(自己)鼠標事件並嘗試重新定位自己(拖動時)並重新調整自身(輪子上)以模擬鼠標移動和縮放。該面板還負責我的應用程序的主要視覺輸出。它存儲一個呈現在JScrollPane的可視區域(但在面板的圖形上)的BufferedImage。圖像的大小和形狀保持與可視區域相匹配。Java Swing繪畫和鼠標事件閃爍
我的問題是這樣的; 2)如果我用自己的繪畫方法重寫paint或paintComponent方法,這是可取的,以擺脫閃爍和其他繪畫問題,我仍然可以獲得相同的閃爍效果,並且從加載的圖像中獲取具有透明區域的圖形,然後將該區域着色爲黑色。當我手動調用我的paint方法而不重寫paint和paintComponent方法時,我仍然閃爍,但透明區域正確顯示。
我是新來的Swing繪畫,顯然做錯了什麼,誰能指出我在正確的方向來解決這個問題?
感謝
import jSim.simulation.Simulation;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
import javax.swing.JViewport;
import javax.swing.event.MouseInputListener;
public class SimPanel extends JPanel implements MouseWheelListener, MouseInputListener {
//Simulation
Simulation sim;
//Viewer
JViewport viewport;
Dimension viewSize;
BufferStrategy strat;
//Drawing
Image renderImage;
Graphics2D g2d;
boolean draw = true;
double scale = 1.0;
Object drawLock = new Object();
//Mouse events
int m_XDifference, m_YDifference;
public SimPanel(JViewport viewport) {
this.viewport = viewport;
this.addMouseListener(this);
this.addMouseMotionListener(this);
this.addMouseWheelListener(this);
//this.setup();
}
public SimPanel(Simulation sim, JViewport viewport) {
this.sim = sim;
this.viewport = viewport;
this.addMouseListener(this);
this.addMouseMotionListener(this);
this.addMouseWheelListener(this);
//this.setup();
}
//Used to initialise the buffered image once drawing begins
private void setup() {
synchronized (drawLock) {
viewSize = viewport.getExtentSize();
renderImage = new BufferedImage(viewSize.width, viewSize.height, BufferedImage.TYPE_INT_RGB);
g2d = (Graphics2D) renderImage.getGraphics();
}
}
// @Override
// public void paint(Graphics g)
// {
// synchronized(drawLock) {
// //super.paintComponent(g);
// paintSimulation();
// }
// }
//Paint the screen for a specific simulation
public void paintSimulation(Simulation sim) {
synchronized (drawLock) {
setSimulation(sim);
paintSimulation();
}
}
//Paint the screen with the panels simulation
public void paintSimulation() {
synchronized (drawLock) {
//if no image, then init
if (renderImage == null) {
setup();
}
//clear the screen
resetScreen();
//draw the simulation if not null, to the image
if (sim != null) {
sim.draw(this);
}
//paint the screen with the image
paintScreen();
}
}
private void resetScreen() {
Dimension newSize = viewport.getExtentSize();
if (viewSize.height != newSize.height || viewSize.width != newSize.width || renderImage == null) {
//System.out.println("Screen Size Changed: " + viewSize + " " + newSize);
viewSize = newSize;
renderImage = new BufferedImage(viewSize.width, viewSize.height, BufferedImage.TYPE_INT_RGB);
g2d = (Graphics2D) renderImage.getGraphics();
} else {
g2d.setBackground(Color.DARK_GRAY);
g2d.clearRect(0, 0, (int) (viewSize.width), (int) (viewSize.height));
}
}
private void paintScreen() {
Graphics g;
Graphics2D g2;
try {
//g = viewport.getGraphics();
g = this.getGraphics();
g2 = (Graphics2D) g;
if ((g != null) && (renderImage != null)) {
g2.drawImage(renderImage, (int) viewport.getViewPosition().getX(), (int) viewport.getViewPosition().getY(), null);
}
Toolkit.getDefaultToolkit().sync(); // sync the display on some systems
g.dispose();
g2.dispose();
this.revalidate();
} catch (Exception e) {
System.out.println("Graphics context error: " + e);
}
}
//Simulation makes calls to this method to draw items on the image
public void draw(BufferedImage image, int x, int y, Color colour) {
synchronized (drawLock) {
Rectangle r = viewport.getViewRect();
if (g2d != null && draw) {
Point p = new Point((int) (x * scale), (int) (y * scale));
if (r.contains(p)) {
if (scale < 1) {
Graphics2D g2 = (Graphics2D) image.getGraphics();
Image test = image.getScaledInstance((int) (image.getWidth(null) * scale), (int) (image.getHeight(null) * scale), Image.SCALE_FAST);
g2d.drawImage(test, (int) ((x * scale - r.x)), (int) ((y * scale - r.y)), null);
} else {
g2d.drawImage(image, x - r.x, y - r.y, null);
}
}
}
}
}
public void setDraw(boolean draw) {
this.draw = draw;
}
public void setSimulation(Simulation sim) {
synchronized (drawLock) {
if (!(this.sim == sim)) {
this.sim = sim;
}
}
}
public void mouseWheelMoved(MouseWheelEvent e) {
synchronized (drawLock) {
updatePreferredSize(e.getWheelRotation(), e.getPoint());
}
}
private void updatePreferredSize(int wheelRotation, Point stablePoint) {
double scaleFactor = findScaleFactor(wheelRotation);
if (scale * scaleFactor < 1 && scale * scaleFactor > 0.05) {
scaleBy(scaleFactor);
Point offset = findOffset(stablePoint, scaleFactor);
offsetBy(offset);
this.getParent().doLayout();
}
}
private double findScaleFactor(int wheelRotation) {
double d = wheelRotation * 1.08;
return (d > 0) ? 1/d : -d;
}
private void scaleBy(double scaleFactor) {
int w = (int) (this.getWidth() * scaleFactor);
int h = (int) (this.getHeight() * scaleFactor);
this.setPreferredSize(new Dimension(w, h));
this.scale = this.scale * scaleFactor;
}
private Point findOffset(Point stablePoint, double scaleFactor) {
int x = (int) (stablePoint.x * scaleFactor) - stablePoint.x;
int y = (int) (stablePoint.y * scaleFactor) - stablePoint.y;
return new Point(x, y);
}
private void offsetBy(Point offset) {
Point location = viewport.getViewPosition();
//this.setLocation(location.x - offset.x, location.y - offset.y);
viewport.setViewPosition(new Point(location.x + offset.x, location.y + offset.y));
}
public void mouseDragged(MouseEvent e) {
synchronized (drawLock) {
//Point p = this.getLocation();
Point p = viewport.getViewPosition();
int newX = p.x - (e.getX() - m_XDifference);
int newY = p.y - (e.getY() - m_YDifference);
//this.setLocation(newX, newY);
viewport.setViewPosition(new Point(newX, newY));
//this.getParent().doLayout();
}
}
public void mousePressed(MouseEvent e) {
synchronized (drawLock) {
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
m_XDifference = e.getX();
m_YDifference = e.getY();
}
}
public void mouseReleased(MouseEvent e) {
synchronized (drawLock) {
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
}
public void mouseClicked(MouseEvent e) {
//throw new UnsupportedOperationException("Not supported yet.");
}
public void mouseEntered(MouseEvent e) {
//throw new UnsupportedOperationException("Not supported yet.");
}
public void mouseExited(MouseEvent e) {
//throw new UnsupportedOperationException("Not supported yet.");
}
public void mouseMoved(MouseEvent e) {
//throw new UnsupportedOperationException("Not supported yet.");
}
}
爲什麼要同步所有的方法?我已與Swing合作多年,從未需要這樣做。 – Paul 2011-05-16 12:53:38
對不起,我添加這些只是爲了看看它嘗試了很多其他的事情,並忘記帶出它們有什麼區別。我只是想檢查沒有什麼愚蠢的事情發生,像調整面板中等或類似的。 – James 2011-05-16 13:36:39
擺動繪畫發生在EDT - 事件派發線程上。 「調整面板」事件將不會被處理,直到繪畫完成,因爲它們都在同一個線程上處理。這就是爲什麼如果一個事件導致一個漫長的過程,你應該在另一個線程中運行這個過程,這樣你的Swing UI仍然會響應並重新繪製自己。 – Paul 2011-05-16 13:47:45