(C++) QGraphicsSimpleTextItemExample4
March 5, 2018 · View on GitHub
QGraphicsSimpleTextItem example 4: use arrow keys to change focus is a QGraphicsSimpleTextItem example that displays multiple QGraphicsSimpleTextItems with their coordinats as text. These items are movable and selectable. By pressing tab, focus will be set to a random item. By pressing the arrow, focus will be given to the nearest item in that direction.

Technical facts
Operating system(s) or programming environment(s)
Lubuntu 15.04 (vivid)
Qt Creator 3.1.1
- G++ 4.9.2
Libraries used:
Qt project file: ./CppQGraphicsSimpleTextItemExample4/CppQGraphicsSimpleTextItemExample4.pro
exists(../../DesktopApplication.pri) { include(../../DesktopApplication.pri) } !exists(../../DesktopApplication.pri) { QT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets win32 { greaterThan(QT_MAJOR_VERSION, 4): QT += svg } TEMPLATE = app CONFIG(debug, debug|release) { message(Debug mode) } CONFIG(release, debug|release) { message(Release mode) DEFINES += NDEBUG NTRACE_BILDERBIKKEL } QMAKE_CXXFLAGS += -std=c++1y -Wall -Wextra -Weffc++ unix { QMAKE_CXXFLAGS += -Werror } } exists(../../Libraries/Boost.pri) { include(../../Libraries/Boost.pri) } !exists(../../Libraries/Boost.pri) { INCLUDEPATH += \ ../../Libraries/boost_1_55_0 } SOURCES += \ qtmain.cpp \ qtwidget.cpp \ qttextitem.cpp HEADERS += \ qtwidget.h \ qttextitem.h
./CppQGraphicsSimpleTextItemExample4/qtmain.cpp
#pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Weffc++" #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #include <QApplication> #include <QDesktopWidget> #include "qtwidget.h" #pragma GCC diagnostic pop int main(int argc, char *argv[]) { QApplication a(argc, argv); QtWidget w; { //Resize the dialog and put it in the screen center w.setGeometry(0,0,600,400); const QRect screen = QApplication::desktop()->screenGeometry(); w.move( screen.center() - w.rect().center() ); } w.show(); return a.exec(); }
./CppQGraphicsSimpleTextItemExample4/qttextitem.h
#ifndef QTTEXTITEM_H #define QTTEXTITEM_H #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Weffc++" #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #include <QGraphicsSimpleTextItem> #pragma GCC diagnostic pop struct QtTextItem : public QGraphicsSimpleTextItem { QtTextItem(QGraphicsItem *parent = 0); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); }; #endif // QTTEXTITEM_H
./CppQGraphicsSimpleTextItemExample4/qttextitem.cpp
#include "qttextitem.h" #include <cassert> #include <sstream> #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Weffc++" #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #include <QGraphicsScene> #pragma GCC diagnostic pop QtTextItem::QtTextItem(QGraphicsItem *parent) : QGraphicsSimpleTextItem(parent) { this->setFlags( QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); } void QtTextItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { std::stringstream s; s << "(" << static_cast<int>(this->pos().x()) << "," << static_cast<int>(this->pos().y()) << ")"; this->setText(s.str().c_str()); QGraphicsSimpleTextItem::paint(painter,option,widget); }
./CppQGraphicsSimpleTextItemExample4/qtwidget.h
#ifndef QTWIDGET_H #define QTWIDGET_H #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Weffc++" #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #include <QGraphicsView> #pragma GCC diagnostic pop ///The widget holding the items struct QtWidget : public QGraphicsView { QtWidget(QWidget *parent = 0); ///Respond to a key press void keyPressEvent(QKeyEvent *event); private: ///Obtain the closest item in the collection QGraphicsItem * GetClosest( const QGraphicsItem * const focus_item, const std::vector<QGraphicsItem *>& items) const; static double GetDistance(const QPointF& a, const QPointF& b); ///Obtain the items above the focus_item const std::vector<QGraphicsItem *> GetItemsAbove(const QGraphicsItem * const focus_item) const; ///Obtain the items below the focus_item const std::vector<QGraphicsItem *> GetItemsBelow(const QGraphicsItem * const focus_item) const; ///Obtain the items left of the focus_item const std::vector<QGraphicsItem *> GetItemsLeft(const QGraphicsItem * const focus_item) const; ///Obtain the items right of the focus_item const std::vector<QGraphicsItem *> GetItemsRight(const QGraphicsItem * const focus_item) const; ///Give focus to a random item void SetRandomFocus(); }; #endif // QTWIDGET_H
./CppQGraphicsSimpleTextItemExample4/qtwidget.cpp
#include "qtwidget.h" #include <cassert> #include <cmath> #include <iostream> #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Weffc++" #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #include <boost/math/constants/constants.hpp> #include <QGraphicsScene> #include <QKeyEvent> #include "qttextitem.h" #pragma GCC diagnostic pop QtWidget::QtWidget(QWidget *parent) : QGraphicsView(new QGraphicsScene,parent) { const int n_items = 16; for (int i=0; i!=n_items; ++i) { const double angle = boost::math::constants::two_pi<double>() * (static_cast<double>(i+0) / static_cast<double>(n_items)); const double ray = 150.0; const double x = std::sin(angle) * ray; const double y = -std::cos(angle) * ray; QtTextItem * const item = new QtTextItem; item->setPos(x,y); scene()->addItem(item); } } QGraphicsItem * QtWidget::GetClosest( const QGraphicsItem * const focus_item, const std::vector<QGraphicsItem *>& items) const { assert(!items.empty()); //Remove focus item for items_all (if needed) //std::vector<QGraphicsItem *> items(items_all); //items.erase(std::remove(items.begin(),items.end(),focus_item),items.end()); assert(std::count(items.begin(),items.end(),focus_item) == 0); QGraphicsItem * best = nullptr; double best_distance = std::numeric_limits<double>::max(); for (QGraphicsItem * const item:items) { assert(item != focus_item); const double distance = GetDistance(focus_item->pos(),item->pos()); if (distance < best_distance) { best_distance = distance; best = item; } } assert(best); return best; } double QtWidget::GetDistance(const QPointF& a, const QPointF& b) { const double dx = a.x() - b.x(); const double dy = a.y() - b.y(); return std::sqrt((dx * dx) + (dy * dy)); } const std::vector<QGraphicsItem *> QtWidget::GetItemsAbove(const QGraphicsItem * const focus_item) const { std::vector<QGraphicsItem *> v; const QList<QGraphicsItem *> items = this->items(); for(QGraphicsItem * const item: items) { const double dy = item->pos().y() - focus_item->pos().y(); if (dy < 0.0) //Use '<' (instead of '<=') to leave out focus_item { const double dx = item->pos().x() - focus_item->pos().x(); if (std::abs(dx) < std::abs(dy)) { assert(item != focus_item); v.push_back(item); } } } return v; } const std::vector<QGraphicsItem *> QtWidget::GetItemsBelow(const QGraphicsItem * const focus_item) const { std::vector<QGraphicsItem *> v; const QList<QGraphicsItem *> items = this->items(); for(QGraphicsItem * const item: items) { const double dy = item->pos().y() - focus_item->pos().y(); if (dy > 0.0) //Use '>' (instead of '>=') to leave out focus_item { const double dx = item->pos().x() - focus_item->pos().x(); if (std::abs(dx) < std::abs(dy)) { assert(item != focus_item); v.push_back(item); } } } return v; } const std::vector<QGraphicsItem *> QtWidget::GetItemsLeft(const QGraphicsItem * const focus_item) const { std::vector<QGraphicsItem *> v; const QList<QGraphicsItem *> items = this->items(); for(QGraphicsItem * const item: items) { const double dx = item->pos().x() - focus_item->pos().x(); if (dx < 0.0) //Use '<' (instead of '<=') to leave out focus_item { const double dy = item->pos().y() - focus_item->pos().y(); if (std::abs(dy) < std::abs(dx)) { assert(item != focus_item); v.push_back(item); } } } return v; } const std::vector<QGraphicsItem *> QtWidget::GetItemsRight(const QGraphicsItem * const focus_item) const { std::vector<QGraphicsItem *> v; const QList<QGraphicsItem *> items = this->items(); for(QGraphicsItem * const item: items) { const double dx = item->pos().x() - focus_item->pos().x(); if (dx > 0.0) //Use '>' (instead of '>=') to leave out focus_item { const double dy = item->pos().y() - focus_item->pos().y(); if (std::abs(dy) < std::abs(dx)) { assert(item != focus_item); v.push_back(item); } } } return v; } void QtWidget::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Up: { QGraphicsItem * const focus_item = scene()->focusItem(); if (!focus_item) { return; } const std::vector<QGraphicsItem *> items = GetItemsAbove(focus_item); if (items.empty()) { return; } QGraphicsItem * const new_focus_item = GetClosest(focus_item,items); focus_item->setEnabled(false); focus_item->clearFocus(); focus_item->setEnabled(true); new_focus_item->setFocus(); } break; case Qt::Key_Right: { QGraphicsItem * const focus_item = scene()->focusItem(); if (!focus_item) { return; } const std::vector<QGraphicsItem *> items = GetItemsRight(focus_item); if (items.empty()) { return; } QGraphicsItem * const new_focus_item = GetClosest(focus_item,items); focus_item->setEnabled(false); focus_item->clearFocus(); focus_item->setEnabled(true); new_focus_item->setFocus(); } break; case Qt::Key_Down: { QGraphicsItem * const focus_item = scene()->focusItem(); if (!focus_item) { return; } const std::vector<QGraphicsItem *> items = GetItemsBelow(focus_item); if (items.empty()) { return; } QGraphicsItem * const new_focus_item = GetClosest(focus_item,items); focus_item->setEnabled(false); focus_item->clearFocus(); focus_item->setEnabled(true); new_focus_item->setFocus(); } break; case Qt::Key_Left: { QGraphicsItem * const focus_item = scene()->focusItem(); if (!focus_item) { return; } const std::vector<QGraphicsItem *> items = GetItemsLeft(focus_item); if (items.empty()) { return; } QGraphicsItem * const new_focus_item = GetClosest(focus_item,items); focus_item->setEnabled(false); focus_item->clearFocus(); focus_item->setEnabled(true); new_focus_item->setFocus(); } break; case Qt::Key_Tab: { SetRandomFocus(); } break; } //Let QGraphicsView do the rest... QGraphicsView::keyPressEvent(event); } void QtWidget::SetRandomFocus() { //Let existing item lose focus if (QGraphicsItem * const item = scene()->focusItem()) { //Really lose focus item->setEnabled(false); item->clearFocus(); item->setEnabled(true); } //Let a random item receive focus const QList<QGraphicsItem *> items = this->items(); items.at( std::rand() % items.size() )->setFocus(); }