# kleines Zeichenprogramm



## jobu0101 (23. Dez 2005)

Ich habe versucht mal selbst ei kleines Zeichenprogramm zu programmieren. Das kann jetzt noch nichts außer in einer Farbe was malen. Auch wenn man das Fenster minimiert und dann wieder maximiert, ist alles weg!
Doch das soll mich erstmal nicht stören, habe nämlich ein ganz anderes Problem: Wenn ich die Maus zu schnell bewege, dann zeichnet er nicht durchgänige Linien, sondern nur Punkte, weil es für ihn eben halt zu schnell ist! In Programmen wie Paint, ist das nicht der Fall, ist zwar auch in einer schnelleren Programmiersprache geschrieben, doch meine Frage ist nun, ob sowas auch in Java möglich ist.

Hier mal mein Programmcode:


```
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Arc2D;
import java.awt.geom.Rectangle2D;

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

public class test03 extends JPanel {
	static int x, y;

	static boolean zeichne = false;

	static test03 gpanel = new test03();;

	protected void paintComponent(Graphics g) {
		int breite = gpanel.getWidth();
		int hoch = gpanel.getHeight();
		Shape wrechteck = new Rectangle2D.Double(0, 0, breite, hoch);
		Shape pinsel = new Arc2D.Double(x - 5, y - 5, 10, 10, 0, 360, Arc2D.PIE);

		if (zeichne == false) {
			g.setColor(Color.WHITE);
			((Graphics2D) g).fill(wrechteck);
		} else {
			zeichne = false;
			g.setColor(Color.BLACK);
			((Graphics2D) g).fill(pinsel);
		}
	}

	public static void main(String args[]) {

		JFrame f = new JFrame("Malprogramm");
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.setSize(300, 300);
		Container con = f.getContentPane();
		con.setLayout(new GridLayout(0, 1, 0, 0));
		con.add(gpanel);
		f.setVisible(true);
		gpanel.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent arg0) {
				zeichne = true;
				x = arg0.getX();
				y = arg0.getY();
				gpanel.repaint();
			}
		});
		gpanel.addMouseMotionListener(new MouseMotionListener() {
			public void mouseDragged(MouseEvent arg0) {
				zeichne = true;
				x = arg0.getX();
				y = arg0.getY();
				gpanel.repaint();
			}

			public void mouseMoved(MouseEvent arg0) {
			}
		});
	}
}
```


----------



## André Uhres (23. Dez 2005)

DrawOnImage


----------



## Roar (23. Dez 2005)

jobu0101 hat gesagt.:
			
		

> In Programmen wie Paint, ist das nicht der Fall, ist zwar auch in einer schnelleren Programmiersprache geschrieben, doch meine Frage ist nun, ob sowas auch in Java möglich ist.


lol der is gut  das hat nix damit zu tun dass manche glauben ein c++ programm sei schneller als ein java programm, sondern damit, dass die programmierer es richtig programmiert haben 
 :gaen:


----------



## jobu0101 (23. Dez 2005)

Roar hat gesagt.:
			
		

> jobu0101 hat gesagt.:
> 
> 
> 
> ...



Genau das ist ja meine Hoffnung!

Deshalb habe ich das ja hier gepostet! Wieprogrammeirt man sowas denn richtig?


----------



## Bleiglanz (23. Dez 2005)

das hast du in der Form auch Paint und z.B. in jedem schnellen Programm in C++ und der Win32 API, die Ereignisse werden halt vom OS nicht schnell genug weiterverarbeitet

Lösung: du merkst dir den "letzen" Punkt und ziehst dann eine Linie zum "aktuellen" Punkt


----------



## SlaterB (23. Dez 2005)

was Andre_Uhres sagen wollte:
du malst bisher direkt auf der Komponente, aber nur einmalig,
irgendwann wird das Bild ja mal völlig gelöscht und wurde vorher nicht gespeichert,
also solltest du auf einem Image-Objekt malen 
und in paint einfach immer das Image-Objekt zeigen,

problematisch ist auch dass du irgendwie ständig die Zeichenfläche weiß übermalst (wenn zeichnen = false),

das ist natürlich ziemlich tötlich selbt beim Zeichnen auf ein Image 
bei jedem repaint der nicht durch ein MosueEvent ausgelöst wird (z.B. ein repaint nach Größenänderung)
wird die Zeichenfäche weiß neu gestrichen 

----------

zu den Sprüngen:
merke dir den vorherigen x,y Punkt und male jedesmal eine Linie zwischen den letzten und den neuen Punkt,

bei deiner dicken Linie wird das natürlich ein Problem, da musst du dir was angepasstes überlegen,
eventuell berechnest du die Entfernung und malst genügend Zwischenpunkte

----------

mit kleinen Erweiterungen und bisschen aufgeräumter als Anregung:


