(C++) QtExample33
February 24, 2017 · View on GitHub
(C++) QtExample33



Qt example 33: moveable and selectable arrows is a Qt example to create some arrows that are (easily) selectable and moveable.
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: ./CppQtExample33/CppQtExample33.pro
exists(../../DesktopApplication.pri) { include(../../DesktopApplication.pri) } !exists(../../DesktopApplication.pri) { QT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TEMPLATE = app CONFIG(debug, debug|release) { message(Debug mode) } CONFIG(release, debug|release) { message(Release mode) DEFINES += NDEBUG NTRACE_BILDERBIKKEL } QMAKE_CXXFLAGS += -std=c++11 -Wall -Wextra unix { QMAKE_CXXFLAGS += -Werror } } exists(../../Libraries/Boost.pri) { include(../../Libraries/Boost.pri) } !exists(../../Libraries/Boost.pri) { win32 { INCLUDEPATH += \ ../../../Projects/Libraries/boost_1_55_0 } } SOURCES += \ qtmain.cpp \ dialog.cpp \ qtarrowswidget.cpp \ qtarrowitem.cpp HEADERS += \ dialog.h \ qtarrowswidget.h \ qtarrowitem.h FORMS += dialog.ui
./CppQtExample33/dialog.h
#ifndef DIALOG_H #define DIALOG_H #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Weffc++" #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #include <QDialog> #pragma GCC diagnostic pop namespace Ui { class Dialog; } class Dialog : public QDialog { Q_OBJECT public: explicit Dialog(QWidget *parent = 0); Dialog(const Dialog&) = delete; Dialog& operator=(const Dialog&) = delete; ~Dialog() noexcept; private: Ui::Dialog *ui; }; #endif // DIALOG_H
./CppQtExample33/dialog.cpp
#pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Weffc++" #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #include "qtarrowswidget.h" #include "dialog.h" #include "ui_dialog.h" #pragma GCC diagnostic pop Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog) { ui->setupUi(this); ui->layout->addWidget(new QtArrowsWidget); } Dialog::~Dialog() noexcept { delete ui; }
./CppQtExample33/qtarrowitem.h
#ifndef QTARROWITEM_H #define QTARROWITEM_H #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Weffc++" #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #include <QGraphicsLineItem> #pragma GCC diagnostic pop struct QtArrowItem : public QGraphicsLineItem { QtArrowItem( const double x1, const double y1, const bool tail, const double x2, const double y2, const bool head, QGraphicsItem *parent = 0); protected: ///Paint a QtTextPositionItem void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *); ///The rectangle that containg the item, used for rough calculations like ///collision detection QRectF boundingRect() const; ///More precise shape compared to boundingRect ///In this example, it is redefined to ease selecting those thin lines QPainterPath shape() const; private: ///Show arrow at head const bool m_head; ///Show arrow at tail const bool m_tail; ///Obtain the angle in radians between two deltas ///12 o'clock is 0.0 * pi /// 3 o'clock is 0.5 * pi /// 6 o'clock is 1.0 * pi /// 9 o'clock is 1.5 * pi //From www.richelbilderbeek.nl/CppGetAngle.htm static double GetAngle(const double dx, const double dy); }; #endif // QTARROWITEM_H
./CppQtExample33/qtarrowitem.cpp
#include <cmath> #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Weffc++" #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #include <boost/math/constants/constants.hpp> #include <QPainter> #include "qtarrowitem.h" #pragma GCC diagnostic pop QtArrowItem::QtArrowItem( const double x1, const double y1, const bool tail, const double x2, const double y2, const bool head, QGraphicsItem *parent) : QGraphicsLineItem(x1,y1,x2,y2,parent), m_head(head), m_tail(tail) { this->setFlag(QGraphicsItem::ItemIsMovable); this->setFlag(QGraphicsItem::ItemIsSelectable); } double QtArrowItem::GetAngle(const double dx, const double dy) { return boost::math::constants::pi<double>() - (std::atan(dx/dy)); } QPainterPath QtArrowItem::shape() const { //Thanks to norobro for posting this code at //http://www.qtcentre.org/threads/49201-Increase-margin-for-detecting-tooltip-events-of-QGraphicsLineItem QPainterPath path; QPainterPathStroker stroker; path.moveTo(line().p1()); path.lineTo(line().p2()); stroker.setWidth(10); return stroker.createStroke(path); } QRectF QtArrowItem::boundingRect() const { return shape().boundingRect(); } void QtArrowItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) { painter->setRenderHint(QPainter::Antialiasing); if (this->isSelected()) { const QColor color(255,0,0); QPen pen; pen.setColor(color); pen.setWidth(3); painter->setPen(pen); QBrush brush; brush.setColor(color); brush.setStyle(Qt::SolidPattern); painter->setBrush(brush); } else { const QColor color(0,0,0); QPen pen; pen.setColor(color); pen.setWidth(1); painter->setPen(pen); QBrush brush; brush.setColor(color); brush.setStyle(Qt::SolidPattern); painter->setBrush(brush); } painter->drawLine(this->line()); //The angle from tail to head double angle = GetAngle(line().dx(),line().dy()); if (line().dy() >= 0.0) angle = (1.0 * boost::math::constants::pi<double>()) + angle; const double sz = 10.0; //pixels { const QPointF p0 = this->line().p1(); const QPointF p1 = p0 + QPointF( std::sin(angle + boost::math::constants::pi<double>() + (boost::math::constants::pi<double>() * 0.1)) * sz, -std::cos(angle + boost::math::constants::pi<double>() + (boost::math::constants::pi<double>() * 0.1)) * sz); const QPointF p2 = p0 + QPointF( std::sin(angle + boost::math::constants::pi<double>() - (boost::math::constants::pi<double>() * 0.1)) * sz, -std::cos(angle + boost::math::constants::pi<double>() - (boost::math::constants::pi<double>() * 0.1)) * sz); painter->drawPolygon(QPolygonF() << p0 << p1 << p2); } { const QPointF p0 = this->line().p2(); const QPointF p1 = p0 + QPointF( std::sin(angle + 0.0 + (boost::math::constants::pi<double>() * 0.1)) * sz, -std::cos(angle + 0.0 + (boost::math::constants::pi<double>() * 0.1)) * sz); const QPointF p2 = p0 + QPointF( std::sin(angle + 0.0 - (boost::math::constants::pi<double>() * 0.1)) * sz, -std::cos(angle + 0.0 - (boost::math::constants::pi<double>() * 0.1)) * sz); painter->drawPolygon(QPolygonF() << p0 << p1 << p2); } }
./CppQtExample33/qtarrowswidget.h
#ifndef QTARROWSWIDGET_H #define QTARROWSWIDGET_H #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Weffc++" #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #include <QGraphicsView> #pragma GCC diagnostic pop struct QtArrowsWidget : public QGraphicsView { QtArrowsWidget(); }; #endif // QTARROWSWIDGET_H
./CppQtExample33/qtarrowswidget.cpp
#include <cassert> #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 <QGraphicsPixmapItem> #include "qtarrowitem.h" #include "qtarrowswidget.h" #pragma GCC diagnostic pop QtArrowsWidget::QtArrowsWidget() { QGraphicsScene * const scene = new QGraphicsScene(this); this->setScene(scene); const int n_arrows = 16; for (int i=0; i!=n_arrows; ++i) { const double angle = boost::math::constants::two_pi<double>() * (static_cast<double>(i) / static_cast<double>(n_arrows)); const double x1 = std::sin(angle) * 100.0; const double y1 = -std::cos(angle) * 100.0; const bool tail = (std::rand() >> 4) % 2; const double x2 = std::sin(angle) * 200.0; const double y2 = -std::cos(angle) * 200.0; //const double x2 = ((static_cast<double>(std::rand()) / static_cast<double>(RAND_MAX)) * 600.0) - 300.0; //const double y2 = ((static_cast<double>(std::rand()) / static_cast<double>(RAND_MAX)) * 400.0) - 200.0; const bool head = (std::rand() >> 4) % 2; QtArrowItem * item = new QtArrowItem(x1,y1,tail,x2,y2,head); scene->addItem(item); } }
./CppQtExample33/qtmain.cpp
#pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Weffc++" #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #include <QApplication> #include <QDesktopWidget> #include "dialog.h" #pragma GCC diagnostic pop int main(int argc, char *argv[]) { QApplication a(argc, argv); Dialog 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(); }