通过 QT 将(rtf)表复制到剪贴板(或:将 QTextDocument 写入剪贴板)
Posted
技术标签:
【中文标题】通过 QT 将(rtf)表复制到剪贴板(或:将 QTextDocument 写入剪贴板)【英文标题】:Copying a (rtf) table into the clipboard via QT (or: Writing a QTextDocument into clipboard) 【发布时间】:2012-03-19 17:57:22 【问题描述】:我需要我的 QT 应用程序创建一个表格并将该表格复制到剪贴板,以便以后可以将其作为表格粘贴到 libreoffice Writer 或 MS Word 中。
我的第一种方法是为表格创建 html 代码并将其插入到剪贴板中
QClipboard *clipboard = QApplication::clipboard();
QMimeData *mimeData = new QMimeData();
mimeData->setData("text/html", html.toUtf8());
clipboard->setMimeData(mimeData, QClipboard::Clipboard);
这种方法不起作用。粘贴时,表格单元格只是相互附加并插入而不进行格式化。
我使用 RTF 的第二种方法:
QTextDocument rtfDocument;
rtfDocument.setHtml(html);
但我发现无法将此 QTextDocument 复制到剪贴板中。有没有? 如果我可以从 QTextDocument 中获取 RTF 代码,我可以使用类似的方式
QClipboard *clipboard = QApplication::clipboard();
QMimeData *mimeData = new QMimeData();
mimeData->setData("text/rtf", rtfDocument.getCode());
clipboard->setMimeData(mimeData, QClipboard::Clipboard);
但我也没有找到返回 rtf 代码的函数。
编辑:
使用上面的最后一个代码框,我可以将 rtf 代码复制到剪贴板。因此,任何可以创建表示表格的 RTF 代码的解决方案都可以解决我的问题。
【问题讨论】:
根据this SO question 上的回答,您可以使用librtf 进行RTF 处理。我会检查一下。 不幸的是 librtf 只允许解析,不能创建 rtf 文件。 【参考方案1】:我不确定您的数据来源是什么,但这里是我们用来子类化普通QTableView
以使其可复制的代码。部分代码已被删减,但您可以了解基本概念。 RTF/HTML 太过分了——所有的电子表格都接受良好的 CSV。
当然,如果您需要格式化,这个答案根本无济于事。我不清楚你的问题是否是要求。
// Escapes a string according to RFC-4180 specification.
static QString csvEscape(const QString &value)
if (value.contains(QRegExp(QLatin1String("[\"\\n\\r,]"))))
QString escaped(value);
escaped.replace(QLatin1String("\""), QLatin1String("\"\""));
return QString::fromLatin1("\"%1\"").arg(escaped);
else
return value;
void ClipboardAwareTableView::Copy() const
QModelIndexList indexes = selectedIndexes();
Q_ASSERT(!indexes.isEmpty());
if(indexes.isEmpty())
return;
// The default sort is by rows then columns. This is what we want.
qSort(indexes);
// Remember the mapping between model columns and visible columns. This is
// local instead of an instance member because it would need to be invalidated
// any time a column is added, removed, or moved. The minor performance hit
// is worth the simplicity.
QHash<int, int> map_cache;
// Before we start exporting text, we have to know the index of the left-
// most column in our selection range so we can add the appropriate number
// of column separators.
int minimum_column = GetViewColumnIndex(indexes.first().column(), &map_cache);
for (int i = 1; i < indexes.size(); ++i)
minimum_column =
qMin(minimum_column,
GetViewColumnIndex(indexes.at(i).column(), &map_cache));
// Keep track of the previous index so that we know if we need a new line and
// how many column separators to insert. We start with an invalid index.
QModelIndex previous;
QString text;
for (int i = 0; i < indexes.size(); ++i)
QModelIndex current = indexes.at(i);
// Do we need to add a new line character?
if (previous.isValid() && current.row() != previous.row())
text.append(QLatin1String("\n"));
// Are we on a new line?
if (!previous.isValid() || current.row() != previous.row())
// Add enough separators to get from the minimum to the current column.
text.append(QString::fromLatin1(",")
.repeated(GetViewColumnIndex(current.column(), &map_cache) -
minimum_column));
else
// Add enough separators to get from the previous to the current column.
text.append(QString::fromLatin1(",")
.repeated(GetViewColumnIndex(current.column(), &map_cache) -
GetViewColumnIndex(previous.column(), &map_cache)));
// Append the text. If the column delegate is a QStyledItemDelegate, we use
// the display text.
QStyledItemDelegate *delegate =
qobject_cast<QStyledItemDelegate*>(
itemDelegateForColumn(current.column()));
if (delegate)
text.append(csvEscape(delegate->displayText(current.data(), QLocale())));
else
text.append(csvEscape(current.data().toString()));
previous = current;
qApp->clipboard()->setText(text);
int ClipboardAwareTableView::GetViewColumnIndex(
int model_column_index,
QHash<int, int> *cached_mappings) const
if (cached_mappings->contains(model_column_index))
return cached_mappings->value(model_column_index);
int view_index = 0;
for (int i = 0; i < model()->columnCount(); ++i)
if (model_column_index == i)
cached_mappings->insert(model_column_index, view_index);
return view_index;
else if (!isColumnHidden(i))
++view_index;
throw std::invalid_argument("model_column_index was out of range.");
void ClipboardAwareTableView::keyPressEvent(QKeyEvent *event)
if (event->matches(QKeySequence::Copy) && !selectedIndexes().isEmpty())
Copy();
event->accept();
return; // The base class implementation will overwrite the clipboard.
event->ignore();
QTableView::keyPressEvent(event);
【讨论】:
我需要 MS Word/LO Writer 中的表格,而不是 Excel/Calc 中的表格。所以我认为我确实需要像 rtf 这样的格式。很抱歉这个不清楚的问题 - 我以一种更清楚的方式改变了它。【参考方案2】:您可以尝试使用 QTextDocument::toHtml() 并将 mime 类型设置为 text/html
【讨论】:
这是我的第一种方法,它不起作用(有关详细信息,请参阅问题)。我自己编写了html代码,但这不应该是问题。当我将一个表从 Firefox 复制到 LO Writer 时,我得到了同样的错误结果。我认为 LO Writer 只是忽略了 html 标签。 我搞定了。 Libreoffice 忽略了 html 标签,因为我毕竟在那里出错了。【参考方案3】:我在 gedit 1[tab space]2[tab space]3\n4[tab space]5[tab space]6
中写入并将其复制到电子表格中并且它有效。因此,我认为如果您使用“\t”来分隔行中的单元格并使用“\n”来分隔行,它会起作用。
【讨论】:
我需要 MS Word/LO Writer 中的表格,而不是 Excel/Calc 中的表格。所以我认为我确实需要像 rtf 这样的格式。很抱歉这个不清楚的问题 - 我以一种更清楚的方式改变了它。以上是关于通过 QT 将(rtf)表复制到剪贴板(或:将 QTextDocument 写入剪贴板)的主要内容,如果未能解决你的问题,请参考以下文章
富文本框 .rtf 字符串与通过剪切和粘贴复制文本不同。如何获得相同的格式?
WPS系统中怎样将“收入.rtf”文档中的表格数据转换到工作表“Sheet1”中
IntelliJ - 是否可以将String.format或StringBuilder的输出复制到剪贴板中?