PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : qt5 creator + designer: super simple graphic examples



HaWe
30.05.2020, 12:39
hallo,
ich habe z.Zt nur sehr simple qt5 creator GUI Programme mit wenigen Buttons und beschrifteten Labels, z.B.
https://github.com/dsyleixa/RaspberryPi/blob/master/qt/btns_wiringPi_toolbar_pthread_textedit_ads1115/GUI_app_ads1115.jpeg

Nun möchte ich einen Zeichnungs-Bereich (eine Leinwand) in die Form einfügen, in dem ich per Programmcode Linien- und Formgrafiken anzeigen kann.
In der Vielzahl der widgets für den qt Designer finde ich aber nichts, was man da in der Form als Leinwand einfügen und zur passenden Größe"aufziehen" kann.
Was nimmt man da?

Als nächstes möchte ich (zum Üben) ein einfaches Quadrat (outline) und einen Kreis (fillshape) platzieren, in der Art
SetBackgound(BLACK);
SetColor(RED);
RectOutline(20, 20, 40, 40);
SetColor(YELLOW);
Circle(30, 24, 10);
wie mache ich das mit welchem qt-Code in dem soeben in die Form eingefügten Paint-Bereich?

HaWe
30.05.2020, 18:40
PS
nimmt man für Zeichnungen das OpenGL widget ?
und dann wie weiter, um darin Linien und geometr. Formen anzuzeigen?

Sisor
01.06.2020, 09:45
https://doc.qt.io/archives/qt-5.5/qtquick-canvas-example.html
https://doc.qt.io/qt-5/qml-qtquick-context2d.html
Zuerst eine Leinwand (canvas) definieren, dann in deren onpaint()-Methode füllen.

HaWe
01.06.2020, 10:22
dankeschön, leider sind mir die Einzelschritte nicht klar...:
Eine Form mit Button und openGL "Leinwand" habe ich ja bereits entworfen https://github.com/dsyleixa/RaspberryPi/tree/master/qt/qt_btn_OpenGL.

Die Ceator IDE erzeugt dabei automatisch ein File mainwindow.cpp mit dem Inhalt

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}

MainWindow::~MainWindow()
{
delete ui;
}


und das canvas widget (QOpenGLWidget) wird in der Creator IDE per d+d in meiner Form durch "automatic code generation" in mainwindow.ui erzeugt:

<widget class="QOpenGLWidget" name="openGLWidget">
<property name="geometry">
<rect>
<x>20</x>
<y>10</y>
<width>311</width>
<height>241</height>
</rect>
</property>
</widget>
</widget>

Nun habe ich also eine Form mit Quit-Button und openGL Leinwand, aber wie kriege ich jetzt Dinge wie

ClearScreen();
SetColor(RED);
SetBrushWidth(2);
RectOutline(20, 20, 40, 40);
SetColor(YELLOW);
Circle(30, 24, 10);

in die mainwindow.cpp-Routine

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{ }
damit sie das in den Bereich der definierten openGL Leinwand zeichnet?

HaWe
02.06.2020, 11:03
OpenGL scheint tatsächlich viel zu schwierig zu sein, QPainter ist angeblich einfacher, doch auch dafür bräuchte ich eine Anleitung, welche Art von canvas Widget dafür ich in die Form einfügen (Graphics_View ?) und welchen genauen Code für die obigen Zeichen-Funktionen und für das passende Widget in mein Hauptprogramm hineinschreiben muss. :confused:

https://github.com/dsyleixa/RaspberryPi/tree/master/qt/qt_btn_paint

Sisor
02.06.2020, 13:10
Um es einfach zu halten würde ich in QML schreiben. Dann schreibst du sowas:
https://doc.qt.io/archives/qt-5.5/qtquick-canvas-squircle-squircle-qml.html

