문제

나는 sqlite-database가 있고 나는 그것을 QSqlTableModel. 데이터베이스를 표시하기 위해 해당 모델을 QTableView.

이제 선택한 행 (또는 전체 라인)이 QClipboard. 그런 다음 OpenOffice.calc-Document에 삽입하고 싶습니다.

그러나 나는 무엇을 해야할지 전혀 모른다 Selected 신호와 QModelIndex 그리고 이것을 클립 보드에 넣는 방법.

도움이 되었습니까?

해결책

실제로 선택을 캡처하려면 항목보기를 사용합니다. 선택 모델 얻기 위해 지수 목록. 당신이 있다는 것을 감안할 때 QTableView * ~라고 불리는 view 이 방법으로 선택을받습니다.

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

그런 다음 인덱스 목록 호출을 통해 루프하십시오 model->data(index) 각 색인에서. 데이터를 아직 문자열로 변환하고 각 문자열을 함께 연결하십시오. 그런 다음 사용할 수 있습니다 QClipboard.setText 결과를 클립 보드에 붙여 넣습니다. Excel 및 Calc의 경우 각 열은 다음 열에서 Newline ( " 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 &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 동등한 작업이 작동했습니다.

다른 팁

비슷한 문제가 있었고 복사/페이스트 기능을 추가하기 위해 QtableWidget (QTableView의 확장)을 적응 시켰습니다. 위의 Quark에서 제공 한 내용을 기반으로하는 코드는 다음과 같습니다.

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의 답변 (선택된 답변)은 사람들을 올바른 방향으로 가리키는 데 좋습니다. 그러나 그의 알고리즘은 완전히 부정확합니다. 한 가지 오류와 잘못된 할당 외에도 구문 적으로 정확하지 않습니다. 아래는 방금 작성하고 테스트 한 작업 버전입니다.

예제 테이블이 그렇게 보인다고 가정 해 봅시다.

A | B | 씨
d | e | 에프

Quark의 알고리즘의 문제는 다음과 같습니다.

우리가 그를 대체한다면 a ' | ',이 출력을 생성합니다.
B | C | 디
e | f |

한 가지 오류는 그게 오류입니다 첫 번째 줄에 나타납니다. 잘못된 할당은 누락에 의해 입증됩니다

다음 알고리즘은 올바른 구문 으로이 두 가지 문제를 수정합니다.

    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 | 씨
d | e | 에프

어떤 이유로 든 STD :: Sort 함수에 액세스 할 수 없었지만 Corwin Joy의 솔루션에 대한 깔끔한 대안으로서 정렬 함수는 교체하여 구현할 수 있습니다.

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

~와 함께

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

출력 예제 (Tab-Separated) :

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

그리고

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 ()'후 인덱스가 비어있을 수 있습니다. 따라서 '전류'는 유효하지 않으며 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());

다음은 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);
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top