1 / 39

Qt – Functionality, Custom Widgets

Qt – Functionality, Custom Widgets. C++ GUI Programming with Qt 4 Qt 4.5 Reference Documentation Blanchette and Summerfield, Ch. 4,5. Overview. Another example of essential Qt concepts – “Application Example” Help > Qt Reference Documentation > Qt Examples > Application Example (in 2 nd pp)

isha
Download Presentation

Qt – Functionality, Custom Widgets

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Qt – Functionality,Custom Widgets C++ GUI Programming with Qt 4 Qt 4.5 Reference Documentation Blanchette and Summerfield, Ch. 4,5

  2. Overview • Another example of essential Qt concepts – “Application Example” • Help > Qt Reference Documentation > Qt Examples > Application Example (in 2nd pp) • Class definition in <app>.h: • For application’s menus, toolbars, slots, function • Create (implement) in <app>.cpp: • Menus, toolbars, status bar • Qt “actions” for menu items • Function to be called upon selection, by connecting item action and function • connect(newAct, SIGNAL(triggered()), this, SLOT(newFile())); • And item stuff – shortcut, status tip • “Functionality”, or just functions, for menu items • Define resources • E.g., images

  3. Application Example • Application with menus, toolbars, and status bar • Simple text editor program built around QTextEdit • “Powerful” Qt widget • Many others … • Documentation next

  4. QTextEdit Reference, 1 • A widget that is a text editor! • Note properties • And where come from

  5. QTextEdit Reference, 2 • Slots and signals

  6. QTextEdit Reference, 3 • Functions

  7. MainWindow Class Definitionmainwindow.h – as before, slots, functions, menus, etc. class MainWindow : public QMainWindow { Q_OBJECT class QAction; class QMenu; class QPlainTextEdit;   public: MainWindow(); protected: void closeEvent(QCloseEvent *event); private slots: void newFile(); void open(); bool save(); bool saveAs(); void about(); void documentWasModified(); private: void createActions(); void createMenus(); void createToolBars(); void createStatusBar(); void readSettings(); void writeSettings(); boolmaybeSave(); void loadFile(const QString &fileName); boolsaveFile(const QString &fileName); void setCurrentFile(const QString &fileName); QStringstrippedName(const QString &fullFileName); QPlainTextEdit *textEdit; QStringcurFile; QMenu *fileMenu; QMenu *editMenu; QMenu *helpMenu; QToolBar *fileToolBar; QToolBar *editToolBar; QAction *newAct; …

  8. The “Central Widget” • Depending on design - central area of main window • In non-Qt-ese • Can be: • Standard widget • E.g., QtextEdit, Qtable • Custom widget • Widgets with layout manager • Splitter (is like Q[V/H]Box) • MDI workspace (multiple wins)

  9. MainWindow Class Implementationmainwindow.cpp #include <QtGui>  #include "mainwindow.h"  // Invoking MainWindow creates all MainWindow::MainWindow() { textEdit = new QPlainTextEdit; // One call for lots of functionality setCentralWidget(textEdit);  createActions(); createMenus(); createToolBars(); createStatusBar();  readSettings();  // Standard to save and restore on start connect(textEdit->document(), SIGNAL(contentsChanged()), this, SLOT(documentWasModified()));  setCurrentFile(""); // Setup for later use setUnifiedTitleAndToolBarOnMac(true); } 

  10. Application’s Menus • Similar to what seen • BTW - status bar at bottom of main window shows description of menu item or toolbar button under cursor

  11. Creating Menu Items with Actionsmainwindow.cpp void MainWindow::createMenus() // Create the top level menus { fileMenu = menuBar()->addMenu(tr("&File")); fileMenu->addAction(newAct); fileMenu->addAction(openAct); fileMenu->addAction(saveAct); fileMenu->addAction(saveAsAct); fileMenu->addSeparator(); fileMenu->addAction(exitAct);  editMenu = menuBar()->addMenu(tr("&Edit")); editMenu->addAction(cutAct); editMenu->addAction(copyAct); editMenu->addAction(pasteAct);  menuBar()->addSeparator();  helpMenu = menuBar()->addMenu(tr("&Help")); helpMenu->addAction(aboutAct); helpMenu->addAction(aboutQtAct); } 

  12. Creating Toolbar and Status Bar void MainWindow::createToolBars() // Toolbar created as menu is { fileToolBar = addToolBar(tr("File")); fileToolBar->addAction(newAct); fileToolBar->addAction(openAct); fileToolBar->addAction(saveAct);  editToolBar = addToolBar(tr("Edit")); editToolBar->addAction(cutAct); editToolBar->addAction(copyAct); editToolBar->addAction(pasteAct); }  void MainWindow::createStatusBar() { statusBar()->showMessage(tr("Ready")); }

  13. Create Actions, 1“Actions” specify what happens when menu item selected // “Actions” specify what happens when menu item selected void MainWindow::createActions() { // From createMenus(): “fileMenu->addAction(newAct);” newAct = new QAction(QIcon(":/images/new.png"), tr("&New"), this); // Note relative location of icon newAct->setShortcuts(QKeySequence::New); newAct->setStatusTip(tr("Create a new file")); connect(newAct, SIGNAL(triggered()), this, SLOT(newFile()));  openAct = new QAction(QIcon(":/images/open.png"), tr("&Open..."), this); openAct->setShortcuts(QKeySequence::Open); openAct->setStatusTip(tr("Open an existing file")); connect(openAct, SIGNAL(triggered()), this, SLOT(open()));  saveAct = new QAction(QIcon(":/images/save.png"), tr("&Save"), this); saveAct->setShortcuts(QKeySequence::Save); saveAct->setStatusTip(tr("Save the document to disk")); connect(saveAct, SIGNAL(triggered()), this, SLOT(save())); 

  14. Create Actions, 2 //Continue specifying actions for rest of menu items saveAsAct = new QAction(tr("Save &As..."), this); saveAsAct->setShortcuts(QKeySequence::SaveAs); saveAsAct->setStatusTip(tr("Save the document under a new name")); connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs()));  exitAct = new QAction(tr("E&xit"), this); … cutAct = new QAction(QIcon(":/images/cut.png"), tr("Cu&t"), this); … copyAct = new QAction(QIcon(":/images/copy.png"), tr("&Copy"), this); … pasteAct = new QAction(QIcon(":/images/paste.png"), tr("&Paste"), this); … aboutAct = new QAction(tr("&About"), this); … aboutQtAct = new QAction(tr("About &Qt"), this); …

  15. “Functionality Implemented”, 1newFile, open - functions // “Functionality” means everything that is done … // From createActions: // connect(newAct, SIGNAL(triggered()), this, SLOT(newFile())); void MainWindow::newFile() { if (maybeSave()) { textEdit->clear(); // Next page setCurrentFile(""); } }  void MainWindow::open() { if (maybeSave()) { // Use Qt function QString fileName = QFileDialog::getOpenFileName(this); // Use it if you have it – next slide if (!fileName.isEmpty()) loadFile(fileName); } }

  16. Reference • QFileDialog

  17. “Functionality Implemented”, 2setCurrentFile – one function among many // “Maintain” file name // E.g., set “” with call from open void MainWindow::setCurrentFile(const QString &fileName) { curFile = fileName; textEdit->document()->setModified(false); setWindowModified(false);  QString shownName; if (curFile.isEmpty()) shownName = "untitled.txt"; else shownName = strippedName(curFile);  setWindowTitle(tr("%1[*] - %2").arg(shownName).arg(tr("Application"))); }

  18. “Functionality Implemented”, 3save, saveAs – more functions bool MainWindow::save() { // curFile value set in func setCurrentFile if (curFile.isEmpty()) { return saveAs(); } else { return saveFile(curFile); } }  bool MainWindow::saveAs() { // Use a Qt widget QString fileName = QFileDialog::getSaveFileName(this); if (fileName.isEmpty()) return false;  return saveFile(fileName); } 

  19. “Functionality implemented”, 4saveFile – another function bool MainWindow::saveFile(const QString &fileName) { QFile file(fileName); if (!file.open(QFile::WriteOnly | QFile::Text)) { QMessageBox::warning(this, tr("Application"), tr("Cannot write file %1:\n%2.") .arg(fileName) .arg(file.errorString())); return false; } QTextStream out(&file); QApplication::setOverrideCursor(Qt::WaitCursor); out << textEdit->toPlainText(); QApplication::restoreOverrideCursor();  setCurrentFile(fileName); statusBar()->showMessage(tr("File saved"), 2000); // status bar message return true; }

  20. “Functionality Implemented”, 5loadFile – another function void MainWindow::loadFile(const QString &fileName) { QFile file(fileName); if (!file.open(QFile::ReadOnly | QFile::Text)) { QMessageBox::warning(this, tr("Application"), tr("Cannot read file %1:\n%2.") .arg(fileName) .arg(file.errorString())); return; }  QTextStream in(&file); QApplication::setOverrideCursor(Qt::WaitCursor); textEdit->setPlainText(in.readAll()); QApplication::restoreOverrideCursor(); setCurrentFile(fileName); statusBar()->showMessage(tr("File loaded"), 2000); }

  21. “Functionality Implemented”, 6about void MainWindow::about() { QMessageBox::about(this, tr("About Application"), tr("The <b>Application</b> example demonstrates how to " "write modern GUI applications using Qt, with a menu bar, " "toolbars, and a status bar.")); }

  22. Summary • Idea was to provide a “template”, or examples of functionality needed • There is more to life than file processing …

  23. “Custom Widgets” • Of course, OO approach allows inheritance and subclassing • And it is good • Subclassing Qt widgets allows “simple” modifications to be simple • Will see the book’s example, which may be simple to the Qt professional! • Hex spin box • But first, simply using code to alter functionality works, too • And to combine separate widget functionality, as well • E.g., age spin and line edit boxes’ • Next slide • Also, changing public properties and calling public functions • This probably how you want to do it in your program • Custom widgets are fine example of how things are done once familiar with system – but, maybe not yet

  24. RecallSynchronization & Layout of 2 Widgets • 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 spinBox->setRange(0, 130); // Set/define range of each slider->setRange(0, 130); // 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)));

  25. Example – Hexadecimal Spin Box • Spin box that accepts and displays hexadecimal values • (sub) Class definition • HexSpinBox inherits most of its functionality from QSpinBox (and that is good) • Reimplements 2 virtual functions from QSpinBox // HexSpinBox.h – (sub)class definition #include <qspinbox.h> class HexSpinBox : public QSpinBox { public: HexSpinBox(QWidget *parent, const char *name = 0); protected: QString mapValueToText(int value); int mapTextToValue(bool *ok); };

  26. Hex Spin Box Functionality • User can modify box’s value by clicking arrows or typing in value • For what entered, restrict input to valid hex numbers • Use QRegExpValidator #include <qvalidator.h> #include "hexspinbox.h“ // Subclass of QSpinBox – hex vs. the decimal of QSpinBox HexSpinBox::HexSpinBox(QWidget *parent, const char *name) : QSpinBox(parent, name) { QRegExp regExp("[0-9A-Fa-f]+"); // Reference next setValidator(new QRegExpValidator(regExp, this)); setRange(0, 255); }

  27. Qt Reference • QRegExp • Regular expression manipulation

  28. Change QSpinBox Functionality • mapValueToText: converts integer value to string • QSpinBox calls it to update editor part of spin box when user presses arrows • Use Qstring::number() with arg 16 to convert value to lower-case hex • Use Qstring::upper() on result to make uppercase • Will change this and mapText to value for subclassing – simple! • (in the way what Petzold did with c was simple – but this really is, just new maybe) QString HexSpinBox::mapValueToText(int value) { return QString::number(value, 16).upper(); } • mapTextToValue: converts string to integer • QSpinBox calls it when user presses enter (line editor) int HexSpinBox::mapTextToValue(bool *ok) { return text().toInt(ok, 16); }

  29. Subclassing QWidget • Very general - can combine, adapt, modify, etc. existing widgets • As we just saw • Or, … can create whatever functionality desired by subclassing Qwidget • Here, will reimplement event handlers to paint widget and respond to mouse clicks • Which seems like a lot, but not too bad (for the Qt professional) • This why we looked at the windows API! • QLabel, QPushbutton, QTable implemented this way • Example – icon editor – IconEditor implementation

  30. IconEditor.h, 1Define (sub) class #include <qimage.h> #include <qwidget.h> class IconEditor : public QWidget // <- main thing { Q_OBJECT Q_PROPERTY(QColor penColor READ penColor WRITE setPenColor) // custom properties Q_PROPERTY(QImage iconImage READ iconImage WRITE setIconImage) Q_PROPERTY(int zoomFactor READ zoomFactor WRITE setZoomFactor) public: IconEditor(QWidget *parent = 0, const char *name = 0); void setPenColor(const QColor &newColor); QColor penColor() const { return curColor; } void setZoomFactor(int newZoom); int zoomFactor() const { return zoom; } void setIconImage(const QImage &newImage); const QImage &iconImage() const { return image; } QSize sizeHint() const;

  31. IconEditor.h, 2 Define (sub) class // Reimplements 3 (important!) functions from QWidget and has private variables for 3 values // (familiar looking variable names?) protected: void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void paintEvent(QPaintEvent *event); private: void drawImagePixel(QPainter *painter, int i, int j); // Accesses image, below void setImagePixel(const QPoint &pos, bool opaque); // “ QColor curColor; QImage image; // Principal data structure int zoom; };

  32. IconEditor.cppAll the functions … #include <qpainter.h> #include "iconeditor.h“ IconEditor::IconEditor(QWidget *parent, const char *name) : QWidget(parent, name, WStaticContents) { setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); curColor = black; // Default (start up) values: zoom = 8; // E.g., render pixel in 8x8 square image.create(16, 16, 32); image.fill(qRgba(0, 0, 0, 0)); image.setAlphaBuffer(true); } QSize IconEditor::sizeHint() const { QSize size = zoom * image.size(); if (zoom >= 3) // Will show grid at higher zooms size += QSize(1, 1); return size; }

  33. IconEditor.cpp void IconEditor::setPenColor(const QColor &newColor) { curColor = newColor; } void IconEditor::setIconImage(const QImage &newImage) { if (newImage != image) { image = newImage.convertDepth(32); // Set right form image.detach(); // Copy for faster update(); // Force a repaint – as invalidaterect! updateGeometry(); // So can use sizehint } }

  34. IconEditor.cpp // paintEvent is an event handler! – this handles the paint event, rather than something else in Qt // (this is down in it) void IconEditor::paintEvent(QPaintEvent *) { QPainter painter(this); if (zoom >= 3) { // if need grid, draw lines painter.setPen(colorGroup().foreground()); for (int i = 0; i <= image.width(); ++i) // Qt drawLine function painter.drawLine(zoom * i, 0, zoom * i, zoom * image.height()); for (int j = 0; j <= image.height(); ++j) painter.drawLine(0, zoom * j, zoom * image.width(), zoom * j); } for (int i = 0; i < image.width(); ++i) { for (int j = 0; j < image.height(); ++j) drawImagePixel(&painter, i, j); // drawImagePixel next page … } }

  35. IconEditor.cpp void IconEditor::drawImagePixel(QPainter *painter, int i, int j) // i, j coords inQImage, NOT in { // widget – it will have zoom lines QColor color; QRgb rgb = image.pixel(i, j); if (qAlpha(rgb) == 0) color = colorGroup().base(); else color.setRgb(rgb); if (zoom >= 3) { // will draw blocks (fillRect) for individual pixels – like, “way zoomed in” painter->fillRect(zoom * i + 1, zoom * j + 1, zoom - 1, zoom - 1, color); } else { painter->fillRect(zoom * i, zoom * j, zoom, zoom, color); } }

  36. IconEditor.cpp // Reimplement mouse handling events void IconEditor::mousePressEvent(QMouseEvent *event) { if (event->button() == LeftButton) setImagePixel(event->pos(), true); // setImagePixel (next) changes image else if (event->button() == RightButton) // to be used in next paint event setImagePixel(event->pos(), false); } void IconEditor::mouseMoveEvent(QMouseEvent *event) { if (event->state() & LeftButton) setImagePixel(event->pos(), true); else if (event->state() & RightButton) setImagePixel(event->pos(), false); }

  37. IconEditor.cpp void IconEditor::setImagePixel(const QPoint &pos, bool opaque) { int i = pos.x() / zoom; int j = pos.y() / zoom; if (image.rect().contains(i, j)) { if (opaque) image.setPixel(i, j, penColor().rgb()); else image.setPixel(i, j, qRgba(0, 0, 0, 0)); QPainter painter(this); drawImagePixel(&painter, i, j); } }

  38. Just a Preview • … of what can be done with interface tools • Idea with the programming this semester was to provide a “foundation” of terms and techniques … for use wherever relevant, e.g., Qt

  39. End • .

More Related