Wenn du es hart willst:
QPainter ist ein Cpp-QObject. Willst du das in QML einbinden, solltest du das hier gelesen haben:
qml-cpp integration (https://doc.qt.io/qt-5/qtqml-cppintegration-topic.html)
Du müsstest eine Klasse vom QWidget ableiten, mit Q_PROPERTYs zur Steuerung versehen, den Zeichnen-Code in der Write/Setter-Methode triggern und als QML_ELEMENT markieren.
Das kannst du dann im QML-Code verwenden.

Viel Erfolg!

HaWe
02.06.2020, 13:53
ich brauche es in meinem C++ Programm, in meiner speziell designten Form, weil auch alles an GPIO i/o , ADC, i2c und UART samt Datenverarbeitung in C++ programmiert ist.
Mir fehlt aber die Kenntnis, wie man genau mit QPainter geometrische Figuren zeichnet, und zwar im Hauptprogramm, und dann nicht in irgendein extra Fenster sondern genau in die dafür eingefügte canvas widget meiner qt GUI form.
Kurz:
Ich brauche ein lauffähiges Programm für den qtcreator mit einer mainwindow.ui Datei.

Sisor
02.06.2020, 23:01
Nagut, das geht dann so:
Die Dateien mywidget.h

#ifndef MYWIDGET_H
#define MYWIDGET_H

#include <QWidget>

class MyWidget : public QWidget
{
Q_OBJECT

public:
explicit MyWidget(QWidget *parent = nullptr);

QSize minimumSizeHint() const override;
QSize sizeHint() const override;

protected:
void paintEvent(QPaintEvent *event) override;
};

#endif // MYWIDGET_H

und
mywidget.cpp
#include "mywidget.h"

#include <QPainter>
#include <QPainterPath>

MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)
{
this->setEnabled(true);
setBackgroundRole(QPalette::Base);
setAutoFillBackground(true);
this->update();
}

QSize MyWidget::minimumSizeHint() const
{
return QSize(100, 100);
}

QSize MyWidget::sizeHint() const
{
return QSize(400, 200);
}

void MyWidget::paintEvent(QPaintEvent * /* event */)
{
QRect rect(10, 20, 80, 60);

QPainterPath path;
path.moveTo(20, 80);
path.lineTo(20, 30);
path.cubicTo(80, 0, 50, 50, 80, 80);

QPainter painter(this);
painter.setPen(QPen(Qt::blue,10));

for (int x = 0; x < width(); x += 100) {
for (int y = 0; y < height(); y += 100) {
painter.save();
painter.translate(x, y);
painter.drawLine(rect.bottomLeft(), rect.topRight());
painter.restore();
}
}

painter.setRenderHint(QPainter::Antialiasing, false);
painter.setPen(palette().dark().color());
painter.setBrush(Qt::NoBrush);
painter.drawRect(QRect(0, 0, width() - 1, height() - 1));
}

dem Projekt hinzufügen.
Im Designer ein Widget (heisst genau so!) einfügen und Größe nach belieben anpassen. Rechtsklick->Als Platzhalter für benutzerdefinierte Klasse festlegen.
Dort QWidget als Basisklasse und MyWidget als Klassennamen angeben.
Kompilieren, fertig.

HaWe
03.06.2020, 11:13
ein "Widget" finde ich nicht,
in der Sektion "Display Widgets" neben "Labels" etc. nur
OpenGL widget
Graphics_View widget
QuickWidget

das 1. und das 3. fallen weg, also bleibt hier nur Graphics_View Widget.
Das Graphics_View widget kann ich im Designer in die Form drag-en,
dort wird es dann in mainwindow.ui gelistet:


<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>474</width>
<height>411</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="QPushButton" name="pushButton1">
<property name="geometry">
<rect>
<x>180</x>
<y>300</y>
<width>101</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>Quit</string>
</property>
</widget>
<widget class="QGraphicsView" name="graphicsView">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>451</width>
<height>271</height>
</rect>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>474</width>
<height>34</height>
</rect>
</property>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
<widget class="QToolBar" name="toolBar">
<property name="windowTitle">
<string>toolBar</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<action name="action">
<property name="text">
<string/>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections>
<connection>
<sender>pushButton1</sender>
<signal>clicked()</signal>
<receiver>MainWindow</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>234</x>
<y>171</y>
</hint>
<hint type="destinationlabel">
<x>260</x>
<y>229</y>
</hint>
</hints>
</connection>
</connections>
</ui>


Der .ui file wird automatisch vom creator generiert und kann/darf auch nicht manuell geändert werden.

