Drag And Drop - tlačítka s nástroji

Třída ToolButton

#include <QMimeData>
#include <QDrag>
#include <QMouseEvent>
 
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. Čtení XML souboru

“Zakompilované” soubory jsou popsány v soubory resources.qrc.
Jsou tam tři ikonky pro naše nástroje.

<RCC>
    <qresource prefix="/">
        <file>icons/ellipse.svg</file>
        <file>icons/line.svg</file>
        <file>icons/rectangle.svg</file>
        <file>data/abc.xml</file>
    </qresource>
</RCC>

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<QTreeWidgetItem *> 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 <QColor> ();
        if (node != nullptr)
        {
           QAbstractGraphicsShapeItem * shape = dynamic_cast < QAbstractGraphicsShapeItem * > (node->item);
           if (shape != nullptr)
           {
               if (action == Qt::CopyAction) /* ctrl */
                  shape->setPen (color); // need #include <QPen>
               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;
}
 
qt/graphics_tool_button.txt · Last modified: 2022/03/13 20:51 by 88.103.111.44
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki