360 likes | 497 Views
QT – Dialogs. Blanchette and Summerfield, Ch. 2. Overview. About Qt – widgets, signals and slots, synchronization, layout Windows vs. Qt dialog handling Example – findDialog Steps in defining and implementing subclass findDialog (objects and c++ file structure) Define subclass: finddialog.h
E N D
QT – Dialogs Blanchette and Summerfield, Ch. 2
Overview • About Qt – widgets, signals and slots, synchronization, layout • Windows vs. Qt dialog handling • Example – findDialog • Steps in defining and implementing subclass findDialog (objects and c++ file structure) • Define subclass: finddialog.h • Implement subclass: finddialog.cpp • Execute: main.cpp • More signals and slots • Qt Designer • Learn by doing
Hello, Qt! • Quick review of last time • Qt-ese
Hello, Qt! #include <QApplication> #include <QLabel> int main(int argc, char *argv[]) { QApplication app(argc, argv); QLabel *label = new QLabel("Hello Qt!"); label->show(); return app.exec(); } • A bit for dramatic effect, but there will be advantages • Just a label in a field with no real “main window” • Will look at some basics tonight • Slots and signals (vs. event queues), and layouts (this is a GUI builder),
Hello, Qt! #include <QApplication> // Definitions of QApplication and #include <QLabel> // QLabel classes // Qt is truly object-oriented int main(int argc, char *argv[]) { QApplication app(argc, argv); // Creates a QApplication object to // manage app-wide resources QLabel *label = new QLabel("Hello Qt!"); // Creates a QApplication widget (used as // a window) that displays string label->show(); // Make label (window) visible return app.exec(); // Passes control to Qt } // (would also delete QLabel)
Handling Events: Signals and Slots • Qt not handle events (or event queue) directly • Qt widgets emit signals when user action or change of state occurs • Signal can be connected to a function, or slot • When signal emitted the slot, or function, is executed • In example, will connect button’s clicked signal to slot - function quit() • quit() is “built-in” QApplication function (object)
A Signal and A Slot #include <QApplication> // Include class definitions #include <QPushButton> int main(int argc, char *argv[]) { QApplication app(argc, argv); // Create QApplication object QPushButton *button = new QPushButton("Quit"); // Create labeled button // Associate (connect) a particular signal of this application with a slot QObject::connect(button, SIGNAL(clicked()), &app, SLOT(quit())); button->show(); return app.exec(); // Pass control to QT }
Synchronization & Layout of 2 Widgets • Creates three widgets: • QSpinbox, QSlider, QWidget (application’s main window, will be parent of others) • Using signals and slots of the QSpinbox and QSlider, set value of one depending on value set in the other • E.g., change spinbox value to 70, slider will move to appropriate position • Change slider to some position, spinbox value will be changed based on position • “Layout manager” object will set size and position of widgets
“Setting up”, 1/3 #include <QApplication> // Include class definitions, #include <QHBoxLayout> // including for layout, slider #include <QSlider> // and spinbox #include <QSpinBox> int main(int argc, char *argv[]) { QApplication app(argc, argv); QWidget *window = new QWidget; // Again, window will be widget window->setWindowTitle("Enter Your Age"); // Not good interface design
Create & Synchronize Widgets, 2/3 QSpinBox *spinBox = new QSpinBox; // Create spinbox and slider QSlider *slider = new QSlider(Qt::Horizontal); spinBox->setRange(0, 130); // Set/define range of each slider->setRange(0, 130); // As before, a particular widget signal causes a function (slot) to be called // here, when the value in the spinbox is changed, the function to set the value in the // slider is called, and passed the new value of the spinbox to be the new value of the slider QObject::connect(spinBox, SIGNAL(valueChanged(int)), slider, SLOT(setValue(int))); // … and vice versa QObject::connect(slider, SIGNAL(valueChanged(int)), spinBox, SLOT(setValue(int))); spinBox->setValue(35); // Set initial value for spinbox, slider will then get set
Dialogs, and Qt • “Dialog” in ui programming refers to exchange of information of user and program • See Dix et al. and others for thorough treatment • Dialog boxes are ui elements that can do this, as are other elements • For Qt-ese, just say “dialogs” • “GUI applications” consist of main window, menu bar, tool bar, … and many dialog boxes (dialogs) • From a programming perspective, could create an application that was just a “dialog”, e.g., calculator
Windows vs. Qt Dialog Handling • Recall, windows api requires: • Creation of form and elements of dialog, or widgets, (resource script or visually – tool - created) • Display of dialog (wndproc – event handling procedure) • Separate dialog function for dialog event handling • Post dialog function handling (in wndproc) • Similarities and differences with Qt • Dialog elements (widgets) created (program or visually - tool) • Display of dialog (by program and widget) • Not separate dialog function – slots and signals for control flow • Different post dialog handling (essentially none, dialog widget)
Dialogs –1st Example • Implement dialog as (sub)class • Independent, self-contained component • Signals and slots all in one • No “window” • QWidget > QDialog > FindDialog • At right, from last time – QDialog not shown • Dialog consists of 5 widgets • Edit box, 2 check boxes, 2 buttons • Program will do class setups, definition and placement of widgets • Three files: • finddialog.h, finddialog.cpp, main.cpp
Steps in Defining and Implementing Subclass findDialog • Will look at the code in detail – “survival kit” for creating dialogs 1. finddialog.h • Set up: include, forward declarations • FindDialog subclass definition 2. finddialog.cpp • Will implement findDialog class: • Create dialog elements (widgets) • Connect signals and slots • Lay out widgets using layout managers • Define slots, or functions 3. main.cpp • As before, create new object, show it, and execute
1. finddialog.hSet up: include, forward declarations #ifndef FINDDIALOG_H // For c++ preprocessor – only include once #define FINDDIALOG_H #include <QDialog> // QDialog is Qt base class (it inherits Qwidget) // Again, below from last time class QCheckBox; // forward declarations of the Qt classes used class QLabel; // tells C++ compiler exists, later defined class QLineEdit; class QPushButton;
finddialog.h FindDialog - Subclass Definition class FindDialog : public QDialog // FindDialog is a subclass of QDialog { Q_OBJECT // Required macro for classes defining sgnls or slots public: FindDialog (QWidget *parent = 0); // Qt widget class constructor, here, no parent // (“signals” and “slots” are macros) signals: // Define signal emitted when “Find” button clicked void findNext (const QString &str, Qt::CaseSensitivity cs); // depends on match case void findPrevious (const QString &str, Qt::CaseSensitivity cs); // Qt::Ca… is an enum type private slots: // Define slots void findClicked (); void enableFindButton (const QString &text); private: // Forward declarations of classes QLabel *label; QLineEdit *lineEdit; QCheckBox *caseCheckBox; QCheckBox *backwardCheckBox; QPushButton *findButton; QPushButton *closeButton; }
2. finddialog.cppImplement finddialog class:Create dialog elts (widgets) #include <QtGui> // Definitions of Qt’s GUI classes - hundreds #include "finddialog.h“ FindDialog::FindDialog (QWidget *parent) : Qdialog (parent) // pass parent to base class constructor { label = new Qlabel (tr ("Find &what")); // ----- Create dialog element, Qlabel, etc. -------- lineEdit = new QLineEdit; // tr func for translation, & indicates shortcut key label->setBuddy (lineEdit); // “buddy” is widget that accepts focus w/shortcut caseCheckBox = new QCheckBox (tr ("Match &case")); // ------ Qcheckbox ------ backwardCheckBox = new QCheckBox (tr ("Search &backward")); // ------ Qcheckbox ------ findButton = new QPushButton (tr ("&Find")); // ------ QPushbutton ------ findButton->setDefault (true); // “default” indicates executed on key Enter findButton->setEnabled (false); // not enabled, grayed out closeButton = new QPushButton (tr ("Close"));
finddialog.cppConnect signals and slots // Signal “textchanged” from lineEdit widget enables button labeled “find” by private slot enableFindButton connect ( lineEdit, SIGNAL (textChanged (const QString &)), this, SLOT (enableFindButton (const QString &))); // Again, private slot, findClicked, called when signal “clicked” emitted by widget findbutton connect ( findButton, SIGNAL (clicked ()), this, SLOT (findClicked ())); // As before, Qt function close called when widget closeButton emits clicked signal connect ( closeButton, SIGNAL (clicked ()), this, SLOT (close ()));
finddialog.cppLay out widgets using layout managers • Layout managers are Qt’s “system” for positioning display elements, e.g., widgets, spacers • MUCH more flexible than windows • Easily, and naturally, supports incremental development • … and have their own terminology and rules, e.g., nested, boxes • Will work through example
finddialog.cppLay out widgets using layout managers // layouts are nested – constrain widgets and other layouts QHBoxLayout *topLeftLayout = new QHBoxLayout; topLeftLayout->addWidget(label); topLeftLayout->addWidget(lineEdit); QVBoxLayout *leftLayout = new QVBoxLayout; leftLayout->addLayout(topLeftLayout); leftLayout->addWidget(caseCheckBox); leftLayout->addWidget(backwardCheckBox);
finddialog.cppLay out widgets using layout managers // layouts are nested – constrain widgets and other layouts QHBoxLayout *topLeftLayout = new QHBoxLayout; topLeftLayout->addWidget(label); topLeftLayout->addWidget(lineEdit); QVBoxLayout *leftLayout = new QVBoxLayout; leftLayout->addLayout(topLeftLayout); leftLayout->addWidget(caseCheckBox); leftLayout->addWidget(backwardCheckBox); QVBoxLayout *rightLayout = new QVBoxLayout; rightLayout->addWidget(findButton); rightLayout->addWidget(closeButton); rightLayout->addStretch(); // fill – here, below
finddialog.cppLay out widgets using layout managers // layouts are nested – constrain widgets and other layouts QHBoxLayout *topLeftLayout = new QHBoxLayout; topLeftLayout->addWidget(label); topLeftLayout->addWidget(lineEdit); QVBoxLayout *leftLayout = new QVBoxLayout; leftLayout->addLayout(topLeftLayout); leftLayout->addWidget(caseCheckBox); leftLayout->addWidget(backwardCheckBox); QVBoxLayout *rightLayout = new QVBoxLayout; rightLayout->addWidget(findButton); rightLayout->addWidget(closeButton); rightLayout->addStretch(); // fill – here, below QHBoxLayout *mainLayout = new QHBoxLayout; mainLayout->addLayout(leftLayout); mainLayout->addLayout(rightLayout); setLayout(mainLayout); setWindowTitle (tr ("Find")); setFixedHeight (sizeHint().height()); }
Define finddialog slots, or functions • // Called when user clicks Find button, emits signal findPrevious() or findNext • void FindDialog:: findClicked() • { • QString text = lineEdit->text(); • Qt::CaseSensitivitycs = • caseCheckBox->isChecked() ? Qt::CaseSensitive • : Qt::CaseInsensitive; • if (backwardCheckBox->isChecked()) { • emit findPrevious(text, cs); • } else { • emit findNext(text, cs); // emit keyword (macro) specific to Qt • } • } • // Called whenever user changes text in line editor, enables button if there is text in line editor • void FindDialog :: enableFindButton(const QString &text) • { • findButton->setEnabled (!text.isEmpty ()); • }
3. main.cpp // As before, simply create a new object, here FindDialog, show it, and execuute #include <QApplication> #include "finddialog.h“ int main (int argc, char *argv[]) { QApplication app (argc, argv); FindDialog *dialog = new FindDialog; dialog->show(); return app.exec(); }
More about Signals and Slots • “Signals and slots enables application programmer to bind objects together without objects knowing anything about each other” • Essentially c++ member functions • Can be virtual, overloaded, public, protected, private, invoked indirectly • Connected to a signal and automatically called each time the signal is emitted • connect (sender, SIGNAL (signal), receiver, SLOT (slot) ) • So far, only different signals to different slots • Other ways, as well
Signals and Slots • Again, form is: connect (sender, SIGNAL (signal), receiver, SLOT (slot) ) 1. One signal can be connected to many slots: • connect(slider, SIGNAL(valueChanged(int)), spinBox, SLOT(setValue(int))); • connect(slider, SIGNAL(valueChanged(int)), this, SLOT(updateStatusBarIndicator(int))); • When signal emitted, slots called one after the other, in arbitrary order 2. Many signals can be connected to the same slot: • connect(lcd, SIGNAL(overflow()), this, SLOT(handleMathError())); • connect(calculator, SIGNAL(divisionByZero()), this, SLOT(handleMathError())); • When either signal is emitted, the slot is called.
Signals and Slots • connect (sender, SIGNAL (signal), receiver, SLOT (slot) ) 3. A signal can be connected to another signal: • connect(lineEdit, SIGNAL(textChanged(const QString &)), this, SIGNAL(updateRecord(const QString &))); • When the first signal is emitted, the second signal is emitted as well. 4. Connections can be removed: • disconnect(lcd, SIGNAL(overflow()), this, SLOT(handleMathError()));
Can Use Signals not only with Widgets, but as More General Mechanism // Define class class Employee : public QObject { Q_OBJECT public: Employee() { mySalary = 0; } int salary() const { return mySalary; } public slots: void setSalary (int newSalary); signals: void salaryChanged (int newSalary); private: int mySalary; }; // Use signal to communicate with any/all slots // (functions) connected to salaryChanged // signal! void Employee::setSalary (intnewSalary) { if (newSalary != mySalary) { mySalary = newSalary; emit salaryChanged (mySalary); } }
Qt Designer • .
End • … and you’re off and running …