Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. How to catch c++ model signals in qml&

How to catch c++ model signals in qml&

Scheduled Pinned Locked Moved Solved QML and Qt Quick
model view progc++ modelmodel signalsanimations
4 Posts 2 Posters 995 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.
  • T Offline
    T Offline
    T_e_d_d_y
    wrote on 9 Aug 2020, 20:52 last edited by
    #1

    I'm a newbie in qml and I'm trying to make barley-break game in qml. In this game you have a 4x4 field with 15 squares which have nums and 1 empty square. If you click on a square with num and it is positioned behind empty square it will move to an empty place. Game is build according to model-view model. I made model in c++ code and interface in qml. Now I'm trying to make animations and faced a problem with catching custom c++ model signals in delegate. I wanted my "move" function to emit custon signal with indexes of squares which are making changes in theirs positions (empry and not empty). But my delegate item doesn't see the signal. How I could fix this problem? Sorry if it is a really stupid question.
    qml interface code:

    import QtQuick 2.12
    import Game 1.0
    GridView {
        id:root
        model:GameBoardModel{
        }
    
        cellHeight: height/root.model.dimension
        cellWidth: width/root.model.dimension
    
    
        delegate: Item{
            id:_backgroundDelegate
            visible:root.model.hiddenElementValue !==display
            width:root.cellWidth
            height:root.cellHeight
            //root.model.onPlacementChanged - this doesn't work
            Tile{
    
                displayText: display
                anchors.fill: _backgroundDelegate
                anchors.margins: 5
    
    
                MouseArea{
                   anchors.fill:parent
    
                   onClicked:{
                       if (root.model.move(index)){}
                   }
                }
            }
        }
    }
    
    

    c++ model header code:

    #ifndef GAMEBOARD_H
    #define GAMEBOARD_H
    #include <vector>
    #include <QAbstractListModel>
    class GameBoard:public QAbstractListModel
    {
        Q_OBJECT
        Q_PROPERTY(int dimension READ dimension CONSTANT)
        Q_PROPERTY(int hiddenElementValue READ boardSize CONSTANT)
    
    public:
        using Position = std::pair<size_t,size_t>;
    
        static constexpr size_t defaultDimension {4};
    
        GameBoard(const size_t boardDimension = defaultDimension, QObject *parent = nullptr);
    
        struct Tile{
            size_t value{};
            Tile& operator=(const size_t newValue){
                value = newValue;
                return *this;
            }
            bool operator==(const size_t other){
                return value == other;
            }
        };
    
        Q_INVOKABLE bool move(int index);
        Q_INVOKABLE int row(int value);
        Q_INVOKABLE int col(int value);
        Q_INVOKABLE void emitDataChanged();
        int rowCount(const QModelIndex& parent = QModelIndex{})const override;
        size_t dimension() const;
    
        QVariant data(const QModelIndex& index,int role = Qt::DisplayRole)const override;
        size_t boardSize() const;
    signals:
        void placementChanged(int index1, int index2);
    
    
    
    private:
        Position getRowCol(size_t index)const;
        bool isPositionValid(const size_t position)const;
        bool isBoardValid();
        void shuffle();
        std::vector<Tile> m_rawBoard;
        size_t m_dimension;
        size_t m_boardSize;
    };
    
    #endif // GAMEBOARD_H
    
    

    c++ model source code:

    #include "gameboard.h"
    #include <algorithm>
    #include <random>
    #include <QDebug>
    #include <windows.h>
    namespace{
    bool isAdjacent(const GameBoard::Position f,const GameBoard::Position s){
        if (f == s){
            return false;
        }
        const auto calcDistance = [](const size_t pos1, size_t pos2){
            int distance = pos1;
            distance-=pos2;
            return std::abs(distance);
        };
        if ((f.first == s.first && calcDistance(f.second,s.second) == 1)
                || (f.second == s.second && calcDistance(f.first,s.first) == 1)){
                return true;
            }
        return false;
    }
    }
    
    
    GameBoard::GameBoard(const size_t boardDimension , QObject *parent):
        QAbstractListModel{parent},
        m_dimension{boardDimension},
        m_boardSize{boardDimension*boardDimension}
    {
        m_rawBoard.resize(m_boardSize);
        std::iota(std::begin(m_rawBoard),std::end(m_rawBoard),1);
        shuffle();
    }
    
    bool GameBoard::move(int index)
    {
        qDebug()<<index;
        if (!isPositionValid(index)){
            return false;
        }
        Position ElementPosition = {getRowCol(index)};
    
        auto hiddenElementIterator = std::find(m_rawBoard.begin(),m_rawBoard.end(),m_boardSize);
        Q_ASSERT(hiddenElementIterator != m_rawBoard.end());
        Position hiddenElementPosition { getRowCol(std::distance(m_rawBoard.begin(),hiddenElementIterator))};
        if (!isAdjacent(ElementPosition,hiddenElementPosition)){
            return false;
        }
        std::iter_swap(hiddenElementIterator,m_rawBoard.begin()+index);
        emit placementChanged(hiddenElementIterator-m_rawBoard.begin(),index);
        //emit dataChanged(createIndex(0,0),createIndex(m_boardSize,0));s
        return true;
    
    }
    
    int GameBoard::row(int value)
    {
        int index = 0;
        for (size_t i = 0; i < m_boardSize;i++){
            if(m_rawBoard[i] == value){
                index =i;
            }
        }
        return getRowCol(index).first;
    }
    
    int GameBoard::col(int value)
    {
        int index = 0;
        for (size_t i = 0; i < m_boardSize;i++){
            if(m_rawBoard[i] == value){
                index =i;
            }
        }
        return getRowCol(index).second;
    }
    
    void GameBoard::emitDataChanged()
    {
        emit dataChanged(createIndex(0,0),createIndex(m_boardSize,0));
    }
    
    int GameBoard::rowCount(const QModelIndex &parent) const
    {
        Q_UNUSED(parent);
        return m_rawBoard.size();
    }
    
    QVariant GameBoard::data(const QModelIndex &index, int role) const
    {
        if (!index.isValid() || role != Qt::DisplayRole){
            return {};
        }
        const int rowIndex{index.row()};
        if (!isPositionValid(rowIndex)){
            return {};
        }
        return QVariant::fromValue(m_rawBoard[rowIndex].value);
    }
    
    bool GameBoard::isPositionValid(const size_t position) const
    {
    
        return position < m_boardSize;
    }
    
    bool GameBoard::isBoardValid()
    {
        size_t  n = 0, sum = 0, rowEmpty = 0;
        for(size_t i = 0;i<m_rawBoard.size();i++){
            if (m_rawBoard[i].value == m_rawBoard.size()){
                rowEmpty = i/m_dimension+1;
            }
            for(size_t j = i+1;j<m_rawBoard.size();j++){
                if (m_rawBoard[i].value<m_rawBoard[j].value){
                    n++;
                }
            }
            sum+=n;
            n = 0;
        }
        return (rowEmpty + sum)%2 == 0;
    }
    
    
    void GameBoard::shuffle(){
        static auto seed = std::chrono::system_clock::now().time_since_epoch().count();
        static std::mt19937 generator(seed);
        do{
            std::shuffle(m_rawBoard.begin(),m_rawBoard.end(),generator);
        }while(!isBoardValid());
    }
    
    size_t GameBoard::boardSize() const
    {
        return m_boardSize;
    }
    
    GameBoard::Position GameBoard::getRowCol(size_t index) const
    {
        size_t row = index / m_dimension;
        size_t column = index % m_dimension;
        return std::make_pair(row,column);
    }
    
    size_t GameBoard::dimension() const
    {
        return m_dimension;
    }
    
    

    Some functions (like row() and col()) were added just for experiments.

    ODБOïO 1 Reply Last reply 9 Aug 2020, 21:02
    0
    • T T_e_d_d_y
      9 Aug 2020, 20:52

      I'm a newbie in qml and I'm trying to make barley-break game in qml. In this game you have a 4x4 field with 15 squares which have nums and 1 empty square. If you click on a square with num and it is positioned behind empty square it will move to an empty place. Game is build according to model-view model. I made model in c++ code and interface in qml. Now I'm trying to make animations and faced a problem with catching custom c++ model signals in delegate. I wanted my "move" function to emit custon signal with indexes of squares which are making changes in theirs positions (empry and not empty). But my delegate item doesn't see the signal. How I could fix this problem? Sorry if it is a really stupid question.
      qml interface code:

      import QtQuick 2.12
      import Game 1.0
      GridView {
          id:root
          model:GameBoardModel{
          }
      
          cellHeight: height/root.model.dimension
          cellWidth: width/root.model.dimension
      
      
          delegate: Item{
              id:_backgroundDelegate
              visible:root.model.hiddenElementValue !==display
              width:root.cellWidth
              height:root.cellHeight
              //root.model.onPlacementChanged - this doesn't work
              Tile{
      
                  displayText: display
                  anchors.fill: _backgroundDelegate
                  anchors.margins: 5
      
      
                  MouseArea{
                     anchors.fill:parent
      
                     onClicked:{
                         if (root.model.move(index)){}
                     }
                  }
              }
          }
      }
      
      

      c++ model header code:

      #ifndef GAMEBOARD_H
      #define GAMEBOARD_H
      #include <vector>
      #include <QAbstractListModel>
      class GameBoard:public QAbstractListModel
      {
          Q_OBJECT
          Q_PROPERTY(int dimension READ dimension CONSTANT)
          Q_PROPERTY(int hiddenElementValue READ boardSize CONSTANT)
      
      public:
          using Position = std::pair<size_t,size_t>;
      
          static constexpr size_t defaultDimension {4};
      
          GameBoard(const size_t boardDimension = defaultDimension, QObject *parent = nullptr);
      
          struct Tile{
              size_t value{};
              Tile& operator=(const size_t newValue){
                  value = newValue;
                  return *this;
              }
              bool operator==(const size_t other){
                  return value == other;
              }
          };
      
          Q_INVOKABLE bool move(int index);
          Q_INVOKABLE int row(int value);
          Q_INVOKABLE int col(int value);
          Q_INVOKABLE void emitDataChanged();
          int rowCount(const QModelIndex& parent = QModelIndex{})const override;
          size_t dimension() const;
      
          QVariant data(const QModelIndex& index,int role = Qt::DisplayRole)const override;
          size_t boardSize() const;
      signals:
          void placementChanged(int index1, int index2);
      
      
      
      private:
          Position getRowCol(size_t index)const;
          bool isPositionValid(const size_t position)const;
          bool isBoardValid();
          void shuffle();
          std::vector<Tile> m_rawBoard;
          size_t m_dimension;
          size_t m_boardSize;
      };
      
      #endif // GAMEBOARD_H
      
      

      c++ model source code:

      #include "gameboard.h"
      #include <algorithm>
      #include <random>
      #include <QDebug>
      #include <windows.h>
      namespace{
      bool isAdjacent(const GameBoard::Position f,const GameBoard::Position s){
          if (f == s){
              return false;
          }
          const auto calcDistance = [](const size_t pos1, size_t pos2){
              int distance = pos1;
              distance-=pos2;
              return std::abs(distance);
          };
          if ((f.first == s.first && calcDistance(f.second,s.second) == 1)
                  || (f.second == s.second && calcDistance(f.first,s.first) == 1)){
                  return true;
              }
          return false;
      }
      }
      
      
      GameBoard::GameBoard(const size_t boardDimension , QObject *parent):
          QAbstractListModel{parent},
          m_dimension{boardDimension},
          m_boardSize{boardDimension*boardDimension}
      {
          m_rawBoard.resize(m_boardSize);
          std::iota(std::begin(m_rawBoard),std::end(m_rawBoard),1);
          shuffle();
      }
      
      bool GameBoard::move(int index)
      {
          qDebug()<<index;
          if (!isPositionValid(index)){
              return false;
          }
          Position ElementPosition = {getRowCol(index)};
      
          auto hiddenElementIterator = std::find(m_rawBoard.begin(),m_rawBoard.end(),m_boardSize);
          Q_ASSERT(hiddenElementIterator != m_rawBoard.end());
          Position hiddenElementPosition { getRowCol(std::distance(m_rawBoard.begin(),hiddenElementIterator))};
          if (!isAdjacent(ElementPosition,hiddenElementPosition)){
              return false;
          }
          std::iter_swap(hiddenElementIterator,m_rawBoard.begin()+index);
          emit placementChanged(hiddenElementIterator-m_rawBoard.begin(),index);
          //emit dataChanged(createIndex(0,0),createIndex(m_boardSize,0));s
          return true;
      
      }
      
      int GameBoard::row(int value)
      {
          int index = 0;
          for (size_t i = 0; i < m_boardSize;i++){
              if(m_rawBoard[i] == value){
                  index =i;
              }
          }
          return getRowCol(index).first;
      }
      
      int GameBoard::col(int value)
      {
          int index = 0;
          for (size_t i = 0; i < m_boardSize;i++){
              if(m_rawBoard[i] == value){
                  index =i;
              }
          }
          return getRowCol(index).second;
      }
      
      void GameBoard::emitDataChanged()
      {
          emit dataChanged(createIndex(0,0),createIndex(m_boardSize,0));
      }
      
      int GameBoard::rowCount(const QModelIndex &parent) const
      {
          Q_UNUSED(parent);
          return m_rawBoard.size();
      }
      
      QVariant GameBoard::data(const QModelIndex &index, int role) const
      {
          if (!index.isValid() || role != Qt::DisplayRole){
              return {};
          }
          const int rowIndex{index.row()};
          if (!isPositionValid(rowIndex)){
              return {};
          }
          return QVariant::fromValue(m_rawBoard[rowIndex].value);
      }
      
      bool GameBoard::isPositionValid(const size_t position) const
      {
      
          return position < m_boardSize;
      }
      
      bool GameBoard::isBoardValid()
      {
          size_t  n = 0, sum = 0, rowEmpty = 0;
          for(size_t i = 0;i<m_rawBoard.size();i++){
              if (m_rawBoard[i].value == m_rawBoard.size()){
                  rowEmpty = i/m_dimension+1;
              }
              for(size_t j = i+1;j<m_rawBoard.size();j++){
                  if (m_rawBoard[i].value<m_rawBoard[j].value){
                      n++;
                  }
              }
              sum+=n;
              n = 0;
          }
          return (rowEmpty + sum)%2 == 0;
      }
      
      
      void GameBoard::shuffle(){
          static auto seed = std::chrono::system_clock::now().time_since_epoch().count();
          static std::mt19937 generator(seed);
          do{
              std::shuffle(m_rawBoard.begin(),m_rawBoard.end(),generator);
          }while(!isBoardValid());
      }
      
      size_t GameBoard::boardSize() const
      {
          return m_boardSize;
      }
      
      GameBoard::Position GameBoard::getRowCol(size_t index) const
      {
          size_t row = index / m_dimension;
          size_t column = index % m_dimension;
          return std::make_pair(row,column);
      }
      
      size_t GameBoard::dimension() const
      {
          return m_dimension;
      }
      
      

      Some functions (like row() and col()) were added just for experiments.

      ODБOïO Offline
      ODБOïO Offline
      ODБOï
      wrote on 9 Aug 2020, 21:02 last edited by
      #2

      hi,
      @T_e_d_d_y said in How to catch c++ model signals in qml&:

      model:GameBoardModel{
      }

      you can try this :

       model:GameBoardModel{
       id:myGameModel
           }
      
      Connections{
        target : myGameModel
       function onPlacementChanged() { console.log(index1  +" " + index2)}
      }
      
      T 1 Reply Last reply 9 Aug 2020, 21:59
      0
      • ODБOïO ODБOï
        9 Aug 2020, 21:02

        hi,
        @T_e_d_d_y said in How to catch c++ model signals in qml&:

        model:GameBoardModel{
        }

        you can try this :

         model:GameBoardModel{
         id:myGameModel
             }
        
        Connections{
          target : myGameModel
         function onPlacementChanged() { console.log(index1  +" " + index2)}
        }
        
        T Offline
        T Offline
        T_e_d_d_y
        wrote on 9 Aug 2020, 21:59 last edited by
        #3

        @LeLev Thanks! It really works! I can't believe that it was so easy

        ODБOïO 1 Reply Last reply 9 Aug 2020, 22:19
        0
        • T T_e_d_d_y
          9 Aug 2020, 21:59

          @LeLev Thanks! It really works! I can't believe that it was so easy

          ODБOïO Offline
          ODБOïO Offline
          ODБOï
          wrote on 9 Aug 2020, 22:19 last edited by ODБOï 8 Sept 2020, 22:24
          #4

          @T_e_d_d_y nice,

          Actually you don't even need the Connections object

           model:GameBoardModel{
           onPlacementChanged : {}
               }
          
          1 Reply Last reply
          1

          1/4

          9 Aug 2020, 20:52

          • Login

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