Per Button auf einem im QtDesigner erstellten Widget zeichne

Verschiedenes zu Qt
Antworten
Qt-nator
Beiträge: 153
Registriert: 18. Dezember 2007 10:31

Per Button auf einem im QtDesigner erstellten Widget zeichne

Beitrag von Qt-nator »

Hallo,

ich habe folgendes Problem und zwar habe ich mir mit dem QtDesigner eine Oberfläche erstellt bei der man Werte in QLineEdits eingeben kann und Ergebnise werden dann ausgegeben wenn man auf den Button klickt. Ich möchte dies jetzt zur veranschaulichung um eine Zeichnung erweitern darum hab ich unter meine Buttons, Labels und LineEdits im Designer ein neues Widget erstellt und in dieses möchte ich jetzt zeichnen. (Wird eine Parabel)

Nur weis ich nicht wie ich jetzt in dieses Widget zeichnen kann. Das einzige was ich hinbekommen habe war ins MainWindow zeichnen aber mein Widget wo ich reinzeichnen möchte liegt ja auf dem MainWindow.

Also ich möchte wenn der Button gedrückt wird zusätzlich zur Ausgabe der Werte noch eine Parabel in ein Widget zeichnen was im Designer schon vorhanden ist.

Hoffe man versteht was ich möchte, für schnelle Hilfe wäre ich sehr dankbar.

Gruß

Qt-nator
Spinoza
Beiträge: 23
Registriert: 4. März 2011 01:07

Beitrag von Spinoza »

Hi,
dazu solltest du ein eigenes Widget von QWidget ableiten. Dort reimplementierst du dann die QWidget::paintEvent methode und zeichnest darin mittels eines QPainters.
Im QtDesigner erzeugst du wie bereits geschehen ein einfaches QWidget, setzt es allerdings (siehe rechtsklick) als Platzhalter für deine abgeleitete Klasse.

In den Qt-Beispielen ist das nochmal sehr ausführlich gezeigt:
http://doc.qt.nokia.com/latest/painting ... awing.html

Für dich sind dort speziell die Abschnitte "RenderArea Class Definition" (das ist das von QWidget abgeleitete Zeichenwidget) und "RenderArea Class Implementation" relevant.

Falls das Setzen eines Widgets als Platzhalter (engl. promoting widgets) noch nicht klar ist:
http://doc.qt.nokia.com/latest/designer ... dgets.html
Qt-nator
Beiträge: 153
Registriert: 18. Dezember 2007 10:31

Beitrag von Qt-nator »

Erstmal vielen dank hat mir sehr geholfen, kann jetzt in das andere Widget zeichnen.

Nur hab ich jetzt noch 2 probleme und zwar: Ich kann zwar in das richtige Widget zeichnen nur halt noch nicht wenn ich ein Button drücke sondern wenn ich das Widget erstelle. Und ich weis nicht wie ich das zeichnen mit dem Button verbinden kann. Und 2tens hab ich schonmal einfach so versucht eine Parabel zu zeichnen mittels punkte habe halt eine schleife gemacht und x wert gesetzt und y wert halt ² genommen. Nur kann ich das wenn ich das im PaintEvent mach nur sehr große schritte wählen sonst hängt sich das Programm dann auf. Und ich wollte halt so 0.1er abschnitte machen aber das geht nicht. Gibts da alternativen?

Danke schonmal

Qt-nator
Spinoza
Beiträge: 23
Registriert: 4. März 2011 01:07

Beitrag von Spinoza »

Zunächst mal musst du zwischen Pixel-Koordinaten und den mathematischen Koordinaten der Parabel unterscheiden. Wenn du 0.1-Intervalle in Pixelkoordinaten machst, ist es kein Wunder, wenn das Ganze langsam wird. Das ist auch genauer als es dein Bildschirm überhaupt darstellen könnte (zehn Punkte pro x-Pixel). Typischerweise geht man so vor, dass man die mathematische Funktion grob im Vergleich zur x-Auflösung abtastet, und dazwischen linear interpoliert (gerade linien zeichnet). Fortgeschrittenere Algorithmen berechnen numerisch die zweite Ableitung der Funktion und passen die Abtast-Schrittweite der Krümmung an, sodass bei starken "Biegungen" ein runderer Verlauf entsteht.

Wenn dir das wiederkehrende Neuzeichnen dennoch zu langsam ist, kannst du die gezeichnete Grafik auch zwischenpuffern, indem du alles in ein QPixmap zeichnest, und im paintEvent immer nur dieses Pixmap auf das Widget zeichnest.

Das Zeichnen auf Knopfdruck musst du über entsprechende Funktionen/Slots deines QWidget machen. z.B. ein Slot "parabelZeichnen()", welcher dann in die Pixmap eine Parabel zeichnet.
Der Knofdruck ruft dann diesen slot auf, sowie ein update() um einen paintEvent herbeizuführen.
Qt-nator
Beiträge: 153
Registriert: 18. Dezember 2007 10:31

