是否可以将同一组源数据与不同模型的表链接起来?
Posted
技术标签:
【中文标题】是否可以将同一组源数据与不同模型的表链接起来?【英文标题】:Is it possible to link one and the same set of source data with different models of tables? 【发布时间】:2019-05-28 09:50:49 【问题描述】:假设我有一个 QString 类型的源数据结构。我的目标是在不同模型 (QAbstractTableModel) 呈现的不同表格 (QTableView) 中显示这些数据。我希望在源数据更改时查看这些表中的数据更改,但无需为每个表模型显式调用 setData (...)。 有可能吗?
------UPD----- 为我的示例添加了代码。在我不知道的cmets中怎么做。
我不知道如何为不同的表使用相同的模型。 如果你知道,请告诉我如何做到这一点。这是我的测试示例。
#TableTest.pro
QT += widgets
DEFINES += QT_DEPRECATED_WARNINGS
SOURCES += \
main.cpp
HEADERS += \
main.h
# Default rules for deployment.
qnx: target.path = /tmp/$$TARGET/bin
else: unix:!android: target.path = /opt/$$TARGET/bin
!isEmpty(target.path): INSTALLS += target
// main.h
#include <QObject>
#include <QTimer>
#include <QString>
#include <QColor>
#include <QTableView>
#include <QHeaderView>
#include <QStandardItemModel>
#include <QStringList>
#define UPDATE_INTERVAL 200
#define MAP_WIDTH 600
#define MAP_HEIGHT 400
#define RAND_HALF (RAND_MAX / 2)
#ifndef MAIN_H
#define MAIN_H
class CTestObject : public QObject
Q_OBJECT
public:
CTestObject(QString name, QString user);
void setData(double x, double y, double speed, const QString &zone);
void setData(double speed, double azimuth);
QString Name;
QString User;
double CoordX;
double CoordY;
double Speed;
double Azimuth;
double Weight;
QColor Color;
QString Zone;
signals:
void changed(CTestObject*);
;
//--------------------------------------------- All Objects Table
class CAllObjectsTable : public QStandardItemModel
Q_OBJECT
public:
CAllObjectsTable(QString Title, QStringList ColumnHeaders);
void addRecord(CTestObject *object);
void deleteRecord(CTestObject *object);
QTableView *view;
public slots:
virtual void updateRecordData(CTestObject *object);
protected:
QVector<CTestObject*> Objects; // local array pointers to objects (each table has its own set)
;
//--------------------------------------------- Table Zone
class CZoneTable : public CAllObjectsTable
Q_OBJECT
public:
CZoneTable(QString Title, QStringList ColumnHeaders) : CAllObjectsTable(Title, ColumnHeaders)
void addRecord(CTestObject *object);
public slots:
virtual void updateRecordData(CTestObject *object) override;
;
//-------------------------------------------- Users Table
class CUsersTable : public CAllObjectsTable
Q_OBJECT
public:
CUsersTable(QString Title, QStringList ColumnHeaders) : CAllObjectsTable(Title, ColumnHeaders)
void addRecord(CTestObject *object);
public slots:
virtual void updateRecordData(CTestObject *object) override;
;
#endif // MAIN_H
// main.cpp
#include <QApplication>
#include <QtMath>
#include <QDebug>
#include "main.h"
void tmrUpdateEvent();
QVector<CTestObject*> g_Objects; // Global source objects array
CAllObjectsTable *AllObjectsTable;
CZoneTable *ZoneObjectsTable;
CUsersTable *UsersTable;
//-----------------------------------------------------------------
int main(int argc, char *argv[])
QApplication app(argc, argv);
// create objects
g_Objects.append(new CTestObject("ObjectA", "John"));
g_Objects.append(new CTestObject("ObjectB", "Peter"));
g_Objects.append(new CTestObject("ObjectC", "Mike"));
g_Objects.append(new CTestObject("ObjectD", "Alice"));
g_Objects.append(new CTestObject("ObjectE", "Megan"));
// create tables
AllObjectsTable = new CAllObjectsTable("All Objects", QStringList() << "Object" << "X" << "Y" << "Speed" << "Zone");
for(int c =0; c < g_Objects.size(); c++)
AllObjectsTable->addRecord(g_Objects[c]);
ZoneObjectsTable = new CZoneTable("Zone B1", QStringList() << "Object" << "Weight" << "Speed" << "Azimuth" << "X" << "Y");
UsersTable = new CUsersTable("Users", QStringList() << "User" << "Object" << "Zone" << "X" << "Y");
tmrUpdateEvent();
return app.exec();
//------------------------------------------------ Table AllObjects
CAllObjectsTable::CAllObjectsTable(QString Title, QStringList ColumnHeaders)
// model
this->setHorizontalHeaderLabels(ColumnHeaders);
// view
view = new QTableView;
view->setWindowTitle(Title);
view->verticalHeader()->hide();
view->setModel(this);
view->show();
void CAllObjectsTable::addRecord(CTestObject *object)
if(!object)
return;
this->Objects.append(object);
this->insertRow(this->Objects.size() - 1);
this->setData(index((Objects.size() - 1), 0), object->Name, Qt::DisplayRole);
connect(object, SIGNAL(changed(CTestObject*)), this, SLOT(updateRecordData(CTestObject*)));
void CAllObjectsTable::deleteRecord(CTestObject *object)
for(int c =0; c < this->Objects.size(); c++)
if(this->Objects[c] == object)
this->Objects.remove(c);
this->removeRow(c);
void CAllObjectsTable::updateRecordData(CTestObject *object)
for(int c =0; c < this->Objects.size(); c++)
if(this->Objects[c] == object)
this->setData(index(c, 1), object->CoordX, Qt::DisplayRole);
this->setData(index(c, 2), object->CoordY, Qt::DisplayRole);
this->setData(index(c, 3), object->Speed, Qt::DisplayRole);
this->setData(index(c, 4), object->Zone, Qt::DisplayRole);
//------------------------------------------------------- Table Zone
void CZoneTable::addRecord(CTestObject *object)
if(!object)
return;
this->Objects.append(object);
this->insertRow(Objects.size() - 1);
this->setData(index((this->Objects.size() - 1), 0), object->Name, Qt::DisplayRole); // Name
this->setData(index((Objects.size() - 1), 1), object->Weight, Qt::DisplayRole); // Weight
connect(object, SIGNAL(changed(CTestObject*)), this, SLOT(updateRecordData(CTestObject*)));
void CZoneTable::updateRecordData(CTestObject *object)
for(int c =0; c < this->Objects.size(); c++)
if(this->Objects[c] == object)
this->setData(index(c, 2), object->Speed, Qt::DisplayRole); // Speed
this->setData(index(c, 3), object->Azimuth, Qt::DisplayRole); // Azimuth
this->setData(index(c, 4), object->CoordX, Qt::DisplayRole); // X
this->setData(index(c, 5), object->CoordY, Qt::DisplayRole); // Y
//------------------------------------------------------- Table Users
void CUsersTable::addRecord(CTestObject *object)
if(!object)
return;
this->Objects.append(object);
this->insertRow(Objects.size() - 1);
this->setData(index((this->Objects.size() - 1), 0), object->User, Qt::DisplayRole); // User
this->setData(index((Objects.size() - 1), 1), object->Name, Qt::DisplayRole); // Name
this->setData(index((Objects.size() - 1), 0), object->Color, Qt::ForegroundRole);
connect(object, SIGNAL(changed(CTestObject*)), this, SLOT(updateRecordData(CTestObject*)));
void CUsersTable::updateRecordData(CTestObject *object)
for(int c =0; c < this->Objects.size(); c++)
if(this->Objects[c] == object)
this->setData(index(c, 2), object->Zone, Qt::DisplayRole); // Zone
this->setData(index(c, 3), object->CoordX, Qt::DisplayRole); // X
this->setData(index(c, 4), object->CoordY, Qt::DisplayRole); // Y
//------------------------------------------------------- Object
CTestObject::CTestObject(QString name, QString user) : Name(name), User(user)
Weight =(std::rand() % 20000);
Color =(std::rand() << 15 | std::rand());
setData((std::rand() % MAP_WIDTH), (std::rand() % MAP_HEIGHT), 0, "");
setData(std::rand(), ((double)(std::rand() - RAND_HALF) / RAND_MAX));
void CTestObject::setData(double x, double y, double speed, const QString &zone)
this->CoordX =x;
this->CoordY =y;
this->Speed =speed;
this->Zone =zone;
emit changed(this);
void CTestObject::setData(double speed, double azimuth)
this->Speed =std::fmod(speed, 1000);
this->Azimuth =azimuth;
emit changed(this);
//----------------------------------------------------------
QString GetZoneXY(double x, double y)
double ZoneWidth =(MAP_WIDTH / 3), ZoneHeight =(MAP_HEIGHT / 3);
QString Zone ="";
if(x < ZoneWidth)
Zone +="A";
else
if(x < (ZoneWidth * 2))
Zone +="B";
else
Zone +="C";
if(y < ZoneHeight)
Zone +="0";
else
if(y < (ZoneHeight * 2))
Zone +="1";
else
Zone +="2";
return(Zone);
//============================================== Update =================================
void tmrUpdateEvent()
for(int c =0; c < g_Objects.size(); c++)
double s;
s =(g_Objects[c]->Speed - (0.001 * g_Objects[c]->Weight));
if(s > 10) // if Object moving - update Coords & Speed
double x =g_Objects[c]->CoordX, y =g_Objects[c]->CoordY, a =g_Objects[c]->Azimuth;
QString z;
x =std::fmod(x + (std::sin(a) * s * 0.01), MAP_WIDTH);
y =std::fmod(y + (std::cos(a) * s * 0.01), MAP_HEIGHT);
while(x < 0)
x +=MAP_WIDTH;
while(y < 0)
y +=MAP_HEIGHT;
z =GetZoneXY(x, y); // current zone
// check objects for Zone table
if(g_Objects[c]->Zone == "B1" && z != "B1")
ZoneObjectsTable->deleteRecord(g_Objects[c]);
else
if(z == "B1" && g_Objects[c]->Zone != "B1")
ZoneObjectsTable->addRecord(g_Objects[c]);
// check objects for Users table
if(z != "B1" && g_Objects[c]->Zone == "B1")
UsersTable->addRecord(g_Objects[c]);
else
if(z == "B1" && g_Objects[c]->Zone != "B1")
UsersTable->deleteRecord(g_Objects[c]);
g_Objects[c]->setData(x, y, s, z);
else // new Speed & Direction
g_Objects[c]->setData(std::rand(), ((double)(std::rand() - RAND_HALF) / RAND_MAX));
QTimer::singleShot(UPDATE_INTERVAL, [=]()tmrUpdateEvent(););
【问题讨论】:
我将其解读为:当数据类型为QString
的数据发生更改时,视图应自动更新。为此,我会将视图的信号槽连接到数据信号。不幸的是,QString
没有提供这样的信号。您必须将 QString
包装到一个提供此类信号的类中,并在包装的字符串被相应的更改时发出它。二传手。您可以完全自己编写包装器,或者考虑使用带有属性的QObject
。关于后者,这可能会有所帮助:The Property System.
如果你想呈现相同的数据,你应该考虑对多个视图使用相同的模型。字符串作为数据源在低级别上很好,但有时您需要将其解析为您选择的模型,我建议使用QStandardItemModel
为什么要创建多个模型?
【参考方案1】:
谢谢大家。我找到了问题的答案——不,这是不可能的。 问题是 setData(...) 通过复制模型来设置数据。我想插入一个指向它们的链接,而不是稍后捕获有关数据更改的信号。像这样。
【讨论】:
正如另一条评论中所说,使用具有多个视图的相同模型还不够吗?以上是关于是否可以将同一组源数据与不同模型的表链接起来?的主要内容,如果未能解决你的问题,请参考以下文章