服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - Qt实现拖动单个控件移动的示例代码

Qt实现拖动单个控件移动的示例代码

2023-02-08 14:37中国好公民st C/C++

做惯了静态图,今天来搞一搞动态图吧!本文将利用Qt实现拖动单个控件移动效果,文中的示例代码讲解详细,感兴趣的可以动手尝试一下

做惯了静态图,今天来搞一搞动态图吧,首先来个最基础的功能:如果让一个控件拖动起来。

展示效果:

Qt实现拖动单个控件移动的示例代码

按照以往简单的做法,使用mouseMoveEvent、mousePressEvent、mouseReleaseEvent也是可以实现的。这是最基础的移动做法。

今天,不使用那种简单的做法,采用Qt一种特有的拖动方法来实现!

使用QDropEvent实现拖拽事件。

实现控件拖拽的流程,如下:

1:创建一个控件,这里使用QLabel控件。

2:选中需要拖拽的控件

3:重写拖拽事件。

根据上述操作流程,来实现一个控件的拖拽吧!

1.设置窗口拖拽属性

在Qt中,默认是不响应拖拽消息的,这跟mouseMoveEvent消息默认不响应是一样的,必须明确调用,告诉窗口,需要响应此消息。

this->setAcceptDrops(true);

2.创建初始控件

创建一个初始控件,用于初始拖动使用。

?
1
2
3
4
5
6
QLabel *labIcon = new QLabel(this);
labIcon->setText("");
labIcon->setPixmap(QPixmap(":/QDragSingleLabel/image/boat.png"));
labIcon->move(10, 10);
labIcon->show();
labIcon->setAttribute(Qt::WA_DeleteOnClose);

偷懒起见,对QLabel控件设置了窗口关闭销毁的功能,很是方便。

3.选中控件进行拖动

鼠标在控件上按下,开始做拖动操作;当鼠标抬起时,不进行拖动操作。

3.1响应mousePressEvent事件

需要知道鼠标是否点击到控件上

这里需要特殊注意的是:QLabel是一个静态控件,正常情况下是不会响应鼠标选中效果的。

此时,需要响应QWidget鼠标按下的事件,将鼠标点击的点转换成是否选中QLabel控件,侧面实现数据点击控件效果。

?
1
2
3
4
5
6
QLabel *child = static_cast<QLabel*>(childAt(event->pos()));
if(!child)
{
    //不是QLabel控件,不进行处理
    return;
}

QWidget::childAt(const QPoint& p)const;说明:返回窗口小部件自身坐标系统中p点处的可见子窗口小部件。

查询到有效QLabel指针后,创建一个可存储在剪贴板中的信息,通过拖放机制进行传输的。这里采用:QMimeData类实现。

优势该类可以确保信息在应用程序之间安全传输,并且可以在相同的应用程序内复制。

创建该类并将QLabel中的数据传入到类中,用于做拖拽使用。

?
1
2
QMimeData *mimeData = new QMimeData;
mimeData->setData(qsEnum, itemData);

设置数据。

qsEnum:类型:QString。

在这里可以设置任意字符串,只要保证在拖拽消息时用的一个字符串就可以。为了方便统一,将该字符串做了统一设置。

const QString qsEnum = "zhongGuoHaoGongMin";//自定义数据类型

itemData:类型:QByteArray。

对QMimeData传入的数据,这里存放了QLabel的图片以及显示位置。

?
1
2
3
4
QPixmap pixmap = *child->pixmap();
QByteArray itemData;
QDataStream dataStream(&itemData, QIODevice::WriteOnly);
dataStream << pixmap << QPoint(event->pos() - child->pos());

上述内容准备就绪后,创建拖拽类,用于数据拖拽。

?
1
2
3
4
QDrag *drag = new QDrag(this);
drag->setMimeData(mimeData);
drag->setPixmap(pixmap);
drag->setHotSpot(event->pos() - child->pos());

将数据传递给拖动对象,设置将在操作期间与光标一起显示的像素图,并定义一个热点的位置,该热点将像素图的位置置于光标之下。

绘制拖动的位置,这里采用了QPainter绘制机制

?
1
2
3
4
5
6
7
QPixmap tempPixmap = pixmap;
QPainter painter;
painter.begin(&tempPixmap);
painter.fillRect(pixmap.rect(), QColor(127, 127, 127, 127));
painter.end();
    
child->setPixmap(tempPixmap);

开始拖动操作,调用QDrag::exec();

3.2判断控件拖动

目前只有一个控件可以拖动,那么,当创建多个拖动控件时,该如何判断要拖动哪个呢?

这时候,在创建QMimeData传入的自定义数据类型就起到作用了。

当数据类型是qsEnum时,进行判断,如果不是,不进行判断。

