選択した行QTableView、コピーをQClipboard
-
22-07-2019 - |
質問
私はSQLiteデータベースとなって QSqlTableModel
.のデータベースを入れているモデルを QTableView
.
今は作りたい方法を選択した列の全線)がコピーされる可能性の QClipboard
.その後私に挟み込んで使ってください。っOpenOffice.Calc-書きします。
がわからないなどの Selected
信号の QModelIndex
どこにクリップボードへ格納します。
解決
実際に選択をキャプチャするには、アイテムビューの選択モデル インデックスのリストを取得します。 view
という QTableView *
がある場合、次のようにして選択を取得します。
QAbstractItemModel * model = view->model();
QItemSelectionModel * selection = view->selectionModel();
QModelIndexList indexes = selection->selectedIndexes();
次に、各インデックスで model-> data(index)
を呼び出してインデックスリストをループします。データがまだない場合はデータを文字列に変換し、各文字列を連結します。次に、 QClipboard.setText
を使用して、結果をクリップボードに貼り付けます。 ExcelとCalcの場合、各列は次の行と改行(" \ n&quot)で区切られ、各行はタブ(" \ 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と同等の機能があります。
他のヒント
同様の問題があり、コピー/貼り付け機能を追加するために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_H
qtablewidgetwithcopypaste.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);
}
}
クォークからの回答の選択したあそこはニューヨークの有名な良いポインティングの右手方向、そのアルゴリズムが完全に間違っています。に加えて、より一誤りや誤配、な構文上正解です。以下の作業バージョンだった。
その例ではテーブルのように見えい:
A|B|C
D|E|F
問題のクォークと反クォークのアルゴリズムは次の通りです:
まだまだ現役として活躍してい彼 セパレータ付 ' | ', することはこの出力:
B|C|D
E|F|
の一つのエラーは 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);
その理由を選んだの利用カウンターではなく、反復子はかりの試験が存在する場合は別のインデックスをチェックの数です。と、反復子かかることができな増加で、大切に保管してくださ弱いポインター試験の場合は有効なものだけを使用カウンターのようになった。
確認する必要がありまさ 次へ 行されました。い新しい行をチェックの前の行としてクォークのアルゴリズムは、すでに遅追加するこの誤動作防止)、そし続けていかなければなトラックの最後の文字列サイズです。上記のコードを以下の出力例のテーブル:
A|B|C
D|E|F
なんらかの理由でstd :: sort関数にアクセスできませんでしたが、Corwin Joyのソリューションのきちんとした代替手段として、sort関数を置き換えることで実装できることがわかりました
std::sort(indexes.begin(), indexes.end());
with
qSort(indexes);
これは書くのと同じです:
qSort(indexes.begin(), indexes.end());
参考になったコードの皆さん、ありがとう!
行う必要があるのは、モデル内のテキストデータにアクセスし、そのテキストを QClipboard
。
モデル内のテキストデータにアクセスするには、 QModelIndex :: dataを使用します。 ()
。デフォルトの引数は Qt :: DisplayRole
、つまり表示されるテキストです。
テキストを取得したら、 QClipboard :: setText()
。
pyqt py2.xの例:
selection = self.table.selectionModel() #self.table = QAbstractItemView
indexes = selection.selectedIndexes()
columns = indexes[-1].column() - indexes[0].column() + 1
rows = len(indexes) / columns
textTable = [[""] * columns for i in xrange(rows)]
for i, index in enumerate(indexes):
textTable[i % rows][i / rows] = unicode(self.model.data(index).toString()) #self.model = QAbstractItemModel
return "\n".join(("\t".join(i) for i in textTable))
私は、他の回答のいくつかに基づいていくつかのコードを書きました。 QTableWidget
をサブクラス化し、 keyPressEvent()
をオーバーライドして、ユーザーがControl-Cを入力して選択した行をクリップボードにコピーできるようにします。
void MyTableWidget::keyPressEvent(QKeyEvent* event) {
// If Ctrl-C typed
if (event->key() == Qt::Key_C && (event->modifiers() & Qt::ControlModifier))
{
QModelIndexList cells = selectedIndexes();
qSort(cells); // Necessary, otherwise they are in column order
QString text;
int currentRow = 0; // To determine when to insert newlines
foreach (const QModelIndex& cell, cells) {
if (text.length() == 0) {
// First item
} else if (cell.row() != currentRow) {
// New row
text += '\n';
} else {
// Next cell
text += '\t';
}
currentRow = cell.row();
text += cell.data().toString();
}
QApplication::clipboard()->setText(text);
}
}
出力例(タブ区切り):
foo bar baz qux
bar baz qux foo
baz qux foo bar
qux foo bar baz
ようやくわかりました、ありがとう。
void Widget::copy() {
QItemSelectionModel *selectionM = tableView->selectionModel();
QModelIndexList selectionL = selectionM->selectedIndexes();
selectionL.takeFirst(); // ID, not necessary
QString *selectionS = new QString(model->data(selectionL.takeFirst()).toString());
selectionS->append(", ");
selectionS->append(model->data(selectionL.takeFirst()).toString());
selectionS->append(", ");
selectionS->append(model->data(selectionL.takeFirst()).toString());
selectionS->append(", ");
selectionS->append(model->data(selectionL.takeFirst()).toString());
clipboard->setText(*selectionS);
}
and
connect (tableView, SIGNAL(clicked(QModelIndex)), this, SLOT(copy()));
foreach()
コンストラクトと QStringList
クラス。便利な join()
関数。
void Widget::copy()
{
QStringList list ;
foreach ( const QModelIndex& index, tableView->selectedIndexes() )
{
list << index.data() ;
}
clipboard->setText( list.join( ", " ) ) ;
}
最後の要素に注意してください。以下に注意してください、「removeFirst()」の後にインデックスが空になる場合があります。したがって、「current」は決して有効ではなく、model()-&gt; data(current)で使用しないでください。
indexes.removeFirst();
QString selected_text;
QModelIndex current;
Q_FOREACH(current, indexes)
{
.
.
.
}
// add last element
selected_text.append(model()->data(current).toString());
検討
QModelIndex last = indexes.last();
indexes.removeFirst();
QString selected_text;
Q_FOREACH(QModelIndex current, indexes)
{
.
.
.
}
// add last element
selected_text.append(model()->data(last).toString());
これは、QTableViewで動作し、スパース選択を異なる方法で処理するCorwin Joyが投稿したもののバリエーションです。このコードでは、異なる行で異なる列が選択されている場合(たとえば、選択されたセルは(1,1)、(1、2)、(2、1)、(3,2)です)、貼り付けると空になります「穴」に対応するセル。選択範囲(例:セル(2,2)および(3,1))。また、選択範囲と交差する列の列ヘッダーテキストも取り込みます。
void CopyableTableView::copy()
{
QItemSelectionModel *selection = selectionModel();
QModelIndexList indices = selection->selectedIndexes();
if(indices.isEmpty())
return;
QMap<int, bool> selectedColumnsMap;
foreach (QModelIndex current, indices) {
selectedColumnsMap[current.column()] = true;
}
QList<int> selectedColumns = selectedColumnsMap.uniqueKeys();
int minCol = selectedColumns.first();
// prepend headers for selected columns
QString selectedText;
foreach (int column, selectedColumns) {
selectedText += model()->headerData(column, Qt::Horizontal, Qt::DisplayRole).toString();
if (column != selectedColumns.last())
selectedText += QLatin1Char('\t');
}
selectedText += QLatin1Char('\n');
// QModelIndex::operator < sorts first by row, then by column.
// this is what we need
qSort(indices);
int lastRow = indices.first().row();
int lastColumn = minCol;
foreach (QModelIndex current, indices) {
if (current.row() != lastRow) {
selectedText += QLatin1Char('\n');
lastColumn = minCol;
lastRow = current.row();
}
if (current.column() != lastColumn) {
for (int i = 0; i < current.column() - lastColumn; ++i)
selectedText += QLatin1Char('\t');
lastColumn = current.column();
}
selectedText += model()->data(current).toString();
}
selectedText += QLatin1Char('\n');
QApplication::clipboard()->setText(selectedText);
}