繁体   English   中英

放大和缩小 JPanel 后的绘画问题

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM