2009-08-04 10 views
15

まず、悪い英語をお詫び申し上げます。が選択されています。QTableViewの行/行がQClipboardにコピーされています。

C++とQtについてです。私はSQLite-Databaseを持っていて、QSqlTableModelに入れました。 データベースを表示するために、私はそのモデルをQTableViewに入れました。

ここで、選択した行(または行全体)をQClipboardにコピーするメソッドを作成します。その後、私はOpenOffice.Calc-Documentに挿入したいと思います。

しかし、「選択済み」の-SIGNALとQModelIndexをどうすればいいのか、これをクリップボードに入れる方法はありません。

私を助けてくれますか?

Berschi

答えて

24

実際に選択を取得するには、アイテムビューの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(current, 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は同等の作品を持っていませんでした。

+0

申し訳ありませんが、この場合、QItemSelectionModelとQModelIndexListをModelとTableViewで使用する方法はありません – Berschi

+0

ここで便利な関数QAbstractItemView :: selectedIndexes()を使用することもできます。 (QAbstractItemViewが親である)QTableViewで利用可能です。返されるのは、QModelIndexオブジェクトの単純なリストコンテナです。 – swongu

+0

swonguの説明を例示するために少し例を拡張しました。 – quark

1

何をする必要がありますすることは、その後QClipboardにそのテキストを渡し、モデル内のテキストデータにアクセスしています。

モデル内のテキストデータにアクセスするには、QModelIndex::data()を使用します。デフォルトの引数はQt::DisplayRole、つまり表示されるテキストです。

テキストを取得したら、QClipboard::setText()を使用してそのテキストをクリップボードに渡します。

+0

ありがとう、本当に助かりました。 次のコードを追加しました: connect(tableView、SIGNAL(clicked(QModelIndex))、this、SLOT(copy(QModelIndex))); これと: void Widget :: copy(QModelIndex sel){ clipboard-> setText((sel.data(Qt :: DisplayRole))。toString()); } これは1つの単一の行に対してうまく機能します。 しかし、2つ以上の行を選択すると、これは機能しません。 行や行全体をクリップボードにコピーするにはどうすればよいですか? – Berschi

+0

ああ申し訳ありませんが、私はここで本当に新しいです... と行(上のコメント)私はセルを意味しました。申し訳ありません:( – Berschi

+0

クリックした(QModelIndex)ので、これはユーザーがクリックしたセルを返します。あなたのコードスニペットを元の質問の更新として – swongu

0

私はついにそれを得ました。

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); 
} 

connect (tableView, SIGNAL(clicked(QModelIndex)), this, SLOT(copy())); 
+2

QStringListを使用する場合は、<<演算子とQStringList :: join()関数を利用できます。 – swongu

0

私は助けるが、あなたが便利join()機能を持ちforeach()構築物およびQStringListクラスを、使用してコードを簡素化することができていることに気づくことができません。

void Widget::copy() 
{ 
    QStringList list ; 
    foreach (const QModelIndex& index, tableView->selectedIndexes()) 
    { 
     list << index.data() ; 
    } 

    clipboard->setText(list.join(", ")) ; 
} 
+0

あなたの助けてくれてありがとうございましたforeach-methodは私には新しくありました – Berschi

13

私は同様の問題を抱えていたし、コピー/貼り付け機能を追加する(QTableViewの拡張である)QTableWidgetを適応させることになりました。上記のクォークによって提供されたものに基づいて作成されたコードは次のとおりです。

qtablewidgetwithcypypaste時間

// 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 

私がのstd ::ソート機能へのアクセスを持っていなかった何らかの理由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); 
    } 

} 
+0

さらに役立つリンクが2つあります:http://books.google.com/books?id=tSCR_4LH2KsC&pg=PA101&lpg=PA101&dq=copy+paste&source=web&ots=E511hS4aCk&sig = EYaYF4Er89UKAnKFRZLHYgtTdO4#PPP1、M1およびhttp://stackoverflow.com/a/12979530/999943および – phyatt

4

、しかし私はコーウィン喜びのソリューションにきちんと代替としてそれを見つけました、ソート機能は

qSort(indexes); 

std::sort(indexes.begin(), indexes.end()); 

を置き換えることにより実現することができます

これは、書き込みと同じです:あなたの役に立つコードの男性のための

qSort(indexes.begin(), indexes.end()); 

ありがとう!

0

最後の要素に注意してください。以下では、 'removeFirst()'の後にインデックスが空になる場合があります。したがって、 'current'は決して有効ではなく、model() - > 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()); 
1

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)) 
1

私は他の人の回答の一部に基づいていくつかのコードを書きました。 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 
0

ここではQTableViewと連携し、異なったまばらな選択を扱うコーウィン喜びを掲載するもののバリエーションです。このコードでは、選択したセルが(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); 
} 
5

クォークの答え(選択されたもの)は正しい方向に人を指すのに適していますが、彼のアルゴリズムは完全に間違っています。 1つのエラーと誤った割り当てによるオフに加えて、それは構文的に正しいものでもない。以下は私が書き、テストした作業バージョンです。

のは、私たちの例のテーブルはそうのように見えると仮定しましょう:

A | B | C
D | E | |我々は'で彼の\トンセパレーターを交換する場合

:F

Quarkのアルゴリズムの問​​題点は次のとおりです。 '、それはこの出力を生成します:
B | C | D
E | F |

1つのエラーによるオフは、Dが最初の行に表示されます。不正確な代入は、省略記号wで示されます。

次のアルゴリズムは、正しい構文でこれらの2つの問題を修正します。

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); 

別の指数は、カウントに対してチェックすることにより、そこに存在するかどうかをテストすることが容易であるという理由だけで、私は代わりにイテレータのカウンタを使用することを選択した理由があります。イテレータを使用すると、それを増分して弱いポインタに格納して、それが有効かどうかをテストすることができますが、上記のようにカウンタを使用するだけです。

次の行が新しい行に表示されるかどうかを確認する必要があります。私たちが新しい列にいて、Quarkのアルゴリズムのように前の行をチェックすると、既に追加するのが遅すぎます。前に付けることもできますが、最後の文字列サイズを追跡する必要があります。上記のコードは、サンプルテーブルから次の出力を生成します:

A | B | C
D | E | F

関連する問題