QPainter Problem

Alles zum Qt Framework für Java
Tobi1988
Beiträge: 28
Registriert: 13. Juni 2008 09:14

QPainter Problem

Beitrag von Tobi1988 »

Hallo zusammen,

habe heute ein neues Projekt angefangen, wo ich mich mit Zeichnen mit Qt Jambi beschäftigen möchte. Leider habe ich direkt auch das erste Problem:

Code: Alles auswählen

public class Zeichnen extends QWidget {

	private int x, y, lm;

	private QPainter painter = null;

	private QPixmap pixmap = new QPixmap(":/forms.JPG");

	private QColor color = new QColor();

	private QPen pen = new QPen();

	public static void main(String[] args) {
		QApplication.initialize(args);

		Zeichnen draw = new Zeichnen();
		draw.show();
		QApplication.exec();
	}

	public Zeichnen() {
		// super(parent);
		painter = new QPainter(this);
		x = y = lm = 0;
		resize(300, 200);

	}

	public void mousePressEvent(QMouseEvent event) {
		if (event.button() == Qt.MouseButton.LeftButton) {
			x = event.x();
			y = event.y();
			lm = 1;
			update();
		}
		if (event.button() == Qt.MouseButton.RightButton) {
			x = event.x();
			y = event.y();
			lm = 2;
			update();
		}
	}

	public void paintEvent(QPaintEvent event) {
		if (lm == 1) {
			color.setRed(255);
			color.setGreen(0);
			color.setBlue(0);
			pen.setColor(color);
			painter.setPen(pen);
		} else {
			color.setRed(0);
			color.setGreen(0);
			color.setBlue(255);
			pen.setColor(color);
			painter.setPen(pen);
		}

		painter.drawPoint(x, y);
		painter.drawPixmap(0, 0, pixmap);
		color.setRed(0);
		color.setGreen(255);
		color.setBlue(0);
		pen.setColor(color);
		painter.setPen(pen);
		painter.drawText(5, 180, "Links oder Rechts klicken");
		painter.end();
	}
}
Das Problem ist, dass "painter" im Konstruktor anlege. Irgendwie funktioniert das nicht so ganz, weil wenn paintEvent aufgerufen wird, erkennt der "painter" nicht obwohl es ja im Konstruktor angelegt wurde. Wenn ich nun erst im paintEvent "painter" anglege, dann funktioniert es. Allerdings wird der zuvor gezeichnete Punkt dann wieder gelöscht. Deshalb wollte ich "painter" im Konstruktor anlegen. Ich danke schonmal im Vorraus auf die hoffentlich zahlreichen Antworten.

MfG
Tobi
Tobi1988
Beiträge: 28
Registriert: 13. Juni 2008 09:14

Beitrag von Tobi1988 »

Hi nochmal,

um es nochmal kürzer zu machen: Ich will eg nur einen Punkt malen. Wenn ich dann einen neuen Punkt male, soll der andere noch erhalten bleiben und nicht verschwinden. Ich bekomme das einfach nicht hin.

MfG Tobi
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Was hat ein QPainter mit irgend einem Punkt der verschwindet zu tun?

In paintEvent() muss alles neugezeichnet werden - also auch dein erster Punkt.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Tobi1988
Beiträge: 28
Registriert: 13. Juni 2008 09:14

Beitrag von Tobi1988 »

hmm danke. Hab irgendwie was durcheinander geworfen. Also muss ich meinen alten Punkt sozusagen zwischenspeichern, um ihn dann beim nächsten paintEvent() nochmals zeichnen. Danke erstmal für die Hilfe. Ich glaube, dass ich es jetzt verstanden habe.

MfG Tobi
Tobi1988
Beiträge: 28
Registriert: 13. Juni 2008 09:14

Beitrag von Tobi1988 »

hab das jetzt hinbekommen mit dem zeichnen. Nur jetzt tritt ein Problem auf. Wenn ich nun eine Linie zeichnen will, und ich ziehe die Maus sehr schnell, dann werden nur einzelne Pixel gemalt. Wenn ich langsam ziehe funktioniert das einwandfrei. Kann mir jemand sagen woran das liegt?

MfG
Tobi
Tobi1988
Beiträge: 28
Registriert: 13. Juni 2008 09:14

