剪切和粘贴Qt应用程序和Windows资源管理器之间的剪贴板交换

时间:2017-11-22 20:39:39

标签: c++ windows qt

我有一个简单的文件处理小部件,可以从/向剪贴板复制/剪切/粘贴所选文件。我希望能够在此窗口小部件和Windows资源管理器之间使用这些命令交换文件(可能还有其他文件管理器,如Total Commander或Free Commander)。我已经发现我可以使用QList<QUrl>将文件名作为QMimeData::setUrls()存储到剪贴板,并以类似方式恢复它们。这样我就可以在我的小部件和上面提到的文件管理器之间进行复制和粘贴,因为它们似乎使用相同的格式来存储文件名。但我不知道如何将项目剪切到剪贴板(即粘贴文件后删除)。我假设接收器(粘贴数据的应用程序)负责删除剪切文件。在这种情况下,它必须以某种方式编码在剪贴板数据中,文件已被剪切而不是复制,接收应用程序可以检索此信息。这是怎么做到的?或者还有其他方法吗?我知道这是可能的,因为它在Windows资源管理器和Free Commander之间完美地工作。即当您在Window Explorer中剪切文件并将其粘贴到Free Commander时,原始文件将被删除,反之亦然。

更新: 我发现还有另一部分MIME数据"Preferred DropEffect",其值可以是5(副本)或2(剪切)。当我将QByteArray设置为4个字节,对应于值52的整数时,我可以区分Windows资源管理器是否启动了剪切或复制。如果它被剪切,那么我可以移动文件而不是复制。它运作良好。不幸的是,这仍然只能从Windows资源管理器到Qt应用程序。我仍然没有找到为什么相反的方向不起作用。还有一些其他MIME数据,但对我来说难以解码。也许有钥匙。

更新2: 重现behvaiour的最小代码就在这里。确保程序中存在硬编码的文件。尝试运行该程序,关闭窗口后打开Windows资源管理器转到任意文件夹,然后按Ctrl + V ...然后该文件的副本应出现在该目录中,但不会从源目录中删除。下面的程序使用常量2,这意味着剪切而不是复制,这意味着原始文件应该消失。

#include <QApplication>
#include <QClipboard>
#include <QDataStream>
#include <QMimeData>
#include <QUrl>
#include <QWidget>

int main(int argc, char *argv[])
{
    QApplication application(argc, argv);

    auto mimeData = new QMimeData;

    // store the URL to files which I want to cut
    QList<QUrl> urls;
    urls.append(QUrl::fromLocalFile("C:/mypath/myfile.txt")); // use your path or make sure this file exist
    mimeData->setUrls(urls);

    // store drop effect indicating whether I want to cut or copy
    int dropEffect = 2; // 2 for cut and 5 for copy
    QByteArray data;
    QDataStream stream(&data, QIODevice::WriteOnly);
    stream << dropEffect;
    mimeData->setData("Preferred DropEffect", data);

    QApplication::clipboard()->setMimeData(mimeData);

    QWidget window;
    window.show();
    return application.exec();
}

另请参阅How to programmatically cut/copy/get files to/from the Windows clipboard in a system standard compliant form?https://msdn.microsoft.com/en-us/library/windows/desktop/bb776904(v=vs.85).aspx#delete_on_paste

1 个答案:

答案 0 :(得分:1)

我似乎找到了答案。字节顺序错误,由于某种原因它必须是小Endian(Qt中的默认顺序是大Endian)。所以示例中的代码应该是:

QByteArray data;
QDataStream stream(&data, QIODevice::WriteOnly);
stream.setByteOrder(QDataStream::LittleEndian);
stream << dropEffect;

这样,其他文件管理器就可以使用我的Qt应用程序使用复制/剪切和粘贴进行互操作。解码剪贴板内容的逆转过程留给读者(这并不困难,只需将用于编码数据的操作转换为剪贴板)。当然,还需要处理文件的复制或移动/删除,这是更多的工作,但它很简单。

所以我错了,我其实是在寻找一个bug ...感谢scopchanov强迫我写出最小的代码! :)