Swing Malen auf JPanel mit transparentem Hintergrund

JDan

Mitglied
Hallo Leute!
Ich bin wieder bei einem Problem steckengelieben und komme bisher alleine nicht weiter.

Ich möchte auf einem JPanel (das in einem JLayeredPane liegt) malen, das einen transparenten Hintergrund hat. Der einzige Weg auf den ich gekommen bin ist mir das Image das ich in meiner überschriebenen paintComponent Methode nutze zu schnappen und mit folgendem Code den Hintergrund Transparent zu machen:
Java:
import java.awt.*;
import java.awt.image.*;

/**
 * Code aus Reals How to
 * @author Real's How to
 *
 */
public class Transparency {
  public static Image makeColorTransparent
    (Image im, final Color color) {
    ImageFilter filter = new RGBImageFilter() {
      // the color we are looking for... Alpha bits are set to opaque
      public int markerRGB = color.getRGB() | 0xFF000000;

      public final int filterRGB(int x, int y, int rgb) {
        if ( ( rgb | 0xFF000000 ) == markerRGB ) {
          // Mark the alpha bits as zero - transparent
          return 0x00FFFFFF & rgb;
          }
        else {
          // return
          return rgb;
          }
        }
      }; 

    ImageProducer ip = new FilteredImageSource(im.getSource(), filter);
    return Toolkit.getDefaultToolkit().createImage(ip);
    }
}

Wenn ich irgendwas beim initialisieren male funktioniert das wunderbar. Wenn ich jedoch aktiv (z.B. über einen Button) Grafiken dazumalen möchte wird nichts gemalt.

Ich habe ein kleines Beispielprojekt gemacht bei dem das ganze deutlich wird, hier mal der Reihe nach die drei übrigen Klassen(im Anhang auch das Projekt, wenn es sich jemand in seiner IDE angucken/ausführen möchte).

Die Hauptframe:
Java:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;


public class MainFrame extends JFrame
{
	Leinwand leinwand ;
	JButton move;
	public static void main(String[] args)
	{
		new MainFrame();
	}
	
	public MainFrame()
	{
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		move = new JButton("move");
		this.setBounds(100,100,200,200);
		leinwand = new Leinwand();
		leinwand.setBounds(this.getBounds());
		this.add(BorderLayout.CENTER,leinwand);
		this.add(BorderLayout.SOUTH,move);

		MyListener ml = new MyListener();
		move.addActionListener(ml);
		
		
		this.setVisible(true);
		leinwand.init();
	}
	
	
	class MyListener implements ActionListener
	{

		@Override
		public void actionPerformed(ActionEvent arg0)
		{
			leinwand.moveIt();
			
		}
		
	}
	

}

Die Leinwand (das JLayeredPane):
Java:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;

import javax.swing.JLayeredPane;


public class Leinwand extends JLayeredPane
{
	Malflaeche malflaeche;
	
	private Image image;
	private Graphics2D g2d;
	private Color background = Color.GREEN;
	
	
	public void moveIt()
	{
		malflaeche.moveIt();
	}
	
	public void init()
	{
		
		malflaeche = new Malflaeche();
		malflaeche.setBounds(this.getBounds());
		this.add(malflaeche);
		malflaeche.setVisible(true);
		malflaeche.setOpaque(false);
		malflaeche.draw();
		
	}


	@Override
	public void paintComponent(final Graphics g)
	{
		super.paintComponent(g);
		// initialises the image with the first paint
		// or checks the image size with the current panelsize
		if (image == null || image.getWidth(this) < getSize().width
				|| image.getHeight(this) < getSize().height)
		{
			resetImage();
		}
		Rectangle r = g.getClipBounds(); // das ClipRectangle holen um zu
		// wissen, welcher Bereich erneuert
		// werden soll
		g.drawImage(image, r.x, r.y, r.width + r.x, r.height + r.y, r.x, r.y,
				r.width + r.x, r.height + r.y, null);
	}

	private void resetImage()
	{
		Image saveImage = image;
		Graphics2D saveG2d = g2d;
		image = this.createImage(getWidth(), getHeight());
		g2d = (Graphics2D) image.getGraphics();
		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
		g2d.setBackground(background);
		// g2d.setBackground(Color.GREEN);
		g2d.clearRect(0, 0, getWidth(), getHeight());
		g2d.setColor(Color.BLACK);
		if (saveG2d != null)
		{
			g2d.setColor(saveG2d.getColor());
			g2d.drawImage(saveImage, 0, 0, this);
			saveG2d.dispose();
		}
	}

	public Graphics2D getGraphics2D()
	{
		return g2d;
	}

}

Und zum Schluss die Malflaeche,also das JPanel auf dem letzendlich gemalt werden soll:
Java:
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;

import javax.swing.JPanel;


public class Malflaeche extends JPanel
{
	private Image image;
	private Graphics2D g2d;
	int movevalue = 1;

	
	
	public void draw()
	{
		image = createImage(this.getWidth(), this.getHeight());
		g2d = (Graphics2D) image.getGraphics();
		//TODO Hier Transparenz setzen
		//image = Transparency.makeColorTransparent(image, this.getBackground());

		getGraphics2D().setPaintMode();
		getGraphics2D().setColor(Color.BLACK);

		int pensize = 3;
		getGraphics2D().setStroke(
				new BasicStroke(pensize, BasicStroke.CAP_ROUND,
						BasicStroke.JOIN_ROUND));
		getGraphics2D().drawRoundRect(10, 10, 50 - 6, 50 - 6, 5, 5);
		repaint();
	}
	
	public void moveIt()
	{
		movevalue++;
		getGraphics2D().setPaintMode();
		getGraphics2D().setColor(Color.BLACK);

		int pensize = 3;
		getGraphics2D().setStroke(
				new BasicStroke(pensize, BasicStroke.CAP_ROUND,
						BasicStroke.JOIN_ROUND));
		getGraphics2D().drawRoundRect(10+movevalue, 10+movevalue, 50 - 6, 50 - 6, 5, 5);
		repaint();
	}
	
	

	private void resetImage()
	{
		Image saveImage = image;
		Graphics2D saveG2d = g2d;
		image = this.createImage(getWidth(), getHeight());
		g2d = (Graphics2D) image.getGraphics();
		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
		g2d.clearRect(0, 0, getWidth(), getHeight());
		g2d.setColor(Color.BLACK);
		if (saveG2d != null)
		{
			g2d.setColor(saveG2d.getColor());
			g2d.drawImage(saveImage, 0, 0, this);
			saveG2d.dispose();
		}
	}

	@Override
	public void paintComponent(final Graphics g)
	{
		super.paintComponent(g);
		if (image == null || image.getWidth(this) < getSize().width
				|| image.getHeight(this) < getSize().height)
		{
			resetImage();
		}
		Rectangle r = g.getClipBounds(); 
		g.drawImage(image, r.x, r.y, r.width + r.x, r.height + r.y, r.x, r.y,
				r.width + r.x, r.height + r.y, null);
	}
	
	public Graphics2D getGraphics2D()
	{
		return g2d;
	}

}


So wie es jetzt im Code steht wird erstmal keine Transparenz gesetzt, das Malen funktioniert wie es soll. Wenn man in der draw() Methode der hier zuletzt aufgeführten Klasse Malflaeche die Zeile "image = Transparency.makeColorTransparent(image, this.getBackground());" wieder entkommentiert wird die Transparenz richtig gesetzt, malen funktioniert aber nicht.

Ich hoffe hier weiss jemand Rat.🙁
 
Hm... das mit dem Transparency-Ding kapier' ich nicht - damit wird (soweit ich das sehe) auf sehr umständliche (und AFAIK nicht mehr zeitgemäße) Art eine einzelne Farbe in "transparent" umgewandelt...

Vielleicht hilft's schon, wenn du überall, wo bisher image=createImage... stand,
Java:
        image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
schreibst. Damit is explizit gesagt, dass man ein BufferedImage mit Transparenz (ARGB) haben will..... behebt das vielleicht schon das Problem...? ???:L
 
Edit²: Hat doch nicht funktioniert! Color(0,0,0,0) scheint einfach schwarz zu sein. Ich dachte wenn der alpha Wert auf null steht wäre die Farbe komplett durchsichtig? Oder ist sie das und kann deswegen eine echte vorhandene Farbe nicht überdecken?

Edit:
Ok, wieder typisch von mir ^^. Aber hab die Lösung kurz nach dem posten entdeckt: Man kann einfach eine transparente Farbe mit new Color(0,0,0,0) erstellen und damit malen. So erspare ich es mir die ganze Leinwand zu zerstören und neu aufzubauen.

Klasse!
Ich bedanke mich nochmals! Das ist ohne zweifel mein Lieblingsforum ^^.
Wow, ihr seid einfach super hier 😀. Ja, das behebt das Problem im Beispielprojekt. Im richtigen Projekt habe ich noch einpaar andere Schwierigkeiten. Wenn ich etwas wieder löschen will, wie komme ich denn dann an diese "Transparente" Farbe? getBackground scheint mir falsche Werte zu liefern (malt es einfach mit weiß).
 
Zuletzt bearbeitet:
Man kann mit einer komplett Transparenten Farbe auch eine nicht-Transparente überdecken, indem man ein passendes AlphaComposite für das Graphics setzt (SRC_OVER wenn ich mich nicht irre) ... aber ich bin bei den Edit's ein bißchen durcheinander
[edit]Obwohl man die
[edit] jetzt schachteln kann 😀 [/edit]
[/edit]
Funktioniert es nun, und wenn nicht, was genau nicht?
 
Es funktioniert leider nicht ^^. Meine Editlogik ist, dass das oberste Edit das neuste ist 😀. Sorry für die Verwirrung.

Also ich zeichne Linien und um sie zu löschen zeichne ich über diese Linien nochmal mit der Hintergrundfarbe. Ich habe versucht ein AlphaComposite zu setzen (SRC_OVER und CLEAR ausprobiert), aber die Linie bleibt einfach bestehen.

Code mit dem ich male:
Java:
		malflaeche.getGraphics2D().setColor(new Color(0,0,0,0));
		malflaeche.getGraphics2D().setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR,0.0f));
		malflaeche.getGraphics2D().setStroke(new BasicStroke(pensize+1, BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND));
		malflaeche.getGraphics2D().setPaintMode();
malflaeche.getGraphics2D().drawLine(_pressedx, _pressedy, _lastx, _lasty);
 
Hab dir ein kleines Beispiel gemacht, ich hoffe das ist das was du meinst:
Java:
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Composite;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

public class TransparentMalen extends JFrame {

	private JPanel contentPane;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					TransparentMalen frame = new TransparentMalen();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame.
	 */
	public TransparentMalen() {
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 450, 300);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(new BorderLayout(0, 0));
		setContentPane(contentPane);	
		JLayeredPane layeredPane = new JLayeredPane();
		contentPane.add(layeredPane, BorderLayout.CENTER);
		
		KreisPanel kreisPanel=new KreisPanel();
		kreisPanel.setOpaque(false);
		kreisPanel.setBounds(20,20,120,120);
		
		QuadratPanel quadratPanel=new QuadratPanel();
		quadratPanel.setOpaque(false);
		quadratPanel.setBounds(20,20,120,120);
		
		layeredPane.add(kreisPanel, 50);
		layeredPane.add(quadratPanel,49);

	}
	
	
	class KreisPanel extends JPanel
	{	
		BufferedImage image=new BufferedImage(100,100,BufferedImage.TYPE_4BYTE_ABGR);
		Color alpha=new Color(0,0,0,0);
		Composite clear=AlphaComposite.getInstance(AlphaComposite.CLEAR);
		Composite over=AlphaComposite.getInstance(AlphaComposite.SRC_OVER);
		
		@Override
		public void paintComponent(Graphics g)
		{
			Graphics2D graph=(Graphics2D)g;
			Graphics2D g2d = (Graphics2D) image.getGraphics();
			
			g2d.setComposite(over);
			g2d.setPaint(Color.red);
			g2d.fillOval(0, 0, 100,100);
			
			g2d.setComposite(clear);
			g2d.setPaint(alpha);
			g2d.fillRect(45, 0, 10, 100);
			g2d.dispose();
			
			graph.drawImage(image,0,0,null);
			
		}
	}
	
	class QuadratPanel extends JPanel
	{		
		@Override
		public void paintComponent(Graphics g)
		{
			g.setColor(Color.blue);
			g.fillRect(0,0,100, 100);
		}
	}
}
 
Hey 🙂. Danke für euere Hilfe, das Problem ist gelöst. Musste nur einiges reimplementieren. Das Problem lag einmal beim PaintMode und in meinem Rubberband modus funktionierte der XORModus nicht mit der Transparenten Farbe. Habe ich nochmal selbst reimplementiert(beseitige einfach von Hand das alte Bild und male das neue).

Edit: Ach ja, auch dein Beitrag hat sehr geholfen bERt0r. So konnte ich sehen, dass ich das malen im Prinzip richtig mache. ^^


Das Forum hilft immer sehr gut weiter. Klasse. Nochmals vielen Dank! 🙂
 
Nur nebenbei: Warum machst du das so, mit dem Löschen und XOR und so? In den ALLERmeisten Fällen malt man in der paintComponent einfach alles, was gemalt werden muss. Es gibt wenige Ausnahmen, bei denen so ein Buffer-Bild sinnvoll sein kann, aber das mit dem Löschen wirkt dann schon wieder dubios... Ich hoffe, du weißt, was du da tust 😉
 
Naja, in der Anwendung kann man wie z.B. bei Paint Rechtecke mit der Maus ziehen, das realisiere ich durch drawRect. Da man nur dieses Rubberband sehen soll und keinen großen schwarzen Kasten muss ich beim Draggen die alte Zeichnung löschen und die Neue zeichnen. Da ich nicht unnötig die ganze Leinwand neumalen möchte übermale ich eben exakt die Stellen, die ich vorher angemalt habe.

Gibt es denn andere performante Wege das zu tun (ohne, dass das Rubberband beim ziehen flackert?). Also ich wüsste jetzt nicht, was an der Lösung schlecht sein sollte.:reflect:
 
Woher kommt denn der "große schwarze Kasten"? Eventuell sollte man nicht alles gleich direkt aufs Bild malen, sondern als Objekt vorhalten und nur in der paintComponent zeichnen. So machen es ja auch diverse Malprogramme.
 
Woher kommt denn der "große schwarze Kasten"? Eventuell sollte man nicht alles gleich direkt aufs Bild malen, sondern als Objekt vorhalten und nur in der paintComponent zeichnen. So machen es ja auch diverse Malprogramme.

Die erste Frage verstehe ich nicht ^^. Also die gesetzte Farbe ist halt schwarz, und wenn ich ein Rechteck mit der Maus großziehen würde ohne alte Linien zu löschen würde man einen gefüllten schwarzen Kasten großziehen, den man auch nicht mehr kleiner machen könnte.

Welchen Vorteil würde das vorbehalten in einem Objekt denn haben? Welchen Nachteil hat denn dieses gepufferte malen? So wie ich das gelernt habe soll das gerade für solche Zeichenoperationen gut sein, an der Uni haben wir zumindest einen Paintklon genau so umgesetzt.
 
Die erste Frage verstehe ich nicht ^^. Also die gesetzte Farbe ist halt schwarz, und wenn ich ein Rechteck mit der Maus großziehen würde ohne alte Linien zu löschen würde man einen gefüllten schwarzen Kasten großziehen, den man auch nicht mehr kleiner machen könnte.
Heisst das, Du zeichnest vährend dem größer Ziehen einens Rechtecks die "Zwischenschritte" auf das Image? Das ist völliger Käse ;-) Sorry.
So ein Objekt zeichnet man frühestens beim Loslassen auf ein Image während des Ziehens zeichnet man es nur auf die Komponente.
Welchen Vorteil würde das vorbehalten in einem Objekt denn haben? Welchen Nachteil hat denn dieses gepufferte malen?
Der Vorteil wäre, dass es als eigenständiges Objekt vorliegt und so jederzeit bearbeitet werden kann.
 
Zuletzt bearbeitet:
Heisst das, Du zeichnest vährend dem größer Ziehen einens Rechtecks die "Zwischenschritte" auf das Image? Das ist völliger Käse ;-) Sorry.
So ein Objekt zeichnet man frühestens beim Loslassen auf ein Image während des Ziehens zeichnet man es nur auf die Komponente.

Der Vorteil wäre, dass es als eigenständiges Objekt vorliegt und so jederzeit bearbeitet werden kann.

Ich kann leider nicht folgen 😀. Während des Ziehens zeichnet man es auf die Komponente? Das hier ist der einzige Weg den ich kenne um etwas zu zeichnen 😀. Hättest du vielleicht irgendwo Beispielcode? Ich glaube es liegen grundlegende Verständnisprobleme vor.

PS. Meine Zeichencommandos sind Objekte, die sich quasi selbst zeichnen. Beim aktiven ziehen male ich jedoch in der Tat auf des pufferimage, das die paintComponent dann bei Gelegenheit darstellt.
PPS. Diese Art zu malen habe ich zum Teil aus diesen Tutorials:
Malen in Swing Teil 1: der grundlegende Mechanismus ? Byte-Welt Wiki
Malen in Swing Teil 2: ein einfaches Malprogramm ? Byte-Welt Wiki
 
