[gelöst] Mit QPainter in Widget zeichnen.

Alles rund um die Programmierung mit Qt
komaton
Beiträge: 11
Registriert: 2. September 2008 13:32

[gelöst] Mit QPainter in Widget zeichnen.

Beitrag von komaton »

Hi,

ich hab mal wieder ne kleine Frage zum Thema.
Also, ich hab ein QStackWidget welches meine Widgets beinhaltet welche als Tabs geöffnet sind. Klingt komisch, ist aber sehr schön funktional.
Das Stack Widget ist das Childwidget meiner QMainApp und ich möchte nu in dem jeweilig geöffneten Tab mit einem QPainter zeichnen, Rechtecke, Kreise, triviales Zeug halt.

Ich hab mir für das Zeichnen ne extra Klasse geschrieben welche selber nur nen Konstruktor, nen Destruktor und die Zeichenfunktion beinhaltet.

Konstruktor

Code: Alles auswählen

painting::painting( QWidget* newparentWidgetPointer, QPoint qp_newOffset)
{
	qp_offset = qp_newOffset;
	parentWidgetPointer = newparentWidgetPointer;
	painter = new QPainter();
}
Zeichenfnkt.

Code: Alles auswählen

void painting::paintEvent( QPaintEvent event )
{
	QRectF qr_rectangle(qp_offset.rx(), qp_offset.ry(), 90, 40);

	painter->begin(parentWidgetPointer);
	painter->setPen(Qt::NoPen);
	painter->setBrush(Qt::black);
	painter->drawRect(qr_rectangle);
	painter->end();
}

Einfacher geht fast nimmer, der parentWidgetPointer ist der Pointer des rufenden Widgets in dem gezeichnet werden soll.

Das Problem daran ist, das einfach mal nix passiert, weder wenn ich update aufrufe (was ja aber zwangsläufiig durch Qt selber passiert) noch wenn ich das versuche in nem separaten Widget zu zeichen, welches mit dem ganzen Programm rings um nichts zu tun hat

Irgendjemand ne Idee?
Danke schon im voraus, und ja, das Thema wurde schon mehrfach durchgekaut, habe diese Threads auch aufmerksam gelesen und ausprobiert. Leider ohne Erfolg

MfG Koma
Zuletzt geändert von komaton am 12. November 2008 10:38, insgesamt 1-mal geändert.
neuschi
Beiträge: 78
Registriert: 23. Mai 2007 10:59

Re: Mit QPainter in Widget zeichnen.

Beitrag von neuschi »

komaton hat geschrieben:Hi,
void painting::paintEvent( QPaintEvent event )
Wenn das wirklich so in deinem Programm steht, dann geht der da gar nicht rein: Die richtige Signatur des paintEvent ist:

void painting::paintEvent( QPaintEvent *event )

\Ralf
komaton
Beiträge: 11
Registriert: 2. September 2008 13:32

Danke erstmal fuer die Antwort ....

Beitrag von komaton »

... aber des Problems loesung ist sie nicht.

Ich vermute ich verstehe etwas grundsaetzliches an dem QPainter nicht.
Ich wollte keinen Eventhandler benutzen, sondern die Zeichenfunktionen der verschiedenen Objekte (Rechtecke, Kreise etc.) in eine separate Klasse auslagern und diese dann ueber Funktionsrufe benutzen.
Sprich ich haette dann, rein hypothetisch, eine Funktion namens paint die ich via

Code: Alles auswählen

zeichenKlasse->paint(targetWidget* )
aufrufen kann.

Und wie ich vermute, sollte sowas eigentlich ohne Probleme moeglich sein.
Denn eigentlich sollte der QPainter ueber den Widgetpointer mitgeteilt bekommen wo er zu zeichnen hat.

Debug is auch seltsam da weder der compiler fehler auspuckt, noch der debugger irgend ne unregelmaessigkeit zeigt, weswegen ich vermute das er schon zeichnet, aber nicht dort wo ich will.

Sofern jemand ne Idee hat, raus damit.
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Wie neuschi schon andeutete und die Doku es auch sagt kann man nur innerhalb von QWidget:::paintEvent( QPaintEvent *event ) zeichnen.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
komaton
Beiträge: 11
Registriert: 2. September 2008 13:32

danke ...

Beitrag von komaton »

.... aber das macht es schwieriger.

Ich ueberlad ja den QPaintEvent Eventhandler der QWidget Klasse mit meinem Zeichenalgorithmus, was das Problem mit sich bringt das ich in nem Widget zeichnen will was erst, zeitlich, spaeter existiert.
Nun ruft aber die Hauptroutine von Qt den Eventhandler bei der Initialisierung meines Programms mit auf und bekommt dort sozusagen nen Out of Range Adresse als Pointer, mit dem es natuerlich nix anfangen kann.
Es muss doch ne moeglichkeit geben das zu umgehen!

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

Beitrag von Christian81 »

Ja - einfach nur im paintEvent() - Aufruf zeichnen und fertig!

Beispiele dafür gibt es bei den Qt-.Examples und Demos ja genug...
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
komaton
Beiträge: 11
Registriert: 2. September 2008 13:32

Beitrag von komaton »

Ok, hab cih gemacht, aber trotz allem zeichnet er nicht.

Code: Alles auswählen

void gemo::paintEvent( QPaintEvent* event )
{
	list<staaux>::iterator stx_tmpIt;

	int i_tmpType;
	int startAngle = 30 * 16;
	int spanAngle = 120 * 16;

	QPoint obCursPos;

	obCursPos = cursorPosition;
	stx_tmpIt = l_staauxList.begin();

	if( tabWidget->count() > 0 )
	{
		QPainter painter(tabWidget->currentWidget());
		painter.begin(tabWidget->currentWidget());
		painter.setPen(Qt::SolidLine);
		painter.setPen(Qt::black);
		painter.setBrush(Qt::black);
	
		while(stx_tmpIt != l_staauxList.end())
		{
			QRectF qr_rectangle(obCursPos.rx(), obCursPos.ry(), 90, 40);
			obCursPos = stx_tmpIt->getOffset();
			i_tmpType = stx_tmpIt->getType();
	
			if( i_tmpType == 0 )
			{
				painter.drawRect(qr_rectangle);
			}
			else
			{	
				painter.drawArc(qr_rectangle, startAngle, spanAngle);
			}
			stx_tmpIt++;
		}
		painter.end();
	}
}
Zur erklaerung, ich hab ein widget welches als parent die mainapp hat, darin ist ein gridlayout fuer die anordnung von statusbar und workspacewidget.
Das Workspacewidget ist ein QStackWidget (tabWidget), welches einzelne tabs beinhaltet.
Daher, ich besorg mir das aktuelle Widget aus dem StackWidget

Code: Alles auswählen

tabWidget->currentWidget()
geb dem QPainter als PaintDevice, setz die Pen propertys und lasse meine objekte Zeichnen.
Die while Schleife dient nur dazu, das beim aktualisieren des Fensters auch alle vorherig
gezeichnetet Objekte mit neu gezeichnet werden (ja, koennte man auch ueber
QPaintEvent::region() loesen).
Der punkt ist, das der EventHandler korrekt aufgerufen wird aber unabhaengig davon nichts gezeichnet wird.
Wenn ich den QPainter direkt mit dem this Pointer initialisiere und das auch dem painter.begin() uebergebe, zeichnet er zwar, aber halt dann, wie zu erwarten,
irgendwo ins fenster der mainapp aber ni in das widget wo ich es haben will.

Und damit es nochma ganz klar wird wie die anordnung der widgets is:

Code: Alles auswählen

                                         mainApp    
                                                |
                                         QWidget  --------------------- in dem widget steckt noch mehr
                                                |                                     aber das hab ich hier weggelassen
                                      QGridLayout 
                                          |           |
                        QStackWidget     QStatusBar
                                    |                       |
                             QWidget               QLabel

In die QWidgets im QStackedWidget soll gezeichnet werden.
So, ich gebs zu, das erscheint etwas wirr, aber bis auf das zeichnen funktioniert halt alles.

Und es geht mir ni darum beim Start des Programms irgendwelche Objekte zeichnen zu lassen,
sondern der user soll in das Widget klicken koennen und an der Position wird dann ein Objekt gezeichnet.

Also wo liegt das Problem?

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

Beitrag von Christian81 »

Du malst schon wieder im falschen paintEvent(). Du musst die Zeichnerei in tabwidget::paintEvent() machen...
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
komaton
Beiträge: 11
Registriert: 2. September 2008 13:32

gut, danke, die quintessenz ....

Beitrag von komaton »

... wäre, das ich für mein tabWidget ne separate Klasse schreiben müsste die direkt von dem QStackedWidget erbt.
Seh ich das richtig?
Oder gibt es ne alternative den QStackedWidget EventHandler zu überladen ohne extra klasse?
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Ja, Du musst von der Klasse ableiten in der Du malen willst - anders geht es leider nicht.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Mit dem eventFilter kann man auch in einer anderen Klasse zeichnen.
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

upsala hat geschrieben:Mit dem eventFilter kann man auch in einer anderen Klasse zeichnen.
Wenn Dir das paintEvent() der Klasse nicht wieder alles killt, ja
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

In your reimplementation of this function, if you want to filter the event out, i.e. stop it being handled further, return true; otherwise return false.
Es dürfte demnach gar nicht erst aufgerufen werden, wenn ich true zurückgebe.
clohr
Beiträge: 7
Registriert: 7. November 2008 15:12

Beitrag von clohr »

Eine andere Frage:

kann man eigentlich auch mit QPainter und der Maus, Striche und Linien in ein Widget zeichnen?
paintEvent wird ja nur am Anfang aufgerufen, und z.B. wenn man das Fenster mit der Maus vergrößert oder verkleinert. Und ich wollte eigentlich Buchstaben und Zahlen in ein Widget zeichnen. Da funktioniert das mit dem paintEvent so gut wie gar nicht.
Wenn jemand eine Lösung für das Problem hat, wäre ich dankbar.
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Da funktioniert das mit dem paintEvent so gut wie gar nicht.
Das ist weder eine Fehlermeldung, noch eine nachvollziehbare Beschreibung.

Außerdem gibt es auch für diesen Fall in den Examples ein passendes Beispiel.
Antworten