Qt实现拖拽功能(支持拖放文件、拖放操作)

这篇具有很好参考价值的文章主要介绍了Qt实现拖拽功能(支持拖放文件、拖放操作)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


拖放

拖放是在一个应用程序内或者多个应用程序之间传递信息的一种直观的现代操作方式。除了为剪贴板提供支持外,通常它还提供数据移动和复制的功能。

拖放操作包括两个截然不同的动作:拖动和放下。Qt窗口部件可以作为拖动点(darg site)、放下点(drop site)或者同时作为拖动点和放下点。

Qt程序接受其他程序的拖拽

我们经常将文本文件推拽到notepate++等类型文本编辑器软件中。那么如何让Qt程序也能够支持这种操作呢?

我们需要在主窗口重新实现了来自父类的dragEnterEvent()dropEvent()函数。

protected:
    virtual void dragEnterEvent(QDragEnterEvent* event) override;
    virtual void dropEvent(QDropEvent* event) override;

在构造函数中,创建了一个QTextEdit并且把它设置为中央窗口部件。默认情况下,QTextEdit可以接受来自其他应用程序文本的拖动,并且如果用户在它上面放下一个文件,它将会把这个文件的内容填充到QTextEdit部件中。

由于拖放事件是从子窗口部件传递给父窗口部件的,所以通过禁用QTextEdit上的放下操作以及启用主窗口上的放下操作,就可以在整个MainWindow窗口中获得放下事件。

#include <QMimeData>
#include <QTextStream>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    
 
    textEdit = new QTextEdit(this);
    setCentralWidget(textEdit);

    textEdit->setAcceptDrops(false);
    setAcceptDrops(true);

    setWindowTitle("Text Editor");
}

当用户把一个对象拖动到这个窗口部件上时,就会调用dragEnterEvent()。如果对这个事件调用acceptProposedAction(),就表明用户可以在这个窗口部件上拖放对象。默认情况下,窗口部件是不接受拖动的。Qt会自动改变光标来向用户说明这个窗口部件是不是有效的放下点

这里,我们希望用户拖动的只能是文件,而非其他类型的东西。为了实现这一点,我们可以检查拖动的MIME类型。

MIME类型中的 text/uri-list 用于存储一系列的统一资源标识符(Universal Re-source Identifier ,URI),它们可以是文件名、统―资源定位器(Uniform Resource Locator , URL,如 HTTP或者FTP路径),或者其他全局资源标识符。标准的MIME类型是由国际因特网地址分配委员会(Internet Assigned Numbers Authority , IANA)定义的,它们由类型、子类型信息以及分隔两者的斜线组·成。MME类通常由剪贴板和拖放系统使用,以识别不同类型的数据。可以从下面的网站得到正式的 MIME类型列表: http://www.iana.org/assignments/media-types/

void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
    if(event->mimeData()->hasFormat("text/uri-list"))
    {
        event->acceptProposedAction();
    }
}

当用户在窗口部件上放下一个对象时,就会调用dropEvent()。.我们调用函数QMimeData::urls()来获得QUrl列表。通常,用户一次只拖动一个文件,但是通过拖动一个选择区域来同时拖动多个文件也是可能的。如果要拖放的URL不止一个,或者要拖放的URL,不是一个本地文件名,则会立即返回到原调用处。
QWidget也提供 dragMoveEvent()和 dragLeaveEvent()函数,但是在绝大多数应用程序中并不需要重新实现它们。

void MainWindow::dropEvent(QDropEvent *event)
{
    QList<QUrl> urls = event->mimeData()->urls();
    if(urls.empty())
        return;

    QString fileName = urls.first().toLocalFile();
    if(fileName.isEmpty())
        return;

    if(ReadFile(fileName))
    {
        setWindowTitle(QString("%1-%2").arg(fileName).arg("Drag File"));
    }
}
bool MainWindow::ReadFile(const QString &filename)
{
    QFile file(filename);
    file.open(QIODevice::ReadOnly | QIODevice::Text | QIODevice::Truncate);
    if(false == file.isOpen())
    {
        return false;
    }
    QTextStream stream(&file);
    textEdit->insertPlainText(stream.readAll());
    file.flush();
    file.close();
    return true;
}

看看效果吧
qt拖动文件到窗口,Qt,qt,c++,拖拽功能,拖放

部件/控件之间相互拖放

我们将实现类似于一个下图的效果,但不需要向左向右的按键,通过拖拽目标实现移动。
qt拖动文件到窗口,Qt,qt,c++,拖拽功能,拖放

思路:创建一个支持拖拽的QListWidget子类ProjectListWidget,并且作为该界面的一个部件。

在ProjectListWidget类中需要重写父类的五个事件,和一个私有方法以及一个坐标记录

