Sophie

Sophie

distrib > Mageia > 7 > armv7hl > media > core-updates > by-pkgid > bdbbdfc3f538bf93bb0eb988a7a43005 > files > 489

qtdoc5-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" />
<!-- photoviewer.qdoc -->
  <title>Qt Quick Demo - Photo Viewer | Qt 5.12</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 ><a href="index.html">Qt 5.12</a></td><td >Qt Quick Demo - Photo Viewer</td></tr></table><table class="buildversion"><tr>
<td id="buildversion" width="100%" align="right">Qt 5.12.6 Reference Documentation</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="#using-custom-types">Using Custom Types</a></li>
<li class="level1"><a href="#creating-the-main-window">Creating the Main Window</a></li>
<li class="level1"><a href="#displaying-photos">Displaying Photos</a></li>
<li class="level1"><a href="#downloading-flickr-feeds">Downloading Flickr Feeds</a></li>
<li class="level1"><a href="#creating-flipable-labels">Creating Flipable Labels</a></li>
<li class="level1"><a href="#laying-out-photos-on-a-path">Laying Out Photos on a Path</a></li>
<li class="level1"><a href="#providing-feedback-to-users">Providing Feedback to Users</a></li>
<li class="level1"><a href="#localizing-applications">Localizing Applications</a></li>
</ul>
</div>
<div class="sidebar-content" id="sidebar-content"></div></div>
<h1 class="title">Qt Quick Demo - Photo Viewer</h1>
<span class="subtitle"></span>
<!-- $$$demos/photoviewer-brief -->
<p>A QML photo viewer that that uses XmlListModel and XmlRole to download Flickr feeds, and Package to display the photos in different views.</p>
<!-- @@@demos/photoviewer -->
<!-- $$$demos/photoviewer-description -->
<div class="descr"> <a name="details"></a>
<p class="centerAlign"><img src="images/qtquick-demo-photoviewer-small.png" alt="" /></p><p><i>Photo Viewer</i> demonstrates the following Qt Quick features:</p>
<ul>
<li>Using custom types to create screens and screen controls.</li>
<li>Using Qt Quick Controls 1 to create an application window.</li>
<li>Using the Package type with a DelegateModel to provide delegates with a shared context to multiple views.</li>
<li>Using XML list models to download Flickr feeds.</li>
<li>Using the Flipable type to create labels with different text on the front and back.</li>
<li>Using the PathView, Path, PathAttribute, and PathLine types to lay out photos on a path.</li>
<li>Providing feedback to users while data is loading.</li>
<li>Localizing applications.</li>
</ul>
<a name="running-the-example"></a>
<h2 id="running-the-example">Running the Example</h2>
<p>To run the example from <a href="http://doc.qt.io/qtcreator/index.html">Qt Creator</a>, open the <b>Welcome</b> mode and select the example from <b>Examples</b>. For more information, visit <a href="http://doc.qt.io/qtcreator/creator-build-example-application.html">Building and Running an Example</a>.</p>
<a name="using-custom-types"></a>
<h2 id="using-custom-types">Using Custom Types</h2>
<p>In the Photo Viewer app, we use the following custom types that are each defined in a separate .qml file:</p>
<ul>
<li><code>AlbumDelegate.qml</code></li>
<li><code>BusyIndicator.qml</code></li>
<li><code>Button.qml</code></li>
<li><code>EditableButton.qml</code></li>
<li><code>PhotoDelegate.qml</code></li>
<li><code>ProgressBar.qml</code></li>
<li><code>RssModel.qml</code></li>
<li><code>Tag.qml</code></li>
</ul>
<p>To use the custom types, we add an import statement to the main QML file, main.qml, that imports the folder called <code>PhotoViewerCore</code> where the types are located:</p>
<pre class="cpp">

  import "PhotoViewerCore"