Für spätere Zwecke ist es auch ganz entscheidend, dass ich alle widgets vom Designer /Creator aus in meine Form ziehen und dort platzieren, ändern, und weitere Eigenschaften (event slots) zufügen kann: daher scheiden manuell definierte widgets aus.


Ich weiß nicht, wo ich im Designer stattdessen eine andere Canvas widget finden kann als diese.
Falls es tatsächlich irgendwo ein "Widget" in der IDE-Liste gibt: wo ist das abgelegt?

Das einfügen von extra libs ist auch schwierig, weil ich die immer kompliziert im .pro file mit verlinken muss, kann ich nicht deinen .cpp code als Text einfach komplett als Code in meine mainwindow.cpp mit einfügen?

Und dann deinen Code wie anpassen, dass er mit dem Graphics_View widget zusammen funktioniert (oder einem anderen aus der Creator/Designer-Liste)?


PS:
hier ist nochmal der Link zu meinem qt creator project (nackte canvas plus Quit button):
https://github.com/dsyleixa/qt_paint/tree/master/qt_btn_paint

Vielleicht kannst du ja mal mein Projekt downloaden/kopieren und meinen .pro file in deinen qt Creator laden...

Sisor
03.06.2020, 11:38
Also bei mir funktionierts. Das Widget ist in der Widget-Box (links im Designer) unter Containers eingeordnet. Das dient nur als Platzhalter für das selbstdefinierte MyWidget.
Wenn du die kurze Anleitung von mir durchführst, kommst du drauf, dass selbstdefinierte Widgets sehr wohl im Designer funktionieren. Ich wüsste auch nicht wie du dein Problem anders lösen solltest.

designer - using custom widgets (https://doc.qt.io/qt-5/designer-using-custom-widgets.html)

HaWe
03.06.2020, 12:50
ah, nicht unter DisplayWidgets, sondern unter Containers - ok, danke, habe es gefunden.
Habe auch deine mywidget.h und deine mywidget.cpp Datei ins Arbeitsverzeichnis kopiert.

wie füge ich sie jetzt dem Projekt hinzu? habe ich bisher noch nie gemacht ...
(deshalb wäre mir ein Code direkt in mainwindow.cpp auch viel lieber)

Und wie rufe ich dann eine Zeichen-Routine in meinem mainwindow.cpp auf?

dadurch, dass ich nur oben mit dazu schreibe
#include "mywidget.h"

passiert nichts, nach Compile +Starten sieht man nur meinen Quit Button, sonst nichts (auch keinen Rahmen vom "Widget")...


mainwindow.cpp :

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include "mywidget.h"



MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//
//....: hier soll der komplette Code für die paint-Funktionen rein!
//.... evt. auch über eine lokale Funktion hier im mainwindow.cpp file
//
}

MainWindow::~MainWindow()
{
delete ui;
}



void MainWindow::on_pushButton1_clicked()
{
QCoreApplication::quit();
}

Sisor
03.06.2020, 13:01
Für mein Beispiel ist kein händisches #include notwendig. Schau rechts im Objekt-Fenster, ob das Widget von der Klasse MyWidget ist. Wenn nicht, hat was mit dem Platzhalter-Zeugs nicht funktioniert (Rechtsklick ins Widget im Designer). Wenn's geklappt hat findest du in der .pro-Datei den Eintrag mywidget.h unter Headers und in der .ui-Datei steht der Eintrag <widget class="MyWidget" name="widget" native="true">.

HaWe
03.06.2020, 13:05
hm - kapier ich nicht, was ich machen soll. Per Rechtsklick ins Widget: da finde ich nichts.
Kannst du mir das komplette Projekt mit allen notwendigen Dateien und Einstellungen mal hochladen?

Ist das mit den extra cpp und h files denn auch unbedingt nötig?
ich wollte eigentlich alles komplett in mainwindow.cpp verfügbar haben...

PS,
insbesondere die aktuelle Malfunktion muss unbedingt in mainwindow.cpp programmiert werden können, nicht in einem externen file (mywidget etc.)

Und gibt es keine "eingebaute" canvas-widget für qpainter, muss man das wirklich unbedingt so kompliziert selber schreiben? Ein fertiges widget kann man ja einfach in die Form ziehen, ohne weitere Schreiberei...

