UI Development
Qt is 2009 Nokia Corporation and/or its subsidiaries. Nokia, Qt, Qt Development Frameworks and their respective logos are trademarks of Nokia Corporation in Finland and/or other countries worldwide.
Disclaimer
These slides are provided free of charge at http://www.symbianresources.com and are used for trainings and during courses at the Upper Austria University of Applied Sciences, Campus Hagenberg, Austria ( http://www.fh-ooe.at/mc ) Respecting the copyright laws, you are allowed to use them:
In all other cases (e.g. for commercial training), please contact andreas.jakl@fh-hagenberg.at The correctness of the contents of these materials cannot be guaranteed. Andreas Jakl is not liable for incorrect information or damage that may arise from using the materials. Parts of these materials are based on books listed at the end of the slides of unit 1 and on official Qt documentation and source code. This document contains copyright materials which are proprietary to Qt Development Frameworks and Nokia. Qt, S60 and their respective logos are a trademark of Nokia. Pictures of mobile phones or applications are copyright their respective manufacturers / developers. Symbian , Symbian OS and all other Symbian-based marks and logos are trademarks of Symbian Foundation. All other trademarks are property of their respective owners.
Contents
Subclassing Widgets
doesnt work that way, clicked()-signal doesnt give required number of arguments to setText()-slot.
Class MyWindow is a widget (parent) Also manages child widgets Put text to display into this slot method instead of the connect statement
myWindow.cpp
#include "MyWindow.h"
int main(int argc, char *argv[]) { QApplication a(argc, argv); MyWindow* window = new MyWindow(); window->show(); return a.exec(); }
main.cpp
MyWindow::MyWindow(QWidget* parent) : QWidget(parent) { label = new QLabel("old text"); button0 = new QPushButton("Update labels"); button1 = new QPushButton("Exit"); layout = new QVBoxLayout(this); layout->addWidget(button0); layout->addWidget(button1); layout->addWidget(label); setLayout(layout);
class MyWindow : public QWidget { Q_OBJECT public: MyWindow(QWidget *parent = 0); private: QLabel* label; QPushButton* button0; QPushButton* button1; QVBoxLayout* layout; }; private slots: void setText(); }; #endif // MYWINDOW_H
Signal: clicked(int) Called whenever button is clicked (internal signal slot connection) Emits the clicked() event plus int parameter
MyButton Signals clicked() clicked(int) Slots click() Slots myMsgBox(int) MyWindow Signals
myButton.cpp
#include "mybutton.h" int MyButton::nextId = 0; MyButton::MyButton(const QString& text, int id, QWidget* parent) : QPushButton(text, parent), m_id(id) { connect(this, SIGNAL(clicked()), this, SLOT(click())); } MyButton::MyButton(const QString& text, QWidget* parent) : QPushButton(text, parent), m_id(nextId++) { connect(this, SIGNAL(clicked()), this, SLOT(click())); } void MyButton::click() { emit clicked(m_id); }
// Overwrite click()
10
myWindow.cpp
#include "myWindow.h" MyWindow::MyWindow(QWidget* parent) : QWidget(parent) { myButton[0] = new MyButton(tr("Press me")); myButton[1] = new MyButton(tr("Me too")); myButton[2] = new MyButton(tr("And me")); QVBoxLayout* layout = new QVBoxLayout(this); for (int i = 0; i < 3; i++) { layout->addWidget(myButton[i]); connect( myButton[i], SIGNAL(clicked(int)), this, SLOT(myMessageBox(int))); } // The qApp pointer is a global variable declared in // the <QApplication> header file. It points to the // application's unique QApplication instance. connect( myButton[2], SIGNAL(clicked()), qApp, SLOT(quit()) ); } void MyWindow::myMessageBox(int id) { QMessageBox::information(this, tr("A button has been clicked"), QString(tr("Button ID: %1")).arg(id), QMessageBox::Ok); }
class MyWindow : public QWidget { Q_OBJECT public: MyWindow(QWidget* parent = NULL); private: MyButton* myButton[3]; public slots: // Slot for output void myMessageBox(int id); }; #endif // MYWINDOW_H
Dialogs
12
QObject
QPaintDevice QWidget
Dialogs
Dialog is:
QDialog
Top-level window Used for short-term tasks, brief user communication Can provide return value
Dialog blocks other application windows (e.g., file open dialog) Usually called with exec(), returns when dialog is closed Call with show(): returns immediately, get results via signals Operates independently from other windows (e.g., find & replace dialog) Always called with show(): returns immediately
13 Andreas Jakl, 2009
Modal
Modeless
Custom Dialog
clicked() signal from button in main widget triggers dialog Change label in main widget depending on user action selected in dialog
14
MyWindow Signals
Slots checkInputDialog()
15
The Dialog
mydialog.h
#ifndef MYDIALOG_H #define MYDIALOG_H #include #include #include #include <QDialog> <QPushButton> <QVBoxLayout> <QLabel>
mydialog.cpp
#include "mydialog.h" MyDialog::MyDialog() { setFixedSize(150, 100); QVBoxLayout* vbox = new QVBoxLayout(); QLabel* label = new QLabel("Please confirm."); QPushButton* okButton = new QPushButton("Ok"); QPushButton* cancelButton = new QPushButton("Cancel"); // Set the ok button as default okButton->setDefault(true); vbox->addWidget(label); vbox->addWidget(okButton); vbox->addWidget(cancelButton); setLayout(vbox); // Connect the buttons to slots defined by QDialog connect(okButton, SIGNAL(clicked()), this, SLOT(accept())); connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); }
16
int exec()
Shows the dialog as a modal dialog, blocking until the user closes it. Returns dialog return value (DialogCode) like Accepted or Rejected.
Description Emitted when dialog has been accepted through calling accept() or done() with the argument QDialog::Accepted Emitted when dialog has been rejected through calling reject() or done() with the argument QDialog::Rejected Emitted when the dialogs result code has been set (setResult()) and either accept(), reject() or done() is called.
Andreas Jakl, 2009
17
The Widget
mywidget.h
[...]
class MyWidget : public QWidget { Q_OBJECT public: MyWidget(QWidget *parent = 0); ~MyWidget(); private slots: void checkInputDialog(); private: QPushButton* startButton; QLabel* instructionsLabel; QLabel* resultLabel; QVBoxLayout* layout; MyDialog* dialog; }; #endif // MYWIDGET_H }
mywidget.cpp
#include "mywidget.h" MyWidget::MyWidget(QWidget *parent) : QWidget(parent) { startButton = new QPushButton("Start dialog"); instructionsLabel = new QLabel("Please push the button"); resultLabel = new QLabel(); layout = new QVBoxLayout(this); layout->addWidget(instructionsLabel); layout->addWidget(startButton); layout->addWidget(resultLabel); dialog = new MyDialog(); connect(startButton, SIGNAL(clicked()), dialog, SLOT(exec())); connect(dialog, SIGNAL(accepted()), this, SLOT(checkInputDialog())); connect(dialog, SIGNAL(rejected()), this, SLOT(checkInputDialog())); setWindowTitle("Main Window - Dialog Example");
18
void MyWidget::checkInputDialog() { int res = dialog->result(); // Gets result (Accepted/Rejected) if (res == QDialog::Accepted) { resultLabel->setText("\"Ok\" was selected"); } else if (res == QDialog::Rejected) { resultLabel->setText("\"Cancel\" was selected"); } }
mydialog.cpp
[...] connect(ignoreButton, SIGNAL(clicked()), this, SLOT(setResult())); [...] void MyDialog::setResult() { int result = 99; emit done(result); }
mywidget.cpp
[...] connect(dialog, SIGNAL(finished(int)), this, SLOT(checkInputDialog(int))); [...] void MyWidget::checkInputDialog(int res) { if (res == 99) { resultLabel->setText("\"Ignore\" was selected"); } }
mywidget.h
[...] private slots: void checkInputDialog(); void checkInputDialog(int); [...]
19
Pre-Defined Dialogs
QColorDialog QErrorMessage
QFontDialog
QInputDialog QFileDialog
QMessageBox
20
Pre-Defined Dialogs
int ret = QMessageBox::warning( this, "Exit?", "Do you really want to exit the application?", QMessageBox::Yes | QMessageBox::No );
21
22
Main Window
Pre-defined layout for standard components Central widget must be defined, others optional Subclass to create your own implementation
Status Bar
Differences?
Possible with dialog / widgets as well But: more comfortable, consistent and efficient
23 Andreas Jakl, 2009
Example QMainWindow
mainwindow.h
[...]
class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0, Qt::WFlags flags = 0); ~MainWindow(); private: QTextEdit* editor; } [...] }; #endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h" MainWindow::MainWindow(QWidget *parent, Qt::WFlags flags) : QMainWindow(parent, flags) { editor = new QTextEdit(); setMinimumSize(160, 160); resize(480, 320); setCentralWidget(editor); setWindowTitle("QMainWindow with Menus"); QString message = "Welcome"; statusBar()->showMessage(message);
24
Represent abstract user interface action Define once, use in multiple components Inserted into widgets
Toolbar buttons
Keyboard shortcuts
25
Action
Menu Bar
QMenu provides a menu widget for menu bars, context menus and other popup menus Supports:
QMenuBar automatically created by QMainWindow QMenu(s) contains individual menu items ( Actions)
26 Andreas Jakl, 2009
Example QAction
mainwindow.h
[...]
class MainWindow : public QMainWindow { Q_OBJECT [...] private slots: void openFile(); private: QMenu *fileMenu; QAction *openAct; };
mainwindow.cpp
[...] // Create a new Open action with an icon, keyboard shortcut and // info-text for the status bar. openAct = new QAction("&Open...", this); openAct->setIcon(QIcon("images/open.png")); openAct->setShortcut(tr("Ctrl+O")); openAct->setStatusTip(tr("Open an existing file")); connect(openAct, SIGNAL(triggered()), this, SLOT(openFile()));
27
Toolbar
Same actions as for menu can be used for toolbar Default automatically enables drag & drop
28
Example QToolBar
mainwindow.h
[...]
class MainWindow : public QMainWindow { Q_OBJECT [...] private: QToolBar *toolFile; };
mainwindow.cpp
#include "mainwindow.h" MainWindow::MainWindow(QWidget *parent, Qt::WFlags flags) : QMainWindow(parent, flags) { [...] // Open action openAct = new QAction("&Open...", this); openAct->setIcon(QIcon("images/open.png")); openAct->setShortcut(tr("Ctrl+O")); openAct->setStatusTip(tr("Open an existing file")); connect(openAct, SIGNAL(triggered()), this, SLOT(openFile())); // Exit action exitAct = new QAction("E&xit", this); exitAct->setIcon(QIcon("images/exit.png")); exitAct->setShortcut(tr("Ctrl+Q")); exitAct->setStatusTip(tr("Exit the application")); connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
29
Properties
30
Property System
31
Query Properties
// Get meta object of target object const QMetaObject *metaobject = but->metaObject(); // Number of properties int count = metaobject->propertyCount(); for (int i=0; i<count; ++i) { // Retrieve current property QMetaProperty metaproperty = metaobject->property(i); // Print name and value to debug out const char *name = metaproperty.name(); QVariant value = but->property(name); qDebug() << "Name:" << name << ", value:" << value; }
Name: Name: Name: Name: Name: Name: Name: Name: Name: Name: Name: Name: Name: Name: Name: Name: Name: Name: Name: Name: ... objectName , value: QVariant(QString, "") enabled , value: QVariant(bool, true) pos , value: QVariant(QPoint, QPoint(0,0) ) size , value: QVariant(QSize, QSize(200, 100) ) width , value: QVariant(int, 200) height , value: QVariant(int, 100) rect , value: QVariant(QRect, QRect(0,0 200x100) ) isActiveWindow , value: QVariant(bool, true) focus , value: QVariant(bool, true) visible , value: QVariant(bool, true) minimized , value: QVariant(bool, false) maximized , value: QVariant(bool, false) fullScreen , value: QVariant(bool, false) sizeHint , value: QVariant(QSize, QSize(76, 23) ) toolTip , value: QVariant(QString, "") statusTip , value: QVariant(QString, "") whatsThis , value: QVariant(QString, "") locale , value: QVariant(QLocale, ) text , value: QVariant(QString, "Hello Property") down , value: QVariant(bool, false)
32
In private section of class READ function: creator(). Must be const. (required) WRITE function: setCreator(). Must return void, exactly one argument with type of property or pointer/reference to that type (optional)
... Name: creator , value: QVariant(QString, "Mopius")
mybutton.h
class MyButton : public QPushButton mainwindow.cpp { but->setCreator(tr("Mopius")); Q_OBJECT Q_PROPERTY(QString creator READ creator WRITE setCreator) public: MyButton(const QString& text, QWidget* parent = NULL); void setCreator(QString aCreator); QString creator() const { return iCreator; }
mybutton.cpp
void MyButton::setCreator(QString aCreator) { iCreator = aCreator; }
33
Dynamic Properties
Name equals existing property & type is compatible: updates property Non-compatible type compatible: no update Name does not exist (not declared with Q_PROPERTY()): new property is added
mainwindow.cpp
but->setProperty("Owner", tr("Andreas Jakl")); QList<QByteArray> dynProperties = but->dynamicPropertyNames(); foreach (QByteArray curProperty, dynProperties) { QVariant value = but->property(curProperty); qDebug() << "Dyn-Name:" << curProperty << ", value:" << value; } Dyn-Name: "Owner" , value: QVariant(QString, "Andreas Jakl")
34
Data Types
35
uint / quint32
ulong qulonglong / quint64
36
unsigned int
unsigned long unsigned long long int
Andreas Jakl, 2009
0 to 4294967296
0 to 4294967296 unsigned 64 bit values
QString
Similar to standard C++ String Qt always uses Unicode (16 bit QChar) Uses implicit sharing to increase efficiency and reduce memory overhead Use QByteArray to store raw bytes and 8-bit \0-terminated strings
37
// Line 2
str1 str2 Data: Hello world Reference count: 2
// Line 3
str1 Data: Hello world Reference count: 1 str2 Data: Hello Qt Reference count: 1
Line 1
Line 2
Assigns value of str1 to str2, but Qt doesnt copy it right away Instead: only pointer is passed (shallow copy) Modifies str2: Qt separates both strings in memory (deep copy) Happens behind the scenes
38 Andreas Jakl, 2009
Line 3
Implicit Sharing
obj1 obj2
Data Ref-count
Pointer to shared data block, which contains reference count and data
Copies
Usage in Qt
QVariant
Union for most common Qt data types Stores one type of data Converts between different types
QDataStream out(...); QVariant v(123); int x = v.toInt(); out << v; v = QVariant("hello"); v = QVariant(tr("hello")); int y = v.toInt(); QString s = v.toString(); out << v; [...] QDataStream in(...); in >> v; int z = v.toInt(); qDebug("Type is %s", v.typeName()); v = v.toInt() + 100; v = QVariant(QStringList()); // // // // // // // // // // // // The variant now contains an int x = 123 Writes a type tag and an int to out The variant now contains a QByteArray The variant now contains a QString y = 0 since v cannot be converted to an int s = tr("hello") (see QObject::tr()) Writes a type tag and a QString to out (opening the previously written stream) Reads an Int variant z = 123 prints "Type is int"
40
Lists, etc.
Less error-prone syntax than STL Using STL is possible, but might not be fully implemented by all compilers
Sequential containers Associative containers
QList (QStringList)
QLinkedList QVector QStack QQueue
QMap
QMultiMap QHash QMultiHash QSet
41
QDebug
// The global functions are available anywhere. qDebug("Processing Fruits..."); // Using the << operator requires including <QDebug> qDebug() << "Fruit: " << sList.at(1);
qDebug(): writing custom debug output. qWarning(): report warnings and recoverable errors in your application. qCritical(): writing critical error messages and reporting system errors. qFatal(): writing fatal error messages shortly before exiting.
Outputs to:
Mac OS X and Unix: stderr Windows: Console application console. GUI application debugger.
43 Andreas Jakl, 2009
Internationalization
44
Internationalization
Spelling Ligatures: Formats (numbers, dates, currencies) Non-spacing or diacritical marks (accents / umlauts in European languages) Special line breaking behaviour Character encoding Presentation conventions (bidirectional writing) Input techniques
Qt Linguist
Translation files (.ts, xml-based) extracted from your source code Qt Linguist only needs xml file simple for external translators
Use tr() from other QObject-derived class QCoreApplication::translate() Completely outside functions: QT_TR_NOOP() / QT_TRANSLATE_NOOP() macros
Andreas Jakl, 2009
47
Translation Context
Open for file in German: ffnen Open for Internet connection in German: Aufbauen Class name automatically provided by Qt Linguist Custom comments through 2nd parameter of tr():
49
Add Languages
Finds translatable strings in source code, headers and Qt Designer files Generates/updates XML file for each language Translate these files with Qt Linguist
50
Finished Translations?
Produces compact binary .qm files out of .ts files Only integrates translations marked as finished
51
Loading Translations
52
Loading Translations II
Locale:
Locale: de_AT (Austrian dialect of German language) translator1_de_at.qm translator1_de_at translator1_de.qm translator1_de translator1.qm translator1
e.g., de_AT
QTranslator::load()
// Get locale of the system QString locale = QLocale::system().name(); // Load the correct translation file (if available) QTranslator translator; translator.load(QString("translator1_") + locale, qApp->applicationDirPath()); // Adds the loaded file to list of active translation files app.installTranslator(&translator); (copy from previous slide)
53
Troubleshooting?
Make sure the translation files are found Copy *.qm to directory of executable if in doubt!
54
Thats it.
55