如何通过鼠标拖放来更改布局中小部件的顺序?

Posted

技术标签:

【中文标题】如何通过鼠标拖放来更改布局中小部件的顺序?【英文标题】:How can i change order of widget in layout by drag and drop with the mouse? 【发布时间】:2016-07-07 04:22:11 【问题描述】:

我从QWidget 创建自己的课程,并重新定义paintEvent()mousePressEvent()mouseReleaseEvent()mouseMoveEvent()。所有将小部件移动到其他小部件上的方法(黄色)。

当我在布局中创建小部件时,它看起来像这样:

但是当我像这样将黑色小部件移动到底部并将红色移动到顶部时:

并调整窗口大小,所有小部件都会刷新到它们的对齐位置:

但我希望,当我将一个小部件移到另一个上方时,小部件应该在新位置的布局中对齐,如下所示:

我应该重新定义哪个函数?

附: There is 一段代码,可以在布局内移动小部件位置(更改它们的索引),但我不知道如何找出它们的 (x,y) 位置来计算布局中的新索引。我想,我可以在resizeEvent() 中做到这一点。 但是当它发出事件时,位置已经变旧了。 (就像在一张照片上移动之前),我需要移动后的位置(就像在第二张照片上)。如何在对齐之前获取小部件的位置? 或者

【问题讨论】:

请正确格式化您的问题并处理句子结构,尤其是在底部的 P.S. 中。就我个人而言,我不知道您所说的“在resizeEvent() 我得到了新职位”是什么意思,尤其是在另一段奇特的文字之后:“但我不知道如何知道他们的职位”。我会格式化您的图像,但其余的取决于您。 顺便说一句,如果您的小部件看起来像您的图像中的样子,我建议您使用QGraphicsSceneQGraphicsProxyWidget,您可以在其中设置z value,以确定哪些项目重叠。 @rbaleksandar 我改变了我的问题。还不清楚吗? 您总是可以使用一些类成员变量来存储小部件的位置。因此,每次您捕获resize event 时,您都可以使用新值和旧值。正如我之前的评论中提到的,你正在做的事情看起来很像QGraphicsScene 的工作。如果您仍然不想使用它,则必须使每个小部件都可以拖动(请参阅dragEnterEventQWidget 的相关功能部分)以及能够接受拖放(请参阅acceptDropsdropEvent - 又是QWidget 的一部分)。 @rbaleksandar 我想在布局上做一些可拖动、对齐的小部件。就像 android 菜单中的图标一样,当您长按时,您可以将图标移动到新位置,当您放下它(释放点击)时,图标会改变它的位置,并且所有其他图标都与所有更改相关联。最好的方法是什么?我需要向 Google 提出什么样的请求,才能获得我想要的一些信息? 【参考方案1】:

我编写自己的小部件,然后重新定义以下方法:mouseReleaseEvent(), paintEvent(), mousePressEvent(), mouseMoveEvent()。在mousePressEvent() 中,我持有旧的 X 和 Y 位置以及鼠标位置。然后在mouseMoveEvent() 我计算鼠标移动的最小距离是否丰富并将小部件移动到新位置(它不会在布局中移动小部件索引)。之后,如果发出mouseReleaseEvent(),我只需计算移动小部件的新索引并更改和更新父布局。如果小部件的移动小于它的高度,那么布局只会更新而不改变小部件索引。

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();

【讨论】:

以上是关于如何通过鼠标拖放来更改布局中小部件的顺序?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过拖放获取鼠标下QLayout中的小部件?

闪亮的小部件,以更改向量中的元素的顺序

qwidget如何拖放由几个小部件组成?

如何拖放自定义小部件?

如何在堆栈中垂直或水平居中小部件?

如何在从另一个小部件拖放事件期间突出显示表格单元格