Sophie

Sophie

distrib > Mageia > 7 > i586 > media > core-updates > by-pkgid > 6e2327ca1c896c6d674ae53117299f21 > files > 1723

qtdeclarative5-doc-5.12.6-1.mga7.noarch.rpm

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- gameoflife.qdoc -->
  <title>Qt Quick TableView examples - Conway’s Game of Life | Qt Quick 5.12.6</title>
  <link rel="stylesheet" type="text/css" href="style/offline-simple.css" />
  <script type="text/javascript">
    document.getElementsByTagName("link").item(0).setAttribute("href", "style/offline.css");
    // loading style sheet breaks anchors that were jumped to before
    // so force jumping to anchor again
    setTimeout(function() {
        var anchor = location.hash;
        // need to jump to different anchor first (e.g. none)
        location.hash = "#";
        setTimeout(function() {
            location.hash = anchor;
        }, 0);
    }, 0);
  </script>
</head>
<body>
<div class="header" id="qtdocheader">
  <div class="main">
    <div class="main-rounded">
      <div class="navigationbar">
        <table><tr>
<td >Qt 5.12</td><td ><a href="qtquick-index.html">Qt Quick</a></td><td >Qt Quick TableView examples - Conway’s Game of Life</td></tr></table><table class="buildversion"><tr>
<td id="buildversion" width="100%" align="right"><a href="qtquick-index.html">Qt 5.12.6 Reference Documentation</a></td>
        </tr></table>
      </div>
    </div>