Beitrag von Qt-nator »

Also ich krieg das irgendwie nicht hin. Ich hab jetzt nen Slot Neuzeichnen und wenn ich den Button drück kommt der dann. Aber ich kann jetzt nichts neues ins Widget zeichnen. Ich kann z.b. ne msg Box öffnen über den Button aber nichts neues zeichnen. Zeichnen kann ich irgendwie immer nur im paintevent.

Also wenn ichs z.b. so mache:

void ZeichenWidget::Neuzeichnen()
{
QPainter painter(this);
painter.drawLine(0,0,50,50);
}

dann kommt

QPainter::begin: Paint device returned engine == 0, type: 1

Und nichts wird gezeichnet. Nur kann ich doch nicht alles im Paintevent zeichnen lassen weil das kommt doch immer gleich beim Starten des Programms. Ich will ja auch noch Werte übergeben und dann halt per Button click zeichnen.

Aufjedenfall hab ich ein Mainwindow und ein ZeichenWidget was von QWidget abgleitet ist in das ich reinzeichnen will. Was ja auch übers paintevent geht. Und ich hab nen Neuzeichnen Slot denn ich über den Button aufrufen kann. Nur wie kann ich jetzt auserhalb des paintevents zeichnen.

Und später dann wegen dem zeichnen ansich interpolieren und ableiten ist für mich dann ein wenig zu komplixiert / aufwendig. Gibts da keine alternativen?
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

Qt-nator hat geschrieben:...Nur kann ich doch nicht alles im Paintevent zeichnen lassen weil das kommt doch immer gleich beim Starten des Programms.
...
Ist doch vollkommen egal.. dann machst du halt eine Statemachine:

Code: Alles auswählen


//----------------------------------------------------------------
ZeichenWidget::ZeichenWidget.....
{
  mZeichneParabel = false;
}


//----------------------------------------------------------------
void ZeichenWidget::Neuzeichnen()
{
  mZeichneParabel=true;
  update(); // Request fuer das paintEvent
} 


//----------------------------------------------------------------
void ZeichenWidget::paintEvent(...
{
  if (mZeichneParabel) {
    QPainter painter(this);
    painter.drawLine(0,0,50,50);
  }
  QWidget::paintEvent(..);
}
Im gleichen Stil kannst du problemlos die Graphik wieder ausschalten oder die Werte (der Parabel) ändern..

hth..
Spinoza
Beiträge: 23
Registriert: 4. März 2011 01:07

Beitrag von Spinoza »

Qt-nator hat geschrieben:Und ich hab nen Neuzeichnen Slot denn ich über den Button aufrufen kann. Nur wie kann ich jetzt auserhalb des paintevents zeichnen.
Wie bereits gesagt, du zeichnest zunächst in ein QPixmap - das geht auch ausserhalb des PaintEvents (Solange du's im GUI-Thread machst, aber das dürfte für dich kein Thema sein). Im PaintEvent zeichnest du immer nur dieses Pixmap in das Widget.

Mit einer Statemachine würd' ich das nicht machen, da sie hier das falsche bzw. ein nicht sonderlich skalierbares Konzept ist. Besser wäre vielleicht ein Container, der alle zu zeichnenden Objekte (Parabeln, andere Funktionen,...) abstrakt enthält. In der Zeichenroutine wird dann dieser Container abgearbeitet und die Sachen darin tatsächlich gezeichnet.
Davon unabhängig kann dein Button dann in diesen Container z.B. das Objekt einfügen, welches der Parabel entspricht. Besonders elegant wäre es natürlich, wenn sich die Objekte im Container selbst zeichnen könnten, mit einer eigenen paintroutine, der man eine Painterreferenz übergibt.

Wenn das ein Funktionsplotter werden soll, könntest du z.B. in der Zeichenroutine grundsätzlich als Hintergrund ein Gitter und die Achsen zeichnen, und über einen solchen Container einen oder mehrere Plots/sonstige Grafiken/Textkommentare/Pfeile... .
Qt-nator hat geschrieben:Und später dann wegen dem zeichnen ansich interpolieren und ableiten ist für mich dann ein wenig zu komplixiert / aufwendig. Gibts da keine alternativen?
Nein. Linear interpolieren ist das Einfachste der Welt, ich denke, der Name schreckt dich hier ab. Es ist wirklich nur das Zeichen einer geraden Linie von Punkt zu Punkt. Das mit der zweiten Ableitung zur adaptiven Schrittweitensteuerung war nur ein Vorschlag, weil ich nicht wusste, wie dein mathematisches Vorwissen aussieht - für einen einfachen Funktionsplotter ist das im Gegensatz zur linearen Interpolation mit konstanter Schrittweite keine Notwendigkeit.
Antworten