protected:
    virtual void mousePressEvent(QMouseEvent* event) override;
    virtual void mouseMoveEvent(QMouseEvent* event) override;
    virtual void dragEnterEvent(QDragEnterEvent* event) override;
    virtual void dragMoveEvent(QDragMoveEvent* event) override;
    virtual void dropEvent(QDropEvent* event) override;
private:
    void performDrag();

private:
    QPoint startPos;

在构造函数中,我们使列表框上的放下生效。

#include <QApplication>
#include <QDrag>
#include <QMimeData>
ProjectListWidget::ProjectListWidget(QWidget* parent)
    :QListWidget{parent}
{
    setAcceptDrops(true);
}

当用户按下鼠标左键,就把鼠标位置保存到statPos私有变量中。然后我们正常调用QListWidget 中mousePressEvent()

void ProjectListWidget::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
        startPos = event->pos();
    }
    QListWidget::mousePressEvent(event);
}

当用户按住鼠标左键并移动鼠标光标时,就认为这是一个拖动的开始。我们计算当前鼠标位置和原来鼠标左键按下的点之间的距离-—这个“曼哈顿长度”(Manhattan Length)其实是从坐标原点到该矢量长度快速计算的近似值。如果这个距离大于或等于QApplication推荐的拖动起始距离值(通常是4个像素),那么就调用私有函数performDrag()以启动拖动操作。这可以避免用户因为手握鼠标抖动而产生拖动。

void ProjectListWidget::mouseMoveEvent(QMouseEvent *event)
{
    if(event->buttons() & Qt::LeftButton)
    {
        if(int distance = (event->pos() - startPos).manhattanLength();
            distance >= QApplication::startDragDistance())
        {
            performDrag();
        }
    }
    QListWidget::mouseMoveEvent(event);
}

perfomDrag()中,创建了一个类型为QDrag的对象,并且把this作为它的父对象。这个QDrag对象将数据存储在QMimeData对象中。在这个实例中,我们利用QMineData::setText()提供了作为text/plain字符串的数据。QMimeData 提供了一些可用于处理最常用拖放类型(诸如图像、URL、颜色,等等)的函数,同时也可以处理任意由QByteArrays表宗的MiME类型。QDrag::setPiximap()调用则可以在拖放发生时使图标随光标移动。
QDrag::exec()调用启动并执行拖动操作;直到用户放下或取消此次拖动操作才会停止。它把所有支持的“拖放动作"(如 Qi: : CopyAction, Qt : : MoveAction和 Qt: : LinkAction)的组合作为其参数,并且返回被执行的拖放动作(如果没有执行任何动作,则返回Qt: IgnoreAction)。至于执行的是哪`个动作,取决于放下发生时源窗口部件是否允许、目标是否支持及按下了哪些组合键。在 exec()调用后,Qt拥有拖动对象的所有权并且可以在不需要它的时候删除它。

void ProjectListWidget::performDrag()
{
    if(QListWidgetItem* item = currentItem();
        nullptr != item)
    {
        QMimeData* mineData = new QMimeData();
        mineData->setText(item->text());

        QDrag* drag = new QDrag(this);
        drag->setMimeData(mineData);
        drag->setPixmap(QPixmap(":/icon.jpg"));

        if(drag->exec(Qt::MoveAction) == Qt::MoveAction)
        {
            delete item;
            item = nullptr;
        }
    }
}	

ProjectListWidget窗口部件不仅能发起拖动,还可以接收同一个应用程序中来自另外一个ProjectListWidget部件的拖动。如果窗口部件是同个应用程序的一部分,QDragEnterEvent::source()返回一个启动这个拖动的窗口部件的指针;否则,返回一个空指针值。

void ProjectListWidget::dragEnterEvent(QDragEnterEvent *event)
{
    ProjectListWidget* source = reinterpret_cast<ProjectListWidget*>(event->source());
    if(nullptr != source && source != this)
    {
        event->setDropAction(Qt::MoveAction);
        event->accept();
    }
}

dragMoveEvent()中的代码与dragEnterEvent()中编写的代码基本相同。因为需要重写QListWidget的函数实现(实际上是 QAbstractItemView的函数实现)。

void ProjectListWidget::dragMoveEvent(QDragMoveEvent *event)
{
    ProjectListWidget* source = reinterpret_cast<ProjectListWidget*>(event->source());
    if(nullptr != source && source != this)
    {
        event->setDropAction(Qt::MoveAction);
        event->accept();
    }
}

在dropEvent()中,我们使用QMimeData::text()重新找回拖动的文本并随文本创建一个拖动项。还需要将事件作为“移动动作”来接受,从而告诉源窗口部件现在可以删除原来的拖动项了。

void ProjectListWidget::dropEvent(QDropEvent *event)
{
    ProjectListWidget* source = reinterpret_cast<ProjectListWidget*>(event->source());
    if(nullptr != source && source != this)
    {
        addItem(event->mimeData()->text());
        event->setDropAction(Qt::MoveAction);
        event->accept();
    }
}