Sisor
03.06.2020, 14:11
mainwindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>474</width>
<height>411</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralWidget">
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>180</x>
<y>300</y>
<width>101</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>Quit</string>
</property>
</widget>
<widget class="MyWidget" name="widget" native="true">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>451</width>
<height>271</height>
</rect>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menuBar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>474</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QToolBar" name="mainToolBar">
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<widget class="QStatusBar" name="statusBar"/>
<widget class="QToolBar" name="toolBar">
<property name="windowTitle">
<string>toolBar</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
</widget>
<action name="action">
<property name="text">
<string/>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>MyWidget</class>
<extends>QWidget</extends>
<header>mywidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>pushButton</sender>
<signal>clicked()</signal>
<receiver>MainWindow</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>234</x>
<y>171</y>
</hint>
<hint type="destinationlabel">
<x>260</x>
<y>229</y>
</hint>
</hints>
</connection>
</connections>
</ui>

qt_btn_paint.pro

#-------------------------------------------------
#
# Project created by QtCreator 2019-09-16T12:09:00
#
#-------------------------------------------------

QT += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = GUI_app
TEMPLATE = app

# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0


SOURCES += main.cpp\
mainwindow.cpp \
mywidget.cpp

HEADERS += mainwindow.h \
mywidget.h

FORMS += mainwindow.ui


- - - Aktualisiert - - -

HaWe
03.06.2020, 14:51
hallo,
vielen Dank für deine Mühe!
Es ließ sich nach ein paar kleinen Anpassungen starten (Dateidaten lagen in der Zukunft, *.pro.user musste gelöscht und neu erstellt werden) , aber leider zeigt es nur ein paar diagonale Striche, kein Rechteck, keinen Kreis.

Außerdem müsste es so sein, dass ich alle Zeichenoperationen bedarfsgerecht vom mainwindow.cpp Hauptprogramm aus machen kann (Ort, Größe, Farbe), ggf per lokaler Funktion, an die Koordinaten etc. übergeben werden, denn was wie und wo in der Canvas gezeichnet werden soll, ist letztlich abhängig von Daten, die genau hier berechnet werden (=> Visualisierung von Mess- und Rechenergebnissen).

In deinem Hauptprogramm ist aber überhaupt keine Zeichenfunktion für Linien, Kreise, Rechtecke etc. aufgerufen worden, wie kann man das umschreiben?

Sisor
03.06.2020, 15:02
Es werden auch nur Striche gezeichnet, das ist also ok.

Die Komponenten kannst du mit Signals und Slots verbinden, um Daten im Programm weiterzuleiten.

In der paintEvent_Methode wird gemalt. Wie findest du schon selbst raus, da gibts genug Beispiele.

HaWe
03.06.2020, 15:18
nein, sorry, genau das kriege ich nicht raus, das habe ich schon aus anderen Beispielen heraus probiert, und ich habe nach wie vor keine Idee, wie man Linien, Kreise, Rechtecke etc. direkt vom Hauptprogramm aus zeichnet:

jede einzelne geometrische Figur je nach Erfordernissen in einer kurzen eigenen Zeile, nacheinander, auch ggf. in anderer Reihenfolge, so wie man auch Text aktualisiert und bedarfsgerecht in ein TextBox-Widget schreiben würde, also z.B.

zum Schreiben (funktioniert):
ui->pin23Label->setText(QString("High"));
ui->plainTextEdit1->appendPlainText("pinstate24="+QString::number(pinstate24));

und nun zum Zeichnen (funktioniert noch nicht):
ui->myWidget1->Qpainter(SetBackground(BLACK));
ui->myWidget1->Qpainter(ClearScreen());
ui->myWidget1->Qpainter(SetColor(RED));
ui->myWidget1->Qpainter(SetBrushWidth(2));
ui->myWidget1->Qpainter(RectOutline(20, 20, 40, 40));
ui->myWidget1->Qpainter(SetColor(YELLOW));
ui->myWidget1->Qpainter(Circle(30, 24, 10));

oder wie auch immer die korrekte Syntax sein mag...

HaWe
10.06.2020, 18:56
war mit Qpainter nicht zu lösen, habe es aber jetzt mit QGraphicsScene:

https://github.com/dsyleixa/RaspberryPi/tree/master/qt/btn_paint_timer