Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to call a model function and update the data in a QTableView?
Forum Updated to NodeBB v4.3 + New Features

How to call a model function and update the data in a QTableView?

Scheduled Pinned Locked Moved Solved General and Desktop
5 Posts 2 Posters 480 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • N Offline
    N Offline
    NullFunction
    wrote on last edited by
    #1

    Hi everyone, I am working a on game which can be represented as a 2D grid, which made the table view useful for this. When a user selects a column (wherever inside the column, rows are not important), I want a signal to be sent to the model, which will update the board accordingly.

    For now, I have the following inside a main.cpp, mainwindow is the default one, nothing was changed there.

    I implemented my own model which has a game attribute, the game has all the relevant data and logic within. In the code here under, nothing happens when I click on a cell and the "buttons" (the pieces of the game) are not moved around. Did I mess up the connection?

    #include "mainwindow.h"
    #include "qtmodel.h"
    #include <QApplication>
    #include <QTableView>
    
    int main(int argc, char *argv[]) {
      QApplication app(argc, argv);
      MainWindow window;
      QTableView tableView;
      Game *gamePointer{new Game};
      QtModel model;
      model.setGame(gamePointer);
      tableView.setModel(&model);
      tableView.setSelectionBehavior(QTableView::SelectColumns);
    // problematic connection here?
      QTableView::connect(&tableView, SIGNAL(clicked(const QModelIndex &)), &model,
                          SLOT(moveStacksOnColumnClicked(const QModelIndex &)));
      tableView.setStyleSheet(
          "selection-background-color: rgba(137, 196, 244, 250)");
      window.setCentralWidget(&tableView);
      window.resize(1400, 600);
      window.setWindowTitle("MyGAME!");
      window.show();
      int ret = app.exec();
      delete gamePointer;
      return ret;
    }
    

    The model is as follows:
    It doesn't do anything fancy aside from changing the background colors of cells depending on some game enumeration, the header numbering is not that important but the important functions are data and moveStackOnColumnClicked which calls a method of the game that moves the "buttons" of my game around, it takes a single integer as parameter, which is the index of the column where the player wants to act.

    #include "qtmodel.h"
    
    #include <QBrush>
    
    QtModel::QtModel(QObject *parent) : QAbstractTableModel(parent) {}
    
    // See https://doc.qt.io/qt-6/modelview.html#2-1-a-read-only-table
    
    QVariant QtModel::headerData(int section, Qt::Orientation orientation,
                                 int role) const {
      if (role == Qt::DisplayRole && orientation == Qt::Vertical) {
        for (int i = 0; i < ButtonStack::N_BUTTONS; i++) {
          const std::string rowHeader = std::to_string(ButtonStack::N_BUTTONS - i);
          if (i == section) {
            return QString(rowHeader.c_str());
          }
        }
      }
      if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
        for (int i = 0; i < ButtonStack::N_BUTTONS; i++) {
          const std::string colHeader = std::to_string(i + 1);
          if (i == section) {
            return QString(colHeader.c_str());
          }
        }
      }
      return QVariant();
    }
    
    int QtModel::rowCount(const QModelIndex & /*parent*/) const { return 9; }
    
    int QtModel::columnCount(const QModelIndex & /*parent*/) const { return 9; }
    
    QVariant QtModel::data(const QModelIndex &index, int role) const {
      int row = index.row();
      int col = index.column();
      if (role == Qt::BackgroundRole) {
        Button dat = (*m_game)[col][ButtonStack::N_BUTTONS - row - 1];
        switch (dat) {
        case Button::EMPTY:
          return QBrush(QColorConstants::Svg::lightgray);
        case Button::RED:
          return QBrush(QColorConstants::Svg::orangered);
        case Button::BLACK:
          return QBrush(QColorConstants::Svg::black);
        case Button::WHITE:
          return QBrush(QColorConstants::Svg::ghostwhite);
        }
      }
    
      return QVariant();
    }
    
    void QtModel::setGame(Game *game) { m_game = game; }
    
    void QtModel::moveStacksOnColumnClicked(const QModelIndex &idx) {
      if (idx.isValid()) {
        m_game->moveStack(idx.column());
      }
    }
    

    Thanks for the help.

    JonBJ 1 Reply Last reply
    0
    • N NullFunction

      Hi everyone, I am working a on game which can be represented as a 2D grid, which made the table view useful for this. When a user selects a column (wherever inside the column, rows are not important), I want a signal to be sent to the model, which will update the board accordingly.

      For now, I have the following inside a main.cpp, mainwindow is the default one, nothing was changed there.

      I implemented my own model which has a game attribute, the game has all the relevant data and logic within. In the code here under, nothing happens when I click on a cell and the "buttons" (the pieces of the game) are not moved around. Did I mess up the connection?

      #include "mainwindow.h"
      #include "qtmodel.h"
      #include <QApplication>
      #include <QTableView>
      
      int main(int argc, char *argv[]) {
        QApplication app(argc, argv);
        MainWindow window;
        QTableView tableView;
        Game *gamePointer{new Game};
        QtModel model;
        model.setGame(gamePointer);
        tableView.setModel(&model);
        tableView.setSelectionBehavior(QTableView::SelectColumns);
      // problematic connection here?
        QTableView::connect(&tableView, SIGNAL(clicked(const QModelIndex &)), &model,
                            SLOT(moveStacksOnColumnClicked(const QModelIndex &)));
        tableView.setStyleSheet(
            "selection-background-color: rgba(137, 196, 244, 250)");
        window.setCentralWidget(&tableView);
        window.resize(1400, 600);
        window.setWindowTitle("MyGAME!");
        window.show();
        int ret = app.exec();
        delete gamePointer;
        return ret;
      }
      

      The model is as follows:
      It doesn't do anything fancy aside from changing the background colors of cells depending on some game enumeration, the header numbering is not that important but the important functions are data and moveStackOnColumnClicked which calls a method of the game that moves the "buttons" of my game around, it takes a single integer as parameter, which is the index of the column where the player wants to act.

      #include "qtmodel.h"
      
      #include <QBrush>
      
      QtModel::QtModel(QObject *parent) : QAbstractTableModel(parent) {}
      
      // See https://doc.qt.io/qt-6/modelview.html#2-1-a-read-only-table
      
      QVariant QtModel::headerData(int section, Qt::Orientation orientation,
                                   int role) const {
        if (role == Qt::DisplayRole && orientation == Qt::Vertical) {
          for (int i = 0; i < ButtonStack::N_BUTTONS; i++) {
            const std::string rowHeader = std::to_string(ButtonStack::N_BUTTONS - i);
            if (i == section) {
              return QString(rowHeader.c_str());
            }
          }
        }
        if (role == Qt::DisplayRole && orientation == Qt::Horizontal) {
          for (int i = 0; i < ButtonStack::N_BUTTONS; i++) {
            const std::string colHeader = std::to_string(i + 1);
            if (i == section) {
              return QString(colHeader.c_str());
            }
          }
        }
        return QVariant();
      }
      
      int QtModel::rowCount(const QModelIndex & /*parent*/) const { return 9; }
      
      int QtModel::columnCount(const QModelIndex & /*parent*/) const { return 9; }
      
      QVariant QtModel::data(const QModelIndex &index, int role) const {
        int row = index.row();
        int col = index.column();
        if (role == Qt::BackgroundRole) {
          Button dat = (*m_game)[col][ButtonStack::N_BUTTONS - row - 1];
          switch (dat) {
          case Button::EMPTY:
            return QBrush(QColorConstants::Svg::lightgray);
          case Button::RED:
            return QBrush(QColorConstants::Svg::orangered);
          case Button::BLACK:
            return QBrush(QColorConstants::Svg::black);
          case Button::WHITE:
            return QBrush(QColorConstants::Svg::ghostwhite);
          }
        }
      
        return QVariant();
      }
      
      void QtModel::setGame(Game *game) { m_game = game; }
      
      void QtModel::moveStacksOnColumnClicked(const QModelIndex &idx) {
        if (idx.isValid()) {
          m_game->moveStack(idx.column());
        }
      }
      

      Thanks for the help.

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by
      #2

      @NullFunction

      • Have you verified whether your moveStacksOnColumnClicked() slot actually gets called (and with a valid index)?
      • Your data() returns QVariant() for the data for any index. Is this an issue?
      N 1 Reply Last reply
      0
      • JonBJ JonB

        @NullFunction

        • Have you verified whether your moveStacksOnColumnClicked() slot actually gets called (and with a valid index)?
        • Your data() returns QVariant() for the data for any index. Is this an issue?
        N Offline
        N Offline
        NullFunction
        wrote on last edited by NullFunction
        #3

        @JonB

        I'm not used to Qt at all so I'm not sure how I would do 1), that is how to ensure the function is called?

        As for the second question, I don't know what it means to be honest, I populate my 9x9 grid entirely with the pieces of the game which looks like this 4c6b10fb-ab0c-4828-af7e-74f6536e7a08-image.png

        Gray = empty, the other colors signify a "button" (a piece of the game) that will be moved around (they will be stacked onto each other to create little stacks of "buttons", hence the name of the function).

        Does that answer the question?

        P.S: I'm somewhat limited in how often I can reply because of reputation apparently?

        JonBJ 1 Reply Last reply
        0
        • N NullFunction

          @JonB

          I'm not used to Qt at all so I'm not sure how I would do 1), that is how to ensure the function is called?

          As for the second question, I don't know what it means to be honest, I populate my 9x9 grid entirely with the pieces of the game which looks like this 4c6b10fb-ab0c-4828-af7e-74f6536e7a08-image.png

          Gray = empty, the other colors signify a "button" (a piece of the game) that will be moved around (they will be stacked onto each other to create little stacks of "buttons", hence the name of the function).

          Does that answer the question?

          P.S: I'm somewhat limited in how often I can reply because of reputation apparently?

          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by
          #4

          @NullFunction
          It's hard to be sure, but I think you are saying you expect moveStacksOnColumnClicked() to be called to do some stuff but you do not see the intended result?

          So first put a qDebug() statement above m_game->moveStack(idx.column()); to ensure that gets called, and then I guess show whatever that does if you are saying it does not have the intended effect.

          N 1 Reply Last reply
          0
          • JonBJ JonB

            @NullFunction
            It's hard to be sure, but I think you are saying you expect moveStacksOnColumnClicked() to be called to do some stuff but you do not see the intended result?

            So first put a qDebug() statement above m_game->moveStack(idx.column()); to ensure that gets called, and then I guess show whatever that does if you are saying it does not have the intended effect.

            N Offline
            N Offline
            NullFunction
            wrote on last edited by NullFunction
            #5

            @JonB

            I realized that in the header of QtModel, the function moveStacksOnColumnClicked was not under public slots: so it did not register and nothing happened.

            Now the function actually works but it's terribly slow to update (on a 9x9 grid this should be really fast). I suspect I should add emit dataChanged(....) in the moveStacksOnColumnClicked? I'd like to redraw the 9x9 grid anytime it's called.

            I'm not so sure about how to do that because dataChanged require specific indices, i just need to redraw the whole grid though.

            EDIT:

            This was actually sufficient:

            void QtModel::moveStacksOnColumnClicked(const QModelIndex &idx) {
              if (idx.isValid()) {
                m_game->moveStack(idx.column());
                emit dataChanged(index(0, 0),
                                 index(9, 9));
              }
            }
            
            1 Reply Last reply
            0

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved