Zoomen in JPanel

vrcat

Mitglied
Hallo zusammen,

ich hoffe ihr könnt mir helfen ich will eine Zoom Funktion auf mein Model welches sich in einem JPanel Visualisiert schreiben nur geht das nicht so einfach wie ich es mir vorgestellt habe. Drum habe ich ein Prototypen geschrieben und hier geprostet und hoffe einer von euch kann mit helfen.

Im Allgemeinen Funktioniert es schon wenn man auf das Image klickt wird diese neu Skaliert und der Bildpunkt wo man geklickt hat ist nach dem Vergrößern auch immer noch da wo die Maus ist.

Fehler Beschreibung: Sobald ich jedoch an den Randgebieten des Panels Zoome funktioniert es nicht wirklich.

Fehlerfall: Einfach mal nach ganz Rechts unten Scrollen und Zoomen dann Springt das bild und kann mir nicht erklären woran es liegen könnte.

Code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.image.BufferedImage;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JViewport;

public class ZoomDemo extends JFrame implements MouseListener {
	
	class ImagePanel extends JPanel{
		
		private BufferedImage image;
		
		{
			setPreferredSize(new Dimension(1000,1000));
			setBackground(Color.BLUE);
			
			image = new BufferedImage(1000,1000,BufferedImage.TYPE_INT_RGB);
			Graphics g = image.getGraphics();
			for (int i=0;i<100;i++)
				g.drawRect((int)(Math.random()*900),
						   (int)(Math.random()*900),100,100);

		}
		
		public void paint(Graphics g){
			g.drawImage(image,0,0,getWidth(),getHeight(),null);
		}
				
	}
	
	private JScrollPane		sp	= new JScrollPane();
	private JViewport		vp  = sp.getViewport();
	private JPanel			pn	= new JPanel();
	private ImagePanel		im	= new ImagePanel();
	
	private Dimension		dim 	= new Dimension(1000,1000);
	private float			scale	= 1.0f;
	
	public ZoomDemo(){
		setTitle("Zoom-Demo");
		setSize(800,600);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		pn.setLayout(new GridBagLayout());
		
		pn.add(im);
		im.addMouseListener(this);
		
		sp.setViewportView(pn);
		getContentPane().add(sp);
				
		setVisible(true);
	}

	public void mouseClicked(MouseEvent e) {
		
		Point p1,np,dp;
		
		p1    = e.getPoint();
		p1.x /= scale;
		p1.y /= scale;
		
		if (e.getButton() == MouseEvent.BUTTON1) scale+=0.2f;
		if (e.getButton() == MouseEvent.BUTTON3) scale-=0.2f;
		if (scale<0.2) scale = 0.2f;
		scale = (float)((int)(scale*10))/10;
		
		im.setPreferredSize(new Dimension((int)(dim.width*scale),
										  (int)(dim.height*scale)));
		
		dp = new Point();
		dp.x = e.getPoint().x - im.getVisibleRect().x;
		dp.y = e.getPoint().y - im.getVisibleRect().y;
		
		np = new Point();
		np.x = (int) (p1.x*scale - dp.x);
		np.y = (int) (p1.y*scale - dp.y);		
		
		vp.setViewPosition(np);
		im.updateUI();
	}

	public void mouseEntered(MouseEvent arg0) 	{}
	public void mouseExited(MouseEvent arg0) 	{}
	public void mousePressed(MouseEvent arg0) 	{}
	public void mouseReleased(MouseEvent arg0) 	{}
	
	public static void main(String[] args) {
		new ZoomDemo();
	}
}

Bin für jede hilfe dankbar.
 
Hmm scheinbar habt ihr auch keine Idee eine mögliche Lösung die ich sehe ist das ich das JScrollPane selber mache. Nun habe ich aber ein Problem mit dem GridBagLayout :confused: kann mir vielleicht einer Verraten wie ich es hinbekomme das die Elemente sich nicht Zentriert im Fenster befinden sonder sich Maximiert darstellen ?

Hier mal der Code wenn ihr in ausführt werdet ihr sehen was ich meine:

Code:
import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollBar;

public class ZoomDemo2 extends JFrame {
	
	public ZoomDemo2() {
		setTitle("Zoom-Demo");
		setSize(800,600);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		GridBagLayout gb = null;
		getContentPane().setLayout(gb = new GridBagLayout());				
		
		GridBagConstraints dC1 = new GridBagConstraints();		
		dC1.gridx 		= 0;
		dC1.gridy 		= 1;
		dC1.gridheight	= 1;
		dC1.gridheight	= 1;
	    dC1.fill 		= GridBagConstraints.BOTH;
	    	    
	    GridBagConstraints dC2 = new GridBagConstraints();
		dC2.gridx 		= 1;
		dC2.gridy 		= 0;
		dC2.gridheight	= 1;
		dC2.gridheight	= 1;
	    dC2.fill 		= GridBagConstraints.BOTH;
	    
	    GridBagConstraints dC3 = new GridBagConstraints();
		dC3.gridx 		= 0;
		dC3.gridy 		= 0;
		dC3.gridheight	= 1;
		dC3.gridheight	= 1;		
	    dC3.fill 		= GridBagConstraints.BOTH;
		
		JScrollBar hr = new JScrollBar(JScrollBar.HORIZONTAL);
		JScrollBar vr = new JScrollBar(JScrollBar.VERTICAL);
		JPanel	   p  = new JPanel();
		p.setBackground(Color.WHITE);
		
		getContentPane().add(hr,dC1);
		getContentPane().add(vr,dC2);
		getContentPane().add(p ,dC3);
		
		setVisible(true);
	}
	

	public static void main(String[] args) {
		new ZoomDemo2();
	}
}
 
Habe nun da Zoomen in einem Selbst Implementierten JScrollPane realisiert aber ich habe auch hier den Effekt das er in den Randgebieten speziell Rechts unten nicht richtig arbeitet hat noch niemand so was ähnlich es mal gemacht.
 
Ja also meine Berechnungen waren wohl richtig es lag nur an der JScrollPane. Es hat nicht richtig Funktioniert die ViewPosition zu setzen nun geht's.

Hier meine Lösung:

Code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

public class ZoomDemo2 extends JComponent implements MouseListener {

	private Dimension 	dim 	= new Dimension(1000,1000);
	private JScrollPane	jsp		= null;
	private float		scale	= 1.0f;
	
	public ZoomDemo2(JScrollPane jsp){
		setPreferredSize(dim);
		addMouseListener(this);
		this.jsp = jsp;
	}
	
	public void paint(Graphics g){
		g.setColor(Color.GRAY);
		g.fillRect(0,0,getWidth(),getHeight());
		g.setColor(Color.RED);

g.drawRect((int)(10*scale),(int)(10*scale),(int)((dim.width-20)*scale),(int)((dim.height-20)*scale));
		g.setColor(Color.BLUE);
		for (int x=0;x<dim.width;x+=40){
			for (int y=0;y<dim.height;y+=40){
				g.fillRect((int)(x*scale),(int)(y*scale),(int)(20*scale),(int)(20*scale));
			}			
		}	
	}

	public void mouseClicked(MouseEvent e) {

		float m_x = e.getPoint().x;
		float m_y = e.getPoint().y;
			
		Point d = new Point((int)(m_x-getVisibleRect().getX()),
							(int)(m_y-getVisibleRect().getY()));
		
		Dimension vS = getVisibleRect().getSize();
		vS.width  /= 2;
		vS.height /= 2;
		
		if (d.x > vS.width +30) d.x -= 3;
		if (d.x < vS.width -30) d.x += 3;
		if (d.y > vS.height+30) d.y -= 3;
		if (d.y < vS.height-30) d.y += 3;
		
		m_x /= scale;
		m_y /= scale;
		
		Dimension new_Size = new Dimension(getPreferredSize());
		if (e.getButton()==1){
			new_Size.height += 100*scale;
			new_Size.width  += 100*scale;
		}
		if (e.getButton()==3){
			new_Size.height -= 100*scale;
			new_Size.width  -= 100*scale;
		}
		scale = (float)new_Size.width / (float)dim.width;
		setPreferredSize(new_Size);

		m_x = m_x * scale - d.x;
		m_y = m_y * scale - d.y;
			
		jsp.getViewport().setView(jsp.getViewport().getView());
		jsp.getViewport().setViewPosition(new Point((int)m_x,(int)m_y));

	}

	public static void main(String[] args){
		JFrame f = new JFrame("T E S T-Frame");
		f.setSize(476,497);
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		JPanel		jp  = new JPanel();
		jp.setLayout(new GridBagLayout());
		jp.setBackground(Color.DARK_GRAY);
		JScrollPane jsp = new JScrollPane();
		ZoomDemo2	zd2 = new ZoomDemo2(jsp);
		
		jp.add(zd2);
		jsp.setViewportView(jp);
		
		f.getContentPane().add(jsp);
		
		f.setVisible(true);
	}
	
	public void mouseEntered(MouseEvent arg0) 	{}
	public void mouseExited(MouseEvent arg0) 	{}
	public void mousePressed(MouseEvent arg0) 	{}
	public void mouseReleased(MouseEvent arg0) 	{}	
	
}
 
Zurück