如何通过鼠标拖放来更改布局中小部件的顺序?
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()
我得到了新职位”是什么意思,尤其是在另一段奇特的文字之后:“但我不知道如何知道他们的职位”。我会格式化您的图像,但其余的取决于您。
顺便说一句,如果您的小部件看起来像您的图像中的样子,我建议您使用QGraphicsScene
和QGraphicsProxyWidget
,您可以在其中设置z value
,以确定哪些项目重叠。
@rbaleksandar 我改变了我的问题。还不清楚吗?
您总是可以使用一些类成员变量来存储小部件的位置。因此,每次您捕获resize event
时,您都可以使用新值和旧值。正如我之前的评论中提到的,你正在做的事情看起来很像QGraphicsScene
的工作。如果您仍然不想使用它,则必须使每个小部件都可以拖动(请参阅dragEnterEvent
和QWidget
的相关功能部分)以及能够接受拖放(请参阅acceptDrops
和dropEvent
- 又是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();
【讨论】:
以上是关于如何通过鼠标拖放来更改布局中小部件的顺序?的主要内容,如果未能解决你的问题,请参考以下文章