===== Drag And Drop - tlačítka s nástroji ===== {{qt:toolbuttons.png}} ==== Třída ToolButton ==== #include #include #include class ToolButton : public QToolButton { public: ToolButton(); private: QString name; QIcon icon; protected: void mousePressEvent (QMouseEvent *event); public: ToolButton (QString p_name, QString p_icon_name = ""); }; void addToolButtons (QToolBar * page); ==== Reakce na stisknutí myši ==== Zavedeme vlastní formát dat //application/x-tool//. \\ Formát s tímto názvem bude přenášet řetězec znaků s jménem tlačítka (//rectangle//, //ellipse//, //line//) const QString toolFormat = "application/x-tool"; void ToolButton::mousePressEvent (QMouseEvent * event) { if (event->button() == Qt::LeftButton ) { QMimeData * mimeData = new QMimeData; mimeData->setData (toolFormat, name.toLatin1()); QDrag * drag = new QDrag (this); drag->setMimeData (mimeData); drag->setPixmap (icon.pixmap (24, 24)); drag->setHotSpot (QPoint (-16, -16)); Qt::DropAction dropAction = drag->exec (Qt::MoveAction | Qt::CopyAction | Qt::LinkAction); } } ==== Ikonka ==== Konstruktor má za parametry jméno tlačítka a cestu k souboru s obrázkem. \\ ToolButton::ToolButton (QString p_name, QString p_icon_name) : name (p_name) { if (p_icon_name == "") p_icon_name = ":/icons/" + p_name + ".svg"; icon = QIcon (p_icon_name); setIcon (icon); setToolTip (name); } Pokud souboru s obrázkem není zadán pokusíme se najít soubor podle jména tlačítka mezi //"zakompilovanými"// soubory. \\ Soubory začínající dvojtečkou jsem již použili pro soubor s počátečními daty. [[qt:graphics_read_xml|Čtení XML souboru]] \\ //"Zakompilované"// soubory jsou popsány v soubory **resources.qrc**. \\ Jsou tam tři ikonky pro naše nástroje. icons/ellipse.svg icons/line.svg icons/rectangle.svg data/abc.xml ==== Drop - vhození na scénu === Soubor **scene.cc** Metoda **dragEnterEvent** schvaluje druh dat tažených myší. \\ Totéž musíme udělat i při pohybu myši nad scénou. void Scene::dragEnterEvent (QGraphicsSceneDragDropEvent * event) { const QMimeData * mimeData = event->mimeData(); if (mimeData->hasColor() || mimeData->hasFormat (toolFormat)) { event->setAccepted (true); } else { event->setAccepted (false); } } // see http://stackoverflow.com/questions/4177720/accepting-drops-on-a-qgraphicsscene void Scene::dragMoveEvent (QGraphicsSceneDragDropEvent *event) { const QMimeData * mimeData = event->mimeData(); if (mimeData->hasColor() || mimeData->hasFormat (toolFormat)) { event->setAccepted (true); } else { event->setAccepted (false); } } Pokud //"upustíme"// data na scénu, vyzvedneme jméno nástroje a souřadnici vzhledem k rohu scény. \\ Funkce **itemFromTool** podle zadaného jména vytvoří grafický prvek. \\ Ten přidáme do scény nebo do jiného prvku na tomto místě. void Scene::dropEvent (QGraphicsSceneDragDropEvent * event) { const QMimeData * mimeData = event->mimeData(); if (mimeData->hasColor()) { /* ... */ } if (mimeData->hasFormat (toolFormat)) { QString tool = mimeData->data (toolFormat); QPointF p = event->scenePos (); int x = int (p.x ()); int y = int (p.y ()); QGraphicsItem * item = itemFromTool (tool, x, y); QGraphicsItem * target = itemAt (p, QTransform ()); if (target == nullptr) addItem (item); else item->setParentItem (target); win->refreshTree (); } } **io.c** QGraphicsItem * itemFromTool (QString tool, int x, int y) { QGraphicsItem * result = nullptr; if (tool == "rectangle") { QGraphicsRectItem * item = new QGraphicsRectItem; item->setRect (0, 0, 100, 80); item->setPen (QColor ("blue")); item->setBrush (QColor ("yellow")); item->setToolTip ("rectangle"); item->setFlags (QGraphicsItem::ItemIsMovable | QGraphicsEllipseItem::ItemIsSelectable); result = item; } else if (tool == "ellipse") { QGraphicsEllipseItem * item = new QGraphicsEllipseItem; item->setRect (0, 0, 60, 40); item->setPen (QColor ("orange")); item->setBrush (QColor ("lime")); item->setToolTip ("ellipse"); result = item; } else if (tool == "line") { QGraphicsLineItem * item = new QGraphicsLineItem; item->setLine (0, 0, 60, 40); item->setPen (QColor ("red")); item->setToolTip ("line"); result = item; } if (result != nullptr) { result->setPos (x, y); result->setFlags (QGraphicsItem::ItemIsMovable | QGraphicsEllipseItem::ItemIsSelectable); } return result; } ==== Drop - vhození do stromu === Pokud nástroj myší táhneme nad stromu (místo nad scénu), musíme předefinovat několik virtuálních funkcí stromu. Soubor **tree.h** class Tree : public QTreeWidget { protected: virtual QStringList mimeTypes () const override; // virtual QMimeData * mimeData (const QList items) const override; virtual bool dropMimeData (QTreeWidgetItem * parent, int index, const QMimeData * data, Qt::DropAction action) override; virtual Qt::DropActions supportedDropActions () const override; }; Soubor **tree.cc** Funkce **mimeTypes** vrací seznam přijatelných formátů dat. (Namísto dragEnterEvent.) \\ Obdobně metoda **supportedDropActions** povoluje přesun, kopírování nebo vyvtváření odkazu. QStringList Tree::mimeTypes() const // <-- importatnt { return QStringList () << "application/x-color" << toolFormat; } Qt::DropActions Tree::supportedDropActions() const { return Qt::MoveAction | Qt::CopyAction | Qt::LinkAction; } Pokud vhozená data obsahují barvu, uložíme ji do proměnné **color**. \\ Pokud byla provváděno kopírování (bylo stisklé //ctrl//) obarvíme okraj grafického prvku. \\ V opačném případě obarvíme vnitřek. Pokud vhozená data obsahují jméno nástroje, vytvoříme nový grafický prvek, prvek přidáme do scény a informaci o něm do stromu. bool Tree::dropMimeData (QTreeWidgetItem * target, int index, const QMimeData * data, Qt::DropAction action) { bool result = false; TreeNode * node = dynamic_cast < TreeNode * > (target); if (data->hasColor ()) { QColor color = data->colorData().value (); if (node != nullptr) { QAbstractGraphicsShapeItem * shape = dynamic_cast < QAbstractGraphicsShapeItem * > (node->item); if (shape != nullptr) { if (action == Qt::CopyAction) /* ctrl */ shape->setPen (color); // need #include else shape->setBrush (color); } } result = true; } else if (data->hasFormat (toolFormat)) { QString tool = data->data (toolFormat); QGraphicsItem * item = itemFromTool (tool, 0, 0); if (item != nullptr) { if (node == nullptr) scene->addItem (item); else item->setParentItem (node->item); } win->refreshNewTreeItem (item); } return result; }