Wie unter Qt Widget-Anwendung größerer Inhalt als angezeigtes Fenster?
-
@Pl45m4 said:
Neben dem, was @J-Hilk und @jsulm wegen der ScrollArea angemerkt haben, wäre in dem Fall eine ScrollArea wirklich sinnvoll?!
Man möchte in einem Cockpit (weder Simulation noch in echt) doch nicht ewig scrollen um alles ablesen zu können oder? Hängt halt alles davon ab, wie groß das alles wirklich sein soll/muss und wie groß der/die Bildschirm(e) sind :)Es gibt schon Mehrere, die Flugzeugcockpits und die ganzen Instrumente (für RC, Simulation oder für echtes Training) in Qt nachgebaut haben... einfach mal googlen, wie die das realisiert haben. Gibt verschiedene Möglichkeiten...
@Pl45m4
Sinnvoll? -> irgendwie schon. Der Text in meinem Cockpit schwankt so zw. 8 und 15 px und sollte schon lesbar sein. Die großen Monitore sind 400x400 groß. Der kleinste (CDU) nur rund 200x200. Scrollen muss man eigentlich nur, um vom oberen Teil (Overheadpanel) Eingaben machen zu können, im mittleren Teil die Monitore mehr während des Flugs sehen zu können und die unteren Teile wie bspw. der FMC-Computer (bzw. CDU) und die Schubhebel hängen eh dicht an letzterem dran.
Der Simulator ist mehr oder weniger eh nur für mich privat. Vielleicht wäre es aber trotzdem sinnvoll, das Overheadpanel als optionales Zweit-Window ein- und auszublenden. Da der Simulator wahrscheinlich nie von meinem PC an jemand anderes wandert, ist es mir auch egal, wenn er nur mit einem "echten" Bildschirm mit der Auflösung1920x1080 pixel angezeigt werden kann...
Und danke für den Hinweis wegen dem "googlen nach Qt-gebauten Simulatoren"!@jsulm @J-Hilk
Ich dachte, man könnte die "parent als Widget" setzen, damit das GESAMTE Parent-Window der zu scrollende Inhalt wird. Ich habe jetzt verstanden, dass ich für die ScrollArea ein Objekt mit "Übergröße" angeben muss. Notfalls muss ich ein Bild mit der Hintergrundfarbe beige in der Größe 1900x2140 erstellen und so zuweisen wie von J.Hilk gezeigt.Vielen Dank an alle!
-
@stefanpc81 said in Wie unter Qt Widget-Anwendung größerer Inhalt als angezeigtes Fenster?:
Ich habe jetzt verstanden, dass ich für die ScrollArea ein Objekt mit "Übergröße" angeben muss. Notfalls muss ich ein Bild mit der Hintergrundfarbe beige in der Größe 1900x2140 erstellen und so zuweisen wie von J.Hilk gezeigt.
Muss man auch nicht unbedingt. Eine
QScrollArea
ist nicht anderes als ein Container für ein Widget, das größer sein KANN, nicht MUSS. Man kann auch was kleineres in eine ScrollArea packen, dann entstehen erstmal keine ScrollBars. Wenn man dann z.B. das Scaling verändert, wie beim Zoomen und der Inhalt größer wird, kann man dann die ScrollBars hinzufügen (wie bei jedem Bildverarbeitungsprogramm wenn man auf einen Bildausschnitt zoomt).Die
QScrollArea
sollte der übergeordnete Container für den/die Widgets sein, die später u.U. gescrollt werden sollen.
IstGraphics
das MainWindow / Hauptwidget?Parent
macht in der ScrollArea echt keinen Sinn, da dasparent
ja das übergeordnete Widget vonGraphics
ist und das willst du nicht in einen Container des "childs" packen.Im Prinzip so:
- MainWindow / First Widget
- Widgets...
- ScrollArea
- Scrollbare / zu große Widgets
- noch mehr Widgets....
Was davon was ist, ist dir überlassen und liegt eben am restlichen Programm, ob du alles in die ScrollArea packst (dann würde sich alles, was auf dem Bild zu erkennen ist als ein ganzes Element verschieben lassen) oder nur einzelne Bereiche, dass man den Bereich über den beiden Messinstrumenten runterscrollen kann und dass man dann mehr sieht, wobei die Messinstrumente dann "stehen" bleiben, da sie fest zu dem
parent
layout gehören und nicht Teil der scrollArea / des Scroll-Widgets sind. - MainWindow / First Widget
-
@Pl45m4 Ist Graphics das MainWindow / Hauptwidget?
Ja.Ich habe inzwischen ein einfarbiges JPG-Bild erstellt und der Code sieht nun wie folgt aus:
main.cpp
#include "graphics.h" #include <QApplication> #include <QLocale> #include <QTranslator> #include <QLabel> #include <QScrollArea> int main(int argc, char *argv[]) { QApplication a(argc, argv); QTranslator translator; const QStringList uiLanguages = QLocale::system().uiLanguages(); for (const QString &locale : uiLanguages) { const QString baseName = "Widget7_" + QLocale(locale).name(); if (translator.load(":/i18n/" + baseName)) { a.installTranslator(&translator); break; } } Graphics w; QScrollArea scrollArea; QLabel label; label.setPixmap(QPixmap("F:/PC/Programmierung mit Qt/Widget7/hintergrund.jpg")); scrollArea.setWidget(&label); w.setCentralWidget(&scrollArea); w.show(); return a.exec(); }
graphics.cpp
#include "graphics.h" #include "./ui_graphics.h" #include <QRegion> #include <QImage> Graphics::Graphics(QWidget *parent) : QMainWindow(parent) , ui(new Ui::Graphics) { ui->setupUi(this); } Graphics::~Graphics() { delete ui; } void Graphics::paintEvent(QPaintEvent *event) { //meine Grafiken mit QPainter }
Dieses Projekt habe ich mit der Vorlage QWidgets-Anwendung mit Qt Creator erstellt. Nach dem Hinzufügen des Bildes hintergrund.jpg sind zwar die Scrollbars da und funktionieren auch, jedoch verdeckt diese jetzt die ganzen Grafiken (siehe graphics.cpp). Was nun?
Was mich bei dieser Projektvorlage stört, ist, dass ich offensichtlich kein "QMainWindow mywindow" o.ä. sehe bzw. erstellen kann. Macht ja keinen Sinn, denn das Fenster wurde ja automatisch vom Qt Creator erstellt.
Eure Beitragsbeispiele sehen so aus, als ob sie manuell nach dem Erstellen eines leeren Projekts geschrieben wurden, richtig?@Pl45m4 schrieb:
MainWindow / First Widget
Widgets...
ScrollArea
Scrollbare / zu große Widgets
noch mehr Widgets....Diese Struktur würde ich gerne versuchen anzuwenden, jedoch steht mir die o.g. Vorlage QWidgets-Anwendung im Weg, wenn du verstehst, was ich meine?
-
@stefanpc81 said in Wie unter Qt Widget-Anwendung größerer Inhalt als angezeigtes Fenster?:
Dieses Projekt habe ich mit der Vorlage QWidgets-Anwendung mit Qt Creator erstellt. Nach dem Hinzufügen des Bildes hintergrund.jpg sind zwar die Scrollbars da und funktionieren auch, jedoch verdeckt diese jetzt die ganzen Grafiken (siehe graphics.cpp). Was nun?
Weil eine ScrollArea i.d.R. nur ein Widget enthalten kann. Wenn du das Label mit dem Bild als Widget der ScrollArea hinzufügst, expandiert das Bild in dem Bereich (je nach sizePolicy etc) und kann dann mit den ScrollBars hin- und hergeschoben werden. Um mehrere Elemente in einer ScrollArea zu haben, muss man diese einem Widget (mit Layout) hinzufügen und dann das gesamte Widget wiederum an die ScrollArea übergeben... aber auch dann wird das GESAMTE Widget gescrollt...
@stefanpc81 said in Wie unter Qt Widget-Anwendung größerer Inhalt als angezeigtes Fenster?:
Was mich bei dieser Projektvorlage stört, ist, dass ich offensichtlich kein "QMainWindow mywindow" o.ä. sehe bzw. erstellen kann. Macht ja keinen Sinn, denn das Fenster wurde ja automatisch vom Qt Creator erstellt.
Wahrscheinlich hast du bei der Erstellung des Projekts im Wizard "Graphics" als Namen für das
MainWindow
angegeben.Graphics
ist ja sogar ein abgeleitetesQMainWindow
Siehe hier:Graphics::Graphics(QWidget *parent)
: QMainWindow(parent)@stefanpc81 said in Wie unter Qt Widget-Anwendung größerer Inhalt als angezeigtes Fenster?:
Eure Beitragsbeispiele sehen so aus, als ob sie manuell nach dem Erstellen eines leeren Projekts geschrieben wurden, richtig?
Das Beispiel von @J-Hilk scheint aus irgendeinem Qt Example zu sein. Da passiert aber auch nichts magisches...
Wenn man ein neues Projekt einer QWidget-Anwendung mit einem
QMainWindow
erstellt, macht man eigentlich nichts falsch.Die ScrollArea und alles andere könnte man auch über den DesignMode in der
Graphics.ui
Datei konfigurieren. So spart man sich das Erstellen der ganzen Sachen in dermain()
bzw. im Code der Klasse selbst. Kann man nutzen, muss man aber nicht. Einiges geht eben leider (manchmal auch "zum Glück") nicht im QtDesigner...@stefanpc81 said in Wie unter Qt Widget-Anwendung größerer Inhalt als angezeigtes Fenster?:
Diese Struktur würde ich gerne versuchen anzuwenden, jedoch steht mir die o.g. Vorlage QWidgets-Anwendung im Weg, wenn du verstehst, was ich meine?
Nee, ehrlich gesagt nicht :D
Was hält dich davon ab in QtCreator auf das Projekt zu rechtsklicken und ne neue Qt GUI / C++ Klasse hinzuzufügen?
Jede "Vorlage" kann beliebig verändert werden. Selbst im Code der offiziellen Qt Examples kann man rumpfuschen :D Aber dann sollte man aufpassen, da man dann seine lokale Version des Example Projekts permanent verändert (außer man installliert Qt neu) -> Eventuell dann Kopie anlegen bzw. als neues Projekt speichern. -
Ich habe jetzt mal näher in Betracht gezogen QGraphicsScene und QGraphicsView zu benutzen.
@Pl45m4 said in Wie unter Qt Widget-Anwendung größerer Inhalt als angezeigtes Fenster?:
Um mehrere Elemente in einer ScrollArea zu haben, muss man diese einem Widget (mit Layout) hinzufügen und dann das gesamte Widget wiederum an die ScrollArea übergeben... aber auch dann wird das GESAMTE Widget gescrollt...
Es ist so gewollt, dass das GESAMTE Widget gescrolt wird. Das QLabel kommt mir nicht als passend vor (nur Bild oder Text als Inhalt). Kann ich ein vertikales Layout erzeugen OHNE den Designer von "mainwindow.ui" (hier neues Projekt, neuer Name) zu verwenden? Es ist nämlich so, wenn ich den Designer verwende, dass ich dann in meiner main.cpp keinen Zugriff auf den von mir bei "objectname" eingetragenen Namen "mywidget" bekomme. z.B.:
MainWindow w; QScrollArea scrollArea; scrollArea.setWidget(&mywidget); w.setCentralWidget(&scrollArea); w.show();
Ich suche ein Layout, welches die volle Größe 1900x2140px haben soll und auf dem es sich zeichnen lässt (mit QGraphicsScene/QGraphicsView). Welches Layout würdest du mir empfehlen bzw. wie muss ich diesen Code anpassen, damit es funktioniert?
-
@stefanpc81 said in Wie unter Qt Widget-Anwendung größerer Inhalt als angezeigtes Fenster?:
Kann ich ein vertikales Layout erzeugen OHNE den Designer von "mainwindow.ui" (hier neues Projekt, neuer Name) zu verwenden?
Layouts sind wie alles andere auch nur Klassen, von denen mal eine Instanz erstellen kann, um sie dann zu nutzen.
Es ist nämlich so, wenn ich den Designer verwende, dass ich dann in meiner main.cpp keinen Zugriff auf den von mir bei "objectname" eingetragenen Namen "mywidget" bekomme.
Das macht man ja auch nicht in der
main()
. Kannst das Layout auch in der Klasse selbst bearbeiten.
Nur eben nicht dem ScrollArea Widget dasparent
übergeben, in dem es sich befindet :)
Sonst kann man das meiste (je nach Programm) in den jeweiligen Widget-Klassen designen und coden.@stefanpc81 said in Wie unter Qt Widget-Anwendung größerer Inhalt als angezeigtes Fenster?:
Ich suche ein Layout, welches die volle Größe 1900x2140px haben soll und auf dem es sich zeichnen lässt (mit QGraphicsScene/QGraphicsView). Welches Layout würdest du mir empfehlen bzw. wie muss ich diesen Code anpassen, damit es funktioniert?
Layouts sind dazu da andere funktionale Widgets zu organisieren und ihr Resize Verhalten usw. zu regeln. Andere Sachen "kann" ein Layout nicht, das machen die Dinge, die sich in dem Layout befinden.
In einerQGraphicsScene
kann man immer zeichnen bzw. grafische Objekte erzeugen. Die Größe der "Scene" kannst du auch anpassen. Und falls die Szene über dieQGraphicsView
(die "Leinwand") hinaus geht, lässt es sich auch scrollen, ohne zusätzliche ScrollArea (die View hat ihre eigene). -
Ich habe festgestellt, dass ich mit dem Code über QPainter besser zurecht komme, als mit QGraphicsScene und was dazu passt. Ich habe es jetzt mit den Scrollbars so gemacht wie von @J-Hilk beschrieben, also in main.cpp
int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; QLabel* imageLabel = new QLabel; QImage image1(":/MainWindow/hintergrund.jpg");; imageLabel->setPixmap(QPixmap::fromImage(image1)); QScrollArea* scrollArea = new QScrollArea; scrollArea->setWidget(imageLabel); w.setCentralWidget(scrollArea); w.show(); return a.exec(); }
Die Scrollbars lassen sich bewegen und das Fenster zeigt mein einfarbiges Bild als Hintergrund an. Mein Problem ist jetzt, dass ich darüber mit QPainter zeichnen will und es nicht angezeigt bekomme. Wenn ich den Code vom Bild ausblende, erscheint der zu zeichnende Bereich, aber mit Standard-weißem Hintergrund und ohne Scrollbars. Code von MainWindow.cpp
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { ui.setupUi(this); } void MainWindow::paintEvent(QPaintEvent* event) { QPainter painter; painter.begin(this); painter.setPen(MyColor::black); painter.drawLine(525, 5, 525, 535); ... painter.end(); }
Mir ist klar, dass ich entweder painter.begin(this); das this ersetzen muss, oder aber gleich eine (oder mehrere) eigene Klasse(n) zum Zeichnen (viele Objekte!) bereitstellen kann. Leider habe ich es selbst nicht hinbekommen und im Web nichts passendes gefunden und hoffe auf eine Lösung von euch. Ich bin dankbar für jede Hilfe! MyColor stellt übrigens eigene statische QColor Farben bereit, das habe ich zum Glück zum Laufen gebracht.
-
@stefanpc81 said in Wie unter Qt Widget-Anwendung größerer Inhalt als angezeigtes Fenster?:
Mein Problem ist jetzt, dass ich darüber mit QPainter zeichnen will und es nicht angezeigt bekomme. Wenn ich den Code vom Bild ausblende, erscheint der zu zeichnende Bereich, aber mit Standard-weißem Hintergrund und ohne Scrollbars
Doch bekommst du definitiv... Das Problem ist, du paintest auf dem
MainWindow
und somit auch in dessen Koordinatensystem. Der vertikale Strich, den daspaintEvent
produziert, landet bei mir irgendwo auf Höhe der ToolBar (dort sieht man ein Stück, vorrausgesetzt die sitzt oben) und würde gerade heruntergehen, wenn er nicht von demcentralWidget
(der ScrollArea) verdeckt werden würde.Nur zur Demo:
Probierw.setCentralWidget(nullptr);
vorw.show()
und du wirst sehen, dass die Linie direkt auf dasMainWindow
Widget gemalt wird.
Ungefähr so:
(Der rote Bereich ist der Bereich, der normalerweise vom centralWidget verdeckt wird)
Hab mal ein kleines Beispiel gebastelt, wie ich wahrscheinlich vorgehen würde, wenn ich es mit paintEvents machen müsste :)
Würde sonst eher zurQGraphicsView
greifen.Die main komplett standard
(ich versuch meist die main so clean wie möglich zu halten und nur generelle und grundlegende Einstellungen / Anpassungen, die die gesamteQApp
oder alle Widgets betreffen sollen dort vorzunehmen)#include "mainwindow.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }
MainWindow header
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <mywidget.h> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: Ui::MainWindow *ui; MyWidget* m_canvas; }; #endif // MAINWINDOW_H
MainWindow.cpp
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QDebug> #include <mywidget.h> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow), m_canvas(new MyWidget) { ui->setupUi(this); m_canvas->setGeometry(0, 0, 800, 600); QScrollArea *scrollArea = new QScrollArea; scrollArea->setWidget(m_canvas); setCentralWidget(scrollArea); } MainWindow::~MainWindow() { delete ui; }
Neues, "blankes" Widget.
Auf dem später gezeichnet wird und welches sich dann in dem scrollbaren Bereich befinden soll.#ifndef MYWIDGET_H #define MYWIDGET_H #include <QWidget> namespace Ui { class MyWidget; } class MyWidget : public QWidget { Q_OBJECT public: explicit MyWidget(QWidget *parent = nullptr); ~MyWidget(); void paintEvent(QPaintEvent *ev); private: Ui::MyWidget *ui; }; #endif // MYWIDGET_H
Widget Code
#include "mywidget.h" #include "ui_mywidget.h" #include <QPainter> MyWidget::MyWidget(QWidget *parent) : QWidget(parent), ui(new Ui::MyWidget) { ui->setupUi(this); } MyWidget::~MyWidget() { delete ui; } void MyWidget::paintEvent(QPaintEvent* ev) { QPainter painter; painter.begin(this); painter.setPen(QPen(Qt::black, 5)); painter.drawLine(10, 5, 100, 250); painter.drawEllipse(250, 50, 125, 300); painter.drawLine(250, 50, 125, 300); painter.drawRect(550, 200, 200, 350); painter.end(); }
Auf dem Widget kann nun beliebig gezeichnet werden. Die Größe hab ich beim Erstellen des Widgets im MainWindow auf 800x600 gestellt (zum Test, damit ScrollBars erscheinen).
DascentralWidget
desMainWindows
is aktuell nur dieQScrollArea
, in der sich wiederum das "Zeichen-Widget" befindet. Lässt sich aber auch anpassen und durch ein Layout ersetzen. Dann hätte man auch Platz für Buttons usw. außerhalb der ScrollArea und des ZeichenbereichsSieht dann ungefähr so aus:
(Den Hintergrund kann man natürlich auch einfarbig färben. Das müsste sogar mit allein StyleSheet gehen.)@stefanpc81 said in Wie unter Qt Widget-Anwendung größerer Inhalt als angezeigtes Fenster?:
MyColor stellt übrigens eigene statische QColor Farben bereit, das habe ich zum Glück zum Laufen gebracht.
Qt::black
hätte es auch getan :)
Falls sowas Probleme bereitet, würde ich mich nochmal genauer mit C++ Grundlagen beschäftigen bzw. das Wissen auffrischen. Denn das was danach noch für dein "Hobby"-Projekt kommen wird, wird mit Sicherheit nicht einfacher :) -
@Pl45m4 Danke für den ausführlichen Code! Leider spuckt dann VS2019 noch 6 Fehlermeldungen aus, die alle mit dem "Ui" zu tun haben. Im Detail:
PaintND.cppPaintND::PaintND(QWidget* parent) : QWidget(parent), ui(new Ui::PaintND) { ui->setupUi(this); }
E0393 Der Typ eines Zeigers auf eine unvollständige Klasse ("Ui::PaintND") ist nicht zulässig.
E0070 Ein unvollständiger Typ ist nicht zulässig.
(2x) -> C2027 Verwendung des undefinierten Typs "Ui::PaintND"und in MainWindow.cpp
MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow), nd_canvas(new PaintND) { ui->setupUi(this); nd_canvas->setGeometry(0,0,1900,2140); QScrollArea* scrollArea = new QScrollArea; scrollArea->setWidget(nd_canvas); setCentralWidget(scrollArea); }
(2x) -> C2027 Verwendung des undefinierten Typs "Ui::MainWindow"
Im Web steht nur sehr wenig dazu und konnte leider nichts passendes dazu finden.
PS: Habe MyWidget in PaintND umbenannt und m_canvas in nd_canvas umbenant
- Edit: #include <mywidget.h> hatte ich bereits durch #include "mywidget.h" bzw. #include "PaintND.h" korrigiert (2x).
- Edit: Und an der Stelle (Widget code bzw. PaintND.cpp schreibst du #include "ui_mywidget.h" -> das habe ich auf #include "ui_MainWindow.h" geändert, ein ui_mywidget.h gibt es nämlich nciht bei mir.
-
@stefanpc81 said in Wie unter Qt Widget-Anwendung größerer Inhalt als angezeigtes Fenster?:
ein ui_mywidget.h gibt es nämlich nciht bei mir.
Ja das wird der Fehler sein. Habe
MyWidget
als Qt Klasse mit UI Form angelegt (auch wenn man es aktuell wahrscheinlich nicht benötigt).
Durch die versuchten Zugriffe auf die UI entstehen bei dir die Fehler.Du kannst alles was in
PaintND
mitUI::....
oderui->
beginnt einfach löschen.Das
m_.....
signalisiert nur dass die nachfolgende Variable eine Membervariable einer Klasse ist.
Das ist reine Namenskonvention und soll nur die Lesbarkeit bzw. das Verständnis des Codes erleichtern.
Einige machen_test
, anderem_test
odertest_
odermTest
...
Irgendwas davon zu nutzen kann ich nur empfehlen, da man so bei zig hundert Variablen besser unterscheiden kann, was lokale sind und welche zu einer Klasse gehören und somit durchgehend verfügbar sind.
Zudem zeigt dir die Auto-Vervollständigung bei z.B.m_
oder_
direkt alle Member an, da sie ja dann alle so beginnen.Edit:
Die
ui_MainWindow.h
inPaintND
einzubinden ist nicht so clever :)
Das soll ja die UI Form Klasse bzw. der compilierte Header vonMainWindow
sein. Klassen sollten keinen direkten Zugriff auf die UI einer anderen Klasse haben.
Wenn du auch keineMainWindow.ui
nutzt / hast, kann ALLES (auch in MainWindow) mitui
erstmal weg...
Dann musst du aber jedes Widget später manuell im Code hinzufügen.
Das Nutzen des QtDesigners und einer UI Datei macht einiges leichter. Coden muss man ja so oder so. -
Vielen Dank, es funktioniert endlich! Ich musste allerdings ein neues Projekt erstellen, da ich mit den Änderungen nicht mehr klar kam (bzw. ohne Fehlermeldungen), einmal beim Kopieren die Anpassung vergessen hatte und festgestellt habe, dass ich mit dem Ui / ui nicht "MainWindow" sondern "MainWindowClass" verwenden muss...
-
Super. Markier am besten noch das Thema über die Themeneinstellungen als "gelöst".