我有一个SQLite数据库,我把它做成了一个QSqlTableModel。为了显示数据库,我将该模型放入一个QTableView中。
现在,我想创建一个方法,其中选定的行(或整行)将被复制到QClipboard中。之后,我想把它插入到我的OpenOffice.Calc-Document中。
但我不知道如何处理Selected信号和QModelIndex,以及如何将其放入剪贴板中。
发布于 2009-08-05 00:03:06
要实际捕获选择,您可以使用item视图的selection model来获取list of indices。假设您有一个名为view的QTableView *,您可以通过以下方式获得选择:
QAbstractItemModel * model = view->model();
QItemSelectionModel * selection = view->selectionModel();
QModelIndexList indexes = selection->selectedIndexes();然后遍历索引列表,对每个索引调用model->data(index)。将数据转换为字符串(如果尚未转换),并将每个字符串连接在一起。然后,您可以使用QClipboard.setText将结果粘贴到剪贴板。请注意,对于Excel和Calc,每列与下一列之间用换行符("\n")分隔,每行用制表符("\t")分隔。您必须检查索引以确定何时移动到下一行。
QString selected_text;
// You need a pair of indexes to find the row changes
QModelIndex previous = indexes.first();
indexes.removeFirst();
foreach(const QModelIndex ¤t, indexes)
{
QVariant data = model->data(current);
QString text = data.toString();
// At this point `text` contains the text in one cell
selected_text.append(text);
// If you are at the start of the row the row number of the previous index
// isn't the same. Text is followed by a row separator, which is a newline.
if (current.row() != previous.row())
{
selected_text.append('\n');
}
// Otherwise it's the same row, so append a column separator, which is a tab.
else
{
selected_text.append('\t');
}
previous = current;
}
QApplication.clipboard().setText(selected_text);警告:我还没有机会尝试这段代码,但PyQt等效项可以工作。
发布于 2010-02-02 07:44:32
我遇到了类似的问题,最终采用了QTableWidget (它是QTableView的一个扩展)来添加复制/粘贴功能。下面是构建在上面夸克提供的内容上的代码:
qtablewidgetwithcopypaste.h
// QTableWidget with support for copy and paste added
// Here copy and paste can copy/paste the entire grid of cells
#ifndef QTABLEWIDGETWITHCOPYPASTE_H
#define QTABLEWIDGETWITHCOPYPASTE_H
#include <QTableWidget>
#include <QKeyEvent>
#include <QWidget>
class QTableWidgetWithCopyPaste : public QTableWidget
{
Q_OBJECT
public:
QTableWidgetWithCopyPaste(int rows, int columns, QWidget *parent = 0) :
QTableWidget(rows, columns, parent)
{}
QTableWidgetWithCopyPaste(QWidget *parent = 0) :
QTableWidget(parent)
{}
private:
void copy();
void paste();
public slots:
void keyPressEvent(QKeyEvent * event);
};
#endif // QTABLEWIDGETWITHCOPYPASTE_Hqtablewidgetwithcopypaste.cpp
#include "qtablewidgetwithcopypaste.h"
#include <QApplication>
#include <QMessageBox>
#include <QClipboard>
#include <QMimeData>
void QTableWidgetWithCopyPaste::copy()
{
QItemSelectionModel * selection = selectionModel();
QModelIndexList indexes = selection->selectedIndexes();
if(indexes.size() < 1)
return;
// QModelIndex::operator < sorts first by row, then by column.
// this is what we need
// std::sort(indexes.begin(), indexes.end());
qSort(indexes);
// You need a pair of indexes to find the row changes
QModelIndex previous = indexes.first();
indexes.removeFirst();
QString selected_text_as_html;
QString selected_text;
selected_text_as_html.prepend("<html><style>br{mso-data-placement:same-cell;}</style><table><tr><td>");
QModelIndex current;
Q_FOREACH(current, indexes)
{
QVariant data = model()->data(previous);
QString text = data.toString();
selected_text.append(text);
text.replace("\n","<br>");
// At this point `text` contains the text in one cell
selected_text_as_html.append(text);
// If you are at the start of the row the row number of the previous index
// isn't the same. Text is followed by a row separator, which is a newline.
if (current.row() != previous.row())
{
selected_text_as_html.append("</td></tr><tr><td>");
selected_text.append(QLatin1Char('\n'));
}
// Otherwise it's the same row, so append a column separator, which is a tab.
else
{
selected_text_as_html.append("</td><td>");
selected_text.append(QLatin1Char('\t'));
}
previous = current;
}
// add last element
selected_text_as_html.append(model()->data(current).toString());
selected_text.append(model()->data(current).toString());
selected_text_as_html.append("</td></tr>");
QMimeData * md = new QMimeData;
md->setHtml(selected_text_as_html);
// qApp->clipboard()->setText(selected_text);
md->setText(selected_text);
qApp->clipboard()->setMimeData(md);
// selected_text.append(QLatin1Char('\n'));
// qApp->clipboard()->setText(selected_text);
}
void QTableWidgetWithCopyPaste::paste()
{
if(qApp->clipboard()->mimeData()->hasHtml())
{
// TODO, parse the html data
}
else
{
QString selected_text = qApp->clipboard()->text();
QStringList cells = selected_text.split(QRegExp(QLatin1String("\\n|\\t")));
while(!cells.empty() && cells.back().size() == 0)
{
cells.pop_back(); // strip empty trailing tokens
}
int rows = selected_text.count(QLatin1Char('\n'));
int cols = cells.size() / rows;
if(cells.size() % rows != 0)
{
// error, uneven number of columns, probably bad data
QMessageBox::critical(this, tr("Error"),
tr("Invalid clipboard data, unable to perform paste operation."));
return;
}
if(cols != columnCount())
{
// error, clipboard does not match current number of columns
QMessageBox::critical(this, tr("Error"),
tr("Invalid clipboard data, incorrect number of columns."));
return;
}
// don't clear the grid, we want to keep any existing headers
setRowCount(rows);
// setColumnCount(cols);
int cell = 0;
for(int row=0; row < rows; ++row)
{
for(int col=0; col < cols; ++col, ++cell)
{
QTableWidgetItem *newItem = new QTableWidgetItem(cells[cell]);
setItem(row, col, newItem);
}
}
}
}
void QTableWidgetWithCopyPaste::keyPressEvent(QKeyEvent * event)
{
if(event->matches(QKeySequence::Copy) )
{
copy();
}
else if(event->matches(QKeySequence::Paste) )
{
paste();
}
else
{
QTableWidget::keyPressEvent(event);
}
}发布于 2015-06-08 07:58:53
夸克的答案(选定的答案)很适合为人们指明正确的方向,但他的算法是完全错误的。除了off by one错误和不正确的赋值之外,它甚至在语法上都不正确。下面是我刚刚编写和测试的工作版本。
假设我们的示例表如下所示:
A |B| C
D |E| F
夸克算法的问题如下:
如果我们将他的\t分隔符替换为‘| ',它将生成以下输出:
B |C| D
E |F |
off by one错误是D出现在第一行。A的省略证明了错误的赋值
下面的算法用正确的语法纠正了这两个问题。
QString clipboardString;
QModelIndexList selectedIndexes = view->selectionModel()->selectedIndexes();
for (int i = 0; i < selectedIndexes.count(); ++i)
{
QModelIndex current = selectedIndexes[i];
QString displayText = current.data(Qt::DisplayRole).toString();
// If there exists another column beyond this one.
if (i + 1 < selectedIndexes.count())
{
QModelIndex next = selectedIndexes[i+1];
// If the column is on different row, the clipboard should take note.
if (next.row() != current.row())
{
displayText.append("\n");
}
else
{
// Otherwise append a column separator.
displayText.append(" | ");
}
}
clipboardString.append(displayText);
}
QApplication::clipboard()->setText(clipboardString);我选择使用计数器而不是迭代器的原因只是因为通过检查计数来测试是否存在另一个索引更容易。使用迭代器,我想也许你可以递增它,并将它存储在弱指针中,以测试它是否有效,但只需使用计数器,就像我上面做的那样。
我们需要检查next行是否会在新行上打开。如果我们在新的一行上,我们像Quark的算法那样检查前一行,那么就已经来不及追加了。我们可以预置,但是我们必须跟踪最后一个字符串的大小。上面的代码将从示例表中生成以下输出:
A |B| C
D |E| F
https://stackoverflow.com/questions/1230222
复制相似问题