Копирование таблицы (rtf) в буфер обмена через QT (или: запись QTextDocument в буфер обмена) - PullRequest
3 голосов
/ 19 марта 2012

Мне нужно, чтобы мое приложение 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 в буфер обмена. Есть ли? Если бы я мог получить код RTF из QTextDocument, я мог бы использовать способ, подобный

QClipboard *clipboard = QApplication::clipboard();
QMimeData *mimeData = new QMimeData();
mimeData->setData("text/rtf", rtfDocument.getCode());
clipboard->setMimeData(mimeData, QClipboard::Clipboard);

Но я также не нашел функции, возвращающей код rtf.

редактирование:

С последним полем кода выше у меня есть рабочий способ скопировать код RTF в буфер обмена. Поэтому любое решение, которое может создать код RTF, представляющий таблицу, решило бы мою проблему.

Ответы [ 3 ]

3 голосов
/ 28 марта 2012

Я не уверен, каков источник ваших данных, но вот код, который мы использовали для подкласса нормального 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);
}
2 голосов
/ 29 марта 2012

Вы можете попробовать использовать QTextDocument :: toHtml () и установить тип mime для text / html

0 голосов
/ 26 марта 2012

Я написал в gedit 1[tab space]2[tab space]3\n4[tab space]5[tab space]6 и скопировал его в электронную таблицу, и это сработало.Поэтому я думаю, что если вы используете "\ t" для разделения ячеек в строках и "\ n" для разделения строк, это сработает.

...