```
import java.awt.*;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.awt.geom.Arc2D;
import java.awt.geom.Rectangle2D;

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



public class ZeichenPanel extends JPanel {

	private int oldx, oldy;
	private int x, y;
	private boolean dragged = false;
	private boolean lastPointPainted = true;
	private Image image = null;

	public ZeichenPanel() {
		addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent arg0) {
				x = arg0.getX();
				y = arg0.getY();
				oldx = x;
				oldy = y;
				repaint();
			}
			public void mouseReleased(MouseEvent e) {
				dragged = false;
			}

		});
		
		addMouseMotionListener(new MouseMotionListener() {
			public void mouseDragged(MouseEvent arg0) {
				if (!lastPointPainted) {
              // MouseEvent ignorieren wenn vorheriger Punkt noch nicht gemalt wurde
					return;
				}
				lastPointPainted = false;
				oldx = x;
				oldy = y;
				x = arg0.getX();
				y = arg0.getY();
				
				if (!dragged) {
					oldx = x;
					oldy = y;
					dragged = true;
				}

				repaint();
			}

			public void mouseMoved(MouseEvent arg0) {
			}
		});
	}

	protected void paintComponent(Graphics g) {
		if (image == null) {
			int breite = getWidth();
			int hoch = getHeight();

			image = createImage(breite, hoch);

			Shape wrechteck = new Rectangle2D.Double(0, 0, breite, hoch);
			image.getGraphics().setColor(Color.WHITE);
			//((Graphics2D) image.getGraphics()).fill(wrechteck);
		}
		zeichne(image.getGraphics());
		
		g.drawImage(image,0,0,this);
	}

	private void zeichne(Graphics g) {
		Shape pinsel = new Arc2D.Double(x - 5, y - 5, 10, 10, 0, 360, Arc2D.PIE);
		g.setColor(Color.BLACK);
	//	((Graphics2D) g).fill(pinsel);
		g.drawLine(oldx,oldy,x,y);
	
		lastPointPainted = true;
	}

	public static void main(String args[]) {

		JFrame f = new JFrame("Malprogramm");
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.setSize(600, 600);
		Container con = f.getContentPane();
		con.setLayout(new GridLayout(0, 1, 0, 0));
		con.add(new ZeichenPanel());
		f.setVisible(true);
	}
}
```

ein Problem am Rande:
die repaint-Operation kommt teilweise nicht so schnell hinterher wie die Maus neue Events liefert,
das heißt dass manchmal mehrere neue Punkte durch das Mouseevent definiert werden bevor die letzten
überhaupt gezeichnet wurden -> Lücken selbst wenn man einen Punkt merkt,

Lösung: mehrere Punkte merken oder mit dem Aufzeichnen eines neuern Punktes warten bis der vorherige gezeichnet wurde (siehe lastPointPainted-Variable im Programm, am besten auch mal rausnehmen um die Lücken zu sehen)


----------



## André Uhres (23. Dez 2005)

Ich weiss nicht ob es bemerkt wurde dass DrawOnImage ein Link ist zu einem Post vom Autor camickr.
Er ist im Sun Java Forum *der* Swing Spezialist. Seine Lösung ist auch net schlecht.


----------



## jobu0101 (23. Dez 2005)

Danke an euch alle, ihr habt mir geholfen!

@SlaterB: Man müsste beim Vergrößern des Fensters auch das Bild vergrößern. Aber das ist natürlich nur eine Kleinigkeit, um die es hier garnicht ging!


Edit:

Aber habe doch noch eine Frage:

in dem


```
if (image == null) {
```

Teil wird die Grafik angelegt und er soll ein weißes Rechteck zeichnen. Der Befehl für das weiße Rechteck ist also Kommentar geschrieben. Macht man die Kommentarstriche weg, wird das Rechteck aber schwarz. Woran liegt das?


----------



## SlaterB (23. Dez 2005)

oja, das wollte ich noch testen und hatte es vergessen,
ich denke es liegt daran dass bei jedem image.getGraphics()-Aufruf das immergleiche Objekt auf die Standardfarbe Schwarz zurückgesetz wird,

folgendes tuts:
Graphics2D g2 = image.getGraphics();
g2.setColor(Color.GREEN); 
g2.fill(wrechteck);

----------

die Variante aus dem anderen Forum ist natürlich viel schicker,
ich dachte erst da stände nur erwas zum BufferedImage


----------



## jobu0101 (23. Dez 2005)

muss aber gecastet werden:

Graphics2D g2 = (Graphics2D) image.getGraphics();

dann klappts!


----------



## jobu0101 (30. Apr 2006)

André Uhres hat gesagt.:
			
		

> DrawOnImage



Zu dem Beispiel habe ich noch eine Frage:

Da gibt es folgende Funktion:


```
private JButton addButton(Color color)
    {
        JButton button = new JButton();
        button.setBackground(new Color(230,240,250));
        button.setBorder(BorderFactory.createEtchedBorder());
 
        if (color != null)
        {
            button.setForeground(Color.white);
            button.setBackground(color);
        }
 
        button.setText("Paint");
        buttonPanel.add(button);
        button.addActionListener(this);
 
        return(button);
    }
```

Worauf bezieht sich denn da das this in dieser Zeile:


```
button.addActionListener(this);
```


----------



## André Uhres (1. Mai 2006)

jobu0101 hat gesagt.:
			
		

> Worauf bezieht sich denn da das this in dieser Zeile:
> 
> ```
> button.addActionListener(this);
> ```


Auf den Frame. Der ist ja der ActionListener:

```
public class DrawOnImage extends JFrame implements ActionListener
```


----------



## jobu0101 (1. Mai 2006)

André Uhres hat gesagt.:
			
		

> jobu0101 hat gesagt.:
> 
> 
> 
> ...



stimmt, klar! Den hatte ich übersehen und dieganze Zeit mich gewundert, warum das funktioniert


----------

