===== 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;
}