Das ist wohl geeignet um wie mit einem Pinsel oder Stift auf Papier zu zeichnen - kommt mir aber trotztdem für den Zweck etwas zu kompliziert vor.
In Deinem Fall - so habe ich das verstanden - willst Du ja geometrische Objekte z.B. ein Rechteck aufziehen, d.h. Du musst erst die Größe zurecht ziehen und kannst dann das Rechteck in passender Größe auf das Papier malen. Wenn Du einen Kreis mit einem Zirkel malst setzt Du ihn ja auch nicht auf das Papier und ziehst ihn mit der Mine auf dem Papier in die passende Größe.

Hier findest Du mal ein Bespiel. Hatte glaube ich auch ein besseren, finde es aber gerade nicht.
in
Code:
actObject
des PaintingPanel wird die Referenz auf das zu zeichnende Objekt gehalten. Es kann noch beliebig in der Größe verändert werden. Sobald die Maustaste losgelassen wird, ist die Größe fest und das Objekt wird in einer Liste gespeichert (statt der Liste könnte man es hier dann auch auf ein Image zeichnen)
http://www.java-forum.org/java-basics-anfaenger-themen/100478-java-gui-swing-mvc-paradigma.html#post639128
 
Ja, genau das passiert bei mir unter anderem auch. Ich realisiere ein Whiteboard auf dem man Kritzeln und eben einige andere Dinge (wie geometrische Formen ziehen, aber auch Bilder/Fotos darstellen) kann. Deswegen brauche ich eine Leinwand, die allerlei darstellen kann.

Ich werde mir deinen Code auf jeden Fall einmal ansehen, vielen Dank für die Anregung. Auf den ersten Blick sehe ich aber keinen riesen Unterschied, nur dass ich mit drawImage in der paintComponent arbeite und du die gemoetrischen Formen per se malst. Aber ich kann mich auch vertun, muss ich mir alles erstemal genauer ansehen.
 
Auf den ersten Blick sehe ich aber keinen riesen Unterschied, nur dass ich mit drawImage in der paintComponent arbeite und du die gemoetrischen Formen per se malst.
Das ist im wesentlichen auch der einzige aber entscheidende Unterschied. Du malst auf ein Image und musst ggf. "radieren" ich male nur auf die Komponente.
Pinselstriche u.a. kann man ja direkt auf das Image zeichnen. Andere Sachen wie Bilder, Figuren... die man noch in Ihrer Größe und Position verändern können soll, würde ich - solange sie noch editierbar sind - nur auf die Komponente und erst wenn sicher ist, dass sie nicht mehr bearbeitet werden auf das Image malen.
 
Hmm, aber bei dir finden doch genauso Radierungen statt oder nicht? Ich verstehe ehrlich gesagt noch nicht, wo hier der (performance?) Unterschied liegen soll. Mit einem repaint() forderst du das panel ja auf sich selbst (also sein Image) neu zu zeichnen. Das heisst auch ein resize von dir wird das Radieren des alten Images mit sich führen, nur werden nicht die alten Stellen übermalt sondern (ob fehlendem Clipping) die komplette Leinwand neugemalt(was sicher nur am Beispiel liegt).

Oder nicht? Ich glaube ich stehe auf dem Schlauch :/.
 
Ich habe den Thread nicht von Anfang an mitverfolgt, aber Du musst ja gezielt die von Dir verursachten "Schlieren" wieder beseitigen. Während mir die "Schlieren" egal sind.
Bei mir wird durch das repaint() die "Leinwand" quasi auch radiert, aber einfach in dem ein Eimer weiße Farbe drüber gekippt und das Bild noch mal neu aufgebaut wird. Wobei in deinem Fall ja auch repaint benötigt wird um das geänderte Bild neuanzuzeigen. Ich radiere mit weiß Du mit einem Bild (was man wie gesagt in meinem Bsp auch so machen könnte)

Bzgl. Performance erwarte ich bei einen so simplen Malprogramme keine Probleme. Wenn man will kann man mit der Clipping Area arbeiten.
Aber grundsätzlich gibt es diesbzgl. keine Unterschiede in Deinem Vorgehen und meinem Bsp. Du änderst etwas und musst repaint() aufrufen, damit es für den Anwender sichtbar wird und ich ändere etwas und rufe repaint() auf. Unterschiede in der Performance würde man erst merken, wenn man immer wieder ziemlich viele Objekte neu zeichnen müsste, die man aber wie gesagt auch in meinem Bsp. auf ein BufferedImage malen kann. Dann hätte man zusätzlich zu Deinem Bild noch ein Rectangle oder sonstiges Objekt.
 
