是否可以将同一组源数据与不同模型的表链接起来?

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(...) 通过复制模型来设置数据。我想插入一个指向它们的链接,而不是稍后捕获有关数据更改的信号。像这样。

【讨论】:

正如另一条评论中所说,使用具有多个视图的相同模型还不够吗?

以上是关于是否可以将同一组源数据与不同模型的表链接起来?的主要内容,如果未能解决你的问题,请参考以下文章

符号表链接器与地址

您可以将一个表中具有另一个表的列名的列与第二个表链接吗

mysql远程表链接

如何填充与laravel中的产品表链接的类别表

如何将 SQL 查询与另一个表链接?

DB2 SELECT MOST 中频繁出现并与其他表链接