I'm trying to get a role to return an object. I'm running into undefined errors when I try to access display.blockNumber and display.time
here's my code
blockdisplay.h:
#ifndef BLOCKDISPLAY_H
#define BLOCKDISPLAY_H
#include <QMetaType>
class BlockDisplay
{
public:
BlockDisplay();
BlockDisplay(int blocknum, long time);
BlockDisplay(const BlockDisplay &other);
~BlockDisplay();
int blockNumber() const;
long time() const;
private:
int m_blocknumber;
long m_time;
};
Q_DECLARE_METATYPE(BlockDisplay)
#endif // BLOCKDISPLAY_H
blockdisplay.cpp:
#include "blockdisplay.h"
BlockDisplay::BlockDisplay() {
}
BlockDisplay::BlockDisplay(int blocknum, long time) {
this->m_blocknumber = blocknum;
this->m_time = time;
}
BlockDisplay::BlockDisplay(const BlockDisplay &other) {
this->m_blocknumber = other.blockNumber();
this->m_time = other.time();
}
BlockDisplay::~BlockDisplay() {
}
int BlockDisplay::blockNumber() const {
return this->m_blocknumber;
}
long BlockDisplay::time() const {
return this->m_time;
}
modelclass.h:
#ifndef MODELCLASS_H
#define MODELCLASS_H
#include <QObject>
#include <QAbstractListModel>
#include <QStringListModel>
#include <blockchain.h>
class ModelClass : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(qint32 blockheight READ blockheight)
protected:
Blockchain bc{};
int first;
public:
ModelClass();
qint32 blockheight();
void init();
int rowCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
};
#endif // MODELCLASS_H
modelclass.cpp:
#include "modelclass.h"
#include <string.h>
#include <qdebug>
#include "blockdisplay.h"
using namespace std;
ModelClass::ModelClass()
{
}
void ModelClass::init() {
bc.init();
if ( !bc.Valid() )
qDebug() << "invalid";
else {
bc.SeekToFirst();
bc.Next();
if ( !bc.Valid() )
qDebug() << "invalid";
else
first = bc.GetCurrentBlock().signedhead().head().num();
}
//setProperty("blockheight",bc.GetBlockHeight());
}
qint32 ModelClass::blockheight() {
return bc.GetBlockHeight();
}
int ModelClass::rowCount(const QModelIndex &parent) const {
//qInfo() << " 0test " << bc.GetBlockHeight();
return bc.GetBlockHeight() - first;
}
QVariant ModelClass::data(const QModelIndex & index, int role) const {
qInfo() << " 1test " << index;
int row = bc.GetBlockHeight() - index.row();// + 1 + first;
if (index.isValid()) {
bc.Seek(row);
if (bc.Valid()) {
if (role == Qt::DisplayRole) {
int blocknum = bc.GetCurrentBlock().signedhead().head().num();
long timestamp = bc.GetCurrentBlock().signedhead().head().timestamp();
BlockDisplay dsply{blocknum, timestamp};
QVariant var = QVariant::fromValue(dsply);
return var;
}
}
}
return QVariant();
}
snippet from block.qml:
Component {
id: gridComp
Row {
Text {
text: display.blockNumber + " "
MouseArea {
anchors.fill: parent
onClicked: {
list.currentIndex = index;
ld.setSource("detail.qml")
}
}
}
Text {
text: display.time + " "
}
}
}
I think Q_DECLARE_METATYPE(BlockDisplay) is not enough. If you want to use its attributes in QML you have to use the Q_PROPERTY macro to create properties, just like you did for ModelClass. You may also have to call qRegisterMetaType
Adding a Q_DECLARE_METATYPE() makes the type known to all template based functions, including QVariant. Note that if you intend to use the type in queued signal and slot connections or in QObject's property system, you also have to call qRegisterMetaType() since the names are resolved at runtime.
Related
I am trying to update a table with data coming from an external process (into QML I lunch a CLI tool that returns a lot of strings and with that, I update the table). I am using TableView to show these data, and I wrote a Model class and a List class: the Model class extend QAbstractTableModel, indeed the list class extend QObject.
I am sure that the list is full (I print the contents with qDebug()), but the table is always empty! Can you help me?
I added some debug prints and I can see that the rowCount function of the model is called a lot of time and return the correct length of the list, but the data function is called only when index.row() is equal to zero! I don't understand why!
#ifndef PAYEELIST_H
#define PAYEELIST_H
#include <QObject>
#include <QList>
#include "payee.h"
class PayeeList : public QObject
{
Q_OBJECT
public:
explicit PayeeList(QObject *parent = nullptr);
QList<Payee> items() const;
// bool setItemAt (int index, const Payee &item);
void clear (void);
void append (const Payee& item);
signals:
void preItemAppended ();
void postItemAppended ();
void preItemRemoved (int index);
void postItemRemoved ();
//public slots:
// void appendItem ();
private:
QList<Payee> mItems;
};
#endif // PAYEELIST_H
#include "payeelist.h"
PayeeList::PayeeList(QObject *parent) : QObject(parent)
{
}
QList<Payee> PayeeList::items() const
{
return mItems;
}
void PayeeList::clear()
{
mItems.clear();
}
void PayeeList::append(const Payee &item)
{
emit preItemAppended();
mItems.append(item);
emit postItemAppended();
}
#ifndef PAYEEMODEL_H
#define PAYEEMODEL_H
#include <QAbstractTableModel>
#include "payeelist.h"
//class PayeeList;
class PayeeModel : public QAbstractTableModel
{
Q_OBJECT
Q_PROPERTY(PayeeList *list READ list WRITE setList)
public:
explicit PayeeModel(QObject *parent = nullptr);
enum
{
HeadingRole = Qt::UserRole + 1,
DataRole
};
enum
{
IdColumn = 0,
NameColumn,
TypeColumn
};
// Basic functionality:
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
virtual QHash<int, QByteArray> roleNames() const override;
PayeeList *list (void) const;
void setList (PayeeList *list);
private:
PayeeList *mList;
};
#endif // PAYEEMODEL_H
#include "payeemodel.h"
PayeeModel::PayeeModel(QObject *parent)
: QAbstractTableModel(parent),
mList(nullptr)
{
}
int PayeeModel::rowCount(const QModelIndex &parent) const
{
// For list models only the root node (an invalid parent) should return the list's size. For all
// other (valid) parents, rowCount() should return 0 so that it does not become a tree model.
if (parent.isValid() || !mList)
return 0;
qDebug() << "LIST SIZE:" << mList->items().size();
return mList->items().size() + 1;
}
int PayeeModel::columnCount(const QModelIndex &parent) const
{
if (parent.isValid() || !mList)
return 0;
return 3;
}
QVariant PayeeModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || !mList)
return QVariant();
switch (role)
{
case DataRole:
{
qDebug() << "INDEX ROW:" << index.row();
if (index.row() > 0)
{
const Payee item = mList->items().at(index.row() - 1);
switch (index.column())
{
case IdColumn:
return QString::number(item.id());
break;
case NameColumn:
return QString(item.name());
break;
case TypeColumn:
return QString(item.type().name());
break;
}
}
else
{
switch (index.column())
{
case IdColumn:
return QString("Id");
break;
case NameColumn:
return QString("Name");
break;
case TypeColumn:
return QString("Type");
break;
}
}
}
break;
case HeadingRole:
if (index.row() == 0)
{
return true;
}
else
{
return false;
}
break;
default:
break;
}
return QVariant();
}
QHash<int, QByteArray> PayeeModel::roleNames() const
{
QHash<int, QByteArray> names;
names[HeadingRole] = "tableheading";
names[DataRole] = "tabledata";
return names;
}
PayeeList *PayeeModel::list (void) const
{
return mList;
}
void PayeeModel::setList (PayeeList *list)
{
beginResetModel();
if (mList)
{
mList->disconnect(this);
}
mList = list;
if (mList)
{
connect(mList, &PayeeList::preItemAppended, this, [=]()
{
const int index = mList->items().size();
beginInsertRows(QModelIndex(), index, index);
});
connect(mList, &PayeeList::postItemAppended, this, [=]()
{
endInsertRows();
});
}
endResetModel();
}
The QML file is:
import QtQuick 2.12
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
import PlutoTool 1.0
Rectangle {
id: payeePage
Layout.fillWidth: true
property var title: "TITLE"
TableView {
columnSpacing: 1
rowSpacing: 1
anchors.fill: parent
clip: false
property var columnWidths: [50, (parent.width - 220), 150]
columnWidthProvider: function (column) { return columnWidths[column] }
model: PayeeModel {
list: lPayeeList
}
delegate: Rectangle {
implicitWidth: 200
implicitHeight: 30
border.color: "black"
border.width: 0
color: (tableheading == true) ? "#990033":"#EEEEEE"
Text {
text: model.tabledata
color: (tableheading == true) ? "#FFFFFF":"#000000"
font.bold: (tableheading == true) ? true : false
anchors.centerIn: parent
}
Component.onCompleted: {
console.log(model.tabledata);
}
}
}
}
Please have a look into the following code:
CMyModel* myModel = new CMyModel(); //This is my main model sub-classing QAbstractListItemModel
CMySortModel* mySortModel = new CMySortModel(); //This is my sort filter proxy model sub-classing QSortFilterProxyModel
mySortModel->setSourceModel(myModel);
mySortModel->setDynamicSortFilter(true);
mySortModel->setSortRole(CMyModel::displayRole);
myModel->Initialize(); // This is working fine
mySortModel->sort(0);
// myModel->Initialize(); // This is not working
The above code is working fine when the data structure (basically a QList of integers linked to CMyModel) is initialized before, mySortModel->sort(0) is called.
If the list is initialized after the sort method call, the view is basically not showing any data.
Then I tried following
mySortModel->sort(0);
myModel->Initialize();
mySortModel->Invalidate(); // This is working fine.
But realized that, every time there is an update in the QList, I need to call mySortModel->Invalidate() to update my view. Otherwise the view is not updating. This is causing a complete view update and in turn a flickering in my screen.
As not much idea on Qt/QML model view coding, so bit stuck with the issue.
Please correct me, if I am doing anything wrong.
MyModel.cpp
#include "MyModel.h"
#include <QDateTime>
CMyModel::CMyModel(QObject *parent)
: QAbstractListModel(parent)
{
m_mapRoles.insert(rolesEnum::displayRole, "displayRole");
}
void CMyModel::Initialize()
{
qsrand(QDateTime::currentMSecsSinceEpoch() / 1000);
quint32 index = 0;
while (index < 200)
{
m_lstOfInts.append(qrand() % 1000);
index++;
}
}
int CMyModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_lstOfInts.count();
}
int CMyModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return 1;
}
QVariant CMyModel::data(const QModelIndex &index, int role) const
{
Q_UNUSED(role)
int rowVal = index.row();
if (role == rolesEnum::displayRole)
{
if (rowVal >= 0 && rowVal < m_lstOfInts.count())
{
return m_lstOfInts.at(rowVal);
}
}
return QVariant();
}
QHash<int, QByteArray> CMyModel::roleNames() const
{
return m_mapRoles;
}
MyModel.h
#ifndef MYMODEL_H
#define MYMODEL_H
#include <QAbstractListModel>
#include <QObject>
#include <QHash>
class CMyModel : public QAbstractListModel
{
Q_OBJECT
public:
enum rolesEnum {
displayRole
};
Q_ENUM(rolesEnum)
public:
explicit CMyModel(QObject *parent = NULL);
// QAbstractItemModel interface
public:
int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
private:
QList<int> m_lstOfInts;
QHash<int, QByteArray> m_mapRoles;
// QAbstractItemModel interface
public:
QHash<int, QByteArray> roleNames() const;
void Initialize();
};
#endif // MYMODEL_H
MySortModel.cpp
#include "MySortModel.h"
#include "MyModel.h"
CMySortModel::CMySortModel(QObject *parent)
: QSortFilterProxyModel(parent)
{
}
bool CMySortModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
{
return sourceModel()->data(source_left, CMyModel::displayRole).toInt() < sourceModel()->data(source_right, CMyModel::displayRole).toInt();
}
MySortModel.h
#ifndef MYSORTMODEL_H
#define MYSORTMODEL_H
#include <QSortFilterProxyModel>
class CMySortModel : public QSortFilterProxyModel
{
public:
explicit CMySortModel(QObject* parent = NULL);
// QSortFilterProxyModel interface
protected:
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const;
};
#endif // MYSORTMODEL_H
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQuickView>
#include <QQmlContext>
#include "MyModel.h"
#include "MySortModel.h"
int main(int argc, char *argv[])
{
#if defined(Q_OS_WIN)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
qmlRegisterType<CMySortModel>("CMySortModel", 1, 0, "CMySortModel");
CMyModel* myModel = new CMyModel();
CMySortModel* mySortModel = new CMySortModel();
mySortModel->setSourceModel(myModel);
mySortModel->setDynamicSortFilter(true);
mySortModel->setSortRole(CMyModel::displayRole);
// myModel->Initialize(); // This works
mySortModel->sort(0);
myModel->Initialize(); // This works when followed by a invalidate call on the proxy model
mySortModel->invalidate();
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("_myModel", mySortModel);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
{
delete mySortModel;
mySortModel = NULL;
delete myModel;
myModel = NULL;
return -1;
}
return app.exec();
}
main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.2
import QtGraphicalEffects 1.0
Window {
id: window
visible: true
width: 800
height: 480
title: qsTr("Hello World")
ScrollView {
anchors.fill: parent
width: parent.width
GridView {
anchors.fill: parent
//columns: 2
model: _myModel
delegate: Text {
id: _text
text: model.displayRole
}
}
}
}
Modified Initialize method as follows and it is working now
void CMyModel::Initialize()
{
qsrand(QDateTime::currentMSecsSinceEpoch() / 1000);
quint32 index = 0;
while (index < 200)
{
beginInsertRows(QModelIndex(), m_lstOfInts.size(), m_lstOfInts.size());
m_lstOfInts.append(qrand() % 1000);
index++;
endInsertRows();
}
}
I wrote a small Qt prototype which consists in a QTreeView on which I plugged QStandardItemModel. From there, I would like to be able to view the last level of my tree in a QTableView which I would like to be sortable and, why not, filterable. That seems to be the perfect scenario for the use of QSortFilterProxyModel. After implementation, the global view looks like what I want with the QTreeView on the left side and the QTableView on the right side(see image attached).
However, I face two issues:
only the first column is sortable
worse, if I select an item which is not in the first column and then click on one of the horizontal header the application crashes unexpectedly without any debugging backtrace in any of my implemented methods.
I may have misunderstood something regarding the use of Qt proxy model but do not know what and I can not find any clear hint on stack or elsewhere.
Here is my prototype cpp file:
#include <string>
#include <vector>
#include <QDebug>
#include <QAbstractProxyModel>
#include <QSortFilterProxyModel>
#include <QStandardItem>
#include <QStandardItemModel>
#include "mainwindow.h"
#include "ui_mainwindow.h"
struct Peak {
Peak(const std::string& name, int index, double qx, double qy, double qz);
std::string _name;
int _index;
double _qx;
double _qy;
double _qz;
};
Peak::Peak(const std::string& name, int index, double qx, double qy, double qz)
: _name(name),
_index(index),
_qx(qx),
_qy(qy),
_qz(qz)
{
}
struct PeakItem : public QStandardItem
{
PeakItem(const Peak& peak);
Peak _peak;
};
PeakItem::PeakItem(const Peak& peak)
: _peak(peak)
{
setText(QString::fromStdString(_peak._name));
appendRow(new QStandardItem(QString::number(_peak._index)));
appendRow(new QStandardItem(QString::number(_peak._qx)));
appendRow(new QStandardItem(QString::number(_peak._qy)));
appendRow(new QStandardItem(QString::number(_peak._qz)));
}
struct PeakListItem : public QStandardItem
{
PeakListItem(const std::vector<Peak>& peaks);
std::vector<Peak> _peaks;
};
PeakListItem::PeakListItem(const std::vector<Peak>& peaks)
: _peaks(peaks)
{
setText("Peaks");
setCheckable(true);
for (size_t r=0; r < _peaks.size(); ++r) {
auto item = new PeakItem(_peaks[r]);
appendRow(item);
}
}
struct PeakListProxyModel : public QSortFilterProxyModel {
PeakListProxyModel(PeakListItem* peak_list_item);
virtual QModelIndex mapFromSource(const QModelIndex &) const override;
virtual QModelIndex mapToSource(const QModelIndex &) const override;
virtual QModelIndex parent(const QModelIndex &) const override;
virtual QModelIndex index(int, int, const QModelIndex & p = QModelIndex()) const override;
virtual int rowCount(const QModelIndex & p = QModelIndex()) const override;
virtual int columnCount(const QModelIndex & p = QModelIndex()) const override;
virtual void sort(int column, Qt::SortOrder order) override;
PeakListItem* _peak_list_item;
};
PeakListProxyModel::PeakListProxyModel(PeakListItem* peak_list_item)
: _peak_list_item(peak_list_item)
{
}
QModelIndex PeakListProxyModel::parent(const QModelIndex &) const
{
return QModelIndex();
}
QModelIndex PeakListProxyModel::index(int row, int column, const QModelIndex& index) const
{
// qDebug()<<"create index "<<row<<" --- "<<column<<" --- "<<index;
return createIndex(row, column);
}
void PeakListProxyModel::sort(int column, Qt::SortOrder order)
{
qDebug()<<"sort "<<column;
QAbstractProxyModel::sort(column,order);
layoutChanged();
}
QModelIndex PeakListProxyModel::mapFromSource(const QModelIndex& source_index) const
{
if (!source_index.isValid()) {
return QModelIndex();
}
auto model = dynamic_cast<QStandardItemModel*>(sourceModel());
auto item = model->itemFromIndex(source_index);
auto parent_item = item->parent();
auto p = dynamic_cast<PeakItem*>(parent_item);
if (!p) {
return QModelIndex();
}
auto proxy_index = createIndex(parent_item->index().row(),item->index().row());
qDebug()<<"map from source --- "<<source_index<<" --- "<<proxy_index;
return proxy_index;
}
QModelIndex PeakListProxyModel::mapToSource(const QModelIndex& proxy_index) const
{
if (!proxy_index.isValid()) {
return QModelIndex();
}
auto peak_item = _peak_list_item->child(proxy_index.row());
auto prop_item = peak_item->child(proxy_index.column());
auto source_index = prop_item->index();
// qDebug()<<"map to source "<<proxy_index<<" --- "<<source_index<<" ---- "<<prop_item;
return source_index;
}
int PeakListProxyModel::rowCount(const QModelIndex& proxy_index) const
{
if (proxy_index.isValid()) {
return 0;
} else {
return _peak_list_item->rowCount();
}
}
int PeakListProxyModel::columnCount(const QModelIndex& proxy_index) const
{
if (proxy_index.isValid()) {
return 0;
} else {
return 4;
}
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QStandardItemModel* model = new QStandardItemModel();
QStandardItem* experiment = new QStandardItem("Experiment");
QStandardItem* peaks_item = new QStandardItem("Peaks");
std::vector<Peak> peaks;
peaks.reserve(4);
for (int i = 0; i < 4; ++i) {
peaks.emplace_back("Peak"+std::to_string(i),i,i,i,i);
}
// PeakListItem* peak_list_item1 = new PeakListItem(peaks);
// peaks_item->appendRow(peak_list_item1);
PeakListItem* peak_list_item2 = new PeakListItem(peaks);
peaks_item->appendRow(peak_list_item2);
experiment->appendRow(peaks_item);
model->appendRow(experiment);
ui->treeView->setModel(model);
PeakListProxyModel* proxy_model = new PeakListProxyModel(peak_list_item2);
proxy_model->setSourceModel(model);
ui->tableView->setModel(proxy_model);
ui->tableView->setSortingEnabled(true);
for (int i = 0; i < peaks.size(); ++i) {
// ui->treeView->setRowHidden(i,peak_list_item1->index(),true);
// ui->treeView->setRowHidden(i,peak_list_item2->index(),true);
}
}
MainWindow::~MainWindow()
{
delete ui;
}
After digging deeper I found that link
Basically explains how to solve my problem. To do the job, we have to pipe two models, one that do the mapping which derives from a QAbstractProxyModel and a second one that do the sorting/filetring which can be a standard QSortFilterProxyModel.
I'm trying to create a widget representing a table and update some data.
In order to do this I am following the Qt Model/View tutorial.
I've created classes (that you can find at the end of the post)
EmittersTableModel that inherits from QAbstractTableModel
EmittersTableWidget that inherits from QTableView
I havethe EmittersTableModel object as private member of EmittersTableWidget. In its constructor I instantiate the model and use the setModel() method.
Then, when I try to update data, I call the EmittersTableWidget::setRadioData() method, and I emit the datachanged() signal.
I've verified with the debugger that:
emit dataChanged(topLeft, bottomRight) is called
EmittersTableModel::rowCount() is called
EmittersTableModel::columnCount() is called
EmittersTableModel::flags() is never called
EmittersTableModel::data() is never called.
It seems for me that I'm doing all that tutorial says (use setModel(), implement needed virtual functions, emit the signal).
What I'm missing?
EmittersTableModel.h
#include <QAbstractTableModel>
#include <QVector>
#include "Radio.h"
typedef QMultiMap<QString, MapScenario::Core::RadioPtr> PlayerRadioMap;
class EmittersTableModel : public QAbstractTableModel
{
Q_OBJECT
public:
EmittersTableModel(QObject *parent);
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const ;
virtual int columnCount(const QModelIndex &parent = QModelIndex()) const;
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
virtual Qt::ItemFlags flags ( const QModelIndex & index ) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
void setRadioData(const PlayerRadioMap &xRadioMap);
private:
typedef struct
{
QString xName;
MapScenario::Core::RadioPtr pxRadio;
} TableRowData;
PlayerRadioMap m_xRadioMap;
QVector<TableRowData> m_xDataVector;
};
EmittersTableModel.cpp
#include "EmittersTableModel.h"
EmittersTableModel::EmittersTableModel(QObject *parent)
:QAbstractTableModel(parent)
{
}
int EmittersTableModel::rowCount(const QModelIndex & /*parent*/) const
{
return m_xDataVector.size() - 1;
}
int EmittersTableModel::columnCount(const QModelIndex & /*parent*/) const
{
return 8;
}
QVariant EmittersTableModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole)
{
switch (index.column())
{
case 0 :
{
return m_xDataVector.at(index.row()).xName;
} break;
case 1 :
{
return m_xDataVector.at(index.row()).pxRadio->getName();
} break;
}
return QString("Row%1, Column%2")
.arg(index.row() + 1)
.arg(index.column() +1);
}
return QVariant();
}
Qt::ItemFlags EmittersTableModel::flags(const QModelIndex &index) const
{
return Qt::ItemIsEnabled | Qt::ItemIsEditable;
}
QVariant EmittersTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == Qt::DisplayRole)
{
if (orientation == Qt::Horizontal) {
switch (section)
{
case 0:
return QString("Player");
case 1:
return QString("Emitter");
case 2:
return QString("Freq.");
case 3:
return QString("Power");
case 4:
return QString("Modulation");
case 5:
return QString("Freq. Hopp.");
case 6:
return QString("Silent");
case 7:
return QString("Rec. Power");
}
}
}
return QVariant();
}
void EmittersTableModel::setRadioData(const PlayerRadioMap &xRadioMap)
{
m_xDataVector.clear();
PlayerRadioMap::const_iterator xIt;
for (xIt = xRadioMap.begin(); xIt != xRadioMap.end(); ++xIt)
{
TableRowData xData;
xData.xName = xIt.key();
xData.pxRadio = xIt.value();
m_xDataVector.append(xData);
}
if (false == m_xDataVector.empty())
{
QModelIndex topLeft = createIndex(0, 0);
QModelIndex bottomRight = createIndex(m_xDataVector.size() - 1, 7);
emit dataChanged(topLeft, bottomRight);
}
}
EmittersTableWidget.h
#include <QTableView>
#include <QHeaderView>
#include <QMultiMap>
#include <boost/smart_ptr.hpp>
#include "EmittersTableModel.h"
#include "Scenario.h"
#include "Radio.h"
namespace MapScenario
{
namespace Core
{
class Player;
}
}
/** Class for the player properties table model window */
class EmittersTableWidget : public QTableView
{
Q_OBJECT
public:
EmittersTableWidget(QWidget *xParent = 0);
~EmittersTableWidget();
public slots:
void refreshScenarioDataSlot(const MapScenario::Core::ScenarioPtr pxScenario);
private:
EmittersTableModel *m_pxModel;
void getTransmitterMap(const MapScenario::Core::ScenarioPtr pxScenario, PlayerRadioMap *pxRadioMap) const;
void sendDataToTableModel(const PlayerRadioMap &xRadioMap);
};
EmittersTableWidget.cpp
#include "EmittersTableWidget.h"
#include "Player.h"
#include "CoreException.h"
using MapScenario::Core::ScenarioPtr;
using MapScenario::Core::Radio;
using MapScenario::Core::PlayerPtr;
///////////////////////////////////////////////////////////////////////////////
// PUBLIC SECTION //
///////////////////////////////////////////////////////////////////////////////
EmittersTableWidget::EmittersTableWidget(QWidget *xParent)
: QTableView(xParent)
{
m_pxModel = new EmittersTableModel(0);
setModel(m_pxModel);
horizontalHeader()->setVisible(true);
verticalHeader()->setVisible(false);
setShowGrid(true);
setGridStyle(Qt::NoPen);
setCornerButtonEnabled(false);
setWordWrap(true);
setAlternatingRowColors(true);
setSelectionMode(QAbstractItemView::SingleSelection);
setSelectionBehavior(QAbstractItemView::SelectRows);
setSortingEnabled(true);
}
EmittersTableWidget::~EmittersTableWidget()
{
delete m_pxModel;
}
///////////////////////////////////////////////////////////////////////////////
// PUBLIC SLOTS SECTION //
///////////////////////////////////////////////////////////////////////////////
void EmittersTableWidget::refreshScenarioDataSlot(const ScenarioPtr pxScenario)
{
PlayerRadioMap xRadioMap;
getTransmitterMap(pxScenario, &xRadioMap);
sendDataToTableModel(xRadioMap);
}
void EmittersTableWidget::getTransmitterMap(const ScenarioPtr pxScenario, PlayerRadioMap *pxRadioMap) const
{
QVector<QString> xNameList;
QVector<QString>::const_iterator xNameIt;
QStringList::const_iterator xRadioIt;
pxScenario->getPlayersNameList(xNameList);
for (xNameIt = xNameList.begin(); xNameIt != xNameList.end(); ++xNameIt)
{
QStringList xRadioList;
PlayerPtr pxPlayer = pxScenario->getPlayer(*xNameIt);
pxPlayer->getRadioNameList(xRadioList);
for (xRadioIt = xRadioList.begin(); xRadioIt != xRadioList.end(); ++xRadioIt)
{
pxRadioMap->insert(pxPlayer->getName(), pxPlayer->getRadio(*xRadioIt));
}
}
}
void EmittersTableWidget::sendDataToTableModel(const PlayerRadioMap &xRadioMap)
{
m_pxModel->setRadioData(xRadioMap);
}
I've found my problem.
In the tutorial that I've seen it was supposed that row and column numbers are Always constant. Instead I start with zero rows, and then I add or remove them when I need. In order to do this, I need to re-implement following methods:
virtual bool insertRows(int row, int count, const QModelIndex &parent)
virtual bool insertColumns(int column, int count, const QModelIndex &parent)
virtual bool removeRows(int row, int count, const QModelIndex &parent)
virtual bool removeColumns(int column, int count, const QModelIndex &parent)
as explained in QAbstractItemModel page in subclassing section. Now I insert and remove rows when needed and table is updated correctly.
this works:
/*Just copy and paste*/
#include <QApplication>
#include <QtGui>
#include <QDebug>
#include <QAbstractProxyModel>
class File_List_Proxy : public QAbstractProxyModel
{
public:
virtual QModelIndex mapFromSource ( const QModelIndex & sourceIndex ) const
{
return sourceModel()->index(sourceIndex.row(),sourceIndex.column());
}
virtual QModelIndex mapToSource ( const QModelIndex & proxyIndex ) const
{
return sourceModel()->index(proxyIndex.row(),proxyIndex.column());
}
virtual QModelIndex index(int row, int column, const QModelIndex&) const
{
return createIndex(row,column);
}
virtual QModelIndex parent(const QModelIndex&) const
{
return QModelIndex();
}
virtual int rowCount(const QModelIndex&) const
{
return sourceModel()->rowCount();
}
virtual int columnCount(const QModelIndex&) const
{
return sourceModel()->columnCount();
}
};
class File_List_Model : public QAbstractItemModel
{
private:
QStringList data_;
public:
File_List_Model(/*const QStringList& value*/)//:QStringListModel(value)
{
}
QVariant data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole){
/*QVariant t = data_.at(index.row());
qDebug() << "index.row(): " << index.row();
qDebug() << "data_.at(index.row()): " << data_.at(index.row());*/
return data_.at(index.row());
}
else
{
return QVariant();
}
}
bool set_entries(const QStringList& entries)
{
beginInsertRows(createIndex(0,0),0,entries.count());
data_ = entries;
endInsertRows();
emit dataChanged(createIndex(0,0),createIndex(0,entries.count()));
return true;
}
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::DisplayRole)
{
switch(role)
{
case Qt::DisplayRole:
data_ = value.toStringList();
emit dataChanged(index,index);
return true;
}
return false;
}
virtual QModelIndex index(int row, int column, const QModelIndex&) const
{
return createIndex(row,column);
}
virtual QModelIndex parent(const QModelIndex&) const
{
return QModelIndex();
}
virtual int rowCount(const QModelIndex&) const
{
return data_.size();
}
virtual int columnCount(const QModelIndex&) const
{
return 1;
}
};
int main(int argc,char** argv)
{
QApplication app(argc,argv);
QDir dir(QDesktopServices::storageLocation(QDesktopServices::HomeLocation));
File_List_Model* model = new File_List_Model;//(dir.entryList());
bool t = model->set_entries(dir.entryList());
File_List_Proxy* proxy = new File_List_Proxy;
proxy->setSourceModel(model);
QListView* view = new QListView;
view->setModel(proxy);
//new ModelTest(model);
view->show();
return app.exec();
}
/*End of copy*/
This on the contrary from a different project where File_List_Model and File_List_Proxy ARE COPIED AND NOT CHANGED from the code above doesn't work:
Line_Counter::Line_Counter(QWidget *parent) :
QDialog(parent), model_(new File_List_Model),
proxy_model_(new File_List_Proxy)
{
setupUi(this);
setup_mvc_();
QDir dir(QDesktopServices::storageLocation(QDesktopServices::HomeLocation));
File_List_Model* model = new File_List_Model;//(dir.entryList());
bool t = model->set_entries(dir.entryList());
}
void Line_Counter::setup_mvc_()
{
proxy_model_->setSourceModel(model_);
listView->setModel(proxy_model_);
}
//Line counter
class Line_Counter : public QDialog, private Ui::Line_Counter
{
Q_OBJECT
private:
File_List_Model* model_;
//QStringListModel* model_;
File_List_Proxy* proxy_model_;
};
What's going on here?!
You call the setup_mvc_ before the model creation. The model_ in this case it a default constructed model where the set_entries has not been called. On the other hand you call the set_entries on the model which you do not set to a view.
This will work:
Line_Counter::Line_Counter(QWidget *parent) :
QDialog(parent), model_(new File_List_Model),
proxy_model_(new File_List_Proxy)
{
setupUi(this);
QDir dir(QDesktopServices::storageLocation(QDesktopServices::HomeLocation));
bool t = model_->set_entries(dir.entryList());
setup_mvc_();
}