سؤال

لدي قاعدة بيانات SQLite وقمت بذلك في ملف QSqlTableModel.لإظهار قاعدة البيانات، قمت بوضع هذا النموذج في ملف QTableView.

أريد الآن إنشاء طريقة حيث سيتم نسخ الصفوف المحددة (أو الخط بأكمله) إلى ملف QClipboard.بعد ذلك أريد إدراجه في مستند OpenOffice.Calc الخاص بي.

ولكن ليس لدي أي فكرة عما يجب القيام به مع Selected سيغنال و QModelIndex وكيفية وضع هذا في الحافظة.

هل كانت مفيدة؟

المحلول

لالتقاط الواقع اختيار استخدام طريقة العرض العنصر نموذج اختيار للحصول على قائمة مؤشرات . وبالنظر إلى أن لديك QTableView * دعا view تحصل على اختيار هذه الطريقة:

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

وبعد ذلك حلقة من خلال قائمة مؤشر يدعو model->data(index) على كل مؤشر. تحويل البيانات إلى سلسلة إذا لم تكن وسلسلة كل سلسلة معا. ثم يمكنك استخدام QClipboard.setText للصق نتيجة إلى الحافظة. لاحظ أنه لبرنامج Excel واحسب، يتم فصل كل عمود من التي تليها سطر جديد ( "\ ن") ويتم فصل كل صف من علامة تبويب ( "\ ر"). لديك للتحقق من مؤشرات لتحديد عند الانتقال إلى الصف التالي.

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

على تحذير : ل. لم تتح لي فرصة لمحاولة هذا الرمز، ولكن باي كيوت أعمال تعادل

نصائح أخرى

وكان لي مشكلة مماثلة، وانتهى التكيف 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);
    }

}

تعتبر إجابة كوارك (الإجابة المختارة) جيدة لتوجيه الأشخاص في الاتجاه الصحيح، لكن خوارزميته غير صحيحة تمامًا.بالإضافة إلى خطأ واحد وتخصيص غير صحيح، فهو ليس صحيحًا من الناحية النحوية.فيما يلي نسخة العمل التي كتبتها واختبرتها للتو.

لنفترض أن جدول المثال الخاص بنا يبدو كالتالي:

أ | ب | ج
د | ه | F

المشكلة في خوارزمية Quark هي التالية:

إذا قمنا باستبداله \ ر فاصل مع أ ' | ', ، سوف ينتج هذا الإخراج:
ب | ج | د
ه | و |

والخروج من خطأ واحد هو ذلك د يظهر في الصف الأول.والدليل على التعيين غير الصحيح هو إغفال أ

تقوم الخوارزمية التالية بتصحيح هاتين المشكلتين باستخدام بناء الجملة الصحيح.

    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، فهذا يعني أن الوقت قد فات بالفعل للإلحاق.يمكننا أن نعلق، ولكن بعد ذلك علينا أن نتتبع حجم السلسلة الأخيرة.سينتج عن الكود أعلاه المخرجات التالية من جدول المثال:

أ | ب | ج
د | ه | F

لسبب ما لم يكن لديك الوصول إلى وظيفة الأمراض المنقولة جنسيا :: نوع، ولكن لم أجد أن كبديل أنيق إلى حل كوروين للفرح، وظيفة الفرز يمكن تنفيذها عن طريق استبدال

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

مع

  qSort(indexes);

وهذا هو نفس الكتابة:

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

وشكرا للرفاق كود مفيدة!

ما عليك القيام به هو الوصول إلى البيانات النصية في النموذج، ثم تمرير هذا النص إلى ملف QClipboard.

للوصول إلى البيانات النصية في النموذج، استخدم QModelIndex::data().الوسيطة الافتراضية هي Qt::DisplayRole, ، أي.النص المعروض.

بمجرد استرداد النص، قم بتمرير هذا النص إلى الحافظة باستخدام QClipboard::setText().

وعلى سبيل المثال باي كيوت 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))

وكتبت بعض رمز استنادا إلى بعض الأجوبة على الآخرين. I subclassed QTableWidget وkeyPressEvent() تجاهلت للسماح للمستخدم لنسخ الصفوف المحددة إلى الحافظة بكتابة تحكم-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);
}

و

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 () '. وهكذا، "التيار" ليست ابدا صحيحة ويجب ألا يستخدم في نموذج () -> البيانات (الحالي)

  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 ويتعامل مع اختيارات قليلة بشكل مختلف. مع هذا الرمز إذا كان لديك أعمدة مختلفة مختارة في صفوف مختلفة (على سبيل المثال اختيار الخلايا (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