Qt
Modell / Ansicht
Suche…
Eine einfache schreibgeschützte Tabelle zum Anzeigen von Daten aus einem Modell
Dies ist ein einfaches Beispiel für die Anzeige von schreibgeschützten Daten, die in der Natur tabellarisch sind, mithilfe von Qt's Model / View Framework . Insbesondere werden die Qt Objects
QAbstractTableModel (in diesem Beispiel Unterklasse ) und QTableView verwendet.
Implementierungen der Methoden rowCount () , columnCount () , data () und headerData () sind erforderlich, um dem QTableView
Objekt die Möglichkeit zu geben, Informationen zu den im QAbstractTableModel
Objekt enthaltenen Daten zu erhalten.
Die Methode populateData()
wurde zu diesem Beispiel hinzugefügt, um ein Mittel bereitzustellen, um das QAbstractTableModel
Objekt mit Daten aus einer beliebigen Quelle zu QAbstractTableModel
.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QAbstractTableModel>
namespace Ui {
class MainWindow;
}
class TestModel : public QAbstractTableModel
{
Q_OBJECT
public:
TestModel(QObject *parent = 0);
void populateData(const QList<QString> &contactName,const QList<QString> &contactPhone);
int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
private:
QList<QString> tm_contact_name;
QList<QString> tm_contact_phone;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QList<QString> contactNames;
QList<QString> contactPhoneNums;
// Create some data that is tabular in nature:
contactNames.append("Thomas");
contactNames.append("Richard");
contactNames.append("Harrison");
contactPhoneNums.append("123-456-7890");
contactPhoneNums.append("222-333-4444");
contactPhoneNums.append("333-444-5555");
// Create model:
TestModel *PhoneBookModel = new TestModel(this);
// Populate model with data:
PhoneBookModel->populateData(contactNames,contactPhoneNums);
// Connect model to table view:
ui->tableView->setModel(PhoneBookModel);
// Make table header visible and display table:
ui->tableView->horizontalHeader()->setVisible(true);
ui->tableView->show();
}
MainWindow::~MainWindow()
{
delete ui;
}
TestModel::TestModel(QObject *parent) : QAbstractTableModel(parent)
{
}
// Create a method to populate the model with data:
void TestModel::populateData(const QList<QString> &contactName,const QList<QString> &contactPhone)
{
tm_contact_name.clear();
tm_contact_name = contactName;
tm_contact_phone.clear();
tm_contact_phone = contactPhone;
return;
}
int TestModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return tm_contact_name.length();
}
int TestModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return 2;
}
QVariant TestModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || role != Qt::DisplayRole) {
return QVariant();
}
if (index.column() == 0) {
return tm_contact_name[index.row()];
} else if (index.column() == 1) {
return tm_contact_phone[index.row()];
}
return QVariant();
}
QVariant TestModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
if (section == 0) {
return QString("Name");
} else if (section == 1) {
return QString("Phone");
}
}
return QVariant();
}
Platzieren Sie mit Qt Creator/Design
ein Table View
Objekt, in diesem Beispiel als tableView bezeichnet , im Hauptfenster :
Das resultierende Programm wird angezeigt als:
Ein einfaches Baummodell
QModelIndex kennt die übergeordneten / untergeordneten Indizes nicht. Es enthält nur eine Zeile , eine Spalte und einen Zeiger . Es ist die Aufgabe des Modells, diese Daten zu verwenden, um Informationen zu den Beziehungen eines Index bereitzustellen. Das Modell muss daher viele Konvertierungen vom in dem QModelIndex
gespeicherten void*
in einen internen Datentyp und zurück durchführen.
TreeModel.h:
#pragma once
#include <QAbstractItemModel>
class TreeModel : public QAbstractItemModel
{
Q_OBJECT
public:
explicit TreeModel(QObject *parent = nullptr);
// Reimplementation of QAbstractItemModel methods
int rowCount(const QModelIndex &index) const override;
int columnCount(const QModelIndex &index) const override;
QModelIndex index(const int row, const int column,
const QModelIndex &parent) const override;
QModelIndex parent(const QModelIndex &childIndex) const override;
QVariant data(const QModelIndex &index, const int role) const override;
bool setData(const QModelIndex &index, const QVariant &value,
const int role) override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
void addRow(const QModelIndex &parent, const QVector<QVariant> &values);
void removeRow(const QModelIndex &index);
private:
struct Item
{
~Item();
// This could individual members, or maybe some other object that
// contains the data we want to display/edit
QVector<QVariant> values;
// It is this information that the model needs to be able to answer
// questions like "What's the parent QModelIndex of this QModelIndex?"
QVector<Item *> children;
Item *parent = nullptr;
// Convenience method that's used in several places
int rowInParent() const;
};
Item *m_root;
};
TreeModel.cpp:
#include "TreeModel.h"
// Adapt this to own needs
static constexpr int COLUMNS = 3;
TreeModel::Item::~Item()
{
qDeleteAll(children);
}
int TreeModel::Item::rowInParent() const
{
if (parent) {
return parent->children.indexOf(const_cast<Item *>(this));
} else {
return 0;
}
}
TreeModel::TreeModel(QObject *parent)
: QAbstractItemModel(parent), m_root(new Item) {}
int TreeModel::rowCount(const QModelIndex &parent) const
{
// Parent being invalid means we ask for how many rows the root of the
// model has, thus we ask the root item
// If parent is valid we access the Item from the pointer stored
// inside the QModelIndex
return parent.isValid()
? static_cast<Item *>(parent.internalPointer())->children.size()
: m_root->children.size();
}
int TreeModel::columnCount(const QModelIndex &parent) const
{
return COLUMNS;
}
QModelIndex TreeModel::index(const int row, const int column,
const QModelIndex &parent) const
{
// hasIndex checks if the values are in the valid ranges by using
// rowCount and columnCount
if (!hasIndex(row, column, parent)) {
return QModelIndex();
}
// In order to create an index we first need to get a pointer to the Item
// To get started we have either the parent index, which contains a pointer
// to the parent item, or simply the root item
Item *parentItem = parent.isValid()
? static_cast<Item *>(parent.internalPointer())
: m_root;
// We can now simply look up the item we want given the parent and the row
Item *childItem = parentItem->children.at(row);
// There is no public constructor in QModelIndex we can use, instead we need
// to use createIndex, which does a little bit more, like setting the
// model() in the QModelIndex to the model that calls createIndex
return createIndex(row, column, childItem);
}
QModelIndex TreeModel::parent(const QModelIndex &childIndex) const
{
if (!childIndex.isValid()) {
return QModelIndex();
}
// Simply get the parent pointer and create an index for it
Item *parentItem = static_cast<Item*>(childIndex.internalPointer())->parent;
return parentItem == m_root
? QModelIndex() // the root doesn't have a parent
: createIndex(parentItem->rowInParent(), 0, parentItem);
}
QVariant TreeModel::data(const QModelIndex &index, const int role) const
{
// Usually there will be more stuff here, like type conversion from
// QVariant, handling more roles etc.
if (!index.isValid() || role != Qt::DisplayRole) {
return QVariant();
}
Item *item = static_cast<Item *>(index.internalPointer());
return item->values.at(index.column());
}
bool TreeModel::setData(const QModelIndex &index, const QVariant &value,
const int role)
{
// As in data there will usually be more stuff here, like type conversion to
// QVariant, checking values for validity etc.
if (!index.isValid() || role != Qt::EditRole) {
return false;
}
Item *item = static_cast<Item *>(index.internalPointer());
item->values[index.column()] = value;
emit dataChanged(index, index, QVector<int>() << role);
return true;
}
Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
{
if (index.isValid()) {
return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
} else {
return Qt::NoItemFlags;
}
}
// Simple add/remove functions to illustrate {begin,end}{Insert,Remove}Rows
// usage in a tree model
void TreeModel::addRow(const QModelIndex &parent,
const QVector<QVariant> &values)
{
Item *parentItem = parent.isValid()
? static_cast<Item *>(parent.internalPointer())
: m_root;
beginInsertRows(parent,
parentItem->children.size(), parentItem->children.size());
Item *item = new Item;
item->values = values;
item->parent = parentItem;
parentItem->children.append(item);
endInsertRows();
}
void TreeModel::removeRow(const QModelIndex &index)
{
if (!index.isValid()) {
return;
}
Item *item = static_cast<Item *>(index.internalPointer());
Q_ASSERT(item != m_root);
beginRemoveRows(index.parent(), item->rowInParent(), item->rowInParent());
item->parent->children.removeOne(item);
delete item;
endRemoveRows();
}