<div class="content">
<div class="line">
<div class="content mainContent">
<div class="sidebar">
<div class="toc">
<h3><a name="toc">Contents</a></h3>
<ul>
<li class="level1"><a href="#running-the-example">Running the Example</a></li>
<li class="level1"><a href="#the-qml-user-interface">The QML User Interface</a></li>
<li class="level1"><a href="#the-c-model">The C++ Model</a></li>
<li class="level1"><a href="#updating-the-data">Updating the Data</a></li>
</ul>
</div>
<div class="sidebar-content" id="sidebar-content"></div></div>
<h1 class="title">Qt Quick TableView examples - Conway’s Game of Life</h1>
<span class="subtitle"></span>
<!-- $$$tableview/gameoflife-brief -->
<p>The <i>Conway’s Game of Life</i> example shows how the QML <a href="qml-qtquick-tableview.html">TableView</a> type can be used to display a C++ model that the user can pan around.</p>
<!-- @@@tableview/gameoflife -->
<!-- $$$tableview/gameoflife-description -->
<div class="descr"> <a name="details"></a>
<p class="centerAlign"><img src="images/gameoflife.png" alt="" /></p><a name="running-the-example"></a>
<h2 id="running-the-example">Running the Example</h2>
<p>To run the example from Qt Creator, open the <b>Welcome</b> mode and select the example from <b>Examples</b>. For more information, visit Building and Running an Example.</p>
<a name="the-qml-user-interface"></a>
<h2 id="the-qml-user-interface">The QML User Interface</h2>
<pre class="qml">

  TableView {
      id: tableView
      anchors.fill: parent

      rowSpacing: 1
      columnSpacing: 1

      ScrollBar.horizontal: ScrollBar {}
      ScrollBar.vertical: ScrollBar {}

      delegate: Rectangle {
          id: cell
          implicitWidth: 15
          implicitHeight: 15

          color: model.value ? "#f3f3f4" : "#b5b7bf"

          MouseArea {
              anchors.fill: parent
              onClicked: model.value = !model.value
          }
      }

</pre>
<p>The example uses the <a href="qml-qtquick-tableview.html">TableView</a> component to display a grid of cells. Each of these cells is drawn on the screen by the <a href="qml-qtquick-tableview.html">TableView</a>’s delegate, which is a Rectangle QML component. We read the cell’s value and we change it using <code>model.value</code> when the user clicks it.</p>
<pre class="qml">

  contentX: (contentWidth - width) / 2;
  contentY: (contentHeight - height) / 2;

</pre>
<p>When the application starts, the <a href="qml-qtquick-tableview.html">TableView</a> is scrolled to its center by using its <code>contentX</code> and <code>contentY</code> properties to update the scroll position, and the <code>contentWidth</code> and <code>contentHeight</code> to compute where the view should be scrolled to.</p>
<pre class="qml">

  model: GameOfLifeModel {
      id: gameOfLifeModel
  }

</pre>
<p>The model that we use is a custom C++ class that we register in the QML system:</p>
<pre class="cpp">

  qmlRegisterType<span class="operator">&lt;</span>GameOfLifeModel<span class="operator">&gt;</span>(<span class="string">&quot;GameOfLifeModel&quot;</span><span class="operator">,</span> <span class="number">1</span><span class="operator">,</span> <span class="number">0</span><span class="operator">,</span> <span class="string">&quot;GameOfLifeModel&quot;</span>);

</pre>
<a name="the-c-model"></a>
<h2 id="the-c-model">The C++ Model</h2>
<pre class="cpp">

  <span class="keyword">class</span> GameOfLifeModel : <span class="keyword">public</span> <span class="type">QAbstractTableModel</span>
  {
      Q_OBJECT

      Q_ENUMS(Roles)
  <span class="keyword">public</span>:
      <span class="keyword">enum</span> Roles {
          CellRole
      };

      <span class="type">QHash</span><span class="operator">&lt;</span><span class="type">int</span><span class="operator">,</span> <span class="type">QByteArray</span><span class="operator">&gt;</span> roleNames() <span class="keyword">const</span> override {
          <span class="keyword">return</span> {
              { CellRole<span class="operator">,</span> <span class="string">&quot;value&quot;</span> }
          };
      }

      <span class="keyword">explicit</span> GameOfLifeModel(<span class="type">QObject</span> <span class="operator">*</span>parent <span class="operator">=</span> nullptr);

      <span class="type">int</span> rowCount(<span class="keyword">const</span> <span class="type">QModelIndex</span> <span class="operator">&amp;</span>parent <span class="operator">=</span> <span class="type">QModelIndex</span>()) <span class="keyword">const</span> override;
      <span class="type">int</span> columnCount(<span class="keyword">const</span> <span class="type">QModelIndex</span> <span class="operator">&amp;</span>parent <span class="operator">=</span> <span class="type">QModelIndex</span>()) <span class="keyword">const</span> override;

      <span class="type">QVariant</span> data(<span class="keyword">const</span> <span class="type">QModelIndex</span> <span class="operator">&amp;</span>index<span class="operator">,</span> <span class="type">int</span> role <span class="operator">=</span> <span class="type">Qt</span><span class="operator">::</span>DisplayRole) <span class="keyword">const</span> override;
      bool setData(<span class="keyword">const</span> <span class="type">QModelIndex</span> <span class="operator">&amp;</span>index<span class="operator">,</span> <span class="keyword">const</span> <span class="type">QVariant</span> <span class="operator">&amp;</span>value<span class="operator">,</span>
                   <span class="type">int</span> role <span class="operator">=</span> <span class="type">Qt</span><span class="operator">::</span>EditRole) override;

      <span class="type">Qt</span><span class="operator">::</span>ItemFlags flags(<span class="keyword">const</span> <span class="type">QModelIndex</span> <span class="operator">&amp;</span>index) <span class="keyword">const</span> override;

      Q_INVOKABLE <span class="type">void</span> nextStep();
      Q_INVOKABLE bool loadFile(<span class="keyword">const</span> <span class="type">QString</span> <span class="operator">&amp;</span>fileName);
      Q_INVOKABLE <span class="type">void</span> loadPattern(<span class="keyword">const</span> <span class="type">QString</span> <span class="operator">&amp;</span>plainText);
      Q_INVOKABLE <span class="type">void</span> clear();

  <span class="keyword">private</span>:
      <span class="keyword">static</span> constexpr <span class="type">int</span> width <span class="operator">=</span> <span class="number">256</span>;
      <span class="keyword">static</span> constexpr <span class="type">int</span> height <span class="operator">=</span> <span class="number">256</span>;
      <span class="keyword">static</span> constexpr <span class="type">int</span> size <span class="operator">=</span> width <span class="operator">*</span> height;

      <span class="keyword">using</span> StateContainer <span class="operator">=</span> std<span class="operator">::</span>array<span class="operator">&lt;</span>bool<span class="operator">,</span> size<span class="operator">&gt;</span>;
      StateContainer m_currentState;

      <span class="type">int</span> cellNeighborsCount(<span class="keyword">const</span> <span class="type">QPoint</span> <span class="operator">&amp;</span>cellCoordinates) <span class="keyword">const</span>;
      <span class="keyword">static</span> bool areCellCoordinatesValid(<span class="keyword">const</span> <span class="type">QPoint</span> <span class="operator">&amp;</span>coordinates);
      <span class="keyword">static</span> <span class="type">QPoint</span> cellCoordinatesFromIndex(<span class="type">int</span> cellIndex);
      <span class="keyword">static</span> std<span class="operator">::</span>size_t cellIndex(<span class="keyword">const</span> <span class="type">QPoint</span> <span class="operator">&amp;</span>coordinates);
  };

</pre>
<p>The <code>GameOfLifeModel</code> class extends QAbstractTableModel so it can be used as the model of our <a href="qml-qtquick-tableview.html">TableView</a> component. Therefore, it needs to implement some functions so the <a href="qml-qtquick-tableview.html">TableView</a> component can interact with the model. As you can see in the <code>private</code> part of the class, the model uses a fixed-size array to store the current state of all the cells.</p>
<pre class="cpp">

  <span class="type">int</span> GameOfLifeModel<span class="operator">::</span>rowCount(<span class="keyword">const</span> <span class="type">QModelIndex</span> <span class="operator">&amp;</span>parent) <span class="keyword">const</span>
  {
      <span class="keyword">if</span> (parent<span class="operator">.</span>isValid())
          <span class="keyword">return</span> <span class="number">0</span>;

      <span class="keyword">return</span> height;
  }

  <span class="type">int</span> GameOfLifeModel<span class="operator">::</span>columnCount(<span class="keyword">const</span> <span class="type">QModelIndex</span> <span class="operator">&amp;</span>parent) <span class="keyword">const</span>
  {
      <span class="keyword">if</span> (parent<span class="operator">.</span>isValid())
          <span class="keyword">return</span> <span class="number">0</span>;

      <span class="keyword">return</span> width;
  }

</pre>
<p>Here, the <code>rowCount</code> and <code>columnCount</code> methods are implemented so the <a href="qml-qtquick-tableview.html">TableView</a> component can know the size of the table. It simply returns the values of the <code>width</code> and <code>height</code> constants.</p>
<pre class="cpp">

  <span class="type">QVariant</span> GameOfLifeModel<span class="operator">::</span>data(<span class="keyword">const</span> <span class="type">QModelIndex</span> <span class="operator">&amp;</span>index<span class="operator">,</span> <span class="type">int</span> role) <span class="keyword">const</span>
  {
      <span class="keyword">if</span> (<span class="operator">!</span>index<span class="operator">.</span>isValid() <span class="operator">|</span><span class="operator">|</span> role <span class="operator">!</span><span class="operator">=</span> CellRole)
          <span class="keyword">return</span> <span class="type">QVariant</span>();

      <span class="keyword">return</span> <span class="type">QVariant</span>(m_currentState<span class="operator">[</span>cellIndex({index<span class="operator">.</span>column()<span class="operator">,</span> index<span class="operator">.</span>row()})<span class="operator">]</span>);
  }

</pre>
<p>This method is called when the <a href="qml-qtquick-tableview.html">TableView</a> component requests some data from the model. In our example, we only have one piece of data by cell: whether it is alive or not. This information is represented by the <code>CellRole</code> value of the <code>Roles</code> enum in our C++ code; this corresponds to the <code>value</code> property in the QML code (the link between these two is made by the <code>roleNames()</code> function of our C++ class).</p>
<p>The <code>GameOfLifeModel</code> class can identify which cell was the data requested from with the <code>index</code> parameter, which is a QModelIndex that contains a row and a column.</p>
<a name="updating-the-data"></a>
<h2 id="updating-the-data">Updating the Data</h2>
<pre class="cpp">

  bool GameOfLifeModel<span class="operator">::</span>setData(<span class="keyword">const</span> <span class="type">QModelIndex</span> <span class="operator">&amp;</span>index<span class="operator">,</span> <span class="keyword">const</span> <span class="type">QVariant</span> <span class="operator">&amp;</span>value<span class="operator">,</span> <span class="type">int</span> role)
  {
      <span class="keyword">if</span> (role <span class="operator">!</span><span class="operator">=</span> CellRole <span class="operator">|</span><span class="operator">|</span> data(index<span class="operator">,</span> role) <span class="operator">=</span><span class="operator">=</span> value)
          <span class="keyword">return</span> <span class="keyword">false</span>;

      m_currentState<span class="operator">[</span>cellIndex({index<span class="operator">.</span>column()<span class="operator">,</span> index<span class="operator">.</span>row()})<span class="operator">]</span> <span class="operator">=</span> value<span class="operator">.</span>toBool();
      <span class="keyword">emit</span> dataChanged(index<span class="operator">,</span> index<span class="operator">,</span> {role});

      <span class="keyword">return</span> <span class="keyword">true</span>;
  }

</pre>
<p>The <code>setData</code> method is called when a property’s value is set from the QML interface: in our example, it toggles a cell’s state when it is clicked. In the same way as the <code>data()</code> function does, this method receives an <code>index</code> and a <code>role</code> parameter. Additionally, the new value is passed as a QVariant, that we convert to a boolean using the <code>toBool</code> function.</p>
<p>When we update the internal state of our model object, we need to emit a <code>dataChanged</code> signal to tell the <a href="qml-qtquick-tableview.html">TableView</a> component that it needs to update the displayed data. In this case, only the cell that was clicked is affected, thus the range of the table that has to be updated begins and ends at the cell’s index.</p>
<pre class="cpp">

  <span class="type">void</span> GameOfLifeModel<span class="operator">::</span>nextStep()
  {
      StateContainer newValues;

      <span class="keyword">for</span> (std<span class="operator">::</span>size_t i <span class="operator">=</span> <span class="number">0</span>; i <span class="operator">&lt;</span> size; <span class="operator">+</span><span class="operator">+</span>i) {
          bool currentState <span class="operator">=</span> m_currentState<span class="operator">[</span>i<span class="operator">]</span>;

          <span class="type">int</span> cellNeighborsCount <span class="operator">=</span> <span class="keyword">this</span><span class="operator">-</span><span class="operator">&gt;</span>cellNeighborsCount(cellCoordinatesFromIndex(<span class="keyword">static_cast</span><span class="operator">&lt;</span><span class="type">int</span><span class="operator">&gt;</span>(i)));

          newValues<span class="operator">[</span>i<span class="operator">]</span> <span class="operator">=</span> currentState <span class="operator">=</span><span class="operator">=</span> <span class="keyword">true</span>
                  <span class="operator">?</span> cellNeighborsCount <span class="operator">=</span><span class="operator">=</span> <span class="number">2</span> <span class="operator">|</span><span class="operator">|</span> cellNeighborsCount <span class="operator">=</span><span class="operator">=</span> <span class="number">3</span>
                  : cellNeighborsCount <span class="operator">=</span><span class="operator">=</span> <span class="number">3</span>;
      }

      m_currentState <span class="operator">=</span> std<span class="operator">::</span>move(newValues);

      <span class="keyword">emit</span> dataChanged(index(<span class="number">0</span><span class="operator">,</span> <span class="number">0</span>)<span class="operator">,</span> index(height <span class="operator">-</span> <span class="number">1</span><span class="operator">,</span> width <span class="operator">-</span> <span class="number">1</span>)<span class="operator">,</span> {CellRole});
  }

</pre>
<p>This function can be called directly from the QML code, because it contains the Q_INVOKABLE macro in its definition. It plays an iteration of the game, either when the user clicks the <i>Next</i> button or when the Timer emits a <code>triggered()</code> signal.</p>
<p>Following the <i>Conway’s Game of Life</i> rules, a new state is computed for each cell depending on the current state of its neighbors. When the new state has been computed for the whole grid, it replaces the current state and a <i>dataChanged</i> signal is emitted for the whole table.</p>
<pre class="cpp">

  bool GameOfLifeModel<span class="operator">::</span>loadFile(<span class="keyword">const</span> <span class="type">QString</span> <span class="operator">&amp;</span>fileName)
  {
      <span class="type">QFile</span> file(fileName);
      <span class="keyword">if</span> (<span class="operator">!</span>file<span class="operator">.</span>open(<span class="type">QIODevice</span><span class="operator">::</span>ReadOnly))
          <span class="keyword">return</span> <span class="keyword">false</span>;

      <span class="type">QTextStream</span> in(<span class="operator">&amp;</span>file);
      loadPattern(in<span class="operator">.</span>readAll());

      <span class="keyword">return</span> <span class="keyword">true</span>;
  }

  <span class="type">void</span> GameOfLifeModel<span class="operator">::</span>loadPattern(<span class="keyword">const</span> <span class="type">QString</span> <span class="operator">&amp;</span>plainText)
  {
      clear();

      <span class="type">QStringList</span> rows <span class="operator">=</span> plainText<span class="operator">.</span>split(<span class="string">&quot;\n&quot;</span>);
      <span class="type">QSize</span> patternSize(<span class="number">0</span><span class="operator">,</span> rows<span class="operator">.</span>count());
      <span class="keyword">for</span> (<span class="type">QString</span> row : rows) {
          <span class="keyword">if</span> (row<span class="operator">.</span>size() <span class="operator">&gt;</span> patternSize<span class="operator">.</span>width())
              patternSize<span class="operator">.</span>setWidth(row<span class="operator">.</span>size());
      }

      <span class="type">QPoint</span> patternLocation((width <span class="operator">-</span> patternSize<span class="operator">.</span>width()) <span class="operator">/</span> <span class="number">2</span><span class="operator">,</span> (height <span class="operator">-</span> patternSize<span class="operator">.</span>height()) <span class="operator">/</span> <span class="number">2</span>);

      <span class="keyword">for</span> (<span class="type">int</span> y <span class="operator">=</span> <span class="number">0</span>; y <span class="operator">&lt;</span> patternSize<span class="operator">.</span>height(); <span class="operator">+</span><span class="operator">+</span>y) {
          <span class="keyword">const</span> <span class="type">QString</span> line <span class="operator">=</span> rows<span class="operator">[</span>y<span class="operator">]</span>;

          <span class="keyword">for</span> (<span class="type">int</span> x <span class="operator">=</span> <span class="number">0</span>; x <span class="operator">&lt;</span> line<span class="operator">.</span>length(); <span class="operator">+</span><span class="operator">+</span>x) {
              <span class="type">QPoint</span> cellPosition(x <span class="operator">+</span> patternLocation<span class="operator">.</span>x()<span class="operator">,</span> y <span class="operator">+</span> patternLocation<span class="operator">.</span>y());
              m_currentState<span class="operator">[</span>cellIndex(cellPosition)<span class="operator">]</span> <span class="operator">=</span> line<span class="operator">[</span>x<span class="operator">]</span> <span class="operator">=</span><span class="operator">=</span> <span class="char">'O'</span>;
          }
      }

      <span class="keyword">emit</span> dataChanged(index(<span class="number">0</span><span class="operator">,</span> <span class="number">0</span>)<span class="operator">,</span> index(height <span class="operator">-</span> <span class="number">1</span><span class="operator">,</span> width <span class="operator">-</span> <span class="number">1</span>)<span class="operator">,</span> {CellRole});
  }

</pre>
<p>When the application opens, a pattern is loaded to demonstrate how <i>Conway’s Game of Life</i> works. These two functions load the file where the pattern is stored and parse it. As in the <code>nextStep</code> function, a <code>dataChanged</code> signal is emitted for the whole table once the pattern has been fully loaded.</p>
<p>Files:</p>
<ul>
<li><a href="qtquick-tableview-gameoflife-gameoflife-pro.html">tableview/gameoflife/gameoflife.pro</a></li>
<li><a href="qtquick-tableview-gameoflife-gameoflifemodel-cpp.html">tableview/gameoflife/gameoflifemodel.cpp</a></li>
<li><a href="qtquick-tableview-gameoflife-gameoflifemodel-h.html">tableview/gameoflife/gameoflifemodel.h</a></li>
<li><a href="qtquick-tableview-gameoflife-main-cpp.html">tableview/gameoflife/main.cpp</a></li>
<li><a href="qtquick-tableview-gameoflife-main-qml.html">tableview/gameoflife/main.qml</a></li>
</ul>
</div>
<!-- @@@tableview/gameoflife -->
        </div>
       </div>
   </div>
   </div>
</div>
<div class="footer">
   <p>
   <acronym title="Copyright">&copy;</acronym> 2019 The Qt Company Ltd.
   Documentation contributions included herein are the copyrights of
   their respective owners.<br/>    The documentation provided herein is licensed under the terms of the    <a href="http://www.gnu.org/licenses/fdl.html">GNU Free Documentation    License version 1.3</a> as published by the Free Software Foundation.<br/>    Qt and respective logos are trademarks of The Qt Company Ltd.     in Finland and/or other countries worldwide. All other trademarks are property
   of their respective owners. </p>
</div>
</body>
</html>