Título Anterior: Java2D: comportamento inesperado ao rolar JPanel depois de usar AffinneTransform (zoom)
Boa tarde a todos.
Estou com um projeto em Java2D e, dentre as coisas que estou tentando fazer, está um mecanismo para zoom em um painel. O scale funciona adequadamente, mas como o painel está dentro de um ScrollPane, ao rolar os elementos a serem desenhados são desenhados incorretamente, ficando cortados quando são rolados para fora da tela. A rolagem funciona normalmente se eu não colocar o AffineTransform. Alguns outros problemas ocorrem junto com este, como o botão “Zoom” sendo desenhado do lado direito às vezes, mas creio que são problemas relacionados. Segue código do Painel:
[code]public class DrawPanel extends JPanel implements MouseListener{
private ArrayList itens;
private float zoom = 1;
public DrawPanel() {
super();
itens = new ArrayList<MyItem>(30);
setSize(1200, 1200);
setPreferredSize(getSize());
addMouseListener(this);
}
@Override
protected void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
AffineTransform at = new AffineTransform();
at.scale(zoom, zoom);
g2.setTransform(at); // sem esta linha, a rolagem não apresenta problemas
setBackground(Color.WHITE);
for(MyItem my : itens){
my.desenhar(g2);
}
g2.setStroke(new BasicStroke(3));
g2.drawRect(40, 40, 50, 50); // para efeito de testes
g2.drawRect(30, 30, 50, 50); // para efeito de testes
g2.dispose();
}
public void adicionar(MyItem my){
itens.add(my);
}
private void selecionar(Point2D ponto){
for(MyItem my : itens){
my.selecionar(ponto);
}
}
public void redesenhar(){
repaint();
}
public void setZoom(float zoom){
this.zoom = zoom;
this.setPreferredSize(new Dimension((int) (1200 * zoom), (int) (1200 * zoom)));
redesenhar();
}
private Point2D traduce(Point2D ponto){
ponto.setLocation(ponto.getX() / zoom, ponto.getY() / zoom);
return ponto;
}
@Override
public void mousePressed(MouseEvent evt) {
selecionar(traduce(evt.getPoint()));
redesenhar();
}
@Override
public void mouseClicked(MouseEvent evt) {}
@Override
public void mouseEntered(MouseEvent evt) {}
@Override
public void mouseExited(MouseEvent evt) {}
@Override
public void mouseReleased(MouseEvent evt) {}
}[/code]
MyItem, MyCircle e MyRectangle são classes simples, que basicamente armazenam e desenham as formas (um círculo e um retângulo). O código do JFrame é este:
[code]package gui;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import elements.MyCircle;
import elements.MyRectangle;
public class Screen extends JFrame {
private DrawPanel painel;
private JButton bAddCircle;
private JButton bAddRect;
private JButton bZoom;
private JScrollPane sp;
public Screen(){
super("Teste de Zoom");
this.setLayout(new BorderLayout());
painel = new DrawPanel();
setMinimumSize(new Dimension(300, 300));
bAddCircle = new JButton("Adicionar Círculo");
bAddRect = new JButton("Adicionar Retângulo");
bZoom = new JButton("Zoom");
sp = new JScrollPane(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
sp.setViewportView(painel);
sp.setAutoscrolls(true);
getContentPane().add(sp, BorderLayout.CENTER);
getContentPane().add(bAddCircle, BorderLayout.NORTH);
getContentPane().add(bAddRect, BorderLayout.SOUTH);
getContentPane().add(bZoom, BorderLayout.EAST);
setExtendedState(JFrame.MAXIMIZED_BOTH);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
bAddCircle.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
adicionarCirculo();
}
});
bAddRect.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
adicionarRetangulo();
}
});
bZoom.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
float f = Float.parseFloat(JOptionPane.showInputDialog("Zoom:"));
painel.setZoom(f);
}
});
}
private void adicionarCirculo(){
painel.adicionar(new MyCircle());
painel.redesenhar();
}
private void adicionarRetangulo(){
painel.adicionar(new MyRectangle());
painel.redesenhar();
}
public static void main(String[] args){
new Screen().setVisible(true);
}
}[/code]O fonte completo está em anexo. É um projeto do Eclipse. Eis uma imagem do problema:
[URL=http://imageshack.us/photo/my-images/577/rolagemantes.png/][/URL]
[URL=http://imageshack.us/photo/my-images/850/rolagemdepois.png/][/URL]
Agradeço desde já a atenção.
Abraço.