效果如下
qt拖动文件到窗口,Qt,qt,c++,拖拽功能,拖放

总结

拖放是在应用程序之间传递数据的有力机制。但是在某些情况下;,有可能在执行拖放时并未使用Qt的拖放工具。如果只是想在一个应用程序的窗口部件中移动数据,通常只要重新实现mousePressEvent()和 mouseReleaseEvent()函数就可以了。文章来源地址https://www.toymoban.com/news/detail-517082.html

到了这里,关于Qt实现拖拽功能(支持拖放文件、拖放操作)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • QT 实现windows系统文件拖拽

    效果预览: 2023-07-05 14-29-11 功能描述: 1.首先实现了根据文件的路径获取了文件的信息,通过 QFileIconProvider 获取图标信息,并在界面上进行展示。 2.dropEvent 是实现拖拽功能的核心。重新此事件函数,并将窗口设置为接受拖拽 3.对文件进行类型判断,为了后续功能的使用。进

    2024年02月12日
    浏览(43)
  • Qt 打开文件列表选择文件,实现拖拽方式打开文件

    这里笔者选用的是 QMainWindow ,创建好工程后在 ui 界面设计中添加 QLineEdit 、 QPushBtton 至少这两个控件,如下图摆放。 在 mainwindow.h 中添加所要用到的所有头文件。 并声明一个槽函数用于打开文件浏览器。 initUi 函数,实现如下: showFiles 槽函数,实现如下: 完成如上函数,并

    2024年02月11日
    浏览(66)
  • React js原生 详解 HTML 拖放 API(鼠标拖放(拖动)功能)

    最近碰到了个需求,大概就是要通过可视化拖拽的方式配置一个冰柜,需要把预设好的冰柜内部架子模板一个个拖到冰箱内。一开始的想法是用鼠标事件(mousedown、mouseup等)那一套去实现,能实现但是过程过于复杂,需要控制的状态太多了。其实 Web Api 为 html 元素拖拽量身定

    2024年01月22日
    浏览(47)
  • 【[Qt]基于QGraphicsView的图像显示控件,支持放大、缩小、鼠标拖动】

    ImageViewer.h文件 ImageViewer.cpp 文件 具体使用代码如下 1、初始化类对象,并加入界面布局中 2、打开图像,并加载到控件中 3、从控件中卸载图片 源码链接:https://download.csdn.net/download/xiaohuihuihuige/87239431 百度云: 链接:https://pan.baidu.com/s/1W-KUlIKUFAktUKFin63N0g 提取码:4g8a

    2024年02月11日
    浏览(62)
  • qt随记:拖动文件方式打开应用程序

    结果 即从main入口进入

    2024年02月10日
    浏览(55)
  • 实现对文件夹的动态检测功能——基于QT

    作者:小 琛 欢迎转载,请标明出处 个人遇到的需求:业务中,需要和其它模块对接,完成某类文件的生成、删除…等一系列操作,如果通过和其它模块定接口的方式,所需要的接口量很多并且所需要考虑的细节也很多。同时有一个很重要的点:这些文件是公用的,也就是说

    2024年02月09日
    浏览(39)
  • Qt拖拽事件简单实现

    重写resizeEvent(这个按需重写)、dragEnterEvent(拖拽事件函数)、dropEvent(放下事件函数),可以将本地图片拖拽到label标签中  

    2024年01月20日
    浏览(50)
  • 个人实现的QT拼图游戏(开源),QT拖拽事件详解

    效果图 引言 在学习QT demo时,发现有一个拼图demo,介绍拖拽事件的。以此为蓝本加了 亿点 修饰,就诞生了这个游戏。 玩法 游戏为拼图游戏,分为俩种模式(闯关与休闲)。 闯关模式:在规定的时间内完成拼图,共有四关,有三种难度,每种难度所需的时间不一致。 休闲模

    2024年01月20日
    浏览(46)
  • PyQt5利用Qt Designer制作一个可以拖动获取文件信息的页面

    前言 本篇在讲什么 用pyqt5制作一个简单的程序,拖动文件或脚本可以读取文件信息 本篇适合什么 适合 初学PyQt5 的小白 本篇需要什么 对 Python 语法有简单认知 对 Qt 有简单认知 依赖 Pycharm 编辑器 本篇的特色 具有全流程的 图文教学 重实践,轻理论,快速上手 提供全流程的

    2024年01月15日
    浏览(67)
  • Qt 实现压缩文件、文件夹和解压缩操作zip

    通过Qt自带的库来实现,使用多线程方式,通过信号和槽来触发压缩与解压缩,并将压缩和解压缩结果回传过来。 使用的类: 1、在.pro文件中添加模块gui-private 若未cmake工程,需要在CMakeList.txt中添加 待验证: 1、中文路径,文件名含有中文 2、隐藏文件夹,.dir和…dir,例如:

    2024年02月14日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包