</pre>
<a name="creating-the-main-window"></a>
<h2 id="creating-the-main-window">Creating the Main Window</h2>
<p>In main.qml, we use the ApplicationWindow Qt Quick Control to create the app main window:</p>
<pre class="cpp">

  ApplicationWindow {
      id: mainWindow

      visible: true

</pre>
<p>We use a ListModel type with ListElement types to display photo albums:</p>
<pre class="cpp">

      ListModel {
          id: photosModel
          ListElement { tag: "Flowers" }
          ListElement { tag: "Wildlife" }
          ListElement { tag: "Prague" }
      }

</pre>
<p>List elements are defined like other QML types except that they contain a collection of <i>role</i> definitions instead of properties. Roles both define how the data is accessed and include the data itself. For each list element, we use the <code>tag</code> role to specify the photos to download.</p>
<p>A DelegateModel type is used together with the Package type to provide delegates to multiple views. The <code>model</code> property holds the model providing data for the delegate model and the <code>delegate</code> property specifies the template defining each item instantiated by a view:</p>
<pre class="cpp">

      DelegateModel { id: albumVisualModel; model: photosModel; delegate: AlbumDelegate {} }

</pre>
<p>We use a GridView type to lay out the albums as a grid:</p>
<pre class="cpp">

      GridView {
          id: albumView; width: parent.width; height: parent.height; cellWidth: 210; cellHeight: 220
          model: albumVisualModel.parts.album; visible: albumsShade.opacity != 1.0
      }

</pre>
<p>The <code>model</code> property references the package name <code>album</code> that we specify in AlbumDelegate.qml. We use the Package type to allow the photos to move between different views. The Package contains the named items <code>browser</code>, <code>fullscreen</code>, and <code>album</code>:</p>
<pre class="cpp">

      Package {

          Item {
              Package.name: 'browser'
              GridView {
                  id: photosGridView; model: visualModel.parts.grid; width: mainWindow.width; height: mainWindow.height - 21
                  x: 0; y: 21; cellWidth: 160; cellHeight: 153; interactive: false
                  onCurrentIndexChanged: photosListView.positionViewAtIndex(currentIndex, ListView.Contain)
              }
          }

          Item {
              Package.name: 'fullscreen'
              ListView {
                  id: photosListView; model: visualModel.parts.list; orientation: Qt.Horizontal
                  width: mainWindow.width; height: mainWindow.height; interactive: false
                  onCurrentIndexChanged: photosGridView.positionViewAtIndex(currentIndex, GridView.Contain)
                  highlightRangeMode: ListView.StrictlyEnforceRange; snapMode: ListView.SnapOneItem
              }
          }

          Item {
              Package.name: 'album'
              id: albumWrapper; width: 210; height: 220

</pre>
<p>The named items are used as the delegates by the views that reference the special DelegateModel::parts property to select the model that provides the chosen delegate.</p>
<p>We use a ListView type to lay out albums in other views:</p>
<pre class="cpp">

      ListView { anchors.fill: parent; model: albumVisualModel.parts.browser; interactive: false }

      ListView { anchors.fill: parent; model: albumVisualModel.parts.fullscreen; interactive: false }

</pre>
<a name="displaying-photos"></a>
<h2 id="displaying-photos">Displaying Photos</h2>
<p>We use the PhotoDelegate custom type that is specified in PhotoDelegate.qml to display photos. We use a Package type to lay out the photos either in a stack, list, or a grid:</p>
<pre class="cpp">

  Package {
      Item { id: stackItem; Package.name: 'stack'; width: 160; height: 153; z: stackItem.PathView.z }
      Item { id: listItem; Package.name: 'list'; width: mainWindow.width + 40; height: 153 }
      Item { id: gridItem; Package.name: 'grid'; width: 160; height: 153 }

</pre>
<p>The photos are rotated at random angles by using the <code>Math.random()</code> JavaScript method:</p>
<pre class="cpp">

      Item {
          width: 160; height: 153

          Item {
              id: photoWrapper

              property double randomAngle: Math.random() * (2 * 6 + 1) - 6
              property double randomAngle2: Math.random() * (2 * 6 + 1) - 6

              x: 0; y: 0; width: 140; height: 133
              z: stackItem.PathView.z; rotation: photoWrapper.randomAngle

</pre>
<p>We use a BorderImage type to create borders for the images:</p>
<pre class="cpp">

              BorderImage {
                  anchors {
                      fill: originalImage.status == Image.Ready ? border : placeHolder
                      leftMargin: -6; topMargin: -6; rightMargin: -8; bottomMargin: -8
                  }
                  source: 'images/box-shadow.png'
                  border.left: 10; border.top: 10; border.right: 10; border.bottom: 10
              }

</pre>
<a name="downloading-flickr-feeds"></a>
<h2 id="downloading-flickr-feeds">Downloading Flickr Feeds</h2>
<p>In AlbumDelegate.qml, we use the DelegateModel to provide the PhotoDelegate delegate to the RssModel model:</p>
<pre class="cpp">

              DelegateModel {
                  id: visualModel; delegate: PhotoDelegate { }
                  model: RssModel { id: rssModel; tags: tag }
              }

</pre>
<p>In RssModel.qml, we use an XmlListModel type as a data source for Package objects to download photos from the selected feeds:</p>
<pre class="cpp">

  import QtQuick.XmlListModel 2.0

  XmlListModel {
      property string tags : ""

      function encodeTags(x) { return encodeURIComponent(x.replace(' ',',')); }

</pre>
<p>We use the <code>tags</code> custom property to specify which photos to download. The <code>encodeTags</code> custom function uses the <code>encodeURIComponent</code> JavaScript method to ensure that the requests to the server are correctly formatted.</p>
<p>We use the <code>source</code> property to fetch photos that have the specified tags attached from public Flickr feeds:</p>
<pre class="cpp">

      source: "http://api.flickr.com/services/feeds/photos_public.gne?"+(tags ? "tags="+encodeTags(tags)+"&" : "")
      query: "/feed/entry"
      namespaceDeclarations: "declare default element namespace 'http://www.w3.org/2005/Atom';"

</pre>
<p>The <code>query</code> property specifies that the XmlListModel generates a model item for each feed entry.</p>
<p>The <code>namespaceDeclarations</code> property specifies that the requested document uses the namespace <code>http://www.w3.org/2005/Atom</code>, which is declared as the default namespace.</p>
<p>We use the XmlRole type to specify the model item attributes. Each model item has the <code>title</code>, <code>content</code>, and <code>hq</code> attributes that match the values of the corresponding feed entry:</p>
<pre class="cpp">

      XmlRole { name: "title"; query: "title/string()" }
      XmlRole { name: "content"; query: "content/string()" }
      XmlRole { name: "hq"; query: "link[@rel='enclosure']/@href/string()" }

</pre>
<a name="creating-flipable-labels"></a>
<h2 id="creating-flipable-labels">Creating Flipable Labels</h2>
<p>When users select the <b>Edit</b> button, the album labels are flipped from their front side to their back side and the text on them changes from album name to <b>Remove</b>.</p>
<p>In AlbumDelegate.qml, we use the Tag custom type to specify the text to display on the front and back sides of album labels:</p>
<pre class="cpp">

              Tag {
                  anchors { horizontalCenter: parent.horizontalCenter; bottom: parent.bottom; bottomMargin: 10 }
                  frontLabel: tag; backLabel: qsTr("Remove"); flipped: mainWindow.editMode
                  onTagChanged: rssModel.tags = tag
                  onBackClicked: if (mainWindow.editMode) photosModel.remove(index);
              }

</pre>
<p>The <code>onTagChanged</code> signal handler is used to change the tag based on which the model is populated. The <code>onBackClicked</code> signal handler is used to remove the album.</p>
<p>In Tag.qml, we use a Flipable type with custom properties and signals to create the labels:</p>
<pre class="cpp">

  Flipable {
      id: flipable

      property alias frontLabel: frontButton.label
      property alias backLabel: backButton.label

      property int angle: 0
      property int randomAngle: Math.random() * (2 * 6 + 1) - 6
      property bool flipped: false

      signal frontClicked
      signal backClicked
      signal tagChanged(string tag)

</pre>
<p>The <code>front</code> property holds the EditableButton custom type that enables users to edit the label text:</p>
<pre class="cpp">

      front: EditableButton {
          id: frontButton; rotation: flipable.randomAngle
          anchors { centerIn: parent; verticalCenterOffset: -20 }
          onClicked: flipable.frontClicked()
          onLabelChanged: flipable.tagChanged(label)
      }

</pre>
<p>The <code>back</code> property holds the <code>Button</code> custom type that is used to remove the album:</p>
<pre class="cpp">

      back: Button {
          id: backButton; tint: "red"; rotation: flipable.randomAngle
          anchors { centerIn: parent; verticalCenterOffset: -20 }
          onClicked: flipable.backClicked()
      }

</pre>
<a name="laying-out-photos-on-a-path"></a>
<h2 id="laying-out-photos-on-a-path">Laying Out Photos on a Path</h2>
<p>In AlbumDelegate.qml, we use a PathView type to lay out the photos provided by the <code>visualModel.parts.stack</code> model on a path that has the form of a stack:</p>
<pre class="cpp">

              PathView {
                  id: photosPathView; model: visualModel.parts.stack; pathItemCount: 5
                  visible: !busyIndicator.visible
                  anchors.centerIn: parent; anchors.verticalCenterOffset: -30
                  path: Path {
                      PathAttribute { name: 'z'; value: 9999.0 }
                      PathLine { x: 1; y: 1 }
                      PathAttribute { name: 'z'; value: 0.0 }
                  }
              }

</pre>
<p>The <code>path</code> property holds the Path type that defines the path used by the PathView. The PathAttribute types are used to set a range of <code>0</code> to <code>9999</code> for the <code>z</code> attribute. This way, the path creates a stack of album photos. Because each PhotoDelegate is slightly rotated at a random angle, this results in a realistic-looking stack of photos.</p>
<a name="providing-feedback-to-users"></a>
<h2 id="providing-feedback-to-users">Providing Feedback to Users</h2>
<p>We use a busy indicator and a progress bar to indicate activity while Flickr feeds and photos are being loaded.</p>
<p>In AlbumDelegate.qml, we use the <code>BusyIndicator</code> custom type and the <code>on</code> custom property to display a rotating image while the Flickr feed is being loaded:</p>
<pre class="cpp">

              BusyIndicator {
                  id: busyIndicator
                  anchors { centerIn: parent; verticalCenterOffset: -20 }
                  on: rssModel.status != XmlListModel.Ready
              }

</pre>
<p>In PhotoDelegate.qml, we use them to indicate activity while a photo is being loaded:</p>
<pre class="cpp">

              BusyIndicator { anchors.centerIn: parent; on: originalImage.status != Image.Ready }

</pre>
<p>We define the <code>BusyIndicator</code> type in <code>BusyIndicator.qml</code>. We use an Image type to display an image and apply a NumberAnimation to its <code>rotation</code> property to rotate the image in an infinite loop:</p>
<pre class="cpp">

  Image {
      id: container
      property bool on: false

      source: "images/busy.png"; visible: container.on
      NumberAnimation on rotation { running: container.on; from: 0; to: 360; loops: Animation.Infinite; duration: 1200 }
  }

</pre>
<p>In your apps, you can also use the BusyIndicator type from the Qt Quick Controls module.</p>
<p>In main.qml, we use the <code>ProgressBar</code> custom type to indicate progress while a high quality version of a photo is being opened on full screen:</p>
<pre class="cpp">

      ProgressBar {
          progress: mainWindow.downloadProgress; width: parent.width; height: 4
          anchors.bottom: parent.bottom; opacity: mainWindow.imageLoading; visible: opacity != 0.0
      }

</pre>
<p>We define the <code>ProgressBar</code> type in <code>ProgressBar.qml</code>. We use a Rectangle type to create the progress bar and apply a NumberAnimation to its <code>opacity</code> property to change the color of the bar from black to white as data loading proceeds:</p>
<pre class="cpp">

  Item {
      id: container

      property real progress: 0

      Behavior on opacity { NumberAnimation { duration: 600 } }

      Rectangle { anchors.fill: parent; color: "black"; opacity: 0.5 }

      Rectangle {
          id: fill; color: "white"; height: container.height
          width: container.width * container.progress
      }
  }

</pre>
<p>In your apps, you can also use the ProgressBar type from the Qt Quick Controls module.</p>
<a name="localizing-applications"></a>
<h2 id="localizing-applications">Localizing Applications</h2>
<p>The example application is translated into German and French. The translated strings are loaded at runtime according to the current locale.</p>
<p>We use a Column type in main.qml to position buttons for adding and editing albums and exiting the application:</p>
<pre class="cpp">

      Column {
          spacing: 20; anchors { bottom: parent.bottom; right: parent.right; rightMargin: 20; bottomMargin: 20 }
          Button {
              id: newButton; label: qsTr("Add"); rotation: 3
              anchors.horizontalCenter: parent.horizontalCenter
              onClicked: {
                  mainWindow.editMode = false
                  photosModel.append( { tag: "" } )
                  albumView.positionViewAtIndex(albumView.count - 1, GridView.Contain)
              }
          }
          Button {
              id: deleteButton; label: qsTr("Edit"); rotation: -2;
              onClicked: mainWindow.editMode = !mainWindow.editMode
              anchors.horizontalCenter: parent.horizontalCenter
          }
          Button {
              id: quitButton; label: qsTr("Quit"); rotation: -2;
              onClicked: Qt.quit()
              anchors.horizontalCenter: parent.horizontalCenter
          }
      }

</pre>
<p>We use the qsTr() command to mark the button labels translatable.</p>
<p>We use the <code>lupdate()</code> tool to generate the translation source files and the <code>lrelease()</code> tool to convert the translated strings to the QM files used by the application at runtime. These files are stored in the <code>i18n</code> directory.</p>
<p>To make the application aware of the translations, we add code to the <code>main()</code> function in the main.cpp file. The code creates a QTranslator object, loads a translation according to the current locale at runtime, and installs the translator object into the application:</p>
<pre class="cpp">

  <span class="type">int</span> main(<span class="type">int</span> argc<span class="operator">,</span> <span class="type">char</span> <span class="operator">*</span>argv<span class="operator">[</span><span class="operator">]</span>)
  {
      <span class="type">QGuiApplication</span> app(argc<span class="operator">,</span> argv);

      <span class="type">QTranslator</span> qtTranslator;
      qtTranslator<span class="operator">.</span>load(<span class="type">QLocale</span>()<span class="operator">,</span> <span class="string">&quot;qml&quot;</span><span class="operator">,</span> <span class="string">&quot;_&quot;</span><span class="operator">,</span> <span class="string">&quot;:/i18n/&quot;</span>);
      app<span class="operator">.</span>installTranslator(<span class="operator">&amp;</span>qtTranslator);

</pre>
<p>Files:</p>
<ul>
<li><a href="qtdoc-demos-photoviewer-photoviewercore-albumdelegate-qml.html">demos/photoviewer/PhotoViewerCore/AlbumDelegate.qml</a></li>
<li><a href="qtdoc-demos-photoviewer-photoviewercore-busyindicator-qml.html">demos/photoviewer/PhotoViewerCore/BusyIndicator.qml</a></li>
<li><a href="qtdoc-demos-photoviewer-photoviewercore-button-qml.html">demos/photoviewer/PhotoViewerCore/Button.qml</a></li>
<li><a href="qtdoc-demos-photoviewer-photoviewercore-editablebutton-qml.html">demos/photoviewer/PhotoViewerCore/EditableButton.qml</a></li>
<li><a href="qtdoc-demos-photoviewer-photoviewercore-photodelegate-qml.html">demos/photoviewer/PhotoViewerCore/PhotoDelegate.qml</a></li>
<li><a href="qtdoc-demos-photoviewer-photoviewercore-progressbar-qml.html">demos/photoviewer/PhotoViewerCore/ProgressBar.qml</a></li>
<li><a href="qtdoc-demos-photoviewer-photoviewercore-rssmodel-qml.html">demos/photoviewer/PhotoViewerCore/RssModel.qml</a></li>
<li><a href="qtdoc-demos-photoviewer-photoviewercore-tag-qml.html">demos/photoviewer/PhotoViewerCore/Tag.qml</a></li>
<li><a href="qtdoc-demos-photoviewer-main-cpp.html">demos/photoviewer/main.cpp</a></li>
<li><a href="qtdoc-demos-photoviewer-main-qml.html">demos/photoviewer/main.qml</a></li>
<li><a href="qtdoc-demos-photoviewer-photoviewer-pro.html">demos/photoviewer/photoviewer.pro</a></li>
</ul>
<p>Images:</p>
<ul>
<li><a href="images/used-in-examples/demos/photoviewer/PhotoViewerCore/images/box-shadow.png">demos/photoviewer/PhotoViewerCore/images/box-shadow.png</a></li>
<li><a href="images/used-in-examples/demos/photoviewer/PhotoViewerCore/images/busy.png">demos/photoviewer/PhotoViewerCore/images/busy.png</a></li>
<li><a href="images/used-in-examples/demos/photoviewer/PhotoViewerCore/images/cardboard.png">demos/photoviewer/PhotoViewerCore/images/cardboard.png</a></li>
</ul>
</div>
<p><b>See also </b><a href="qmlapplications.html">QML Applications</a>.</p>
<!-- @@@demos/photoviewer -->
        </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>