Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Ich male etwas in ein Graphics z.B. drei - vier Rechtecke nebeneinander.
Nun möchte ich einen Rahmen langsam von links nach Rechts wandern lassen.
Alles was sich im Rahmen befindet soll gezoomt dargestellt werden!
Eine Art Lupenfunktion. Habe es schon versucht mit BufferImage und dann getSubImage.
Hat leider nicht gut funktioniert.
Wäre schön, wenn jemand eine Idee oder einen Link zu einem Javaprogramm hätte
Hm... sowas wollte ich schon ewig mal implementieren. Ich hatte zwar mal sowas in Swogl gemacht (screenshot) aber das ist sicher nicht das, was du suchst, nicht mehr ganz up to date, und außerdem ein Overkill.
Das für eine Swing-Component in seiner allgemeinsten Form zu machen ist alles andere als einfach - genaugenommen sogar SEHR schwierig: Damit so eine Lupe überhaupt Sinn macht, müßte alles, was gezeichnet wird, größer gezeichnet werden, als es angezeigt wird, und nur dort wo die Lupe ist, wird es so groß angezeigt, wie es gezeichnet wird - andernfalls bekommt man unter der Lupe nur häßlich vergrößerten Pixelmatsch.
@xehpuk: Eine Frage noch zu deinen guten, lauffähigen Programm: Hat es einen bestimmten Sinn, warum du die paint() - Methode überschreibst und nicht wie üblich die paintComponent() ?
unberührt. Dadurch fehlen in der "Lupe" diese beiden Bestandteile. Und selbst wenn es damit funktionierte, wüsste ich jetzt nicht, wie man das am geschicktesten neben anderem Malcode in der
Code:
paintComponent()
unterbringen könnte.
Wie dem auch sei, ich habe da ein wenig verrückt abstrahiert, um die Komponente "wiederverwendbarer" zu machen:
Java:
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LayoutManager;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.awt.geom.AffineTransform;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.event.MouseInputListener;
public abstract class ZoomPanel extends JPanel {
{
final ZoomListener listener = new ZoomListener();
addMouseListener(listener);
addMouseMotionListener(listener);
addMouseWheelListener(listener);
}
public ZoomPanel() {
super();
}
public ZoomPanel(final boolean isDoubleBuffered) {
super(isDoubleBuffered);
}
public ZoomPanel(final LayoutManager layout, final boolean isDoubleBuffered) {
super(layout, isDoubleBuffered);
}
public ZoomPanel(final LayoutManager layout) {
super(layout);
}
public abstract AbstractMagnifier getMagnifier();
@Override
public void paint(final Graphics g) {
super.paint(g);
final AbstractMagnifier magnifier = getMagnifier();
final Shape shape = magnifier.getShape();
if (shape != null) {
final Graphics2D g2 = (Graphics2D) g.create();
g2.setClip(shape);
final Rectangle b = shape.getBounds();
g2.clearRect(b.x, b.y, b.width, b.height);
final AffineTransform transform = new AffineTransform();
final double centerX = b.getCenterX();
final double centerY = b.getCenterY();
transform.translate(centerX, centerY);
final double scale = Math.pow(magnifier.step, magnifier.zoom);
transform.scale(scale, scale);
transform.translate(-centerX, -centerY);
g2.setTransform(transform);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
super.paint(g2);
g2.setTransform(new AffineTransform());
g2.setClip(g.getClip());
g2.setStroke(magnifier.getStroke());
g2.draw(shape);
g2.dispose();
}
}
protected abstract class AbstractMagnifier {
private double step = 1.1;
private int zoom = 0;
private Point point;
private Stroke stroke = new BasicStroke(1f);
public double getStep() {
return this.step;
}
public void setStep(final double step) {
this.step = step;
}
public int getZoom() {
return this.zoom;
}
public void setZoom(final int zoom) {
this.zoom = zoom;
}
public Stroke getStroke() {
return this.stroke;
}
public void setStroke(final Stroke stroke) {
this.stroke = stroke;
}
public Point getPoint() {
return this.point;
}
public void setPoint(final Point point) {
this.point = point;
}
public abstract Shape getShape();
}
private class ZoomListener implements MouseInputListener, MouseWheelListener {
private void movePoint(final MouseEvent e) {
getMagnifier().setPoint(e.getPoint());
repaint();
}
@Override
public void mousePressed(final MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
movePoint(e);
}
}
@Override
public void mouseReleased(final MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
getMagnifier().setPoint(null);
repaint();
}
}
@Override
public void mouseDragged(final MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
movePoint(e);
}
}
@Override
public void mouseWheelMoved(final MouseWheelEvent e) {
if (getMagnifier().getPoint() != null) {
final int rotation = e.getWheelRotation();
getMagnifier().setZoom(getMagnifier().getZoom() - rotation);
repaint();
}
}
@Override
public void mouseClicked(final MouseEvent e) {
}
@Override
public void mouseEntered(final MouseEvent e) {
}
@Override
public void mouseExited(final MouseEvent e) {
}
@Override
public void mouseMoved(final MouseEvent e) {
}
}
}
Das
Code:
ZoomPanel
ist nun abstrakt und beinhaltet die Lupenfunktionalität gekapselt in einer inneren abstrakten Klasse
Code:
AbstractMagnifier
, welche eine abstrakte Methode
Code:
getShape()
hat, welche die Form der Lupe bestimmt. Um an die Lupenimplementation zu kommen, gibt es wiederum im
Code:
ZoomPanel
eine abstrakte Methode
Code:
getMagnifier()
.
Außerdem kann man nun, wenn die Lupe eingeblendet ist, über das Mausrad den Zoomfaktor verstellen.
Hier eine mögliche Implementation:
Java:
import java.awt.BasicStroke;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class StarZoomPanel extends ZoomPanel {
private final BufferedImage img = fetchImage();
private BufferedImage fetchImage() {
try {
return ImageIO.read(new URL("http://www.java-forum.org/images/misc/java_forum_org.gif"));
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
{
setPreferredSize(new Dimension(img.getWidth(), img.getHeight()));
}
private final AbstractMagnifier magnifier = new AbstractMagnifier() {
{
setStroke(new BasicStroke(3f));
}
@Override
public Shape getShape() {
final Point point = getPoint();
[url]http://www.java-forum.org/blogs/tfa/30-snippet-transparente-rechteckige-fenster.html[/url]
if (point != null) {
final GeneralPath gp = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
gp.moveTo(0, -250);
gp.lineTo(56, -77);
gp.lineTo(238, -77);
gp.lineTo(91, 30);
gp.lineTo(147, 202);
gp.lineTo(0, 95);
gp.lineTo(-147, 202);
gp.lineTo(-91, 30);
gp.lineTo(-238, -77);
gp.lineTo(-56, -77);
gp.closePath();
final AffineTransform af = AffineTransform.getTranslateInstance(point.x, point.y);
af.scale(.5, .5);
return gp.createTransformedShape(af);
}
return null;
}
};
@Override
public AbstractMagnifier getMagnifier() {
return this.magnifier;
}
@Override
protected void paintComponent(final Graphics g) {
super.paintComponent(g);
g.drawImage(img, 0, 0, null);
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
final JFrame frame = new JFrame("ZoomPanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final StarZoomPanel contentPane = new StarZoomPanel();
contentPane.add(new JLabel("Hallo"));
contentPane.add(new JTextField("Welt!"));
contentPane.add(new JButton(":)"));
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
Wieder dasselbe Hintergrundbild wie im ersten Beispiel. Um die Flexibilität zu zeigen, habe ich diesmal keinen Kreis, sondern einen Stern als Lupenform genommen. Woher ich die Form geklaut habe, habe ich im Quelltext in gültiger Java-Syntax als URL eingebracht. (Leider setzt die Forensoftware das url-Tag drum.)
Das alles ist jedoch nicht perfekt.
Das Caret des Textfelds wird sich beim Blinken über die Lupe malen und das Blinken wird an sich nicht in der Lupe sichtbar sein, weil es nicht das Neuzeichnen der gesamten Komponente triggert.
Außerdem ist das "o" vom "Hallo" des Labels ein wenig abgeschnitten, wenn man reinzoomt. Das scheint aber eher ein Problem in Swing zu sein?
Des Weiteren wird die Lupe nicht angezeigt, wenn eine Kindkomponente den Mausklick konsumiert.
Vielleicht lässt sich das mit der GlassPane besser realisieren?
Ab Java 7 soll das angeblich leicht mit JLayer umsetzbar sein, das habe ich mir aber auch noch nicht genauer angeschaut.
Supercoole Sache! Herzlichen Dank!
Im Vergleich zum ersten Beispiel wird bei mir allerdings nicht mehr gezoomed, sondern lediglich der Stern eingeblendet (Win7 64Bit, Java 7.0.02).
auf 0 gesetzt, siehe hier:
[JAVA=76]private int zoom = 0;[/code]
Wenn du diesen Wert also änderst oder das Mausrad (innerhalb des Panels) drehst, während die Lupe eingeblendet ist, sollte herein- oder herausgezoomt werden.
Ich habe noch ein wenig herumprobiert, das mit einer GlassPane hinzubekommen. Scheint aber recht schwierig zu sein … zumindest für mich.
Ich probier das nachher mal mit
Code:
JLayer
, wenn ich Java 7 und ein wenig Zeit zur Verfügung habe.