2

I am implementing a little interface with Qt. In the step I am currently working on, I have Scores (custom class) I can move on Docks (again, custom class) that can hold only one Score.

I inspired myself (a lot) with this example: Fridge magnets.
In this configuration, the information of the dragged object are brought along thanks to a QByteArray, stocked in the mime data, thanks to serialization by QDataStream.

I would like for a Score, when dropped on an occupied Dock, to make the "residing" Score to go to his original space. I thought I could do that by having an attribute containing the adress of its original Dock, but I can't get this pointer stocked in the datastream.

Here follows part of my code:

/* Part of the definition of my classes */

class Score : public QLabel
{
    Q_OBJECT

    protected:
        QString labelText;
        Dock * dock;
        QImage * click;
};

class Dock : public QFrame
{
Q_OBJECT

protected:
    Score * score;
};


/* And the 4 methods allowing the drag and drop */
void Dock::mousePressEvent(QMouseEvent *event)
{
    Score * child = dynamic_cast<Score *>(childAt(event->pos()));
    if (!child)
        return;

    QPoint hotSpot = event->pos() - child->pos();

    QByteArray itemData;
    QDataStream dataStream(&itemData, QIODevice::WriteOnly);
    dataStream << child->getLabelText() << child->getClick() << QPoint(hotSpot);

    QMimeData *mimeData = new QMimeData;
    mimeData->setData("application/x-score", itemData);
    mimeData->setText(child->getLabelText());

    QDrag *drag = new QDrag(this);
    drag->setMimeData(mimeData);
    drag->setPixmap(QPixmap::fromImage(*child->getClick()));
    drag->setHotSpot(hotSpot);

    child->hide();

    if (drag->exec(Qt::MoveAction) == Qt::MoveAction)
        child->close();
    else
        child->show();
}

void Dock::dragEnterEvent(QDragEnterEvent *event)
{
    if (event->mimeData()->hasFormat("application/x-score"))
    {
        if (children().contains(event->source()))
        {
            event->setDropAction(Qt::MoveAction);
            event->accept();
        }
        else
            event->acceptProposedAction();
    }
    else
        event->ignore();

}

void Dock::dragMoveEvent(QDragMoveEvent *event)
{
    if (event->mimeData()->hasFormat("application/x-score"))
    {
        if (children().contains(event->source()))
        {
            event->setDropAction(Qt::MoveAction);
            event->accept();
        }
        else
            event->acceptProposedAction();
    }
   else
        event->ignore();
}

void Dock::dropEvent(QDropEvent *event)
{
    if (event->mimeData()->hasFormat("application/x-score"))
    {
        const QMimeData *mime = event->mimeData();

        QByteArray itemData = mime->data("application/x-score");
        QDataStream dataStream(&itemData, QIODevice::ReadOnly);

        QString text;
        QImage * img;
        QPoint offset;
        dataStream >> text >> img >> offset;

        Score * newScore = new Score(text, this);
        newScore->show();
        newScore->setAttribute(Qt::WA_DeleteOnClose);

        if (event->source() == this) {
            event->setDropAction(Qt::MoveAction);
            event->accept();
        }
        else
            event->acceptProposedAction();

    }
    else
        event->ignore();

    static_cast<FrameCC *>(parentWidget())->calcTotal();
}

I couldn't overload the << and the >> operator for QDataStream and Dock * because the only way I found of doing that with a pointer was to stock the actual data. But the problem is I don't want the data, I litteraly just need the pointer!

I you have an idea, even if it means I have to rethink the way of doing this, I would gladly hear it. Thank you!

  • So I changed my approach on the subject and attributed a number (int) to my docks and gave this number to the docks. It kinda works now (other issues but I don't think they are related to this) but it sure would be nice to have an idea to serialize this pointers^^ – Benji-jumping Jun 23 '14 at 22:07

1 Answers1

1

If I understood right, you'd like to serialize a pointer to a dock? I don't really understand why you are doing this the hard way.

What about this:

  • make your mime-data simply a pointer to the score like itemData.fromRawData(reinterpret_cast<char*>(&score, sizeof(Score&ast;)));
  • in the dropEvent()
    • use event->source() to get the dock's pointer
    • use another stream and the reverse procedure to extract the pointer from the mimeData, or simply an uber-cast union: union {char chr[8]; Score &ast;score} scorecast; memcpy(scorecast.chr, itemData.data(), sizeof(Score&ast;)); , then access your score-pointer via scorecast.score

That would also save you from sending around all the data in the Score-to-drop ...

Just a last thought: QByteArray.data() gives a const char * to the data making up your pointer. What about *reinterpret_cast<Score * *>(imageData.data()) to get your pointer back?

And a second last though came up reading my own QDataStream marshalling code:

QDataStream & operator << (QDataStream & s, const Score * scoreptr)
{
    qulonglong ptrval(*reinterpret_cast<qulonglong *>(&scoreptr));
    return s << ptrval;
}
QDataStream & operator >> (QDataStream & s, Score *& scoreptr)
{
    qulonglong ptrval;
    s >> ptrval;
    scoreptr = *reinterpret_cast<Score **>(&ptrval);
    return s;
}
St0fF
  • 1,553
  • 12
  • 22