[英]Issues with paint after zooming in and zooming out of JPanel
我有一个可滚动的 JPanel,其中有一些数字是通过“drawString”方法绘制的。 当我单击放大按钮时,重绘方法被调用并且数字变大,如预期的那样。 但是,当我尝试向右滚动时,部分数字要么丢失,要么以其原始大小绘制,而不是新的缩放大小。 下面是最小的可重现代码。
package sometest;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenuBar;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
public class SomeTest implements Runnable
{
public static JButton in;
public static JButton out;
public static void main(String[] args)
{
SomeTest st = new SomeTest();
st.run();
}
@Override
public void run()
{
JMenuBar mb = new JMenuBar();
in = new JButton("Zoom In");
out = new JButton("Zoom Out");
JFrame f = new JFrame("Example");
Visualization v = new Visualization();
JScrollPane sp = new JScrollPane(v);
MouseAdapter mouseAdapter = new MouseAdapter()
{
private Point origin;
@Override
public void mousePressed(MouseEvent e)
{
origin = new Point(e.getPoint());
}
@Override
public void mouseDragged(MouseEvent e)
{
JViewport vp = null;
if (origin != null)
{
vp = sp.getViewport();
}
if (vp != null)
{
int deltaX = origin.x - e.getX();
int deltaY = origin.y - e.getY();
Rectangle view = vp.getViewRect();
view.x += deltaX;
view.y += deltaY;
v.scrollRectToVisible(view);
}
}
};
sp.getViewport().addMouseListener(mouseAdapter);
sp.getViewport().addMouseMotionListener(mouseAdapter);
f.add(sp);
f.setJMenuBar(mb);
mb.add(in);
mb.add(out);
f.setContentPane(sp);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
package sometest;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.AffineTransform;
import javax.swing.JPanel;
import javax.swing.Scrollable;
import javax.swing.SwingUtilities;
import static sometest.SomeTest.in;
import static sometest.SomeTest.out;
public class Visualization extends JPanel implements Scrollable, ActionListener
{
private double zoomFactor = 1;
private double prevZoomFactor = 1;
private boolean zoomer;
private double xOffset = 0;
private double yOffset = 0;
public Visualization()
{
in.addActionListener(this);
out.addActionListener(this);
Font currentFont = getFont();
Font newFont = currentFont.deriveFont(currentFont.getSize() * 18F);
setFont(newFont);
setBackground(Color.WHITE);
}
@Override
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==in)
{
zoomer = true;
zoomFactor *= 1.1;
repaint();
}
if(e.getSource()==out)
{
zoomer = true;
zoomFactor /= 1.1;
repaint();
}
}
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if(zoomer)
{
AffineTransform at = new AffineTransform();
Dimension center = getPreferredScrollableViewportSize();
Double xRel = center.getWidth()/2;
Double yRel = center.getHeight()/2;
double zoomDiv = zoomFactor / prevZoomFactor;
xOffset = (zoomDiv) * (xOffset) + (1 - zoomDiv) * xRel;
yOffset = (zoomDiv) * (yOffset) + (1 - zoomDiv) * yRel;
at.translate(xOffset, yOffset);
at.scale(zoomFactor, zoomFactor);
prevZoomFactor = zoomFactor;
g2d.transform(at);
zoomer = false;
}
g2d.drawString("1234567890", 500, 200);
g2d.dispose();
}
@Override
public Dimension getPreferredSize()
{
if(zoomer)
{
return new Dimension((int)(2000*zoomFactor), (int)(750*zoomFactor));
}
else
{
return new Dimension(2000, 750);
}
}
@Override
public Dimension getPreferredScrollableViewportSize()
{
return new Dimension(1550, 750);
}
@Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction)
{
return 32;
}
@Override
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction)
{
return 32;
}
@Override
public boolean getScrollableTracksViewportWidth()
{
return false;
}
@Override
public boolean getScrollableTracksViewportHeight()
{
return false;
}
}
当我放大和滚动时,我希望绘制的数字保持相同的大小。 据我所知,重绘方法应该自动处理滚动或调整大小时等情况。 我误用了重绘方法还是我的问题完全不同?
最好使用AffineTransform#concatenate(AffineTransform)方法组合用于缩放的AffineTransform
和用于平移的AffineTransform
。
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
AffineTransform scrollTransform = g2d.getTransform();
scrollTransform.concatenate(zoomTransform);
g2d.setTransform(scrollTransform);
g2d.drawString("1234567890", 500, 200);
g2d.dispose();
}
SomeTest2.java
// package sometest;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.AffineTransform;
import javax.swing.*;
public class SomeTest2 {
public JComponent makeUI() {
Visualization v = new Visualization();
MouseAdapter mouseAdapter = new DragScrollListener();
v.addMouseListener(mouseAdapter);
v.addMouseMotionListener(mouseAdapter);
JButton in = new JButton("Zoom In");
in.addActionListener(e -> v.setZoomFactor(1.1));
JButton out = new JButton("Zoom Out");
out.addActionListener(e -> v.setZoomFactor(1 / 1.1));
JMenuBar mb = new JMenuBar();
mb.add(in);
mb.add(out);
EventQueue.invokeLater(() -> v.getRootPane().setJMenuBar(mb));
return new JScrollPane(v);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new SomeTest2().makeUI());
f.setSize(640, 480);
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}
class Visualization extends JPanel {
private final AffineTransform zoomTransform = new AffineTransform();
private final Rectangle rect = new Rectangle(2000, 750);
public Visualization() {
Font currentFont = getFont();
Font newFont = currentFont.deriveFont(currentFont.getSize() * 18F);
setFont(newFont);
setBackground(Color.WHITE);
}
public void setZoomFactor(double zoomFactor) {
zoomTransform.scale(zoomFactor, zoomFactor);
revalidate();
repaint();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
AffineTransform scrollTransform = g2d.getTransform();
scrollTransform.concatenate(zoomTransform);
g2d.setTransform(scrollTransform);
g2d.drawString("1234567890", 500, 200);
g2d.dispose();
}
@Override
public Dimension getPreferredSize() {
Rectangle r = zoomTransform.createTransformedShape(rect).getBounds();
return new Dimension(r.width, r.height);
}
}
class DragScrollListener extends MouseAdapter {
private final Point origin = new Point();
@Override
public void mouseDragged(MouseEvent e) {
Component c = e.getComponent();
Container p = SwingUtilities.getUnwrappedParent(c);
if (p instanceof JViewport) {
JViewport viewport = (JViewport) p;
Point cp = SwingUtilities.convertPoint(c, e.getPoint(), viewport);
Point vp = viewport.getViewPosition();
vp.translate(origin.x - cp.x, origin.y - cp.y);
((JComponent) c).scrollRectToVisible(new Rectangle(vp, viewport.getSize()));
origin.setLocation(cp);
}
}
@Override
public void mousePressed(MouseEvent e) {
Component c = e.getComponent();
Container p = SwingUtilities.getUnwrappedParent(c);
if (p instanceof JViewport) {
JViewport viewport = (JViewport) p;
Point cp = SwingUtilities.convertPoint(c, e.getPoint(), viewport);
origin.setLocation(cp);
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.