Beitrag von Tobi1988 »

Hallo nochmal. Habe das Problem jetzt schon längere Zeit gelößt bekommen.

Ich hatte mouseMoveEvent nicht verwendet.

Nun wollte ich versuchen die "Zeichenfläche" in eine QScrollArea zu machen, damit ich bei großen Flächen halt scrollen kann. Dazu habe ich mir gedacht, dass ich das paintEvent so schreiben muss:

Code: Alles auswählen

protected void paintEvent(QPaintEvent event) {
		QPainter painter = new QPainter(ui.scroll);
		painter.drawImage(new QPoint(ui.x, ui.y), ui.image);
		painter.end();
	}
Leider tritt aus irgendeinem Grund ein Fehler auf und er zeigt mir dann nur die QScrollArea an.

Fehler:
QPainter::begin: Widget painting can only begin as a result of a paintEvent
QPainter::end: Painter not active, aborted

MfG Tobi
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Du musst schon das paintEvent von der ScrollArea überschreiben. Wird ja auch so in der Fehlermeldung gesagt.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Tobi1988
Beiträge: 28
Registriert: 13. Juni 2008 09:14

Beitrag von Tobi1988 »

Hallo nochmal,

danke für deine Hilfe, aber ich glaube, dass das mit dem paintEvent() usw noch nicht ganz verstehe. Ich poste mal den code und versuche zu erklären, was in welcher reihenfolge ausgeführt wird. Bitte sagt mir, wenn ich was falsch sage. Hier erstmal der Code:

Code: Alles auswählen


import com.trolltech.qt.core.QPoint;
import com.trolltech.qt.core.QSize;
import com.trolltech.qt.core.Qt;
import com.trolltech.qt.gui.QApplication;
import com.trolltech.qt.gui.QColor;
import com.trolltech.qt.gui.QImage;
import com.trolltech.qt.gui.QMouseEvent;
import com.trolltech.qt.gui.QPaintEvent;
import com.trolltech.qt.gui.QPainter;
import com.trolltech.qt.gui.QPen;
import com.trolltech.qt.gui.QResizeEvent;
import com.trolltech.qt.gui.QWidget;

public class ZeichnenImpl extends QWidget {

    Zeichnen ui = new Zeichnen();
    QPainter painter;
    QWidget scrollimage;
    QImage image;
    QPoint lastPoint;
    QPoint endPoint;

    public static void main(String[] args) {
        QApplication.initialize(args);

        ZeichnenImpl testZeichnenImpl = new ZeichnenImpl();
        testZeichnenImpl.show();

        QApplication.exec();
    }

    public ZeichnenImpl() {
        ui.setupUi(this);
    }
    
    protected void paintEvent(QPaintEvent event)
    {
        QPainter painter = new QPainter(this);
        painter.drawImage(new QPoint(0, 0), image);
    }
    
    private void drawto(QPoint endPoint) {
    	QPainter painter = new QPainter(image);
        painter.setPen(new QPen(QColor.red, 5, Qt.PenStyle.SolidLine, Qt.PenCapStyle.RoundCap,
                            Qt.PenJoinStyle.RoundJoin));
        painter.drawLine(lastPoint, endPoint);
        
        update();
        lastPoint = endPoint;
        
        

        painter.end();
    }
    
    protected void mouseMoveEvent(QMouseEvent event)
    {
        
            drawto(event.pos());
    }
    
    protected void mouseReleaseEvent(QMouseEvent event)
    {
      
            drawto(event.pos());
        
    }
    
    protected void mousePressEvent(QMouseEvent event)
    {

           lastPoint = event.pos();
        
    }
    
    protected void resizeEvent(QResizeEvent event)
    {

            image = resizeImage(image, new QSize(200, 200));

    }
    
