Qt跨平台开发:Mac剪贴板Standard MIDI File数据为空问题排查
问题描述
我用Qt开发一款支持Windows和Mac的C++应用,需要把MIDI数据同时以audio/midi和Standard MIDI File两种MIME类型存入系统剪贴板。Windows平台功能正常,两种类型下都能显示相同数据;但在MacOS平台,虽然重写了QMacPasteboardMime类,目前仅public.midi-audio类型下有数据,Standard MIDI File类型条目为空。以下是相关实现代码及日志,请分析问题原因。
相关代码
clipboard.cpp
bool GuiClipboard::CopyMIDIDataToSystemClipboard(const QByteArray& midiData) { bool success = false; QClipboard* clipboard = QApplication::clipboard(); if (clipboard) { QMimeData* qmd = new QMimeData(); qmd->setData("Standard MIDI File", midiData); // 新增行 qmd->setData("audio/midi", midiData); clipboard->setMimeData(qmd); success = true; } return success; }
clipboard.h(Mac平台专属代码)
#if MAC #include <QtMacExtras/qmacpasteboardmime.h> struct MIDIMime : public QMacPasteboardMime { MIDIMime() : QMacPasteboardMime(MIME_ALL) { } QString convertorName(){return QString("MIDIMime");} bool canConvert(const QString &mime, QString flav){ QString debug1 = "> canConvert: mime: " + mime + " flav: " + flav; LOG (debug1.toLatin1()); // return mimeFor(flav) == mime || mimeFor(flav) == "Standard MIDI File"; return mimeFor(flav) == mime || mime == "Standard MIDI File"; } QString mimeFor(QString flav){ if (flav == QString("public.midi-audio")){ LOG("> mimeFor: public.midi-audio -> audio/midi"); return QString("audio/midi"); } if (flav == QString("Standard MIDI File")){ LOG("> mimeFor: Standard MIDI File"); return QString("Standard MIDI File"); } return QString(); } QString flavorFor(const QString &mime){ if (mime == QString("audio/midi")){ LOG("> flavorFor: audio/midi -> public.midi-audio"); return QString("public.midi-audio"); } if (mime == QString("Standard MIDI File")){ LOG("> flavorFor: Standard MIDI File"); return QString("Standard MIDI File"); } return QString(); } QVariant convertToMime(const QString &mime, QList<QByteArray> data, QString flav){ //Q_UNUSED(mime); //Q_UNUSED(flav); QByteArray all; int cc = 0; foreach (QByteArray i, data) { all += i; cc++; } QString debug2 = "> convert2Mime: mime: " + mime + " flav: " + flav + " n: " + QString::number(cc); LOG(debug2.toLatin1()); return QVariant(all); } QList<QByteArray> convertFromMime(const QString &mime, QVariant data, QString flav){ //Q_UNUSED(mime); //Q_UNUSED(data); //Q_UNUSED(flav); QList<QByteArray> list; list.push_back(data.toByteArray()); int cc = list.count(); QString debug3 = "> convertFromMime: mime: " + mime + " flav: " + flav + " n: " + QString::number(cc); LOG(debug3.toLatin1()); return list; } }; #endif
日志内容
Clipboard.h(55) : > flavorFor: Standard MIDI File Clipboard.h(51) : > flavorFor: audio/midi -> public.midi-audio Clipboard.h(31) : > canConvert: mime: Standard MIDI File flav: public.midi-audio Clipboard.h(39) : > mimeFor: public.midi-audio -> audio/midi Clipboard.h(85) : > convertFromMime: mime: Standard MIDI File flav: public.midi-audio n: 1 Clipboard.h(31) : > canConvert: mime: Standard MIDI File flav: com.trolltech.anymime.audio--midi Clipboard.h(85) : > convertFromMime: mime: Standard MIDI File flav: com.trolltech.anymime.audio--midi n: 1
问题分析及解决方案
核心原因
MacOS剪贴板用Flavor(而非直接的MIME类型)标识数据格式,你的实现有两个关键问题:
Standard MIDI File不是Mac系统原生支持的Flavor名称,系统无法识别这个自定义Flavor,因此不会为其分配数据存储。- 当Qt处理未映射到系统原生Flavor的MIME类型时,会自动生成
com.trolltech.anymime.audio--midi这类私有Flavor,但你的转换逻辑没正确关联Standard MIDI File到这个私有Flavor,导致数据无法正常映射。
修复步骤
1. 修正flavorFor方法逻辑
Standard MIDI File和audio/midi本质是同一种数据格式(SMF文件),直接复用系统原生的public.midi-audio即可:
QString flavorFor(const QString &mime){ if (mime == QString("audio/midi")){ LOG("> flavorFor: audio/midi -> public.midi-audio"); return QString("public.midi-audio"); } if (mime == QString("Standard MIDI File")){ LOG("> flavorFor: Standard MIDI File -> public.midi-audio"); return QString("public.midi-audio"); // 复用系统原生Flavor } return QString(); }
2. 调整canConvert方法匹配逻辑
确保能正确处理Standard MIDI File和系统Flavor的关联:
bool canConvert(const QString &mime, QString flav){ QString debug1 = "> canConvert: mime: " + mime + " flav: " + flav; LOG (debug1.toLatin1()); // 允许从public.midi-audio转换到两种MIME类型 if (flav == "public.midi-audio") { return mime == "audio/midi" || mime == "Standard MIDI File"; } // 处理Qt生成的私有Flavor return mimeFor(flav) == mime; }
3. 优化mimeFor方法
确保系统Flavor能正确映射回两种MIME类型:
QString mimeFor(QString flav){ if (flav == QString("public.midi-audio")){ LOG("> mimeFor: public.midi-audio -> audio/midi/Standard MIDI File"); return QString("audio/midi"); // 两种类型数据一致,返回任意一个均可 } // 处理Qt私有Flavor if (flav.startsWith("com.trolltech.anymime")) { QString mime = flav.replace("com.trolltech.anymime.", "").replace("--", "/"); LOG("> mimeFor: " + flav + " -> " + mime); return mime; } return QString(); }
内容的提问来源于stack exchange,提问作者SimplyBlue
相关产品推荐
相关产品推荐