?
1
2
3
4
5
6
7
8
if (event->mimeData()->hasFormat(qsEnum))
{
    //进行判断
}
else
{
    event->ingnore(); //忽略判断
}

事件:dragEnterEvent、dragMoveEvent、dropEvent都需要这样判断。

3.3事件处理

当前是匹配的自定义数据类型时,并且是该资源是,接受拖动进入事件,并设置当前为拖动事件。

?
1
2
3
4
5
if (event->source() == this)
{
    event->setDropAction(Qt::MoveAction);
    event->accept();
}

否则设置执行操作并接收该事件

?
1
2
3
4
else
{
    event->acceptProposedAction();
}

3.4结束拖动

结束拖动,响应事件:virtual void dropEvent(QDropEvent *event)override;

除了处理操作3中的事件处理,还需要当鼠标结束操作时,需要在新的位置上重新创建QLabel控件。并将鼠标按下时创建的QMimeData数据获取出来,显示到新创建的QLabel控件上。

?
1
2
3
4
5
6
7
8
9
10
11
QByteArray itemData = event->mimeData()->data(qsEnum);
QDataStream dataStream(&itemData, QIODevice::ReadOnly);
QPixmap pixmap;
QPoint offset;
dataStream >> pixmap >> offset;
 
QLabel *newIcon = new QLabel(this);
newIcon->setPixmap(pixmap);
newIcon->move(event->pos() - offset);
newIcon->show();
newIcon->setAttribute(Qt::WA_DeleteOnClose);

dropEvent消息是什么时候被触发呢?

当鼠标左键弹起时,说明结束了控件拖动事件,需要调用dropEvent并重新创建控件,显示新位置。

?
1
2
3
4
5
6
7
8
9
10
11
12
Qt::DropAction n = drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction);
if (n == Qt::MoveAction)
{
    //结束操作
    child->close();
}
else
{
    //继续拖动控件,实时显示新位置
    child->show();
    child->setPixmap(pixmap);
}

到此这篇关于Qt实现拖动单个控件移动的示例代码的文章就介绍到这了,更多相关Qt拖动控件移动内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://juejin.cn/post/7111515493227298852

延伸 · 阅读

精彩推荐
  • C/C++C++中CopyFile和MoveFile函数使用区别的示例分析

    C++中CopyFile和MoveFile函数使用区别的示例分析

    这篇文章主要介绍了C++中CopyFile和MoveFile函数使用区别的示例分析,CopyFile表示将文件A拷贝到B,如果B已经存在则覆盖,MoveFile表示将文件A移动到。对此感兴...

    悦悦的小屋12162021-09-15
  • C/C++十分钟学会C++ Traits

    十分钟学会C++ Traits

    本文试图以最简洁的方式阐述对C++ traits 的理解,当你理解了第二个例子的时候,相信你已经理解了C++ traits,本文通过示例代码给大家介绍的非常详细,需...

    SolidMango11592022-09-16
  • C/C++C++类与对象深入之运算符重载与const及初始化列表详解

    C++类与对象深入之运算符重载与const及初始化列表详解

    运算符是程序中最最常见的操作,例如对于内置类型的赋值我们直接使用=赋值即可,因为这些编译器已经帮我们做好了,但是对象的赋值呢?能直接赋值吗...

    Rookiep8512022-12-21
  • C/C++C++类型转换归纳总结

    C++类型转换归纳总结

    这篇文章主要介绍了C++类型转换归纳总结,通过本文可以加深读者对于C++变量类型及其相互转换方法的理解,需要的朋友可以参考下...

    C++教程网7602021-01-24
  • C/C++C++实例讲解引用的使用

    C++实例讲解引用的使用

    引用是C++一个很重要的特性,顾名思义是某一个变量或对象的别名,对引用的操作与对其所绑定的变量或对象的操作完全等价,这篇文章主要给大家总结介绍...

    tianyvHon8912022-12-13
  • C/C++四叉树有损位图压缩处理程序示例

    四叉树有损位图压缩处理程序示例

    这篇文章主要介绍了四叉树有损位图压缩处理程序示例,可以对24位图进行压缩,应用于windows平台,需要的朋友可以参考下...

    C语言程序设计5992021-01-18
  • C/C++C语言 详解如何删除有序数组中的重复项

    C语言 详解如何删除有序数组中的重复项

    数组不擅长插入(添加)和删除元素。数组的优点在于它是连续的,所以查找数据速度很快。但这也是它的一个缺点。正因为它是连续的,所以当插入一个...

    许同学。。7692022-11-01
  • C/C++C++实现简易通讯录功能

    C++实现简易通讯录功能

    这篇文章主要为大家详细介绍了C++实现简易通讯录功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    良缘白马9722023-02-07