/usr/share/qt5/doc/qtdoc/gettingstartedqml.html is in qt5-doc-html 5.9.5-0ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 | <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- gettingstartedqml.qdoc -->
<title>Getting Started Programming with Qt Quick | Qt 5.9</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.9</a></td><td >Getting Started Programming with Qt Quick</td></tr></table><table class="buildversion"><tr>
<td id="buildversion" width="100%" align="right">Qt 5.9.5 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="#qml-to-build-user-interfaces">QML to Build User Interfaces</a></li>
<li class="level1"><a href="#defining-a-button-and-a-menu">Defining a Button and a Menu</a></li>
<li class="level2"><a href="#basic-component-a-button">Basic Component - a Button</a></li>
<li class="level2"><a href="#creating-a-menu-page">Creating a Menu Page</a></li>
<li class="level1"><a href="#implementing-a-menu-bar">Implementing a Menu Bar</a></li>
<li class="level2"><a href="#using-data-models-and-views">Using Data Models and Views</a></li>
<li class="level1"><a href="#building-a-text-editor">Building a Text Editor</a></li>
<li class="level2"><a href="#declaring-a-textarea">Declaring a TextArea</a></li>
<li class="level2"><a href="#combining-components-for-the-text-editor">Combining Components for the Text Editor</a></li>
<li class="level1"><a href="#decorating-the-text-editor">Decorating the Text Editor</a></li>
<li class="level2"><a href="#implementing-a-drawer-interface">Implementing a Drawer Interface</a></li>
<li class="level2"><a href="#extending-qml-using-qt-c">Extending QML using Qt C++</a></li>
<li class="level2"><a href="#final-text-editor-application">Final Text Editor Application</a></li>
<li class="level1"><a href="#running-the-text-editor">Running the Text Editor</a></li>
</ul>
</div>
<div class="sidebar-content" id="sidebar-content"></div></div>
<h1 class="title">Getting Started Programming with Qt Quick</h1>
<span class="subtitle"></span>
<!-- $$$gettingstartedqml.html-description -->
<div class="descr"> <a name="details"></a>
<p>Welcome to the world of <b>QML</b>, the declarative UI language. In this Getting Started guide, we will create a simple text editor application using QML. After reading this guide, you should be ready to develop your own applications using QML and Qt C++.</p>
<a name="qml-to-build-user-interfaces"></a>
<h2 id="qml-to-build-user-interfaces">QML to Build User Interfaces</h2>
<p>The application we are building is a simple text editor that will load, save, and perform some text manipulation. This guide will consist of two parts. The first part will involve designing the application layout and behaviors using declarative language in QML. For the second part, file loading and saving will be implemented using Qt C++. Using <a href="../qtcore/metaobjects.html">Qt's Meta-Object System</a>, we can expose C++ functions as properties that <a href="../qtqml/qtqml-typesystem-topic.html#qml-object-types">QML object types</a> can use. Utilizing QML and Qt C++, we can efficiently decouple the interface logic from the application logic.</p>
<p class="centerAlign"><img src="images/qml-texteditor5_editmenu.png" alt="" /></p><p>The complete source code is in the <code>examples/quick/tutorials/gettingStartedQml</code> directory. If you wish to see how the finalized application looks like, you can skip to chapter <a href="gettingstartedqml.html#running-the-text-editor">Running the Text Editor</a>.</p>
<p>The C++ portion of this tutorial assumes that the reader possesses basic knowledge of Qt's compilation procedures.</p>
<p>Tutorial chapters:</p>
<ol class="1" type="1"><li><a href="gettingstartedqml.html#defining-a-button-and-a-menu">Defining a Button and a Menu</a></li>
<li><a href="gettingstartedqml.html#implementing-a-menu-bar">Implementing a Menu Bar</a></li>
<li><a href="gettingstartedqml.html#building-a-text-editor">Building a Text Editor</a></li>
<li><a href="gettingstartedqml.html#decorating-the-text-editor">Decorating the Text Editor</a></li>
<li><a href="gettingstartedqml.html#extending-qml-using-qt-c">Extending QML using Qt C++</a></li>
</ol>
<p>Information about QML, such as syntax and features, is included in the <a href="../qtqml/qmlreference.html">The QML Reference</a>.</p>
<a name="defining-a-button-and-a-menu"></a>
<h2 id="defining-a-button-and-a-menu">Defining a Button and a Menu</h2>
<a name="basic-component-a-button"></a>
<h3 >Basic Component - a Button</h3>
<p>We start our text editor by building a button. Functionally, a button has a mouse sensitive area and a label. Buttons perform actions when a user presses the button.</p>
<p>In QML, the basic visual item is the <a href="../qtquick/qml-qtquick-rectangle.html">Rectangle</a> type. The <code>Rectangle</code> <a href="../qtqml/qtqml-typesystem-topic.html#qml-object-types">QML object type</a> has <a href="../qtqml/qtqml-syntax-propertybinding.html">QML properties</a> to control its appearance and location.</p>
<pre class="cpp">
import <span class="type"><a href="../qtqml/qtquick-qmlmodule.html">QtQuick</a></span> <span class="number">2.3</span>
Rectangle {
id: simpleButton
color: <span class="string">"grey"</span>
width: <span class="number">150</span>; height: <span class="number">75</span>
Text {
id: buttonLabel
anchors<span class="operator">.</span>centerIn: parent
text: <span class="string">"button label"</span>
}
}
</pre>
<p>First, the <code>import QtQuick 2.3</code> statement allows the <a href="qtquick-qmlscene.html">qmlscene</a> tool to import the QML types we will later use. This line must exist for every QML file. Notice that the version of Qt modules is included in the import statement.</p>
<p>This simple rectangle has a unique identifier, <code>simpleButton</code>, which is bound to the <code>id</code> property. The <code>Rectangle</code> object's properties are bound to values by listing the property, followed by a colon, then the value. In the code sample, the color <code>grey</code> is bound to the Rectangle's <code>color</code> property. Similarly, we bind the <code>width</code> and <code>height</code> of the Rectangle.</p>
<p>The <a href="whatsnew50.html#text">Text</a> type is a non-editable text field. We name this object <code>buttonLabel</code>. To set the string content of the Text field, we bind a value to the <code>text</code> property. The label is contained within the Rectangle and in order to center it in the middle, we assign the <code>anchors</code> of the Text object to its parent, which is called <code>simpleButton</code>. Anchors may bind to other items' anchors, allowing layout assignments simpler.</p>
<p>We shall save this code as <code>SimpleButton.qml</code>. Running <code>qmlscene</code> with the file as the argument will display the grey rectangle with a text label.</p>
<p class="centerAlign"><img src="images/qml-texteditor1_simplebutton.png" alt="" /></p><p>To implement the button click functionality, we can use QML's event handling. QML's event handling is very similar to <a href="../qtcore/signalsandslots.html">Qt's signal and slot</a> mechanism. Signals are emitted and the connected slot is called.</p>
<pre class="cpp">
Rectangle {
id: simpleButton
<span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
MouseArea {
id: buttonMouseArea
<span class="comment">// Anchor all sides of the mouse area to the rectangle's anchors</span>
anchors<span class="operator">.</span>fill: parent
<span class="comment">// onClicked handles valid mouse button clicks</span>
onClicked: console<span class="operator">.</span>log(buttonLabel<span class="operator">.</span>text <span class="operator">+</span> <span class="string">" clicked"</span>)
}
}
</pre>
<p>We include a <a href="../qtquick/qml-qtquick-mousearea.html">MouseArea</a> object in our simpleButton. <code>MouseArea</code> objects describe the interactive area where mouse movements are detected. For our button, we anchor the whole <code>MouseArea</code> to its parent, which is <code>simpleButton</code>. The <code>anchors.fill</code> syntax is one way of accessing a specific property called <code>fill</code> inside a group of properties called <code>anchors</code>. QML uses <a href="../qtquick/qtquick-positioning-anchors.html">anchor-based layouts</a> where items can anchor to another item, creating robust layouts.</p>
<p>The <code>MouseArea</code> has many signal handlers that are called during mouse movements within the specified <code>MouseArea</code> boundaries. One of them is <code>onClicked</code> and it is called whenever the acceptable mouse button is clicked, the left click being the default. We can bind actions to the onClicked handler. In our example, <code>console.log()</code> outputs text whenever the mouse area is clicked. The function <code>console.log()</code> is a useful tool for debugging purposes and for outputting text.</p>
<p>The code in <code>SimpleButton.qml</code> is sufficient to display a button on the screen and output text whenever it is clicked with a mouse.</p>
<pre class="cpp">
Rectangle {
id: button
<span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
property color buttonColor: <span class="string">"lightblue"</span>
property color onHoverColor: <span class="string">"gold"</span>
property color borderColor: <span class="string">"white"</span>
signal buttonClick()
onButtonClick: {
console<span class="operator">.</span>log(buttonLabel<span class="operator">.</span>text <span class="operator">+</span> <span class="string">" clicked"</span>)
}
MouseArea{
id: buttonMouseArea
onClicked: buttonClick()
hoverEnabled: <span class="keyword">true</span>
onEntered: parent<span class="operator">.</span>border<span class="operator">.</span>color <span class="operator">=</span> onHoverColor
onExited: parent<span class="operator">.</span>border<span class="operator">.</span>color <span class="operator">=</span> borderColor
}
<span class="comment">// Determines the color of the button by using the conditional operator</span>
color: buttonMouseArea<span class="operator">.</span>pressed <span class="operator">?</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">.</span>darker(buttonColor<span class="operator">,</span> <span class="number">1.5</span>) : buttonColor
}
</pre>
<p>A fully functioning button is in <code>Button.qml</code>. The code snippets in this article have some code omitted, denoted by ellipses because they were either introduced earlier in the previous sections or irrelevant to the current code discussion.</p>
<p>Custom properties are declared using the <code>property type name</code> syntax. In the code, the property <code>buttonColor</code>, of type <code>color</code>, is declared and bound to the value <code>"lightblue"</code>. The <code>buttonColor</code> is later used in a conditional operation to determine the button's fill color. Note that property value assignment is possible using the <code>=</code> equals sign, in addition to value binding using the <code>:</code> colon character. Custom properties allow internal items to be accessible outside of the Rectangle's scope. There are basic <a href="../qtqml/qtqml-typesystem-basictypes.html">QML types</a> such as <code>int</code>, <code>string</code>, <code>real</code>, as well as a type called <code>variant</code>.</p>
<p>By binding the <code>onEntered</code> and <code>onExited</code> signal handlers to colors, the button's border will turn yellow when the mouse hovers above the button and reverts the color when the mouse exits the mouse area.</p>
<p>A <code>buttonClick()</code> signal is declared in <code>Button.qml</code> by placing the <code>signal</code> keyword in front of the signal name. All signals have their handlers automatically created, their names starting with <code>on</code>. As a result, the <code>onButtonClick</code> is <code>buttonClick</code>'s handler. The <code>onButtonClick</code> is then assigned an action to perform. In our button example, the <code>onClicked</code> mouse handler will simply call <code>onButtonClick</code>, which displays a text. The <code>onButtonClick</code> enables outside objects to access the <code>Button</code>'s mouse area easily. For example, items may have more than one <code>MouseArea</code> declarations and a <code>buttonClick</code> signal can make the distinction between the several <code>MouseArea</code> signal handlers better.</p>
<p>We now have the basic knowledge to implement items in QML that can handle basic mouse movements. We created a <code>Text</code> label inside a <code>Rectangle</code>, customized its properties, and implemented behaviors that respond to mouse movements. This idea of creating QML objects within objects is repeated throughout the text editor application.</p>
<p>This button is not useful unless used as a component to perform an action. In the next section, we will soon create a menu containing several of these buttons.</p>
<p class="centerAlign"><img src="images/qml-texteditor1_button.png" alt="" /></p><a name="creating-a-menu-page"></a>
<h3 >Creating a Menu Page</h3>
<p>Up to this stage, we covered how to create objects and assign behaviors inside a single QML file. In this section, we will cover how to import QML types and how to reuse some of the created components to build other components.</p>
<p>Menus display the contents of a list, each item having the ability to perform an action. In QML, we can create a menu in several ways. First, we will create a menu containing buttons which will eventually perform different actions. The menu code is in <code>FileMenu.qml</code>.</p>
<pre class="cpp">
import <span class="type"><a href="../qtqml/qtquick-qmlmodule.html">QtQuick</a></span> <span class="number">2.3</span> <span class="comment">// Import the main Qt QML module</span>
import <span class="string">"folderName"</span> <span class="comment">// import the contents of a folder</span>
import <span class="string">"script.js"</span> as Script <span class="comment">// Import a Javascript file and name it as Script</span>
</pre>
<p>The syntax shown above shows how to use the <code>import</code> keyword. This is required to use JavaScript files, or QML files that are not within the same directory. Since <code>Button.qml</code> is in the same directory as <code>FileMenu.qml</code>, we do not need to import the <code>Button.qml</code> file to use it. We can directly create a <code>Button</code> object by declaring <code>Button{}</code>, similar to a <code>Rectangle{}</code> declaration.</p>
<pre class="cpp">
In FileMenu<span class="operator">.</span>qml:
Row {
anchors<span class="operator">.</span>centerIn: parent
spacing: parent<span class="operator">.</span>width <span class="operator">/</span> <span class="number">6</span>
Button {
id: loadButton
buttonColor: <span class="string">"lightgrey"</span>
label: <span class="string">"Load"</span>
}
Button {
buttonColor: <span class="string">"grey"</span>
id: saveButton
label: <span class="string">"Save"</span>
}
Button {
id: exitButton
label: <span class="string">"Exit"</span>
buttonColor: <span class="string">"darkgrey"</span>
onButtonClick: <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">.</span>quit()
}
}
</pre>
<p>In <code>FileMenu.qml</code>, we declare three <code>Button</code> objects. They are declared inside a <a href="../qdoc/10-qdoc-commands-tablesandlists.html#row">Row</a> type, a positioner that will position its children along a vertical row. The <code>Button</code> declaration resides in Button.qml, which is the same as the one we used in the previous section. New property bindings can be declared within the newly created buttons, effectively overwriting the properties set in <code>Button.qml</code>. The button called <code>exitButton</code> will quit and close the window when it is clicked. Note that the signal handler <code>onButtonClick</code> in <code>Button.qml</code> will be called in addition to the <code>onButtonClick</code> handler in <code>exitButton</code>.</p>
<p class="centerAlign"><img src="images/qml-texteditor1_filemenu.png" alt="" /></p><p>The <code>Row</code> declaration is declared in a <code>Rectangle</code>, creating a rectangle container for the row of buttons. This additional rectangle creates an indirect way of organizing the row of buttons inside a menu.</p>
<p>The declaration of the edit menu is very similar at this stage. The menu has buttons that have the labels: <code>Copy</code>, <code>Paste</code>, and <code>Select All</code>.</p>
<p class="centerAlign"><img src="images/qml-texteditor1_editmenu.png" alt="" /></p><p>Armed with our knowledge of importing and customizing previously made components, we may now combine these menu pages to create a menu bar, consisting of buttons to select the menu, and look at how we may structure data using QML.</p>
<a name="implementing-a-menu-bar"></a>
<h2 id="implementing-a-menu-bar">Implementing a Menu Bar</h2>
<p>Our text editor application will need a way to display menus using a menu bar. The menu bar will switch the different menus and the user can choose which menu to display. Menu switching implies that the menus need more structure than merely displaying them in a row. QML uses models and views to structure data and display the structured data.</p>
<a name="using-data-models-and-views"></a>
<h3 >Using Data Models and Views</h3>
<p>QML has different <a href="../qtquick/qtquick-modelviewsdata-modelview.html#qml-data-models">data views</a> that display <a href="../qtquick/qtquick-modelviewsdata-modelview.html#qml-data-models">data models</a>. Our menu bar will display the menus in a list, with a header that displays a row of menu names. The list of menus are declared inside a <a href="../qtqml/qml-qtqml-models-objectmodel.html">ObjectModel</a>. The <code>ObjectModel</code> type contains items that already are displayable, such as <code>Rectangle</code> objects. Other model types, like the <a href="../qtqml/qml-qtqml-models-listmodel.html">ListModel</a> type, need a delegate to display their data.</p>
<p>We declare two visual items in the <code>menuListModel</code>, the <code>FileMenu</code> and the <code>EditMenu</code>. We customize the two menus and display them in a <a href="../qtquick/qml-qtquick-listview.html">ListView</a>. The <code>MenuBar.qml</code> file contains the QML declarations and a simple edit menu is defined in <code>EditMenu.qml</code>.</p>
<pre class="cpp">
ObjectModel {
id: menuListModel
FileMenu {
width: menuListView<span class="operator">.</span>width
height: menuBar<span class="operator">.</span>height
color: fileColor
}
EditMenu {
color: editColor
width: menuListView<span class="operator">.</span>width
height: menuBar<span class="operator">.</span>height
}
}
</pre>
<p>The <a href="../qtquick/qml-qtquick-listview.html">ListView</a> type will display a model according to a delegate. The delegate can display the model items in a <code>Row</code> object or in a grid. Our <code>menuListModel</code> already has visible items, therefore, we do not need to declare a delegate.</p>
<pre class="cpp">
ListView {
id: menuListView
<span class="comment">// Anchors are set to react to window anchors</span>
anchors<span class="operator">.</span>fill: parent
anchors<span class="operator">.</span>bottom: parent<span class="operator">.</span>bottom
width: parent<span class="operator">.</span>width
height: parent<span class="operator">.</span>height
<span class="comment">// The model contains the data</span>
model: menuListModel
<span class="comment">// Control the movement of the menu switching</span>
snapMode: ListView<span class="operator">.</span>SnapOneItem
orientation: ListView<span class="operator">.</span>Horizontal
boundsBehavior: Flickable<span class="operator">.</span>StopAtBounds
flickDeceleration: <span class="number">5000</span>
highlightFollowsCurrentItem: <span class="keyword">true</span>
highlightMoveDuration: <span class="number">240</span>
highlightRangeMode: ListView<span class="operator">.</span>StrictlyEnforceRange
}
</pre>
<p>Additionally, <code>ListView</code> inherits from <a href="../qtquick/qml-qtquick-flickable.html">Flickable</a>, making the list respond to mouse drags and other gestures. The last portion of the code above sets <code>Flickable</code> properties to create the desired flicking movement to our view. In particular, the property <code>highlightMoveDuration</code> changes the duration of the flick transition. A higher <code>highlightMoveDuration</code> value results in slower menu switching.</p>
<p>The <code>ListView</code> maintains the model items through an <code>index</code> and each visual item in the model is accessible through the <code>index</code>, in the order of the declaration. Changing the <code>currentIndex</code> effectively changes the highlighted item in the <code>ListView</code>. The header of our menu bar exemplifies this effect. There are two buttons in a row, both changing the current menu when clicked. The <code>fileButton</code> changes the current menu to the file menu when clicked, the <code>index</code> being <code>0</code> because <code>FileMenu</code> is declared first in the <code>menuListModel</code>. Similarly, the <code>editButton</code> will change the current menu to the <code>EditMenu</code> when clicked.</p>
<p>The <code>labelList</code> rectangle has <code>z</code> value of <code>1</code>, denoting that it is displayed at the front of the menu bar. Items with higher <code>z</code> values are displayed in front of items with lower <code>z</code> values. The default <code>z</code> value is <code>0</code>.</p>
<pre class="cpp">
Rectangle {
id: labelList
<span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
z: <span class="number">1</span>
Row {
anchors<span class="operator">.</span>centerIn: parent
spacing: <span class="number">40</span>
Button {
label: <span class="string">"File"</span>
id: fileButton
<span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
onButtonClick: menuListView<span class="operator">.</span>currentIndex <span class="operator">=</span> <span class="number">0</span>
}
Button {
id: editButton
label: <span class="string">"Edit"</span>
<span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
onButtonClick: menuListView<span class="operator">.</span>currentIndex <span class="operator">=</span> <span class="number">1</span>
}
}
}
</pre>
<p>The menu bar we just created can be flicked to access the menus or by clicking on the menu names at the top. Switching menu screens feel intuitive and responsive.</p>
<p class="centerAlign"><img src="images/qml-texteditor2_menubar.png" alt="" /></p><a name="building-a-text-editor"></a>
<h2 id="building-a-text-editor">Building a Text Editor</h2>
<a name="declaring-a-textarea"></a>
<h3 >Declaring a TextArea</h3>
<p>Our text editor is not a text editor if it didn't contain an editable text area. QML's <a href="../qtquick/qml-qtquick-textedit.html">TextEdit</a> type allows the declaration of a multi-line editable text area. <code>TextEdit</code> is different from the <a href="whatsnew50.html#text">Text</a> type, which doesn't allow the user to directly edit the text.</p>
<pre class="cpp">
TextEdit {
id: textEditor
anchors<span class="operator">.</span>fill: parent
width: parent<span class="operator">.</span>width
height: parent<span class="operator">.</span>height
color: <span class="string">"midnightblue"</span>
focus: <span class="keyword">true</span>
wrapMode: TextEdit<span class="operator">.</span>Wrap
onCursorRectangleChanged: flickArea<span class="operator">.</span>ensureVisible(cursorRectangle)
}
</pre>
<p>The editor has its font <code>color</code> property set and <code>wrapMode</code> set to wrap the text. The <code>TextEdit</code> area is inside a flickable item that will scroll the text if the text cursor is outside the visible area. The function <code>ensureVisible()</code> will check if the cursor rectangle is outside the visible boundaries and move the text area accordingly. QML uses Javascript syntax for its scripts, and as previously mentioned, Javascript files can be imported and used within a QML file.</p>
<pre class="cpp">
function ensureVisible(r) {
<span class="keyword">if</span> (contentX <span class="operator">></span><span class="operator">=</span> r<span class="operator">.</span>x)
contentX <span class="operator">=</span> r<span class="operator">.</span>x;
<span class="keyword">else</span> <span class="keyword">if</span> (contentX <span class="operator">+</span> width <span class="operator"><</span><span class="operator">=</span> r<span class="operator">.</span>x <span class="operator">+</span> r<span class="operator">.</span>width)
contentX <span class="operator">=</span> r<span class="operator">.</span>x <span class="operator">+</span> r<span class="operator">.</span>width <span class="operator">-</span> width;
<span class="keyword">if</span> (contentY <span class="operator">></span><span class="operator">=</span> r<span class="operator">.</span>y)
contentY <span class="operator">=</span> r<span class="operator">.</span>y;
<span class="keyword">else</span> <span class="keyword">if</span> (contentY <span class="operator">+</span> height <span class="operator"><</span><span class="operator">=</span> r<span class="operator">.</span>y <span class="operator">+</span> r<span class="operator">.</span>height)
contentY <span class="operator">=</span> r<span class="operator">.</span>y <span class="operator">+</span> r<span class="operator">.</span>height <span class="operator">-</span> height;
}
</pre>
<a name="combining-components-for-the-text-editor"></a>
<h3 >Combining Components for the Text Editor</h3>
<p>We are now ready to create the layout of our text editor using QML. The text editor has two components, the menu bar we created and the text area. QML allows us to reuse components, therefore making our code simpler, by importing components and customizing when necessary. Our text editor splits the window into two; one-third of the screen is dedicated to the menu bar and two-thirds of the screen displays the text area. The menu bar is displayed in front of any other objects.</p>
<pre class="cpp">
Rectangle {
id: screen
width: <span class="number">1000</span>
height: <span class="number">1000</span>
<span class="comment">// The screen is partitioned into the MenuBar and TextArea.</span>
<span class="comment">// One-third of the screen is assigned to the MenuBar</span>
property <span class="type">int</span> partition: height <span class="operator">/</span> <span class="number">3</span>
MenuBar {
id: menuBar
height: partition
width: parent<span class="operator">.</span>width
z: <span class="number">1</span>
}
TextArea {
id: textArea
anchors<span class="operator">.</span>bottom: parent<span class="operator">.</span>bottom
y: partition
color: <span class="string">"white"</span>
width: parent<span class="operator">.</span>width
height: partition <span class="operator">*</span> <span class="number">2</span>
}
}
</pre>
<p>By importing reusable components, our <code>TextEditor</code> code looks much simpler. We can then customize the main application, without worrying about properties that already have defined behaviors. Using this approach, application layouts and UI components can be created easily.</p>
<p class="centerAlign"><img src="images/qml-texteditor3_texteditor.png" alt="" /></p><a name="decorating-the-text-editor"></a>
<h2 id="decorating-the-text-editor">Decorating the Text Editor</h2>
<a name="implementing-a-drawer-interface"></a>
<h3 >Implementing a Drawer Interface</h3>
<p>Our text editor looks simple and we need to decorate it. Using QML, we can declare transitions and animate our text editor. Our menu bar is occupying one-third of the screen and it would be nice to have it only appear when we want it.</p>
<p>We can add a drawer interface, that will contract or expand the menu bar when clicked. In our implementation, we have a thin rectangle that responds to mouse clicks. The <code>drawer</code>, as well as the application, has two sates: the "drawer is open" state and the "drawer is closed" state. The <code>drawer</code> item is a strip of rectangle with a small height. There is a nested <a href="../qdoc/09-qdoc-commands-includingimages.html#image">Image</a> object declaring that an arrow icon will be centered inside the drawer. The drawer assigns a state to the whole application, with the identifier <code>screen</code>, whenever a user clicks the mouse area.</p>
<pre class="cpp">
Rectangle {
id: drawer
height: <span class="number">15</span>
Image {
id: arrowIcon
source: <span class="string">"images/arrow.png"</span>
anchors<span class="operator">.</span>horizontalCenter: parent<span class="operator">.</span>horizontalCenter
}
MouseArea {
id: drawerMouseArea
anchors<span class="operator">.</span>fill: parent
onClicked: {
<span class="keyword">if</span> (screen<span class="operator">.</span>state <span class="operator">=</span><span class="operator">=</span> <span class="string">"DRAWER_CLOSED"</span>)
screen<span class="operator">.</span>state <span class="operator">=</span> <span class="string">"DRAWER_OPEN"</span>
<span class="keyword">else</span> <span class="keyword">if</span> (screen<span class="operator">.</span>state <span class="operator">=</span><span class="operator">=</span> <span class="string">"DRAWER_OPEN"</span>)
screen<span class="operator">.</span>state <span class="operator">=</span> <span class="string">"DRAWER_CLOSED"</span>
}
<span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
}
}
</pre>
<p>A state is simply a collection of configurations and it is declared with the <a href="../qtqml/qml-qtqml-statemachine-state.html">State</a> type. A list of states can be listed and bound to the <code>states</code> property. In our application, the two states are called <code>DRAWER_CLOSED</code> and <code>DRAWER_OPEN</code>. Item configurations are declared in <a href="../qtquick/qml-qtquick-propertychanges.html">PropertyChanges</a> objects. In the <code>DRAWER_OPEN</code> state, there are four items that will receive property changes. The first target, <code>menuBar</code>, will change its <code>y</code> property to <code>0</code>. Similarly, the <code>textArea</code> will lower to a new position when the state is <code>DRAWER_OPEN</code>. The <code>textArea</code>, the <code>drawer</code>, and the drawer's icon will undergo property changes to meet the current state.</p>
<pre class="cpp">
states:<span class="operator">[</span>
State {
name: <span class="string">"DRAWER_OPEN"</span>
PropertyChanges { target: menuBar; y: <span class="number">0</span> }
PropertyChanges { target: textArea; y: partition <span class="operator">+</span> drawer<span class="operator">.</span>height }
PropertyChanges { target: drawer; y: partition }
PropertyChanges { target: arrowIcon; rotation: <span class="number">180</span> }
}<span class="operator">,</span>
State {
name: <span class="string">"DRAWER_CLOSED"</span>
PropertyChanges { target: menuBar; y: <span class="operator">-</span>height; }
PropertyChanges { target: textArea; y: drawer<span class="operator">.</span>height; height: screen<span class="operator">.</span>height <span class="operator">-</span> drawer<span class="operator">.</span>height }
PropertyChanges { target: drawer; y: <span class="number">0</span> }
PropertyChanges { target: arrowIcon; rotation: <span class="number">0</span> }
}
<span class="operator">]</span>
</pre>
<p>State changes are abrupt and needs smoother transitions. Transitions between states are defined using the <a href="../qtquick/qmlexampletoggleswitch.html#transition">Transition</a> type, which can then bind to the item's <code>transitions</code> property. Our text editor has a state transition whenever the state changes to either <code>DRAWER_OPEN</code> or <code>DRAWER_CLOSED</code>. Importantly, the transition needs a <code>from</code> and a <code>to</code> state but for our transitions, we can use the wild card <code>*</code> symbol to denote that the transition applies to all state changes.</p>
<p>During transitions, we can assign animations to the property changes. Our <code>menuBar</code> switches position from <code>y: 0</code> to <code>y: -partition</code> and we can animate this transition using the <a href="../qtquick/qml-qtquick-numberanimation.html">NumberAnimation</a> type. We declare that the targets' properties will animate for a certain duration of time and using a certain easing curve. An easing curve controls the animation rates and interpolation behavior during state transitions. The easing curve we chose is <a href="../qtquick/qml-qtquick-propertyanimation.html#easing.type-prop"><code>Easing.OutExpo</code></a>, which slows the movement near the end of the animation. For more information, see QML's <a href="../qtquick/qtquick-statesanimations-animations.html">animation</a> article.</p>
<pre class="cpp">
transitions: <span class="operator">[</span>
Transition {
to: <span class="string">"*"</span>
NumberAnimation { target: textArea; properties: <span class="string">"y, height"</span>; duration: <span class="number">100</span>; easing<span class="operator">.</span>type:Easing<span class="operator">.</span>OutExpo }
NumberAnimation { target: menuBar; properties: <span class="string">"y"</span>; duration: <span class="number">100</span>; easing<span class="operator">.</span>type: Easing<span class="operator">.</span>OutExpo }
NumberAnimation { target: drawer; properties: <span class="string">"y"</span>; duration: <span class="number">100</span>; easing<span class="operator">.</span>type: Easing<span class="operator">.</span>OutExpo }
}
<span class="operator">]</span>
</pre>
<p>Another way of animating property changes is by declaring a <a href="../qtquick/qml-qtquick-behavior.html">Behavior</a> type. A transition only works during state changes and <code>Behavior</code> can set an animation for a general property change. In the text editor, the arrow has a <code>NumberAnimation</code> animating its <code>rotation</code> property whenever the property changes.</p>
<p>In <code>TextEditor.qml</code>:</p>
<pre class="cpp">
Behavior {
NumberAnimation { property: <span class="string">"rotation"</span>; easing<span class="operator">.</span>type: Easing<span class="operator">.</span>OutExpo }
}
</pre>
<p>Going back to our components with knowledge of states and animations, we can improve the appearances of the components. In <code>Button.qml</code>, we can add <code>color</code> and <code>scale</code> property changes when the button is clicked. Color types are animated using <a href="../qtquick/qtquick-animation-example.html#coloranimation">ColorAnimation</a> and numbers are animated using <a href="../qtquick/qml-qtquick-numberanimation.html">NumberAnimation</a>. The <code>on propertyName</code> syntax displayed below is helpful when targeting a single property.</p>
<p>In <code>Button.qml</code>:</p>
<pre class="cpp">
<span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
color: buttonMouseArea<span class="operator">.</span>pressed <span class="operator">?</span> <span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">.</span>darker(buttonColor<span class="operator">,</span> <span class="number">1.5</span>) : buttonColor
Behavior on color { ColorAnimation{ duration: <span class="number">55</span> } }
scale: buttonMouseArea<span class="operator">.</span>pressed <span class="operator">?</span> <span class="number">1.1</span> : <span class="number">1.0</span>
Behavior on scale { NumberAnimation{ duration: <span class="number">55</span> } }
</pre>
<p>Additionally, we can enhance the appearances of our QML components by adding color effects such as gradients and opacity effects. Declaring a <a href="../qtgraphicaleffects/graphicaleffects.html#gradient">Gradient</a> object will override the <code>color</code> property. You may declare a color in the gradient using the <a href="../qtquick/qml-qtquick-gradientstop.html">GradientStop</a> type. The gradient is positioned using a scale, between <code>0.0</code> and <code>1.0</code>.</p>
<p>In <code>MenuBar.qml</code>:</p>
<pre class="cpp">
gradient: Gradient {
GradientStop { position: <span class="number">0.0</span>; color: <span class="string">"#8C8F8C"</span> }
GradientStop { position: <span class="number">0.17</span>; color: <span class="string">"#6A6D6A"</span> }
GradientStop { position: <span class="number">0.98</span>; color: <span class="string">"#3F3F3F"</span> }
GradientStop { position: <span class="number">1.0</span>; color: <span class="string">"#0e1B20"</span> }
}
</pre>
<p>This gradient is used by the menu bar to display a gradient simulating depth. The first color starts at <code>0.0</code> and the last color is at <code>1.0</code>.</p>
<a name="where-to-go-from-here"></a>
<h4 >Where to Go from Here</h4>
<p>We are finished building the user interface of a very simple text editor. Going forward, the user interface is complete, and we can implement the application logic using regular Qt and C++. QML works nicely as a prototyping tool, separating the application logic away from the UI design.</p>
<p class="centerAlign"><img src="images/qml-texteditor4_texteditor.png" alt="" /></p><a name="extending-qml-using-qt-c"></a>
<h3 >Extending QML using Qt C++</h3>
<p>Now that we have our text editor layout, we may now implement the text editor functionalities in C++. Using QML with C++ enables us to create our application logic using Qt. We can create a QML context in a C++ application using <a href="../qtqml/qtqml-cppintegration-topic.html">Qt's Quick classes</a> and display the QML types using a <a href="../qtquick/qquickview.html">QQuickView</a>. Alternatively, we can export our C++ code into an extension plugin, and make it accessible to QML as a new <a href="../qtqml/qtqml-modules-identifiedmodules.html">identified module</a>. When launching QML files with <a href="qtquick-qmlscene.html">qmlscene</a>, we only need to ensure our module is found under one of the <a href="../qtqml/qtqml-syntax-imports.html#qml-import-path">import paths</a> the QML engine searches for modules to import. For our application we shall the latter approach. This way, we can load the QML file directly with <code>qmlscene</code> instead of running an executable.</p>
<a name="exposing-c-classes-to-qml"></a>
<h4 >Exposing C++ Classes to QML</h4>
<p>We will be implementing file loading and saving using Qt and C++. C++ classes and functions can be used in QML by registering them. They also needs to be compiled as a Qt plugin and then exposed as a QML module.</p>
<p>For our application, we need to create the following items:</p>
<ol class="1" type="1"><li><code>Directory</code> class that will handle directory related operations</li>
<li><code>File</code> class which is a <a href="../qtcore/qobject.html">QObject</a>, simulating the list of files in a directory</li>
<li>A plugin class that will register the classes to the QML context</li>
<li>Qt project file that will compile the plugin</li>
<li>A <a href="../qtqml/qtqml-modules-qmldir.html">module definition qmldir file</a> that defines the identifier (import URI) and content (in this case, our plugin) to be made available by the QML module</li>
</ol>
<p><b>Note: </b>Since Qt 5.1, <a href="../qtquickdialogs/qtquickdialogs-index.html">Qt Quick Dialogs</a> module provides a file dialog component that you can use for choosing files from the local file system. For illustrative purposes, we write our own in this tutorial.</p><a name="building-a-qt-plugin"></a>
<h4 >Building a Qt Plugin</h4>
<p>To build a plugin, we need to set the following in a Qt project file. First, the necessary sources, headers, and Qt modules need to be added into our project file. All the C++ code and project files are in the <code>filedialog</code> directory.</p>
<p>In <code>filedialog.pro</code>:</p>
<pre class="cpp">
TEMPLATE <span class="operator">=</span> lib
CONFIG <span class="operator">+</span><span class="operator">=</span> qt plugin
QT <span class="operator">+</span><span class="operator">=</span> qml
DESTDIR <span class="operator">+</span><span class="operator">=</span> <span class="operator">.</span><span class="operator">.</span><span class="operator">/</span>imports<span class="operator">/</span>FileDialog
OBJECTS_DIR <span class="operator">=</span> tmp
MOC_DIR <span class="operator">=</span> tmp
TARGET <span class="operator">=</span> filedialogplugin
HEADERS <span class="operator">+</span><span class="operator">=</span> \
directory<span class="operator">.</span>h \
file<span class="operator">.</span>h \
dialogPlugin<span class="operator">.</span>h
SOURCES <span class="operator">+</span><span class="operator">=</span> \
directory<span class="operator">.</span>cpp \
file<span class="operator">.</span>cpp \
dialogPlugin<span class="operator">.</span>cpp
</pre>
<p>In particular, we link the project with the <code>qml</code> module and configure it as a <code>plugin</code>, using a <code>lib</code> template. We shall put the compiled plugin into the parent's <code>imports/FileDialog</code> directory.</p>
<a name="registering-a-class-into-qml"></a>
<h4 >Registering a Class into QML</h4>
<p>In <code>dialogPlugin.h</code>:</p>
<pre class="cpp">
<span class="preprocessor">#include <QtQml/QQmlExtensionPlugin></span>
<span class="keyword">class</span> DialogPlugin : <span class="keyword">public</span> <span class="type"><a href="../qtqml/qqmlextensionplugin.html">QQmlExtensionPlugin</a></span>
{
Q_OBJECT
Q_PLUGIN_METADATA(IID <span class="string">"org.qt-project.QmlExtensionPlugin.FileDialog"</span>)
<span class="keyword">public</span>:
<span class="comment">// registerTypes is inherited from QQmlExtensionPlugin</span>
<span class="type">void</span> registerTypes(<span class="keyword">const</span> <span class="type">char</span> <span class="operator">*</span>uri);
};
</pre>
<p>We need to export the plugin using the <a href="plugins-howto.html">Q_PLUGIN_METADATA</a> macro. Note that in our <code>dialogPlugin.h</code> file, we have the <a href="../qtcore/qobject.html#Q_OBJECT">Q_OBJECT</a> macro at the top of our class. As well, we need to run <code>qmake</code> on the project file to generate the necessary meta-object code.</p>
<p>Our plugin class, <code>DialogPlugin</code>, is a subclass of <a href="../qtqml/qqmlextensionplugin.html">QQmlExtensionPlugin</a>. We need to implement the inherited function, <a href="../qtqml/qqmlextensionplugin.html#registerTypes">registerTypes()</a>.</p>
<p>In <code>DialogPlugin.cpp</code>:</p>
<pre class="cpp">
<span class="preprocessor">#include "dialogPlugin.h"</span>
<span class="preprocessor">#include "directory.h"</span>
<span class="preprocessor">#include "file.h"</span>
<span class="preprocessor">#include <QtQml></span>
<span class="type">void</span> DialogPlugin<span class="operator">::</span>registerTypes(<span class="keyword">const</span> <span class="type">char</span> <span class="operator">*</span>uri)
{
<span class="comment">// Register the class Directory into QML as a "Directory" type version 1.0</span>
<span class="comment">// @uri FileDialog</span>
qmlRegisterType<span class="operator"><</span>Directory<span class="operator">></span>(uri<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">"Directory"</span>);
qmlRegisterType<span class="operator"><</span>File<span class="operator">></span>(uri<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">"File"</span>);
}
</pre>
<p>The <code>registerTypes()</code> function registers our File and Directory classes into QML. This function needs the class name for its template, a major version number, a minor version number, and a name for our classes. A <code>// @uri <module identifier></code> comment allows Qt Creator to be aware of the registered types when editing QML files that import this module.</p>
<a name="creating-qml-properties-in-a-c-class"></a>
<h4 >Creating QML Properties in a C++ Class</h4>
<p>We can create QML types and properties using C++ and <a href="../qtcore/metaobjects.html">Qt's Meta-Object System</a>. We can implement properties using slots and signals, making Qt aware of these properties. These properties can then be used in QML.</p>
<p>For the text editor, we need to be able to load and save files. Typically, these features are contained in a file dialog. Fortunately, we can use <a href="../qtcore/qdir.html">QDir</a>, <a href="../qtcore/qfile.html">QFile</a>, and <a href="../qtcore/qtextstream.html">QTextStream</a> to implement directory reading and input/output streams.</p>
<pre class="cpp">
<span class="keyword">class</span> Directory : <span class="keyword">public</span> <span class="type"><a href="../qtcore/qobject.html">QObject</a></span> {
Q_OBJECT
Q_PROPERTY (<span class="type">int</span> filesCount READ filesCount CONSTANT)
Q_PROPERTY (<span class="type"><a href="../qtcore/qstring.html">QString</a></span> filename READ filename WRITE setFilename NOTIFY filenameChanged)
Q_PROPERTY (<span class="type"><a href="../qtcore/qstring.html">QString</a></span> fileContent READ fileContent WRITE setFileContent NOTIFY fileContentChanged)
Q_PROPERTY (<span class="type"><a href="../qtqml/qqmllistproperty.html">QQmlListProperty</a></span><span class="operator"><</span>File<span class="operator">></span> files READ files CONSTANT)
<span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
</pre>
<p>The <code>Directory</code> class uses Qt's Meta-Object System to register properties it needs to accomplish file handling. The <code>Directory</code> class is exported as a plugin and is useable in QML as the <code>Directory</code> type. Each of the listed properties using the <a href="../qtcore/qobject.html#Q_PROPERTY">Q_PROPERTY</a>() macro is a QML property.</p>
<p>The <a href="../qtcore/qobject.html#Q_PROPERTY">Q_PROPERTY</a> declares a property as well as its read and write functions into Qt's Meta-Object System. For example, the <code>filename</code> property, of type <a href="../qtcore/qstring.html">QString</a>, is readable using the <code>filename()</code> function and writable using the function <code>setFilename()</code>. Additionally, there is a signal associated to the filename property called <code>filenameChanged()</code>, which is emitted whenever the property changes. The read and write functions are declared as <code>public</code> in the header file.</p>
<p>Similarly, we have the other properties declared according to their uses. The <code>filesCount</code> property indicates the number of files in a directory. The filename property is set to the currently selected file's name and the loaded/saved file content is stored in <code>fileContent</code> property.</p>
<pre class="cpp">
Q_PROPERTY(<span class="type"><a href="../qtqml/qqmllistproperty.html">QQmlListProperty</a></span><span class="operator"><</span>File<span class="operator">></span> files READ files CONSTANT)
</pre>
<p>The <code>files</code> list property is a list of all the filtered files in a directory. The <code>Directory</code> class is implemented to filter out invalid text files; only files with a <code>.txt</code> extension are valid. Further, <a href="../qtcore/qlist.html">QList</a>s can be used in QML files by declaring them as a <a href="../qtqml/qqmllistproperty.html">QQmlListProperty</a> in C++. The templated object needs to inherit from a <a href="../qtcore/qobject.html">QObject</a>, therefore, the <code>File</code> class must also inherit from <a href="../qtcore/qobject.html">QObject</a>. In the <code>Directory</code> class, the list of <code>File</code> objects is stored in a <a href="../qtcore/qlist.html">QList</a> called <code>m_fileList</code>.</p>
<pre class="cpp">
<span class="keyword">class</span> File : <span class="keyword">public</span> <span class="type"><a href="../qtcore/qobject.html">QObject</a></span>{
Q_OBJECT
Q_PROPERTY(<span class="type"><a href="../qtcore/qstring.html">QString</a></span> name READ name WRITE setName NOTIFY nameChanged)
<span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
};
</pre>
<p>The properties can then be used in QML as part of the <code>Directory</code> object's properties. Note that we do not have to create an identifier <code>id</code> property in our C++ code.</p>
<pre class="cpp">
Directory {
id: directory
filesCount
filename
fileContent
files
files<span class="operator">[</span><span class="number">0</span><span class="operator">]</span><span class="operator">.</span>name
}
</pre>
<p>Because QML uses Javascript's syntax and structure, we can iterate through the list of files and retrieve its properties. To retrieve the first file's name property, we can call <code>files[0].name</code>.</p>
<p>Regular C++ functions are also accessible from QML. The file loading and saving functions are implemented in C++ and declared using the <a href="../qtcore/qobject.html#Q_INVOKABLE">Q_INVOKABLE</a> macro. Alternatively, we can declare the functions as a <code>slot</code> and the functions will be accessible from QML.</p>
<p>In <code>directory.h</code>:</p>
<pre class="cpp">
Q_INVOKABLE <span class="type">void</span> saveFile();
Q_INVOKABLE <span class="type">void</span> loadFile();
</pre>
<p>The <code>Directory</code> class also has to notify other objects whenever the directory contents change. This feature is performed using a <code>signal</code>. As previously mentioned, QML signals have a corresponding handler with their names prepended with <code>on</code>. The signal is called <code>directoryChanged</code> and it is emitted whenever there is a directory refresh. The refresh simply reloads the directory contents and updates the list of valid files in the directory. QML items can then be notified by attaching an action to the <code>onDirectoryChanged</code> signal handler.</p>
<p>The <code>list</code> properties need to be explored further. This is because list properties use callbacks to access and modify the list contents. The list property is of type <code>QQmlListProperty<File></code>. Whenever the list is accessed, the accessor function needs to return a <code>QQmlListProperty<File></code>. The template type, <code>File</code>, needs to be a <code>QObject</code> derivative. Further, to create the <code>QQmlListProperty</code>, the list's accessor and modifiers need to be passed to the constructor as function pointers. The list, a <code>QList</code> in our case, also needs to be a list of <code>File</code> pointers.</p>
<p>The constructor of <a href="../qtqml/qqmllistproperty.html">QQmlListProperty</a> is declared as follows:</p>
<pre class="cpp">
<span class="type"><a href="../qtqml/qqmllistproperty.html">QQmlListProperty</a></span> (<span class="type"><a href="../qtcore/qobject.html">QObject</a></span> <span class="operator">*</span>object<span class="operator">,</span> <span class="type">void</span> <span class="operator">*</span>data<span class="operator">,</span> AppendFunction append<span class="operator">,</span>
CountFunction count <span class="operator">=</span> <span class="number">0</span><span class="operator">,</span> AtFunction at <span class="operator">=</span> <span class="number">0</span><span class="operator">,</span> ClearFunction clear <span class="operator">=</span> <span class="number">0</span>);
</pre>
<p>It takes pointers to functions that will append the list, count the list, retrieve the item using an index, and empty the list. Only the <code>append</code> function is mandatory. Note that the function pointers must match the definition of <a href="../qtqml/qqmllistproperty.html#AppendFunction-typedef">AppendFunction</a>, <a href="../qtqml/qqmllistproperty.html#CountFunction-typedef">CountFunction</a>, <a href="../qtqml/qqmllistproperty.html#AtFunction-typedef">AtFunction</a>, or <a href="../qtqml/qqmllistproperty.html#ClearFunction-typedef">ClearFunction</a>.</p>
<p>The <code>Directory</code> class constructs a <a href="../qtqml/qqmllistproperty.html">QQmlListProperty</a> instance like this:</p>
<pre class="cpp">
<span class="type"><a href="../qtqml/qqmllistproperty.html">QQmlListProperty</a></span><span class="operator"><</span>File<span class="operator">></span>(<span class="keyword">this</span><span class="operator">,</span> <span class="operator">&</span>m_fileList<span class="operator">,</span> <span class="operator">&</span>appendFiles<span class="operator">,</span> <span class="operator">&</span>filesSize<span class="operator">,</span> <span class="operator">&</span>fileAt<span class="operator">,</span> <span class="operator">&</span>clearFilesPtr);
</pre>
<p>Where the parameters are pointers to following functions:</p>
<pre class="cpp">
<span class="type">void</span> appendFiles(<span class="type"><a href="../qtqml/qqmllistproperty.html">QQmlListProperty</a></span><span class="operator"><</span>File<span class="operator">></span> <span class="operator">*</span>property<span class="operator">,</span> File <span class="operator">*</span>file);
File<span class="operator">*</span> fileAt(<span class="type"><a href="../qtqml/qqmllistproperty.html">QQmlListProperty</a></span><span class="operator"><</span>File<span class="operator">></span> <span class="operator">*</span>property<span class="operator">,</span> <span class="type">int</span> index);
<span class="type">int</span> filesSize(<span class="type"><a href="../qtqml/qqmllistproperty.html">QQmlListProperty</a></span><span class="operator"><</span>File<span class="operator">></span> <span class="operator">*</span>property);
<span class="type">void</span> clearFilesPtr(<span class="type"><a href="../qtqml/qqmllistproperty.html">QQmlListProperty</a></span><span class="operator"><</span>File<span class="operator">></span> <span class="operator">*</span>property);
</pre>
<p>To simplify our file dialog, the <code>Directory</code> class filters out invalid text files, which are files that do not have a <code>.txt</code> extension. If a file name doesn't have the <code>.txt</code> extension, then it won't be seen in our file dialog. Also, the implementation makes sure that saved files have a <code>.txt</code> extension in the file name. <code>Directory</code> uses <a href="../qtcore/qtextstream.html">QTextStream</a> to read the file and to output the file contents to a file.</p>
<p>With our <code>Directory</code> object, we can retrieve the files as a list, know how many text files is in the application directory, get the file's name and content as a string, and be notified whenever there are changes in the directory contents.</p>
<p>To build the plugin, run <code>qmake</code> on the <code>filedialog.pro</code> project file, then run <code>make</code> to build and transfer the plugin to the <code>plugins</code> directory.</p>
<a name="importing-a-plugin-in-qml"></a>
<h4 >Importing a Plugin in QML</h4>
<p>The <code>qmlscene</code> tool imports files that are in the same directory as the application. We can also create a <code>qmldir</code> file containing the locations of content we wish to import. In this case, there is only the plugin, but other resources (QML types, JavaScript files) can be defined in a <code>qmldir</code> as well.</p>
<p>Contents of the <code>qmldir</code> file:</p>
<pre class="cpp">
module FileDialog
plugin filedialogplugin
</pre>
<p>The module we just created is called <code>FileDialog</code>, and it makes available a plugin called <code>filedialogplugin</code> that matches the <code>TARGET</code> field in the project file. Because we did not specify a path for the plugin, the QML engine expects to find it in the same directory as the <code>qmldir</code> file.</p>
<p>The QML types that are registered by our plugin can now be imported in QML:</p>
<pre class="cpp">
import FileDialog <span class="number">1.0</span>
Directory {
id: directory
}
<span class="operator">.</span><span class="operator">.</span><span class="operator">.</span>
</pre>
<a name="integrating-a-file-dialog-into-the-file-menu"></a>
<h4 >Integrating a File Dialog into the File Menu</h4>
<p>Our <code>FileMenu</code> needs to display the <code>FileDialog</code> object, containing a list of the text files in a directory thus allowing the user to select the file by clicking on the list. We also need to assign the save, load, and new buttons to their respective actions. The FileMenu contains an editable text input to allow the user to type a file name using the keyboard.</p>
<p>The <code>Directory</code> object is used in the <code>FileMenu.qml</code> file and it notifies the <code>FileDialog</code> object that the directory refreshed its contents. This notification is performed in the signal handler, <code>onDirectoryChanged</code>.</p>
<p>In <code>FileMenu.qml</code>:</p>
<pre class="cpp">
Directory {
id: directory
filename: textInput<span class="operator">.</span>text
onDirectoryChanged: fileDialog<span class="operator">.</span>notifyRefresh()
}
</pre>
<p>Keeping with the simplicity of our application, the file dialog will always be visible and will not display invalid text files, which do not have a <code>.txt</code> extension to their filenames.</p>
<p>In <code>FileDialog.qml</code>:</p>
<pre class="cpp">
signal notifyRefresh()
onNotifyRefresh: dirView<span class="operator">.</span>model <span class="operator">=</span> directory<span class="operator">.</span>files
</pre>
<p>The <code>FileDialog</code> object will display the contents of a directory by reading its list property called <code>files</code>. The files are used as the model of a <a href="../qtquick/qml-qtquick-gridview.html">GridView</a> object, which displays data items in a grid according to a delegate. The delegate handles the appearance of the model and our file dialog will simply create a grid with text centered in the middle. Clicking on the file name will result in the appearance of a rectangle to highlight the file name. The <code>FileDialog</code> is notified whenever the <code>notifyRefresh</code> signal is emitted, reloading the files in the directory.</p>
<p>In <code>FileMenu.qml</code>:</p>
<pre class="cpp">
Button {
id: newButton
label: <span class="string">"New"</span>
onButtonClick: {
textArea<span class="operator">.</span>textContent <span class="operator">=</span> <span class="string">""</span>
}
}
Button {
id: loadButton
label: <span class="string">"Load"</span>
onButtonClick: {
directory<span class="operator">.</span>filename <span class="operator">=</span> textInput<span class="operator">.</span>text
directory<span class="operator">.</span>loadFile()
textArea<span class="operator">.</span>textContent <span class="operator">=</span> directory<span class="operator">.</span>fileContent
}
}
Button {
id: saveButton
label: <span class="string">"Save"</span>
onButtonClick: {
directory<span class="operator">.</span>fileContent <span class="operator">=</span> textArea<span class="operator">.</span>textContent
directory<span class="operator">.</span>filename <span class="operator">=</span> textInput<span class="operator">.</span>text
directory<span class="operator">.</span>saveFile()
}
}
Button {
id: exitButton
label: <span class="string">"Exit"</span>
onButtonClick: {
<span class="type"><a href="../qtcore/qt.html">Qt</a></span><span class="operator">.</span>quit()
}
}
</pre>
<p>Our <code>FileMenu</code> can now connect to their respective actions. The <code>saveButton</code> will transfer the text from the <code>TextEdit</code> onto the directory's <code>fileContent</code> property, then copy its file name from the editable text input. Finally, the button calls the <code>saveFile()</code> function, saving the file. The <code>loadButton</code> has a similar execution. Also, the <code>New</code> action will empty the contents of the <code>TextEdit</code>.</p>
<p>Further, the <code>EditMenu</code> buttons are connected to the <code>TextEdit</code> functions to copy, paste, and select all the text in the text editor.</p>
<p class="centerAlign"><img src="images/qml-texteditor5_filemenu.png" alt="" /></p><a name="final-text-editor-application"></a>
<h3 >Final Text Editor Application</h3>
<p class="centerAlign"><img src="images/qml-texteditor5_newfile.png" alt="" /></p><p>The application can function as a simple text editor, able to accept text and save it into a file. It can also load a file and perform text manipulation.</p>
<a name="running-the-text-editor"></a>
<h2 id="running-the-text-editor">Running the Text Editor</h2>
<p>We need to build the file dialog C++ plugin before the text editor can run. To build it, enter the <code>filedialog</code> directory, then run <code>qmake</code> and compile using <code>make</code> or <code>nmake</code>, depending on your platform.</p>
<p>Run the text editor with <a href="qtquick-qmlscene.html">qmlscene</a>, passing the imports directory as a parameter so that the QML engine knows where to look for the module that imports our file dialog plugin:</p>
<pre class="cpp">
qmlscene <span class="operator">-</span>I <span class="operator">.</span><span class="operator">/</span>imports texteditor<span class="operator">.</span>qml
</pre>
<p>The complete source code is in <code>examples/quick/tutorials/gettingStartedQml</code> directory.</p>
</div>
<!-- @@@gettingstartedqml.html -->
</div>
</div>
</div>
</div>
</div>
<div class="footer">
<p>
<acronym title="Copyright">©</acronym> 2017 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>
|