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.:(
 

Marco13

Top Contributor
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
 

JDan

Mitglied
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 :D. 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:

Marco13

Top Contributor
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 :D [/edit]
[/edit]
Funktioniert es nun, und wenn nicht, was genau nicht?
 

JDan

Mitglied
Es funktioniert leider nicht ^^. Meine Editlogik ist, dass das oberste Edit das neuste ist :D. 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);
 

bERt0r

Top Contributor
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);
		}
	}
}
 

JDan

Mitglied
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! :)
 

Marco13

Top Contributor
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 ;)
 

JDan

Mitglied
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:
 

Michael...

Top Contributor
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.
 

JDan

Mitglied
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.
 

Michael...

Top Contributor
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:

JDan

Mitglied
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 :D. Während des Ziehens zeichnet man es auf die Komponente? Das hier ist der einzige Weg den ich kenne um etwas zu zeichnen :D. 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
 

Michael...

Top Contributor
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
 

JDan

Mitglied
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.
 

Michael...

Top Contributor
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.
 

JDan

Mitglied
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 :/.
 

Michael...

Top Contributor
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.
 

Marco13

Top Contributor
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...
 

JDan

Mitglied
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:
 

André Uhres

Top Contributor
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é
 

JDan

Mitglied
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.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
E Auf JPanel malen und davor JComponenten anzeigen AWT, Swing, JavaFX & SWT 12
N Schnelleres Malen AWT, Swing, JavaFX & SWT 22
Java_RY Bin Ratlos bzgl Malen in Swing AWT, Swing, JavaFX & SWT 5
M Punkte malen AWT, Swing, JavaFX & SWT 1
M Schrift "malen" AWT, Swing, JavaFX & SWT 11
Regedit JavaFX Java Canvas hört ständig auf zu aktualisieren/malen AWT, Swing, JavaFX & SWT 3
Z Auf ein JLabel drauf malen? AWT, Swing, JavaFX & SWT 1
J Swing Bild laden, Kreise drin malen, Schreiben AWT, Swing, JavaFX & SWT 2
L Gradient Hintergrund malen und durchscheinen lassen AWT, Swing, JavaFX & SWT 8
windl Querstreifen beim Bilder malen und anpassen an neue CPU AWT, Swing, JavaFX & SWT 12
S JButton in JLabel malen AWT, Swing, JavaFX & SWT 7
E JButton Text malen AWT, Swing, JavaFX & SWT 3
B 2D-Grafik Malen/übermalen mit Canvas AWT, Swing, JavaFX & SWT 5
K swing/awt Panel punkte malen AWT, Swing, JavaFX & SWT 4
G Auf Image malen AWT, Swing, JavaFX & SWT 12
B Wie Panel neu Laden/Malen/Aktualisieren AWT, Swing, JavaFX & SWT 14
G kreis malen -> welche funktion? AWT, Swing, JavaFX & SWT 3
V Framework zum Zeichnen/Malen? AWT, Swing, JavaFX & SWT 7
D bei Thread in JComponent malen NullPointerException AWT, Swing, JavaFX & SWT 3
J Einmal gleichzeitig auf zwei Graphics malen? AWT, Swing, JavaFX & SWT 5
C ".tif" Image in Java einbinden und malen lassen AWT, Swing, JavaFX & SWT 7
H auf einem Bild malen AWT, Swing, JavaFX & SWT 4
N malen => 1 Sekunde warten => malen AWT, Swing, JavaFX & SWT 2
V Punkte malen im Panel AWT, Swing, JavaFX & SWT 3
U Malen auf Buffered Image AWT, Swing, JavaFX & SWT 9
V Auf Knopfdruck malen ?????? AWT, Swing, JavaFX & SWT 5
P Zwei JPanel übereianderlegen AWT, Swing, JavaFX & SWT 14
XWing Basic JPanel mit 2 Buttons beutzen. AWT, Swing, JavaFX & SWT 10
G JPanel per Drag and Drop JButtons und Bilder ablegen AWT, Swing, JavaFX & SWT 1
G JPanel mit JButtons und Bilder AWT, Swing, JavaFX & SWT 5
N AWT JPanel zu Jframe hinzufügen AWT, Swing, JavaFX & SWT 2
M clear JPanel before repainting AWT, Swing, JavaFX & SWT 1
B ImageIcon auf JPanel austauschen AWT, Swing, JavaFX & SWT 3
T Swing Reload JPanel + darin liegende ProgressBar AWT, Swing, JavaFX & SWT 9
P Swing Mehrere JLabels mit ImageIcon in JPanel lesen AWT, Swing, JavaFX & SWT 1
E JScrollPane mit JPanel verbinden AWT, Swing, JavaFX & SWT 1
F JPanel Celleditor AWT, Swing, JavaFX & SWT 8
B JPanel-Inhalte inkl. JTextarea zoomen? AWT, Swing, JavaFX & SWT 3
B Mit ContentPane werden Komponenten angezeigt, mit SplitPane, JPanel nicht? AWT, Swing, JavaFX & SWT 6
CptK Funktionsgraphen effizient zeichnen und nur Teile von JPanel erneuern AWT, Swing, JavaFX & SWT 2
P Button simpler random auf einem JPanel verteilen? AWT, Swing, JavaFX & SWT 3
O Swing "Eigenes" JPanel wird dem JScrollPane nicht hinzugefügt AWT, Swing, JavaFX & SWT 5
Ich lerne Java. Swing Von JPanel A auf JPanel B zugreifen. AWT, Swing, JavaFX & SWT 4
A JPanel austauschen und Focus geben AWT, Swing, JavaFX & SWT 3
L JComponent aus JPanel anhand Mausposition ermitteln AWT, Swing, JavaFX & SWT 10
J JPanel wird nicht angezeigt AWT, Swing, JavaFX & SWT 2
B Verschiebbares JPanel "ruckelt" im Randbereich AWT, Swing, JavaFX & SWT 2
S Swing JPanel nimmt keinen KeyListener an AWT, Swing, JavaFX & SWT 7
K JLabel mit Bilder im nicht initialisierten JPanel hinzufügen AWT, Swing, JavaFX & SWT 5
Hatsi09 Swing JPanel Bild einfügen AWT, Swing, JavaFX & SWT 14
L JPanel zeigt keinen Inhalt AWT, Swing, JavaFX & SWT 1
dereki2000 JPanel mit Rückgbe wie bei JOptionPane AWT, Swing, JavaFX & SWT 3
E Hintergrundfarbe setzen in JPanel funktioneirt nicht AWT, Swing, JavaFX & SWT 4
P JPanel KeyListener hinzufügen AWT, Swing, JavaFX & SWT 8
S Nach scrollen verschwindet das zuvor im JPanel gezeichnete AWT, Swing, JavaFX & SWT 2
P Bewegung eines Balkens in eineum JPanel welches als Spielfeld fungiert AWT, Swing, JavaFX & SWT 2
L Swing JPanel Größe anpassen AWT, Swing, JavaFX & SWT 6
D Platzierung von JTextfield in JPanel AWT, Swing, JavaFX & SWT 3
D Swing Anwendung ohne JPanel erstellen AWT, Swing, JavaFX & SWT 1
M Swing JPanel in JScrollPane AWT, Swing, JavaFX & SWT 3
M Zwei JPanel übereinander nur vorderes "repainten" AWT, Swing, JavaFX & SWT 3
J 2D-Grafik Background einer Jpanel Klasse ändern AWT, Swing, JavaFX & SWT 1
J Ziehen eines Buttons im JPanel AWT, Swing, JavaFX & SWT 2
J Button lässt sich nicht auf dem JPanel verschieben AWT, Swing, JavaFX & SWT 5
D zwei JLabel stapeln in einem JPanel AWT, Swing, JavaFX & SWT 5
DaCrazyJavaExpert Swing JPanel "ContentPane" wird nicht gesetzt/angezeigt AWT, Swing, JavaFX & SWT 16
DaCrazyJavaExpert Swing Größe des JPanel ändern/wird nicht geändert. AWT, Swing, JavaFX & SWT 3
DaCrazyJavaExpert Swing JPanel wird in JScollPane nicht angezeigt AWT, Swing, JavaFX & SWT 2
it_is_all JPanel verschwindet nach Button-Klick AWT, Swing, JavaFX & SWT 2
B Bar Plot in Swing JPanel AWT, Swing, JavaFX & SWT 0
F Screenshot eines JPanel AWT, Swing, JavaFX & SWT 3
S JPanel rotieren, Bild ist abgeschnitten, Clipping? AWT, Swing, JavaFX & SWT 0
M Swing JPanel flüssig verschieben AWT, Swing, JavaFX & SWT 5
G Nur ein JPanel wird angezeigt AWT, Swing, JavaFX & SWT 9
kilopack15 JPanel im laufenden Zustand einfärben AWT, Swing, JavaFX & SWT 2
kilopack15 JPanel Farbverwaltung AWT, Swing, JavaFX & SWT 1
A JScrollPane soll JPanel mit JButtons enthalten und eine Scollbar anzeigen AWT, Swing, JavaFX & SWT 1
A Swing JLabels in einer ForEach Schleife an den JPanel anheften (UNO Netzwerkspiel) AWT, Swing, JavaFX & SWT 1
L JPanel zeichnet im Konstrukter erzeugten Hintergrund nicht AWT, Swing, JavaFX & SWT 10
Java_RY wie kann ich auf JButtons in einem JPanel zugreifen AWT, Swing, JavaFX & SWT 3
F Zeichnung einem JPanel im Layoutmanager zuweisen AWT, Swing, JavaFX & SWT 3
Meeresgott Swing Umgang mit JPanel AWT, Swing, JavaFX & SWT 4
R 2D-Grafik PNG Bild per Graphics auf JPanel AWT, Swing, JavaFX & SWT 9
K JPanel Bilder bei Windows nicht darstellbar AWT, Swing, JavaFX & SWT 6
W Swing JPanel nur einmal nach mehreren Änderungen neu zeichnen AWT, Swing, JavaFX & SWT 1
J Swing Zeichenfläche im JPanel des Haupfenster anzeigen lassen AWT, Swing, JavaFX & SWT 4
A Swing JPanel zeigt Buttons nicht an AWT, Swing, JavaFX & SWT 4
R JPanel überzeichnet alles? AWT, Swing, JavaFX & SWT 1
D Von JPanel auf anderes JPanel zugreifen AWT, Swing, JavaFX & SWT 9
L Swing Teile eines JPanel in eigene Klasse auslagern AWT, Swing, JavaFX & SWT 3
I JPanel - Verwaltung/ Anordnung AWT, Swing, JavaFX & SWT 4
T JComponents zur Laufzeit auf JPanel darstellen AWT, Swing, JavaFX & SWT 10
F Java Swing Rechteck in JPanel zeichnen AWT, Swing, JavaFX & SWT 7
J Linien auf JPanel zeichnen AWT, Swing, JavaFX & SWT 3
L ImageIcon auf JPanel wird nicht angezeigt(keiner Fehlermeldung) AWT, Swing, JavaFX & SWT 11
M Swing JPanel innerhalb eines Frames verschieben AWT, Swing, JavaFX & SWT 3
T JTextField Array im JPanel wird nicht komplett angezeigt AWT, Swing, JavaFX & SWT 7
K Swing JPanel ueber komplette Form legen AWT, Swing, JavaFX & SWT 1
W Swing Größenänderung vom JPanel im JScrollPane und anschließendes positionieren AWT, Swing, JavaFX & SWT 2
R Komponenten von JPanel bleiben unsichtbar AWT, Swing, JavaFX & SWT 2

Ähnliche Java Themen

Neue Themen


Oben