Frage

Ich habe eine SQLite-Datenbank und habe sie in eine umgewandelt QSqlTableModel.Um die Datenbank anzuzeigen, habe ich dieses Modell in ein QTableView.

Jetzt möchte ich eine Methode erstellen, in die die ausgewählten Zeilen (oder die gesamte Zeile) kopiert werden QClipboard.Danach möchte ich es in mein OpenOffice.Calc-Dokument einfügen.

Aber ich habe keine Ahnung, was ich damit machen soll Selected SIGNAL und die QModelIndex und wie man dies in die Zwischenablage legt.

War es hilfreich?

Lösung

Zur Erfassung tatsächlich an die Auswahl der Artikel Ansicht der Verwendung Auswahlmodell Liste der Indizes . Da haben Sie eine QTableView * genannt view Sie die Auswahl auf diese Weise erhalten:

QAbstractItemModel * model = view->model();
QItemSelectionModel * selection = view->selectionModel();
QModelIndexList indexes = selection->selectedIndexes();

Dann Schleife durch die Liste Index für jeden Index Aufruf model->data(index). Konvertieren Sie die Daten in einen String, wenn es nicht bereits ist und verketten zusammen jede Saite. Dann können Sie QClipboard.setText verwenden Sie das Ergebnis in die Zwischenablage einzufügen. Man beachte, dass für Excel und Calc, wobei jede Spalte von der nächsten durch eine neue Zeile getrennt ist ( „\ n“), und jede Zeile wird durch ein Register ( „\ t“) getrennt. Sie müssen die Indizes überprüfen, um zu bestimmen, wann Sie in der nächsten Zeile zu bewegen.

QString selected_text;
// You need a pair of indexes to find the row changes
QModelIndex previous = indexes.first();
indexes.removeFirst();
foreach(const QModelIndex &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);

Warnung . Ich habe noch keine Gelegenheit hatte diesen Code, um zu versuchen, aber ein PyQt Äquivalent Werke

Andere Tipps

Ich hatte ein ähnliches Problem und schließlich die Anpassung QTableWidget (die eine Erweiterung von QTableView ist) Kopieren / Einfügen-Funktionalität hinzuzufügen. Hier ist der Code, der auf baut, was von Quark zur Verfügung gestellt wurde oben:

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

}

Quark Antwort (die ausgewählten) ist gut für die Menschen in der richtigen Richtung, aber sein Algorithmus ist völlig falsch. Neben einem Off von einem Fehler und falsche Zuordnung, seine nicht einmal syntaktisch korrekt. Nachfolgend finden Sie eine funktionierende Version, die ich gerade geschrieben habe und getestet.

Nehmen wir an, unsere Beispieltabelle wie so aussieht:

A | B | C
D | E | F

Das Problem mit Quark-Algorithmus ist die folgende:

Wenn wir ersetzen sein \ t Separator mit einem ‘| ‚, wird es diese Ausgabe erzeugen:
B | C | D
E | F |

Die off von einem Fehler ist, dass D in der ersten Reihe erscheint. Die falsche Zuordnung wird durch den Wegfall von belegt A

Der folgende Algorithmus korrigiert diese zwei Probleme mit der korrekten Syntax.

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

Der Grund, warum ich einen Zähler anstelle eines Iterators verwenden gewählt ist, nur weil es einfacher zu testen ist, wenn es durch die Überprüfung gegen die Zählung einen anderen Index existiert. Mit einem Iterator, nehme ich vielleicht könnten Sie erhöhen sie einfach und speichern sie in einem schwachen Zeiger zu testen, ob es gültig ist, aber nur einen Zähler verwenden, wie ich oben tat.

Wir müssen überprüfen, ob die Weiter Linie auf einer neuen Zeile auf sein wird. Wenn wir in einer neuen Zeile sind, und wir überprüfen die vorherige Zeile als Quark-Algorithmus tut, seine schon zu spät anzuhängen. Wir konnten voranstellen, aber dann haben wir den Überblick über die letzten Stringgröße zu halten. Der obige Code wird die folgende Ausgabe aus der Beispieltabelle erzeugen:

A | B | C
D | E | F

Aus irgendeinem Grund hatte ich keinen Zugriff auf die Funktion std::sort, fand jedoch, dass die Sortierfunktion als nette Alternative zu Corwin Joys Lösung durch Ersetzen implementiert werden kann

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

mit

  qSort(indexes);

Das ist dasselbe wie das Schreiben:

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

Vielen Dank für eure hilfreichen Code-Leute!

Was Sie tun müssen, um die Textdaten im Modell zugreifen, dann passieren, dass der Text auf den QClipboard .

Um die Textdaten im Modell zuzugreifen, verwenden Sie QModelIndex::data() . Das Standardargument ist Qt::DisplayRole, das heißt der angezeigte Text.

Wenn Sie den Text abgerufen haben, übergeben Sie diesen Text in die Zwischenablage mit QClipboard::setText() .

ein pyqt py2.x Beispiel:

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

Ich schrieb einige Code basiert auf einigen der anderen Antworten. Ich subclassed QTableWidget und overrode keyPressEvent() dem Benutzer zu ermöglichen, indem Sie bei gedrückter Ctrl-C die ausgewählten Zeilen in die Zwischenablage zu kopieren.

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

Ausgabe Beispiel (Tab-getrennt):

foo bar baz qux
bar baz qux foo
baz qux foo bar
qux foo bar baz

Ich habe es endlich, danke.

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

und

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

Ich kann nicht umhin zu bemerken, dass Sie Ihren Code ein foreach() konstruieren und die QStringList -Klasse, die eine bequeme join() Funktion.

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

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

Vorsicht mit dem letzten Element. Hinweis unten, Indizes kann leer werden nach ‚removeFirst ()‘. Somit ist ‚aktuelle‘ nie gültig und soll nicht in Modell verwendet werden (.) -> Daten (Strom)

  indexes.removeFirst();
  QString selected_text;
  QModelIndex current;
  Q_FOREACH(current, indexes)
  {
  .
  .
  .
  }
  // add last element
  selected_text.append(model()->data(current).toString());

Betrachten

  QModelIndex last = indexes.last();
  indexes.removeFirst();
  QString selected_text;
  Q_FOREACH(QModelIndex current, indexes)
  {
  .
  .
  .
  }
  // add last element
  selected_text.append(model()->data(last).toString());
Hier

ist eine Variation auf das, was Corwin Joy geschrieben, die mit QTableView arbeitet und Griffe spärliche Auswahl unterschiedlich. Mit diesem Code, wenn Sie in verschiedenen Reihen (zB ausgewählten Zellen (1,1), (1, 2), (2, 1), (3,2)) dann ausgewählt verschiedene Spalten haben, wenn Sie es einfügen werden Sie leer bekommen Zellen an die „Löcher“ in Ihrer Auswahl entsprechen (zB Zellen (2,2) und (3,1)). Er zieht auch in der Spaltenüberschrift für die Spalten, die die Auswahl schneiden.

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);
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top