J'ai une classe qui étend JPanel (ci-dessous), ce panneau se trouve à l'intérieur d'un JScrollPane. Il écoute (à lui-même) les événements de la souris et essaie de se repositionner (en faisant glisser) et de se redimensionner (sur la roue) pour simuler le mouvement de la souris et le zoom. Le panneau est également responsable de la sortie visuelle principale de mon application. Il stocke un BufferedImage qui est rendu dans la zone visible du JScrollPane (mais sur les graphiques du panneau). La taille et la forme de l'image sont conservées pour correspondre à la zone visible.Java Swing painting & Mouse événement scintillement
Mes problèmes sont tels quels; 1) Sur les événements souris, je reçois une quantité massive de scintillement et des baisses de performance 2) Si je remplace les méthodes paint ou paintComponent avec ma propre méthode de peinture, ce qui est souhaitable pour se débarrasser de scintillement et d'autres problèmes de peinture, je obtiennent toujours le même effet de scintillement et les mêmes graphiques tirés d'images chargées qui ont une zone transparente puis colorent cette zone en noir. Lorsque j'appelle ma méthode de peinture manuellement sans surcharger les méthodes paint et paintComponent, je reçois toujours des scintillements mais les zones transparentes s'affichent correctement.
Je suis nouveau à la peinture Swing et évidemment faire quelque chose de mal, quelqu'un pourrait me pointer dans la bonne direction pour résoudre ce problème?
Merci
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.");
}
}
Pourquoi synchroniser toutes vos méthodes? J'ai travaillé avec Swing pendant des années et je n'ai jamais eu besoin de faire ça. – Paul
Désolé j'ai ajouté ceux juste pour voir si cela a fait une différence après avoir essayé beaucoup d'autres choses et j'ai oublié de les sortir. Je voulais juste vérifier qu'il ne se passait rien d'idiot, comme redimensionner le tableau au milieu du tableau ou similaire. – James
La peinture Swing se déroule sur le fil EDT - Envoi d'événement. L'événement "redimensionner le panneau" ne sera pas traité tant que la peinture n'aura pas été terminée, car ils sont tous deux traités sur le même fil. C'est pourquoi, si un événement entraîne un long processus, vous devez exécuter ce processus dans un autre thread afin que votre interface utilisateur Swing reste sensible et se repeigne. – Paul