Ja, das zuletzt gesagte war vielleicht der Kackpu.. Knackpunkt. Wenn man sowas macht wie
Java:
private List<Rectangle> rectangles = ...
protected void paintComponent(Graphics g)
{
    super.paintComponent(g);
    for (Rectangle r : rectangles) draw(r, rectangle);
}
dann werden bei JEDEM Neuzeichnen ALLE Rechtecke neu gemalt. Das ist sehr, sehr lange egal: Selbst wenn es 10000 Rechtecke sind, geht das noch schneller, als man gucken kann.

Wenn man aber wirklich "viele" Objekte hat (oder "aufwändigere" als Rechtecke - z.B. mit GradientPaint gefüllte, komplexe Shapes) dann kann das langsam werden. In diesem Fall könnte man diese angedeutete Mischform implementieren: Das aktuell gezeichnete Objekt wird in der paintComponent gemalt, und wenn es fertig ist, in das Bild gelegt. Das Bild zu zeichnen ist immer gleich schnell, egal, was auf dem Bild drauf ist.

Im Pseudocode (!) angedeutet wäre das sowas
Java:
class Painting
{
    private BufferedImage image = ...

    private Rectangle currentRectangle = null;

    protected void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        g.drawImage(image, 0, 0, null); // Male alles, was schon fertig ist, als Bild

        // FALLS man gerade dabei ist, ein Rechteck zu zeichnen, male das über das Bild:
        if (currentRectangle != null) 
        {
            draw(g, currentRectangle);
        }
    }

    public void mousePressed(MouseEvent e)
    {
        // Fange an ein rechteck zu malen
        currentRectangle = new Rectangle(e.getX(), e.getY(), 1,1);
        repaint();
    }

    public void mouseDragged(MouseEvent e)
    {
        // Verändere die Größe des Rechtecks passend zur Mausbewegung
        currentRectangle.width = computeNewWidth(e);
        currentRectangle.height = computeNewHeight(e);
        repaint();
    }

    public void mouseReleased(MouseEvent e)
    {
        // Male das fertige Rechteck ins Bild
        draw(image.getGraphics(), currentRectangle);
        currentRectangle = null;
        repaint();
    }

In Wirklichkeit ist das an manchen Stellen noch ein bißchen "frickeliger", aber kann eine Alternative sein...
 
Das Bild zu zeichnen ist immer gleich schnell, egal, was auf dem Bild drauf ist.

Eben das war mein Gedanke. Also ist mit meiner Implementierung ja garnichts verkehrt. Man könnte für die kurze Dauer der Manipulation durch den User vielleicht irgendwas einbauen, aber ich finde es so wie es bei mir ist ziemlich gemütlich(und so selten/kurz wie Manipulation im vergleich zur schlichten Darstellung vorkommt vernachlässigbar). Alles was ich mag auf das gepufferte Image hauen und paintComponent wird es darstellen wie es das halt in jedem Durchlauf auch darstellt.

Dennoch gute Anregungen 🙂. Ich sage es zu oft, aber ist ein schönes Forum hier ^^. Ich bin schon gespannt was ich zu hören bekomme, wenn ich demnächst mit meinen zich Problemen in Punkto Animation angekrochen komme ^^.:toll:
 
Nebenbei bemerkt: wenn Du in "draw" immer ein neues Image anlegst, dann hilft "resetImage" kaum etwas; und wenn Du "repaint" immer ohne Argumente aufrufst, dann nützt "getClipBounds" auch nicht viel.

Gruß,
André
 
Nebenbei bemerkt: wenn Du in "draw" immer ein neues Image anlegst, dann hilft "resetImage" kaum etwas; und wenn Du "repaint" immer ohne Argumente aufrufst, dann nützt "getClipBounds" auch nicht viel.

Gruß,
André

Ja, dessen bin ich mir bewusst ^^. Das ist nur hier im KSKB so, im echten Projekt wird das Image nicht seperat erstellt und repaint bekommt x,y,w und h des zu erneuernden Bereichs mit.
 

Neue Themen


Zurück
Oben