    public QImage resizeImage(QImage image, QSize newSize)
    {
        

        QImage newImage = new QImage(newSize, QImage.Format.Format_RGB32);
        newImage.fill(new QColor(Qt.GlobalColor.white).rgb());
        QPainter painter = new QPainter(newImage);
        painter.drawImage(new QPoint(0, 0), image);
        painter.end();

        return newImage;
    }
}
Meine (hoffentlich) richtige Erklärung des Codes:
Beim Fenster öffnen wird das paintEvent und das resizeEvent(?!) aufgerufen. Wenn man eine Maustaste drückt, wird lastPoint auf die aktuelle Position gesetzt. Bewegt man nun die Maus, wird die methode drawto() aufgerufen, wo nun an lastPoint etwas im image gemalt wird. Durch update() wird nun das paintEvent() aufgerufen, welches das image im Fenster zeichnet und somit die Änderung auch auf dem Bildschirm angezeigt wird.

Ist das so richtig, wie ich das nun geschrieben habe oder werfe ich was durcheinander? Bei dem resizeEvent bin ich mir nicht ganz sicher. Aber das wird doch nur aufgerufen, wenn das Fenster geöffnet wird, und wenn man die Fenstergrößte ändert.

Jetzt verstehe ich leider nicht, wie du das meinst, dass ich die ScrollArea neu zeichnen soll.

painter.drawScrollArea (oder was ähnliches) gibt es ja nicht, oder wie meintest du das?

MfG Tobi
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Es ist ganz einfach - man kann im PaintEvent nur auf dsas Widget zeichnen für das das PaintEvent ist. Du versuchst im PaintEvent für ZeichnenImpl auf das Widget ui.scroll zu zeichnen. Das geht nicht.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Tobi1988
Beiträge: 28
Registriert: 13. Juni 2008 09:14

Beitrag von Tobi1988 »

Hi danke, dass du mir hilfst :-)

Ich habe nun eine neue "scroll"-Klasse erstellt, die von QScrollArea abgeleitet ist. Dort habe ich dann das paintEvent und alle anderen Sachen (mouseMoveEvent usw.) eingefügt. Mein paintEvent sieht nun so aus:

Code: Alles auswählen

protected void paintEvent(QPaintEvent event) {
			QPainter painter = new QPainter(this);
			painter.drawImage(new QPoint(ui.x, ui.y), ui.image);
			painter.end();
		}
Also genauso wie oben (wo ich das ohne ScrollArea habe und es funktioniert). Leider bleibt die Fehlermeldung. Muss ich jetzt auch noch ein paintEvent im parent Widget (also im Hauptfenster machen).

MfG Tobi
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Hast Du es auch aus dem Hauptwidget entfernt? Oder rufst Du paintEvent() direkt auf? Ansonsten glaube ich nicht das die Fehlermeldung so kommt.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Tobi1988
Beiträge: 28
Registriert: 13. Juni 2008 09:14

Beitrag von Tobi1988 »

Also im Hauptwidget (Konstruktor) erstelle ich nur das Objekt von scroll. Weiß nicht genau, was du mit paintEvent direkt aufrufen meinst. Poste dazu mal den Quellcode:

Code: Alles auswählen

public ZeichnenImpl() {
        ui.setupUi(this);
		ui.taste = 0;
		setAttribute(Qt.WidgetAttribute.WA_StaticContents);
		scroll = new myscroll(this);
		scroll.setGeometry(ui.x, ui.y, 100, 100);
		
    }
    
    
	
    public class myscroll extends QScrollArea {
		
		public myscroll (QMainWindow fenster) {
			this.setParent(fenster);
		}
		
		protected void paintEvent(QPaintEvent event) {
			QPainter painter = new QPainter(this);
			painter.drawImage(new QPoint(ui.x, ui.y), ui.image);
			painter.end();
		}
		
		protected void mousePressEvent(QMouseEvent event)
	    {
			ui.lastPoint.setX(event.pos().x()-ui.x);
			ui.lastPoint.setY(event.pos().y()-ui.y);
			if(event.button() == Qt.MouseButton.LeftButton)
				ui.taste=1;
			else
				ui.taste=2;
	    } 
		
		protected void mouseMoveEvent(QMouseEvent event) {
			drawto(event.pos());
		}
		
		protected void resizeEvent(QResizeEvent event)
	    {
	         ui.image = resizeImage(ui.image, ui.image.size());
	    }
		
		protected void mouseReleaseEvent(QMouseEvent event)
	    {
	        if (event.button() == Qt.MouseButton.LeftButton || event.button() == Qt.MouseButton.RightButton) {
	            drawto(event.pos());
	    	}
	    }
		
		private void drawto(QPoint pos) {
			QPainter painter = new QPainter(ui.image);
			if(ui.taste==1) {
				painter.setPen(new QPen(QColor.red,15, Qt.PenStyle.SolidLine, Qt.PenCapStyle.RoundCap,
	                    Qt.PenJoinStyle.RoundJoin));
			}
			else {
				painter.setPen(new QPen(QColor.yellow,2));
			}
			pos.setX(pos.x()-ui.x);
			pos.setY(pos.y()-ui.y);
			painter.drawLine(ui.lastPoint,pos);
			update();
			ui.lastPoint=pos;
			painter.end();
			
		}
		
		
		
		private QImage resizeImage(QImage image, QSize newSize)
	    {
	        QImage newImage = new QImage(newSize, QImage.Format.Format_RGB32);
	        newImage.fill(new QColor(Qt.GlobalColor.black).rgb());
	        QPainter painter = new QPainter(newImage);
	        painter.drawImage(new QPoint(0, 0), image);
	        painter.end();

	        return newImage;
	    }
	}
