Ich schlage vor, eine kleine Anwendung zu studieren, in der ein Dialogfeld erstellt wird, dank dessen der Benutzer die Funktionalität Ihres Programms kennenlernen und Schritt für Schritt erklären kann, welches Software-Widget wofür verantwortlich ist.
Um eine solche Funktionalität zu implementieren, muss ein Anwendungsfenster erstellt werden, in dem sich die Schaltflächen "Vorheriges Widget", "Nächstes Widget", "Fenster schließen" befinden. Vor dem Start werden Widgets in der Reihenfolge an dieses Fenster übergeben, in der sie dem Benutzer in Ihrem Programm angezeigt werden sollen, sowie Textnachrichten, die die Widgets beschreiben.
Das Programm wird wie folgt aussehen:
Einführung
Wie wir vereinbart haben, werden wir einen
Trainings
-Dialog erstellen, der eine Reihe von Widgets akzeptiert, über die wir sprechen müssen.
In diesem Fall wird das aktuelle Widget durch Umdefinieren seines Stils hervorgehoben, dh es wird ein roter Widget-Rahmen gesetzt.
Ich muss gleich sagen, dass die Neudefinition von Stilen über
Stylesheet
eine vollständige Neudefinition der Stile einiger Widgets für einige Plattformen nach sich ziehen kann, daher ist es besser, einen vollständig benutzerdefinierten Anwendungsstil zu erstellen oder Widgets mit einer Überschreibung des
paintEvent
-Methode. In jedem Fall müssen Sie für ein schöneres Highlight viel Arbeit in das Styling der Anwendung investieren, aber für die Zwecke des Tutorials werde ich nur eine minimale Neudefinition von Stilen zeigen.
TutorialDialog
Der Qt-Grafikdesigner hat einen Dialog, um nützlichen Code sauber zu halten. Das heißt, der Dialog selbst wird mithilfe der Benutzeroberfläche gebildet. Es wird so aussehen. Den Programmcode erhalten Sie im EVILEG-Beispielrepository am Ende des Artikels.
TutorialDialog.h
In der Header-Datei des Dialogfelds müssen Sie die
TutorialInfo
-Struktur verwenden, die einen Zeiger auf das Widget sowie seine Beschreibung speichert.
Wir brauchen auch eine Variable, die den alten Stil des aktuellen Widgets und den Index des aktuellen Widgets speichert.
#ifndef TUTORIALDIALOG_H #define TUTORIALDIALOG_H #include <QDialog> namespace Ui { class TutorialDialog; } class TutorialDialog : public QDialog { Q_OBJECT public: explicit TutorialDialog(QWidget *parent = nullptr); ~TutorialDialog(); // add widget and text information about this widget to tutorial dialog void addWidgetToTutorial(QWidget* widget, const QString& text); private: void onPreviousButtonClicked(); // slot which reacts on click of previous button void onNextButtonClicked(); // slot which reacts on click of next button void updateButtonsEnabled(); // update actual enabled status of buttons void returnOldStyle(); // return old style to widget, which was highlighted void setTextAndStyle(); // set text information to tutorial dialog and set highlight style to widget Ui::TutorialDialog *ui; // This structure contains text information aboout some widget struct TutorialInfo { QWidget* widget; QString text; }; // highlight style const QString HIGHLIGHT_STYLE {"border: 1px solid red"}; QVector<TutorialInfo> m_infoItems; // vector of widgets in tutorial int m_currentTutorialInfoIndex {-1}; // index of current highlighted widget QString m_oldStyleOfWidget; // old widget style }; #endif // TUTORIALDIALOG_H
TutorialDialog.cpp
#include "TutorialDialog.h" #include "ui_TutorialDialog.h" #include <QDebug> TutorialDialog::TutorialDialog(QWidget *parent) : QDialog(parent), ui(new Ui::TutorialDialog) { ui->setupUi(this); setModal(true); // this dialog should be modal setWindowFlags(Qt::Window); // but it doesn`t create shadow on mainwindow connect(ui->closeButton, &QPushButton::clicked, this, &TutorialDialog::close); connect(ui->previousButton, &QPushButton::clicked, this, &TutorialDialog::onPreviousButtonClicked); connect(ui->nextButton, &QPushButton::clicked, this, &TutorialDialog::onNextButtonClicked); updateButtonsEnabled(); } TutorialDialog::~TutorialDialog() { // When dialog was destrcucted, we should set up old style to current widget returnOldStyle(); delete ui; } void TutorialDialog::addWidgetToTutorial(QWidget* widget, const QString& text) { if (m_infoItems.empty()) { m_currentTutorialInfoIndex = 0; } m_infoItems.push_back({widget, text}); updateButtonsEnabled(); if (m_infoItems.size() == 1) { setTextAndStyle(); } } void TutorialDialog::onPreviousButtonClicked() { returnOldStyle(); --m_currentTutorialInfoIndex; setTextAndStyle(); updateButtonsEnabled(); } void TutorialDialog::onNextButtonClicked() { returnOldStyle(); ++m_currentTutorialInfoIndex; setTextAndStyle(); updateButtonsEnabled(); } void TutorialDialog::updateButtonsEnabled() { ui->previousButton->setEnabled(m_currentTutorialInfoIndex != -1 && m_currentTutorialInfoIndex > 0); ui->nextButton->setEnabled(m_currentTutorialInfoIndex != -1 && m_currentTutorialInfoIndex < m_infoItems.size() - 1); } void TutorialDialog::returnOldStyle() { if (m_currentTutorialInfoIndex != -1) { m_infoItems[m_currentTutorialInfoIndex].widget->setStyleSheet(m_oldStyleOfWidget); } } void TutorialDialog::setTextAndStyle() { ui->textBrowser->setText(m_infoItems[m_currentTutorialInfoIndex].text); m_oldStyleOfWidget = m_infoItems[m_currentTutorialInfoIndex].widget->styleSheet(); m_infoItems[m_currentTutorialInfoIndex].widget->setStyleSheet(HIGHLIGHT_STYLE); }
Hauptfenster
Und dann müssen wir diesen Dialog im Dialog-Startslot des Lernprogramms erstellen und dem Dialog auch Widgets und Informationen zu diesen Widgets hinzufügen.
MainWindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> QT_BEGIN_NAMESPACE namespace Ui { class MainWindow; } QT_END_NAMESPACE class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr); ~MainWindow(); private: void onStartTutorialButtonClicked(); Ui::MainWindow *ui; }; #endif // MAINWINDOW_H
MainWindow.cpp
#include "MainWindow.h" #include "ui_MainWindow.h" #include "TutorialDialog.h" #include "TutorialDialog.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) , ui(new Ui::MainWindow) { ui->setupUi(this); connect(ui->startTutorialButton, &QPushButton::clicked, this, &MainWindow::onStartTutorialButtonClicked); } MainWindow::~MainWindow() { delete ui; } void MainWindow::onStartTutorialButtonClicked() { TutorialDialog tutorialDialog; // Create tutorial dialog // Add widgets to tutorial dialog tutorialDialog.addWidgetToTutorial(ui->projectStructureTreeView, tr("This is project structure")); tutorialDialog.addWidgetToTutorial(ui->createProjectButton, tr("Create new project using this button")); tutorialDialog.addWidgetToTutorial(ui->openProjectButton, tr("Open your project using this button")); tutorialDialog.addWidgetToTutorial(ui->infoWidget, tr("Here You will see some information about objects in your project")); // Start tutorial dialog tutorialDialog.exec(); }
Fazit
Um die Idee eines Lernfensters zu entwickeln, können Sie entweder die Vererbung aller im Programm verwendeten Widgets verwenden, indem Sie die Methode paintEvent überschreiben, um den ausgewählten Rahmen hinzuzufügen und zu entfernen, oder alle von Widgets verwendeten Stile damit vollständig neu definieren dass beim Setzen von stylesheet jene Styles, die nicht gebrochen werden sollen.