1
votes

I make my own class from QWidget with redefine of paintEvent(), mousePressEvent(), mouseReleaseEvent() and mouseMoveEvent(). All that methods for move widgets over other widget (yellow).

When i create my widgets in a layout, it looks like this:

But when I move black widget to the bottom and red to the top like this:

and resize window, all widgets refresh to their align positions:

But i want, when i move one widget higher then another, the widgets should align in layout in new places, like this:

Which function i should redefine to do it?

P.S. There is a piece of code, that can move widgets positions inside layout (change their indexes), but i don't know how find out their (x,y) position to calculate new indexes in layout. I think, that i can do it in resizeEvent(). But it when it event was emitted, positions already changed to old. (like before moveing on 1 picture), and i need positions after moveing (like on secon picture). How can i get position of widget before it will be aligned? or How can i change order of widget in layout by drag and drop with the mouse?

1
Please format your question properly and work on the sentence structure especially in your P.S. at the bottom. Personally I have no idea what you mean by "In resizeEvent() i got new position yet" especially after another peculiar piece of text: "but i don't know how know their positions". I will format your images but the rest is up to you.rbaleksandar
Btw if your widgets look the way they do in your images I would suggest using QGraphicsScene with QGraphicsProxyWidget where you can set the z value which determines which item overlaps which.rbaleksandar
@rbaleksandar I change my question. Is it still unclear?murzagurskiy
You can always use some class member variables to store the positions of your widgets. So every time you capture a resize event you will have both the new and the old values at your disposal. As mentioned in my previous comment what you are doing seems a lot like a job for QGraphicsScene. If you still don't want to use it you have to enable each of your widgets to be draggable (see the dragEnterEvent and relative functions part of QWidget) as well as being able to accept drops (see acceptDrops and dropEvent - again part of QWidget).rbaleksandar
@rbaleksandar I want do something like dragable, aligned widgets on layout. Like icons in Android menu, when you do long tap, and then you can move you icon in new place, when you drop it (release tap) icon change it position and all other icons aligned related to all changes. What is the best way to do it? What kind of request to Google i need to do, to get some info about what i want?murzagurskiy

1 Answers

1
votes

I write my own widget, then redefine following methods: mouseReleaseEvent(), paintEvent(), mousePressEvent(), mouseMoveEvent(). In mousePressEvent() I hold old X and Y positions and mouse position on figure. Then in mouseMoveEvent() i calculate if minimum distance of mouse move is riched and move widget to new position (it not moves widget index in layout). After it, if emitted mouseReleaseEvent() i just calculate new index of moving widget and change and update parent layout. If widget moves less then it height, then layout just updates without changing widget index.

void SimpleWidget::mouseMoveEvent(QMouseEvent *event)
{
    if (!(event->buttons() & Qt::LeftButton))
        return;
    if (!IsMinimumDistanceRiched(event))
    {
        return;
    }
    int y = event->globalY() - mouseClickY + oldY;
    int BottomBorder = parentWidget->geometry().height() - this->geometry().height();
    if(y < 0) y = 0;
    else if(y > BottomBorder) y = BottomBorder;
    move(oldX, y);
}

void SimpleWidget::mousePressEvent(QMouseEvent *event)
{
    if (event->buttons() & Qt::LeftButton)
        dragStartPosition = event->pos();
    oldX = this->geometry().x();
    oldY = this->geometry().y();
    mouseClickX = event->globalX();
    mouseClickY = event->globalY();
}

bool SimpleWidget::IsMinimumDistanceRiched(QMouseEvent *event)
{
    return (event->pos() - dragStartPosition).manhattanLength() >= QApplication::startDragDistance();
}

bool SimpleWidget::moveInLayout(QWidget *widget, MoveDirection direction)
{
    QVBoxLayout* myLayout = qobject_cast<QVBoxLayout*>(widget->parentWidget()->layout());

    const int index = myLayout->indexOf(widget);
    if (direction == MoveUp && index == 0)
    {
        return false;
    }
    if (direction == MoveDown && index == myLayout->count()-1 )
    {
        return false;
    }
    const int newIndex = direction == MoveUp ? index - 1 : index + 1;
    myLayout->removeWidget(widget);
    myLayout->insertWidget(newIndex , widget);
    return true;
}

void SimpleWidget::paintEvent(QPaintEvent *)
{
    QStyleOption o;
    o.initFrom(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &o, &p, this);
}

void SimpleWidget::mouseReleaseEvent(QMouseEvent *)
{
    int y = geometry().y();
    MoveDirection direct;
    int offset;
    if(oldY > y)
    {
        offset = oldY - y;
        direct = MoveUp;
    }
    else if(oldY < y)
    {
        offset = y - oldY;
        direct = MoveDown;
    }
    int count = offset/height();
    for(int i = 0; i < count; i++)
    {
        moveInLayout(this, direct);
    }
    update();
    QVBoxLayout* myLayout = qobject_cast<QVBoxLayout*>(this->parentWidget->layout());
    myLayout->update();
    this->saveGeometry();
}