Fehlermeldung:
QPainter::begin: Widget painting can only begin as a result of a paintEvent
QPainter::end: Painter not active, aborted

Ich verzweifel langsam :?

MfG
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Wie ich sagte - du hast immer noch

Code: Alles auswählen

 QPainter painter = new QPainter(ui.image); 
stehen und wunderst dich ...
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Tobi1988
Beiträge: 28
Registriert: 13. Juni 2008 09:14

Beitrag von Tobi1988 »

Funktioniert troztdem nicht :(

Code: Alles auswählen

    public class myscroll extends QScrollArea {
    	
    	private QImage image;
    	private QPoint lastPoint;
		
		public myscroll (QMainWindow fenster) {
			this.setParent(fenster);
			image = new QImage();
		}
		
		protected void paintEvent(QPaintEvent event)
	    {
	        QPainter painter = new QPainter(this);
	        painter.drawImage(new QPoint(0, 0), image);
	    }
	   
	    private void drawto(QPoint endPoint) {
	       QPainter painter = new QPainter(image);
	        painter.setPen(new QPen(QColor.red, 5, Qt.PenStyle.SolidLine, Qt.PenCapStyle.RoundCap,
	                            Qt.PenJoinStyle.RoundJoin));
	        painter.drawLine(lastPoint, endPoint);
	       
	        update();
	        lastPoint = endPoint;
	       
	       

	        painter.end();
	    }
	   
	    protected void mouseMoveEvent(QMouseEvent event)
	    {
	            drawto(event.pos());
	    }
	   
	    protected void mouseReleaseEvent(QMouseEvent event)
	    {
	            drawto(event.pos());
	    }
	   
	    protected void mousePressEvent(QMouseEvent event)
	    {
	           lastPoint = event.pos();
	    }
	   
	    protected void resizeEvent(QResizeEvent event)
	    {
	            image = resizeImage(image, new QSize(200, 200));
	    }
	   
	    public QImage resizeImage(QImage image, QSize newSize)
	    {
	       

	        QImage newImage = new QImage(newSize, QImage.Format.Format_RGB32);
	        newImage.fill(new QColor(Qt.GlobalColor.white).rgb());
	        QPainter painter = new QPainter(newImage);
	        painter.drawImage(new QPoint(0, 0), image);
	        painter.end();

	        return newImage;
	    } 
	}
Habe nun mal testweise nicht von QScrollArea sondern von QWidget abgeleitet (sonst alles gleich geblieben). Das hat dann funktioniert.

MfG
Tobi1988
Beiträge: 28
Registriert: 13. Juni 2008 09:14

Beitrag von Tobi1988 »

Ich habe das jetzt einfach mal so gelassen, dass ich von QWidget ableite und habe dann in der Hauptklasse ein Objekt davon erzeugt und das habe ich dann wiederum in eine ScrollArea gemacht. Etwas umständlich aber anders schein es nicht zu funktionieren.

Wenn es natürlich jemand geschaft hat, dass direkt in eine ScrollArea abzuleiten, dann würde mich es freuen, wenn ihr diesen Code posten könntet. Danke :D

MfG
Tobi
Antworten