diff options
author | David Boddie <dboddie@trolltech.com> | 2010-08-13 12:04:29 (GMT) |
---|---|---|
committer | David Boddie <dboddie@trolltech.com> | 2010-08-13 12:04:29 (GMT) |
commit | 7d805a6717692b540c02b8caace25a0b47c7f0d6 (patch) | |
tree | 3368927682df73ac437e8f321ba28e51d1463cd0 /doc/src/getting-started | |
parent | c6ed32dc7e9c8a566f376d1baa7e616a1019f9af (diff) | |
parent | 58d0e46dcc50a3cddabc177c9dfdfec5c66e932d (diff) | |
download | Qt-7d805a6717692b540c02b8caace25a0b47c7f0d6.zip Qt-7d805a6717692b540c02b8caace25a0b47c7f0d6.tar.gz Qt-7d805a6717692b540c02b8caace25a0b47c7f0d6.tar.bz2 |
Merge branch '4.7' of ../oslo-staging-2 into 4.7
Conflicts:
doc/src/declarative/declarativeui.qdoc
doc/src/examples/simpletreemodel.qdoc
doc/src/examples/spinboxdelegate.qdoc
doc/src/getting-started/demos.qdoc
doc/src/getting-started/gettingstartedqml.qdoc
doc/src/index.qdoc
src/declarative/qml/qdeclarativeimageprovider.cpp
Diffstat (limited to 'doc/src/getting-started')
-rw-r--r-- | doc/src/getting-started/demos.qdoc | 18 | ||||
-rw-r--r-- | doc/src/getting-started/examples.qdoc | 4 | ||||
-rw-r--r-- | doc/src/getting-started/gettingstartedqml.qdoc | 2045 | ||||
-rw-r--r-- | doc/src/getting-started/gettingstartedqt.qdoc | 6 |
4 files changed, 1040 insertions, 1033 deletions
diff --git a/doc/src/getting-started/demos.qdoc b/doc/src/getting-started/demos.qdoc index 94b19c3..719c861 100644 --- a/doc/src/getting-started/demos.qdoc +++ b/doc/src/getting-started/demos.qdoc @@ -46,7 +46,7 @@ \o \inlineimage qtdemo-small.png \o If you run the \l{Examples and Demos Launcher}, you'll see many of Qt's widgets in action. - + The \l{Qt Widget Gallery} also provides overviews of selected Qt widgets in each of the styles used on various supported platforms. \endtable @@ -134,15 +134,23 @@ \section1 QtWebKit \list - \o \l{Web Browser} demonstrates how Qt's \l{WebKit in Qt}{WebKit module} - can be used to implement a small Web browser. + \o \l{Web Browser} demonstrates how Qt's \l{QtWebKit} module can be used to + implement a small Web browser. + \endlist + + \section1 Multimedia + + \list + \o \l{demos/spectrum}{Spectrum Analyser} shows how the \l{QtMultimedia} + module can be used to manipulate audio as it is played. \endlist \section1 Phonon \list - \o \l{demos/qmediaplayer}{Media Player} demonstrates how the \l{Phonon Module} can be - used to implement a basic media player application. + \o \l{demos/qmediaplayer}{Media Player} demonstrates how the + \l{Phonon Module}{Phonon module} can be used to implement a basic media player + application. \endlist \note The Phonon demos are currently not available for the MinGW platform. diff --git a/doc/src/getting-started/examples.qdoc b/doc/src/getting-started/examples.qdoc index 1bf86e5..708c44e 100644 --- a/doc/src/getting-started/examples.qdoc +++ b/doc/src/getting-started/examples.qdoc @@ -343,8 +343,8 @@ /*! \page examples-draganddrop.html \ingroup all-examples - \title Drag & Drop Examples - \brief How to access your platform's native darg & drop functionality + \title Drag and Drop Examples + \brief How to access your platform's native drag and drop functionality. \image draganddrop-examples.png diff --git a/doc/src/getting-started/gettingstartedqml.qdoc b/doc/src/getting-started/gettingstartedqml.qdoc index 6c85776..885e6ce 100644 --- a/doc/src/getting-started/gettingstartedqml.qdoc +++ b/doc/src/getting-started/gettingstartedqml.qdoc @@ -26,1026 +26,1025 @@ ****************************************************************************/ /*! - \page qml-textEditor.html - - \title Getting Started programming with QML - \ingroup gettingStarted - - Welcome to the world of QML - the declarative UI language. In this Getting - Started guide, we create a simple text editor application using QML. - After reading this guide, you should be ready to start developing your own - applications using QML and Qt C++. - - \example tutorials/gettingStarted/gsQml - - \section1 QML to Build User Interfaces - - Here we are building is a simple text editor that con load, save, - and perform some text manipulation. This guide consists of two parts. The - first part involves designing the application layout and behaviors using - declarative language in QML. For the second part, file loading and saving is - implemented using Qt C++. - Using \l {The Meta-Object System}{Qt's Meta-Object System}, we can expose C++ - functions as properties that QML elements can use. By utilizing QML and Qt C++, - we can efficiently decouple the interface logic from the application logic. - - \image qml-texteditor5_editmenu.png - - To run the QML example code, we merely provide the included \l{QML Viewer}{qmlviewer} - tool with the QML file as the argument. The C++ portion of this tutorial assumes - that the reader possesses basic knowledge of Qt's compilation procedures. - - \omit - Tutorial chapters: - \list 1 - \o \l {Defining a Button and a Menu}{Defining a Button and a Menu} - \o \l {Implementing a Menu Bar}{Implementing a Menu Bar} - \o \l {Building a Text Editor}{Building a Text Editor} - \o \l {Decorating the Text Editor}{Decorating the Text Editor} - \o \l {Extending QML using Qt C++}{Extending QML using Qt C++} - \endlist - \endomit - - \section1 Defining a Button and a Menu - - \section2 Basic Component - a Button - - 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. - - In QML, the basic visual item is the \l {Rectangle}{Rectangle} element. The - \c Rectangle element has properties to control the element's appearance and location. - - \code - import Qt 4.7 - Rectangle { - id: simplebutton - color: "grey" - width: 150; height: 75 - - Text{ - id: buttonLabel - anchors.centerIn: parent - text: "button label" - } - } - \endcode - - First, the \c { import Qt 4.7 } allows the qmlviewer tool to import the QML elements - 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. - - This simple rectangle has a unique identifier, \c simplebutton, which is bound to the - id property. The \c Rectangle element's properties are bound to values by listing the - property, followed by a colon, then the value. In the code sample, the color \c grey - is bound to the the Rectangle's \c color property. Similarly, we bind the \c width - and \c height of the Rectangle. - - The \l {Text}{Text} element is a non-editable text field. We name this \c Text element - \c buttonLabel. To set the string content of the Text field, we bind a value to the - \c text property. The label is contained within the Rectangle and in order to center - it in the middle, we assign the \c anchors of the Text element to its parent, which - is called \c simplebutton. Anchors may bind to other items' anchors, allowing layout - assignments simpler. - - We save this code as \c SimpleButton.qml. Running qmlviewer with the file as the - argument will display the grey rectangle with a text label. - - \image qml-texteditor1_simplebutton.png - - To implement the button click functionality, we can use QML's event handling. QML's event - handling is very similar to \l {Signals & Slots}{Qt's signal and slot} mechanism. Signals - are emitted and the connected slot is called. - - \code - Rectangle{ - id:simplebutton - ... - - MouseArea{ - id: buttonMouseArea - - anchors.fill: parent //anchor all sides of the mouse area to the rectangle's anchors - //onClicked handles valid mouse button clicks - onClicked: console.log(buttonLabel.text + " clicked" ) - } - } - \endcode - - We include a \l{MouseArea} element in our simplebutton. \c MouseArea elements describe - the interactive area where mouse movements are detected. For our button, we anchor the - whole MouseArea to its parent, which is \c simplebutton. The \c anchors.fill syntax is - one way of accessing a specific property called \c fill inside a group of properties - called \c anchors. QML uses \l {Anchor-based Layout in QML}{anchor based layouts} where - items can anchor to another item, creating robust layouts. - - The \c MouseArea has many signal handlers that are called during mouse movements within - the specfied \c MouseArea boundaries. One of them is \c onClicked 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, \c console.log() outputs text - whenever the mouse area is clicked. The function \c console.log() is a useful tool for - debugging purposes and for outputting text. - - The code in \c SimpleButton.qml is sufficient to display a button on the screen and - output text whenever it is clicked with a mouse. - - \code - Rectangle { - id:Button - ... - - property color buttonColor: "lightblue" - property color onHoverColor: "gold" - property color borderColor: "white" - - signal buttonClick() - onButtonClick: { - console.log(buttonLabel.text + " clicked" ) - } - - MouseArea{ - onClicked: buttonClick() - hoverEnabled: true - onEntered: parent.border.color = onHoverColor - onExited: parent.border.color = borderColor - } - - //determines the color of the button by using the conditional operator - color: buttonMouseArea.pressed ? Qt.darker(buttonColor, 1.5) : buttonColor - } - \endcode - - A fully functioning button is in \c Button.qml. 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. - - Custom properties are declared using the \c {property type name} syntax. In the - code, the property \c buttonColor, of type \c color, is declared and bound to - the value \c{"lightblue"}. The \c buttonColor is later used in a conditional - operation to determine the buttons's fill color. Note that property value - assignment is possible using the \c= equals sign, in addition to value binding - using the \c : colon character. Custom properties allow internal items to be - accessible outside of the Rectangle's scope. There are basic - \l{QML Basic Types}{QML types} such as \c int, \c string, \c real, as well as - a type called \c variant. - - By binding the \c onEntered and \c onExited 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. - - A \c buttonClick() signal is declared in \c Button.qml by placing the \c signal - keyword in front of the signal name. All signals have their handlers automatically - created, their names starting with \c on. As a result, the \c onButtonClick is - \c buttonClick's handler. The \c onButtonClick is then assigned an action to - perform. In our button example, the \c onClicked mouse handler will simply call - \c onButtonClick, which displays a text. The \c onButtonClick enables outside - objects to access the \c {Button}'s mouse area easily. For example, items may - have more than one \c MouseArea declarations and a \c buttonClick signal can - make the distinction between the several \c MouseArea signal handlers better. - - We now have the basic knowledge to implement items in QML that can handle - basic mouse movements. We created a \c Text label inside a \c Rectangle, - customized its properties, and implemented behaviors that respond to mouse - movements. This idea of creating elements within elements is repeated - throughout the text editor application. - - 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. - - \image qml-texteditor1_button.png - - \section2 Creating a Menu Page - - Up to this stage, we covered how to create elements and assign behaviors inside - a single QML file. In this section, we will cover how to import QML elements and how - to reuse some of the created components to build other components. - - 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 - \c FileMenu.qml. - - \code - import Qt 4.7 \\import the main Qt QML module - import “folderName” \\import the contents of the folder - import “Button.qml” \\import a QML file - import “NewButton.qml” as ButtonModule \\import a QML file and give it a name - import “script.js” as Script \\import a Javascript file and name it as Script - \endcode - - To use the \c Button element in \c FileMenu.qml, we need to import \c Button.qml. - The syntax shown above, shows how to use the \c import keyword. However, the - \c {import Button.qml} is not necessary; qmlviewer will import all the contents - of the current directory. We can directly create a \c Button element by declaring - \c Button{}, similar to a \c Rectangle{} declaration. - - \code - In FileMenu.qml: - - Row{ - anchors.centerIn: parent - spacing: parent.width/6 - - Button{ - id: loadButton - buttonColor: "lightgrey" - label: "Load" - } - Button{ - buttonColor: "grey" - id: saveButton - label: "Save" - } - Button{ - id: exitButton - label: "Exit" - buttonColor: "darkgrey" - - onButtonClick: Qt.quit() - } - } - \endcode - - In \c FileMenu.qml, we declare three \c Button elements. They are declared - inside a \l {Row}{Row} element, a positioner that will position its children - along a vertical row. The \c Button declaration resides in Button.qml, - which is the same as the \c Button.qml we used in the previous section. - New property bindings can be declared within the newly created buttons, - effectively overwriting the properties set in \c Button.qml. The button - called \c exitButton will quit and close the window when it is clicked. - Note that the signal handler \c onButtonClick in \c Button.qml will be - called in addition to the \c onButtonClick handler in \c exitButton. - - \image qml-texteditor1_filemenu.png - - The \c Row declaration is declared in a \c Rectangle, 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. - - The declaration of the edit menu is very similar at this stage. The menu has - buttons that have the labels: \c Copy, \c Paste, and \c {Select All}. - - \image qml-texteditor1_editmenu.png - - 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. - - \section1 Implementing a Menu Bar - - 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. - - \section2 Using Data Models and Views - - QML has different \l {Data Models}{data views} that display - \l {Data Models}{data models}. 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 \c VisualItemModel. The \l{VisualItemModel}{\c VisualItemModel} - element contains items that already have views such as \c Rectangle elements - and imported UI elements. Other model types such as the \l {ListModel}{\c ListModel} - element need a delegate to display their data. - - We declare two visual items in the \c menuListModel, the \c FileMenu and the - \c EditMenu. We customize the two menus and display them using a - \l {ListView}{ListView}. The \c MenuBar.qml file contains the QML declarations - and a simple edit menu is defined in \c EditMenu.qml. - - \code - VisualItemModel{ - id: menuListModel - FileMenu{ - width: menuListView.width - height: menuBar.height - color: fileColor - } - EditMenu{ - color: editColor - width: menuListView.width - height: menuBar.height - } - } - \endcode - - The \l {ListView}{ListView} element will display a model according to a delegate. - The delegate may declare the model items to display in a \c Row element or display - the items in a grid. Our \c menuListModel already has visible items, therefore, - we do not need to declare a delegate. - - \code - ListView{ - id: menuListView - - //Anchors are set to react to window anchors - anchors.fill:parent - anchors.bottom: parent.bottom - width:parent.width - height: parent.height - - //the model contains the data - model: menuListModel - - //control the movement of the menu switching - snapMode: ListView.SnapOneItem - orientation: ListView.Horizontal - boundsBehavior: Flickable.StopAtBounds - flickDeceleration: 5000 - highlightFollowsCurrentItem: true - highlightMoveDuration:240 - highlightRangeMode: ListView.StrictlyEnforceRange - } - \endcode - - Additionally, \c ListView inherits from \l {Flickable}{\c Flickable}, making - the list respond to mouse drags and other gestures. The last portion of the - code above sets \c Flickable properties to create the desired flicking movement - to our view. In particular,the property \c highlightMoveDuration changes the - duration of the flick transition. A higher \c highlightMoveDuration value - results in slower menu switching. - - The \c ListView maintains the model items through an \c index and each visual - item in the model is accessible through the \c index, in the order of the - declaration. Changing the \c currentIndex effectively changes the highlighted - item in the \c ListView. The header of our menu bar exemplify this effect. - There are two buttons in a row, both changing the current menu when clicked. - The \c fileButton changes the current menu to the file menu when clicked, - the \c index being \c 0 because \c FileMenu is declared first in the - \c menuListModel. Similarly, the \c editButton will change the current - menu to the \c EditMenu when clicked. - - The \c labelList rectangle has \c z value of \c 1, denoting that it is displayed - at the front of the menu bar. Items with higher \c z values are displayed in front - of items with lower \c z values. The default \c z value is \c 0. - - \code - Rectangle{ - id: labelList - ... - z: 1 - Row{ - anchors.centerIn: parent - spacing:40 - Button{ - label: "File" - id: fileButton - ... - onButtonClick: menuListView.currentIndex = 0 - } - Button{ - id: editButton - label: "Edit" - ... - onButtonClick: menuListView.currentIndex = 1 - } - } - } - \endcode - - 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. - - \image qml-texteditor2_menubar.png - - \section1 Building a Text Editor - - \section2 Declaring a TextArea - - Our text editor is not a text editor if it didn't contain an editable text area. - QML's \l {TextEdit}{TextEdit} element allows the declaration of a multi-line - editable text area. \l {TextEdit}{TextEdit} is different from a \l {Text}{Text} - element, which doesn't allow the user to directly edit the text. - - \code - TextEdit{ - id: textEditor - anchors.fill:parent - width:parent.width; height:parent.height - color:"midnightblue" - focus: true - - wrapMode: TextEdit.Wrap - - onCursorRectangleChanged: flickArea.ensureVisible(cursorRectangle) - } - \endcode - - The editor has its font color property set and set to wrap the text. The - \c TextEdit area is inside a flickable area that will scroll the text if the - text cursor is outside the visible area. The function \c ensureVisible() 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. - - \code - function ensureVisible(r){ - if (contentX >= r.x) - contentX = r.x; - else if (contentX+width <= r.x+r.width) - contentX = r.x+r.width-width; - if (contentY >= r.y) - contentY = r.y; - else if (contentY+height <= r.y+r.height) - contentY = r.y+r.height-height; - } - \endcode - - \section1 Combining Components for the Text Editor - - 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 elements. - - \code - Rectangle{ - - id: screen - width: 1000; height: 1000 - - //the screen is partitioned into the MenuBar and TextArea. 1/3 of the screen is assigned to the MenuBar - property int partition: height/3 - - MenuBar{ - id:menuBar - height: partition - width:parent.width - z: 1 - } - - TextArea{ - id:textArea - anchors.bottom:parent.bottom - y: partition - color: "white" - height: partition*2 - width:parent.width - } - } - \endcode - - By importing reusable components, our \c TextEditor 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. - - \image qml-texteditor3_texteditor.png - - \section1 Decorating the Text Editor - \section2 Implementing a Drawer Interface - - 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. - - 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 - \c drawer, as well as the application, has two sates: the "drawer is open" state and - the "drawer is closed" state. The \c drawer item is a strip of rectangle with a small - height. There is a nested \l {Image}{Image} element declaring that an arrow icon will - be centered inside the drawer. The drawer assigns a state to the whole application, - with the identifier \c screen, whenever a user clicks the mouse area. - - \code - Rectangle{ - id:drawer - height:15 - - Image{ - id: arrowIcon - source: "images/arrow.png" - anchors.horizontalCenter: parent.horizontalCenter - } - - MouseArea{ - id: drawerMouseArea - anchors.fill:parent - onClicked:{ - if (screen.state == "DRAWER_CLOSED"){ - screen.state = "DRAWER_OPEN" - } - else if (screen.state == "DRAWER_OPEN"){ - screen.state = "DRAWER_CLOSED" - } - } - ... - } - } - \endcode - - A state is simply a collection of configurations and it is declared in a - \l{State}{State} element. A list of states can be listed and bound to the - \c states property. In our application, the two states are called - \c DRAWER_CLOSED and \c DRAWER_OPEN. Item configurations are declared in - \l {PropertyChanges}{PropertyChanges} elements. In the \c DRAWER_OPEN state, - there are four items that will receive property changes. The first target, - \c menuBar, will change its \c y property to \c 0. Similarly, the \c textArea - will lower to a new position when the state is \c DRAWER_OPEN. The \c textArea, - the \c drawer, and the drawer's icon will undergo property changes to meet the - current state. - - \code - - states:[ - State{ - name: "DRAWER_OPEN" - PropertyChanges { target: menuBar; y:0} - PropertyChanges { target: textArea; y: partition + drawer.height} - PropertyChanges { target: drawer; y: partition} - PropertyChanges { target: arrowIcon; rotation: 180} - }, - State{ - name: "DRAWER_CLOSED" - PropertyChanges { target: menuBar; y:-partition} - PropertyChanges { target: textArea; y: drawer.height; height: screen.height - drawer.height} - PropertyChanges { target: drawer; y: 0} - PropertyChanges { target: arrowIcon; rotation: 0} - } - - ] - - \endcode - - State changes are abrupt and needs smoother transitions. Transitions between states - are defined using the \l {Transition}{Transition} element, which can then bind to - the item's \c transitions property. Our text editor has a state transition whenever - the state changes to either \c DRAWER_OPEN or \c DRAWER_CLOSED. Importantly, the - transition needs a \c from and a \c to state but for our transitions, we can use - the wild card \c * symbol to denote that the transition applies to all state changes. - - During transitions, we can assign animations to the property changes. Our - \c menuBar switches position from \c {y:0} to \c {y:-partition} and we can animate - this transition using the \l {NumberAnimation}{NumberAnimation} element. 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 - \l{PropertyAnimation::easing.type}{Easing.OutQuint}, which slows the movement near - the end of the animation. Pleae read \l {qdeclarativeanimation.html}{QML's Animation} - article. - - \code - transitions: [ - Transition{ - to: "*" - NumberAnimation { target: textArea; properties: "y, height"; duration: 100; easing.type: Easing.OutQuint } - NumberAnimation { target: menuBar; properties: "y"; duration: 100;easing.type: Easing.OutQuint } - NumberAnimation { target: drawer; properties: "y"; duration: 100;easing.type: Easing.OutQuint } - } - ] - \endcode - - Another way of animating property changes is by declaring a \l {Behavior}{Behavior} - element. A transition only works during state changes and \c Behavior can set an - animation for a general property change. In the text editor, the arrow has a - \c NumberAnimation animating its \c rotation property whenever the property changes. - - \code - In TextEditor.qml: - - Behavior{ - NumberAnimation{property: "rotation";easing.type: Easing.OutExpo } - } - \endcode - - Going back to our components with knowledge of states and animations, we can improve - the appearances of the components. In \c Button.qml, we can add \c color and \c scale - property changes when the button is clicked. Color types are animated using - \l {ColorAnimation}{ColorAnimation} and numbers are animated using - \l {NumberAnimation}{NumberAnimation}. The \c {on propertyName} syntax displayed below - is helpful when targeting a single property. - - \code - In Button.qml: - ... - - color: buttonMouseArea.pressed ? Qt.darker(buttonColor, 1.5) : buttonColor - Behavior on color { ColorAnimation{ duration: 55} } - - scale: buttonMouseArea.pressed ? 1.1 : 1.00 - Behavior on scale { NumberAnimation{ duration: 55} } - \endcode - - Additionally, we can enhance the appearances of our QML components by adding color - effects such as gradients and opacity effects. Declaring a \l {Gradient}{Gradient} - element will override the \c color property of the element. You may declare a color - in the gradient using the \l {GradientStop}{GradientStop} element. The gradient is - positioned using a scale, between \c 0.0 and \c 1.0. - - \code - In MenuBar.qml - gradient: Gradient { - GradientStop { position: 0.0; color: "#8C8F8C" } - GradientStop { position: 0.17; color: "#6A6D6A" } - GradientStop { position: 0.98;color: "#3F3F3F" } - GradientStop { position: 1.0; color: "#0e1B20" } - } - \endcode - - This gradient is used by the menu bar to display a gradient simulating depth. - The first color starts at \c 0.0 and the last color is at \c 1.0. - - - \section2 Where to Go from Here - - 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. - - \image qml-texteditor4_texteditor.png - - \section1 Extending QML using Qt C++ - - 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 the - \l {Using QML in C++ Applications}{Qt's Declarative} classes and display the QML - elements using a Graphics Scene. Alternatively, we can export our C++ code into - a plugin that the \l {QML Viewer}{qmlviewer} tool can read. For our application, - we shall implement the load and save functions in C++ and export it as a plugin. - This way, we only need to load the QML file directly instead of running an executable. - - \section2 Exposing C++ Classes to QML - - We will be implementing file loading and saving using Qt and C++. C++ classes - and functions can be used in QML by registering them. The class also needs to be - compiled as a Qt plugin and the QML file will need to know where the plugin is located. - - For our application, we need to create the following items: - \list 1 - \o \c Directory class that will handle directory related operations - \o \c File class which is a QObject, simulating the list of files in a directory - \o plugin class that will register the class to the QML context - \o Qt project file that will compile the plugin - \o A \c qmldir file telling the qmlviewer tool where to find the plugin - \endlist - - \section2 Building a Qt Plugin - - 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 \c filedialog - directory. - - \code - In cppPlugins.pro: - - TEMPLATE = lib - CONFIG += qt plugin - QT += declarative - - DESTDIR += ../plugins - OBJECTS_DIR = tmp - MOC_DIR = tmp - - TARGET = FileDialog - - HEADERS += directory.h \ - file.h \ - dialogPlugin.h - - SOURCES += directory.cpp \ - file.cpp \ - dialogPlugin.cpp - \endcode - - In particular, we compile Qt with the \c declarative module and configure it as a - \c plugin, needing a \c lib template. We shall put the compiled plugin into the - parent's \c plugins directory. - - - \section2 Registering a Class into QML - - \code - In dialogPlugin.h: - - #include <QtDeclarative/QDeclarativeExtensionPlugin> - - class DialogPlugin : public QDeclarativeExtensionPlugin - { - Q_OBJECT - - public: - void registerTypes(const char *uri); - - }; - - \endcode - - Our plugin class, \c DialogPlugin is a subclass of \l - {QDeclarativeExtensionPlugin}{QDeclarativeExtensionPlugin}. We - need to implement the inherited function, \l - {QDeclarativeExtensionPlugin::registerTypes()}{registerTypes}. The - \c dialogPlugin.cpp file looks like this: - - \code - DialogPlugin.cpp: - - #include "dialogPlugin.h" - #include "directory.h" - #include "file.h" - #include <QtDeclarative/qdeclarative.h> - - void DialogPlugin::registerTypes(const char *uri){ - - qmlRegisterType<Directory>(uri, 1, 0, "Directory"); - qmlRegisterType<File>(uri, 1, 0,"File"); - } - - Q_EXPORT_PLUGIN2(FileDialog, DialogPlugin); - \endcode - - The \l {QDeclarativeExtensionPlugin::registerTypes()}{registerTypes} - 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. - - We need to export the plugin using the \l {Q_EXPORT_PLUGIN2}{Q_EXPORT_PLUGIN2} - macro. Note that in our \c dialogPlugin.h file, we have the \l {Q_OBJECT}{Q_OBJECT} - macro at the top of our class. As well, we need to run \c qmake on the project - file to generate the necessary meta-object code. - - - \section2 Creating QML Properties in a C++ class - - We can create QML elements and properties using C++ and - \l {The Meta-Object System}{Qt's Meta-Object System}. We can implement - properties using slots and signals, making Qt aware of these properties. - These properties can then be used in QML. - - 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 - \l {QDir}{QDir}, \l {QFile}{QFile}, and \l {QTextStream}{QTextStream} to - implement directory reading and input/output streams. - - \code - class Directory : public QObject{ - - Q_OBJECT - - Q_PROPERTY(int filesCount READ filesCount CONSTANT) - Q_PROPERTY(QString filename READ filename WRITE setFilename NOTIFY filenameChanged) - Q_PROPERTY(QString fileContent READ fileContent WRITE setFileContent NOTIFY fileContentChanged) - Q_PROPERTY(QDeclarativeListProperty<File> files READ files CONSTANT ) - - ... - \endcode - - The \c Directory class uses Qt's Meta-Object System to register properties it - needs to accomplish file handling. The \c Directory class is exported as a plugin - and is useable in QML as the \c Directory element. Each of the listed properties - using the \l {Q_PROPERTY()}{Q_PROPERTY} macro is a QML property. - - The \l {Q_PROPERTY()} {Q_PROPERTY} declares a property as well as its read and - write functions into Qt's Meta-Object System. For example, the \c filename - property, of type \l {QString}{QString}, is readable using the \c filename() - function and writable using the function \c setFilename(). Additionally, there - is a signal associated to the filename property called \c filenameChanged(), - which is emitted whenever the property changes. The read and write functions - are declared as \c public in the header file. - - Similarly, we have the other properties declared according to their uses. The - \c filesCount 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 \c fileContent property. - - \code - Q_PROPERTY(QDeclarativeListProperty<File> files READ files CONSTANT ) - \endcode - - The \c files list property is a list of all the filtered files in a directory. - The \c Directory class is implemented to filter out invalid text files; only - files with a \c .txt extension are valid. Further, \l {QList}{QLists} can be - used in QML files by declaring them as a \c QDeclarativeListProperty in C++. - The templated object needs to inherit from a \l {QObject}{QObject}, therefore, - the \c File class must also inherit from \c QObject. In the \c Directory class, - the list of \c File objects is stored in a \c QList called \c m_fileList. - - \code - class File : public QObject{ - - Q_OBJECT - Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) - - ... - }; - \endcode - - The properties can then be used in QML as part of the \c Directory element's - properties. Note that we do not have to create an identifier \c id property - in our C++ code. - - \code - Directory{ - id: directory - - filesCount - filename - fileContent - files - - files[0].name - } - - \endcode - - 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 \c { files[0].name }. - - Regular C++ functions are also accessible from QML. The file loading and saving - functions are implemented in C++ and declared using the - \l {Q_INVOKABLE}{Q_INVOKABLE} macro. Alternatively, we can declare the functions - as a \c slot and the functions will be accessible from QML. - - \code - In Directory.h: - - Q_INVOKABLE void saveFile(); - Q_INVOKABLE void loadFile(); - \endcode - - The \c Directory class also has to notify other objects whenever the directory - contents change. This feature is performed using a \c signal. As previously - mentioned, QML signals have a corresponding handler with their names prepended - with \c on. The signal is called \c directoryChanged 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 \c onDirectoryChanged signal handler. - - The \c list 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 \c QDeclarativeListProperty<File>. Whenever the list - is accessed, the accessor function needs to return a - \c QDeclarativeListProperty<File>. The template type, \c File, needs to be a - \c QObject derivative. Further, to create the - \l {QDeclarativeListProperty}{QDeclarativeListProperty}, the list's accessor - and modifiers need to be passed to the consructor as function pointers. The list, - a \c QList in our case, also needs to be a list of \c File pointers. - - The constructor of \l {QDeclarativeListProperty}{QDeclarativeListProperty} - constructor and the \c Directory implementation: - \code - QDeclarativeListProperty ( QObject * object, void * data, AppendFunction append, CountFunction count = 0, AtFunction at = 0, ClearFunction clear = 0 ) - QDeclarativeListProperty<File>( this, &m_fileList, &appendFiles, &filesSize, &fileAt, &clearFilesPtr ); - \endcode - - The constructor passes pointers to functions that will append the list, count - the list, retrieve the item using an index, and empty the list. Only the append - function is mandatory. Note that the function pointers must match the definition - of \l {QDeclarativeListProperty::AppendFunction}{AppendFunction}, - \l {QDeclarativeListProperty::CountFunction}{CountFunction}, - \l {QDeclarativeListProperty::AtFunction}{AtFunction}, or - \l {QDeclarativeListProperty::ClearFunction}{ClearFunction}. - - \code - void appendFiles(QDeclarativeListProperty<File> * property, File * file) - File* fileAt(QDeclarativeListProperty<File> * property, int index) - int filesSize(QDeclarativeListProperty<File> * property) - void clearFilesPtr(QDeclarativeListProperty<File> *property) - \endcode - - To simplify our file dialog, the \c Directory class filters out invalid text - files, which are files that do not have a \c .txt extension. If a file name - doesn't have the \c .txt extension, then it won't be seen in our file dialog. - Also, the implementation makes sure that saved files have a \c .txt extension in - the file name. \c Directory uses \l {QTextStream}{QTextStream} to read the file - and to output the file contents to a file. - - With our \c Directory element, 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. - - To build the plugin, run \c qmake on the \c cppPlugins.pro project file, then run - \c make to build and transfer the plugin to the \c plugins directory. - - - \section2 Importing a Plugin in QML - - The qmlviewer tool imports files that are in the same directory as the - application. We can also create a \c qmldir file containing the locations of - QML files we wish to import. The \c qmldir file can also store locations of - plugins and other resources. - - \code - In qmldir: - - Button ./Button.qml - FileDialog ./FileDialog.qml - TextArea ./TextArea.qml - TextEditor ./TextEditor.qml - EditMenu ./EditMenu.qml - - plugin FileDialog plugins - \endcode - - The plugin we just created is called \c FileDialog, as indicated by the - \c TARGET field in the project file. The compiled plugin is in the \c plugins directory. - - - \section2 Integrating a File Dialog into the File Menu - - Our \c FileMenu needs to display the \c FileDialog element, 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. - - The \c Directory element is used in the \c FileMenu.qml file and it notifies the - \c FileDialog element that the directory refreshed its contents. This notification - is performed in the signal handler, \c onDirectoryChanged. - - \code - In FileMenu.qml: - - Directory{ - id:directory - filename: textInput.text - onDirectoryChanged: fileDialog.notifyRefresh() - } - \endcode - - 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 \c .txt - extension to their filenames. - - \code - In FileDialog.qml: - - signal notifyRefresh() - onNotifyRefresh: dirView.model = directory.files - \endcode - - The \c FileDialog element will display the contents of a directory by reading its - list property called \c files. The files are used as the model of a - \l {GridView}{GridView} element, 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 \c FileDialog is notified whenever the \c notifyRefresh signal is emitted, - reloading the files in the directory. - - \code - In FileMenu.qml: - - Button{ - id: newButton - label: "New" - onButtonClick:{ - textArea.textContent = "" - } - } - Button{ - id: loadButton - label: "Load" - onButtonClick:{ - directory.filename = textInput.text - directory.loadFile() - textArea.textContent = directory.fileContent - } - } - Button{ - id: saveButton - label: "Save" - onButtonClick:{ - directory.fileContent = textArea.textContent - directory.filename = textInput.text - directory.saveFile() - } - } - Button{ - id: exitButton - label: "Exit" - onButtonClick:{ - Qt.quit() - } - } - \endcode - - Our \c FileMenu can now connect to their respective actions. The \c saveButton - will transfer the text from the \c TextEdit onto the directory's \c fileContent - property, then copy its file name from the editable text input. Finally, the button - calls the \c saveFile() function, saving the file. The \c sloadButton has a similar - execution. Also, the \c New action will empty the contents of the \c TextEdit. - - Further, the \c EditMenu buttons are connected to the \c TextEdit functions to copy, - paste, and select all the text in the text editor. - - \image qml-texteditor5_filemenu.png - - \section1 Text Editor Completion - - \image qml-texteditor5_newfile.png - - The application can function as a simple text editor, able to accept text - and save the text into a file. The text editor can also load from a file and - perform text manipulation. - - -*/
\ No newline at end of file + \page gettingstartedqml.html + \title Getting Started Programming with QML + \ingroup gettingStarted + + Welcome to the world of QML, 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++. + + \section1 QML to Build User Interfaces + + 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 + \l {The Meta-Object System}{Qt's Meta-Object System}, we can expose C++ functions + as properties that QML elements can use. Utilizing QML and Qt C++, we can + efficiently decouple the interface logic from the application logic. + + \image qml-texteditor5_editmenu.png + + To run the QML example code, merely provide the included \l{QML Viewer}{qmlviewer} + tool with the QML file as the argument. The C++ portion of this tutorial assumes + that the reader possesses basic knowledge of Qt's compilation procedures. + + Tutorial chapters: + \list 1 + \o \l {Defining a Button and a Menu}{Defining a Button and a Menu} + \o \l {Implementing a Menu Bar}{Implementing a Menu Bar} + \o \l {Building a Text Editor}{Building a Text Editor} + \o \l {Decorating the Text Editor}{Decorating the Text Editor} + \o \l {Extending QML using Qt C++}{Extending QML using Qt C++} + \endlist + + \section1 Defining a Button and a Menu + + \section2 Basic Component - a Button + + 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. + + In QML, the basic visual item is the \l {Rectangle}{Rectangle} element. The + \c Rectangle element has properties to control the element's appearance and location. + + \code + import Qt 4.7 + Rectangle { + id: simplebutton + color: "grey" + width: 150; height: 75 + + Text{ + id: buttonLabel + anchors.centerIn: parent + text: "button label" + } + } + \endcode + + First, the \c { import Qt 4.7 } allows the qmlviewer tool to import the QML elements + 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. + + This simple rectangle has a unique identifier, \c simplebutton, which is bound to the + id property. The \c Rectangle element's properties are bound to values by listing the + property, followed by a colon, then the value. In the code sample, the color \c grey + is bound to the the Rectangle's \c color property. Similarly, we bind the \c width + and \c height of the Rectangle. + + The \l {Text}{Text} element is a non-editable text field. We name this \c Text element + \c buttonLabel. To set the string content of the Text field, we bind a value to the + \c text property. The label is contained within the Rectangle and in order to center + it in the middle, we assign the \c anchors of the Text element to its parent, which + is called \c simplebutton. Anchors may bind to other items' anchors, allowing layout + assignments simpler. + + We shall save this code as \c SimpleButton.qml. Running qmlviewer with the file as the + argument will display the grey rectangle with a text label. + + \image qml-texteditor1_simplebutton.png + + To implement the button click functionality, we can use QML's event handling. QML's event + handling is very similar to \l {Signals & Slots}{Qt's signal and slot} mechanism. Signals + are emitted and the connected slot is called. + + \code + Rectangle{ + id:simplebutton + ... + + MouseArea{ + id: buttonMouseArea + + anchors.fill: parent //anchor all sides of the mouse area to the rectangle's anchors + //onClicked handles valid mouse button clicks + onClicked: console.log(buttonLabel.text + " clicked" ) + } + } + \endcode + + We include a \l{MouseArea} element in our simplebutton. \c MouseArea elements describe + the interactive area where mouse movements are detected. For our button, we anchor the + whole MouseArea to its parent, which is \c simplebutton. The \c anchors.fill syntax is + one way of accessing a specific property called \c fill inside a group of properties + called \c anchors. QML uses \l {Anchor-based Layout in QML}{anchor based layouts} where + items can anchor to another item, creating robust layouts. + + The \c MouseArea has many signal handlers that are called during mouse movements within + the specfied \c MouseArea boundaries. One of them is \c onClicked 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, \c console.log() outputs text + whenever the mouse area is clicked. The function \c console.log() is a useful tool for + debugging purposes and for outputting text. + + The code in \c SimpleButton.qml is sufficient to display a button on the screen and + output text whenever it is clicked with a mouse. + + \code + Rectangle { + id:Button + ... + + property color buttonColor: "lightblue" + property color onHoverColor: "gold" + property color borderColor: "white" + + signal buttonClick() + onButtonClick: { + console.log(buttonLabel.text + " clicked" ) + } + + MouseArea{ + onClicked: buttonClick() + hoverEnabled: true + onEntered: parent.border.color = onHoverColor + onExited: parent.border.color = borderColor + } + + //determines the color of the button by using the conditional operator + color: buttonMouseArea.pressed ? Qt.darker(buttonColor, 1.5) : buttonColor + } + \endcode + + A fully functioning button is in \c Button.qml. 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. + + Custom properties are declared using the \c {property type name} syntax. In the + code, the property \c buttonColor, of type \c color, is declared and bound to + the value \c{"lightblue"}. The \c buttonColor is later used in a conditional + operation to determine the buttons's fill color. Note that property value + assignment is possible using the \c= equals sign, in addition to value binding + using the \c : colon character. Custom properties allow internal items to be + accessible outside of the Rectangle's scope. There are basic + \l{QML Basic Types}{QML types} such as \c int, \c string, \c real, as well as + a type called \c variant. + + By binding the \c onEntered and \c onExited 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. + + A \c buttonClick() signal is declared in \c Button.qml by placing the \c signal + keyword in front of the signal name. All signals have their handlers automatically + created, their names starting with \c on. As a result, the \c onButtonClick is + \c buttonClick's handler. The \c onButtonClick is then assigned an action to + perform. In our button example, the \c onClicked mouse handler will simply call + \c onButtonClick, which displays a text. The \c onButtonClick enables outside + objects to access the \c {Button}'s mouse area easily. For example, items may + have more than one \c MouseArea declarations and a \c buttonClick signal can + make the distinction between the several \c MouseArea signal handlers better. + + We now have the basic knowledge to implement items in QML that can handle + basic mouse movements. We created a \c Text label inside a \c Rectangle, + customized its properties, and implemented behaviors that respond to mouse + movements. This idea of creating elements within elements is repeated + throughout the text editor application. + + 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. + + \image qml-texteditor1_button.png + + \section2 Creating a Menu Page + + Up to this stage, we covered how to create elements and assign behaviors inside + a single QML file. In this section, we will cover how to import QML elements and how + to reuse some of the created components to build other components. + + 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 + \c FileMenu.qml. + + \code + import Qt 4.7 \\import the main Qt QML module + import "folderName" \\import the contents of the folder + import "Button.qml" \\import a QML file + import "NewButton.qml" as ButtonModule \\import a QML file and give it a name + import "script.js" as Script \\import a Javascript file and name it as Script + \endcode + + To use the \c Button element in \c FileMenu.qml, we need to import \c Button.qml. + The syntax shown above, shows how to use the \c import keyword. However, the + \c {import Button.qml} is not necessary; qmlviewer will import all the contents + of the current directory. We can directly create a \c Button element by declaring + \c Button{}, similar to a \c Rectangle{} declaration. + + \code + In FileMenu.qml: + + Row{ + anchors.centerIn: parent + spacing: parent.width/6 + + Button{ + id: loadButton + buttonColor: "lightgrey" + label: "Load" + } + Button{ + buttonColor: "grey" + id: saveButton + label: "Save" + } + Button{ + id: exitButton + label: "Exit" + buttonColor: "darkgrey" + + onButtonClick: Qt.quit() + } + } + \endcode + + In \c FileMenu.qml, we declare three \c Button elements. They are declared + inside a \l {Row}{Row} element, a positioner that will position its children + along a vertical row. The \c Button declaration resides in Button.qml, + which is the same as the \c Button.qml we used in the previous section. + New property bindings can be declared within the newly created buttons, + effectively overwriting the properties set in \c Button.qml. The button + called \c exitButton will quit and close the window when it is clicked. + Note that the signal handler \c onButtonClick in \c Button.qml will be + called in addition to the \c onButtonClick handler in \c exitButton. + + \image qml-texteditor1_filemenu.png + + The \c Row declaration is declared in a \c Rectangle, 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. + + The declaration of the edit menu is very similar at this stage. The menu has + buttons that have the labels: \c Copy, \c Paste, and \c {Select All}. + + \image qml-texteditor1_editmenu.png + + 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. + + \section1 Implementing a Menu Bar + + 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. + + \section2 Using Data Models and Views + + QML has different \l {Data Models}{data views} that display + \l {Data Models}{data models}. 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 \c VisualItemModel. The \l{VisualItemModel}{\c VisualItemModel} + element contains items that already have views such as \c Rectangle elements + and imported UI elements. Other model types such as the \l{ListModel}{\c ListModel} + element need a delegate to display their data. + + We declare two visual items in the \c menuListModel, the \c FileMenu and the + \c EditMenu. We customize the two menus and display them using a + \l {ListView}{ListView}. The \c MenuBar.qml file contains the QML declarations + and a simple edit menu is defined in \c EditMenu.qml. + + \code + VisualItemModel{ + id: menuListModel + FileMenu{ + width: menuListView.width + height: menuBar.height + color: fileColor + } + EditMenu{ + color: editColor + width: menuListView.width + height: menuBar.height + } + } + \endcode + + The \l {ListView}{ListView} element will display a model according to a delegate. + The delegate may declare the model items to display in a \c Row element or display + the items in a grid. Our \c menuListModel already has visible items, therefore, + we do not need to declare a delegate. + + \code + ListView{ + id: menuListView + + //Anchors are set to react to window anchors + anchors.fill:parent + anchors.bottom: parent.bottom + width:parent.width + height: parent.height + + //the model contains the data + model: menuListModel + + //control the movement of the menu switching + snapMode: ListView.SnapOneItem + orientation: ListView.Horizontal + boundsBehavior: Flickable.StopAtBounds + flickDeceleration: 5000 + highlightFollowsCurrentItem: true + highlightMoveDuration:240 + highlightRangeMode: ListView.StrictlyEnforceRange + } + \endcode + + Additionally, \c ListView inherits from \l{Flickable}{\c Flickable}, making + the list respond to mouse drags and other gestures. The last portion of the + code above sets \c Flickable properties to create the desired flicking movement + to our view. In particular,the property \c highlightMoveDuration changes the + duration of the flick transition. A higher \c highlightMoveDuration value + results in slower menu switching. + + The \c ListView maintains the model items through an \c index and each visual + item in the model is accessible through the \c index, in the order of the + declaration. Changing the \c currentIndex effectively changes the highlighted + item in the \c ListView. The header of our menu bar exemplify this effect. + There are two buttons in a row, both changing the current menu when clicked. + The \c fileButton changes the current menu to the file menu when clicked, + the \c index being \c 0 because \c FileMenu is declared first in the + \c menuListModel. Similarly, the \c editButton will change the current + menu to the \c EditMenu when clicked. + + The \c labelList rectangle has \c z value of \c 1, denoting that it is displayed + at the front of the menu bar. Items with higher \c z values are displayed in front + of items with lower \c z values. The default \c z value is \c 0. + + \code + Rectangle{ + id: labelList + ... + z: 1 + Row{ + anchors.centerIn: parent + spacing:40 + Button{ + label: "File" + id: fileButton + ... + onButtonClick: menuListView.currentIndex = 0 + } + Button{ + id: editButton + label: "Edit" + ... + onButtonClick: menuListView.currentIndex = 1 + } + } + } + \endcode + + 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. + + \image qml-texteditor2_menubar.png + + */ + + /*! + \page qml-textEditor3.html + \title Building a Text Editor + + \section1 Declaring a TextArea + + Our text editor is not a text editor if it didn't contain an editable text area. + QML's \l {TextEdit}{TextEdit} element allows the declaration of a multi-line + editable text area. \l {TextEdit}{TextEdit} is different from a \l {Text}{Text} + element, which doesn't allow the user to directly edit the text. + + \code + TextEdit{ + id: textEditor + anchors.fill:parent + width:parent.width; height:parent.height + color:"midnightblue" + focus: true + + wrapMode: TextEdit.Wrap + + onCursorRectangleChanged: flickArea.ensureVisible(cursorRectangle) + } + \endcode + + The editor has its font color property set and set to wrap the text. The + \c TextEdit area is inside a flickable area that will scroll the text if the + text cursor is outside the visible area. The function \c ensureVisible() 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. + + \code + function ensureVisible(r){ + if (contentX >= r.x) + contentX = r.x; + else if (contentX+width <= r.x+r.width) + contentX = r.x+r.width-width; + if (contentY >= r.y) + contentY = r.y; + else if (contentY+height <= r.y+r.height) + contentY = r.y+r.height-height; + } + \endcode + + \section1 Combining Components for the Text Editor + + 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 elements. + + \code + Rectangle{ + + id: screen + width: 1000; height: 1000 + + //the screen is partitioned into the MenuBar and TextArea. 1/3 of the screen is assigned to the MenuBar + property int partition: height/3 + + MenuBar{ + id:menuBar + height: partition + width:parent.width + z: 1 + } + + TextArea{ + id:textArea + anchors.bottom:parent.bottom + y: partition + color: "white" + height: partition*2 + width:parent.width + } + } + \endcode + + By importing reusable components, our \c TextEditor 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. + + \image qml-texteditor3_texteditor.png + + */ + + /*! + \page qml-textEditor4 + \title Decorating the Text Editor + \section1 Implementing a Drawer Interface + + 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. + + 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 + \c drawer, as well as the application, has two sates: the "drawer is open" state and + the "drawer is closed" state. The \c drawer item is a strip of rectangle with a small + height. There is a nested \l {Image}{Image} element declaring that an arrow icon will + be centered inside the drawer. The drawer assigns a state to the whole application, + with the identifier \c screen, whenever a user clicks the mouse area. + + \code + Rectangle{ + id:drawer + height:15 + + Image{ + id: arrowIcon + source: "images/arrow.png" + anchors.horizontalCenter: parent.horizontalCenter + } + + MouseArea{ + id: drawerMouseArea + anchors.fill:parent + onClicked:{ + if (screen.state == "DRAWER_CLOSED"){ + screen.state = "DRAWER_OPEN" + } + else if (screen.state == "DRAWER_OPEN"){ + screen.state = "DRAWER_CLOSED" + } + } + ... + } + } + \endcode + + A state is simply a collection of configurations and it is declared in a + \l{State}{State} element. A list of states can be listed and bound to the + \c states property. In our application, the two states are called + \c DRAWER_CLOSED and \c DRAWER_OPEN. Item configurations are declared in + \l {PropertyChanges}{PropertyChanges} elements. In the \c DRAWER_OPEN state, + there are four items that will receive property changes. The first target, + \c menuBar, will change its \c y property to \c 0. Similarly, the \c textArea + will lower to a new position when the state is \c DRAWER_OPEN. The \c textArea, + the \c drawer, and the drawer's icon will undergo property changes to meet the + current state. + + \code + + states:[ + State{ + name: "DRAWER_OPEN" + PropertyChanges { target: menuBar; y:0} + PropertyChanges { target: textArea; y: partition + drawer.height} + PropertyChanges { target: drawer; y: partition} + PropertyChanges { target: arrowIcon; rotation: 180} + }, + State{ + name: "DRAWER_CLOSED" + PropertyChanges { target: menuBar; y:-partition} + PropertyChanges { target: textArea; y: drawer.height; height: screen.height - drawer.height} + PropertyChanges { target: drawer; y: 0} + PropertyChanges { target: arrowIcon; rotation: 0} + } + + ] + + \endcode + + State changes are abrupt and needs smoother transitions. Transitions between states + are defined using the \l {Transition}{Transition} element, which can then bind to + the item's \c transitions property. Our text editor has a state transition whenever + the state changes to either \c DRAWER_OPEN or \c DRAWER_CLOSED. Importantly, the + transition needs a \c from and a \c to state but for our transitions, we can use + the wild card \c * symbol to denote that the transition applies to all state changes. + + During transitions, we can assign animations to the property changes. Our + \c menuBar switches position from \c {y:0} to \c {y:-partition} and we can animate + this transition using the \l {NumberAnimation}{NumberAnimation} element. 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 + \l{PropertyAnimation::easing.type}{Easing.OutQuint}, which slows the movement near + the end of the animation. Pleae read \l {qdeclarativeanimation.html}{QML's Animation} + article. + + \code + transitions: [ + Transition{ + to: "*" + NumberAnimation { target: textArea; properties: "y, height"; duration: 100; easing.type: Easing.OutQuint } + NumberAnimation { target: menuBar; properties: "y"; duration: 100;easing.type: Easing.OutQuint } + NumberAnimation { target: drawer; properties: "y"; duration: 100;easing.type: Easing.OutQuint } + } + ] + \endcode + + Another way of animating property changes is by declaring a \l {Behavior}{Behavior} + element. A transition only works during state changes and \c Behavior can set an + animation for a general property change. In the text editor, the arrow has a + \c NumberAnimation animating its \c rotation property whenever the property changes. + + \code + In TextEditor.qml: + + Behavior{ + NumberAnimation{property: "rotation";easing.type: Easing.OutExpo } + } + \endcode + + Going back to our components with knowledge of states and animations, we can improve + the appearances of the components. In \c Button.qml, we can add \c color and \c scale + property changes when the button is clicked. Color types are animated using + \l {ColorAnimation}{ColorAnimation} and numbers are animated using + \l {NumberAnimation}{NumberAnimation}. The \c {on propertyName} syntax displayed below + is helpful when targeting a single property. + + \code + In Button.qml: + ... + + color: buttonMouseArea.pressed ? Qt.darker(buttonColor, 1.5) : buttonColor + Behavior on color { ColorAnimation{ duration: 55} } + + scale: buttonMouseArea.pressed ? 1.1 : 1.00 + Behavior on scale { NumberAnimation{ duration: 55} } + \endcode + + Additionally, we can enhance the appearances of our QML components by adding color + effects such as gradients and opacity effects. Declaring a \l {Gradient}{Gradient} + element will override the \c color property of the element. You may declare a color + in the gradient using the \l {GradientStop}{GradientStop} element. The gradient is + positioned using a scale, between \c 0.0 and \c 1.0. + + \code + In MenuBar.qml + gradient: Gradient { + GradientStop { position: 0.0; color: "#8C8F8C" } + GradientStop { position: 0.17; color: "#6A6D6A" } + GradientStop { position: 0.98;color: "#3F3F3F" } + GradientStop { position: 1.0; color: "#0e1B20" } + } + \endcode + + This gradient is used by the menu bar to display a gradient simulating depth. + The first color starts at \c 0.0 and the last color is at \c 1.0. + + + \section2 Where to Go from Here + + 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. + + \image qml-texteditor4_texteditor.png + + \section1 Extending QML using Qt C++ + + 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 the + \l {Using QML in C++ Applications}{Qt's Declarative} classes and display the QML + elements using a Graphics Scene. Alternatively, we can export our C++ code into + a plugin that the \l {QML Viewer}{qmlviewer} tool can read. For our application, + we shall implement the load and save functions in C++ and export it as a plugin. + This way, we only need to load the QML file directly instead of running an executable. + + \section2 Exposing C++ Classes to QML + + We will be implementing file loading and saving using Qt and C++. C++ classes + and functions can be used in QML by registering them. The class also needs to be + compiled as a Qt plugin and the QML file will need to know where the plugin is located. + + For our application, we need to create the following items: + \list 1 + \o \c Directory class that will handle directory related operations + \o \c File class which is a QObject, simulating the list of files in a directory + \o plugin class that will register the class to the QML context + \o Qt project file that will compile the plugin + \o A \c qmldir file telling the qmlviewer tool where to find the plugin + \endlist + + \section2 Building a Qt Plugin + + 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 \c filedialog + directory. + + \code + In cppPlugins.pro: + + TEMPLATE = lib + CONFIG += qt plugin + QT += declarative + + DESTDIR += ../plugins + OBJECTS_DIR = tmp + MOC_DIR = tmp + + TARGET = FileDialog + + HEADERS += directory.h \ + file.h \ + dialogPlugin.h + + SOURCES += directory.cpp \ + file.cpp \ + dialogPlugin.cpp + \endcode + + In particular, we compile Qt with the \c declarative module and configure it as a + \c plugin, needing a \c lib template. We shall put the compiled plugin into the + parent's \c plugins directory. + + + \section2 Registering a Class into QML + + \code + In dialogPlugin.h: + + #include <QtDeclarative/QDeclarativeExtensionPlugin> + + class DialogPlugin : public QDeclarativeExtensionPlugin + { + Q_OBJECT + + public: + void registerTypes(const char *uri); + + }; + + \endcode + + Our plugin class, \c DialogPlugin is a subclass of \l{QDeclarativeExtensionPlugin}. + We need to implement the inherited function, \l {QDeclarativeExtensionPlugin::}{registerTypes()}. + The \c dialogPlugin.cpp file looks like this: + + \code + DialogPlugin.cpp: + + #include "dialogPlugin.h" + #include "directory.h" + #include "file.h" + #include <QtDeclarative/qdeclarative.h> + + void DialogPlugin::registerTypes(const char *uri){ + + qmlRegisterType<Directory>(uri, 1, 0, "Directory"); + qmlRegisterType<File>(uri, 1, 0,"File"); + } + + Q_EXPORT_PLUGIN2(FileDialog, DialogPlugin); + \endcode + + The \l{QDeclarativeExtensionPlugin::}{registerTypes()} 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. + + We need to export the plugin using the \l {Q_EXPORT_PLUGIN2}{Q_EXPORT_PLUGIN2} + macro. Note that in our \c dialogPlugin.h file, we have the \l {Q_OBJECT}{Q_OBJECT} + macro at the top of our class. As well, we need to run \c qmake on the project + file to generate the necessary meta-object code. + + + \section2 Creating QML Properties in a C++ class + + We can create QML elements and properties using C++ and + \l {The Meta-Object System}{Qt's Meta-Object System}. We can implement + properties using slots and signals, making Qt aware of these properties. + These properties can then be used in QML. + + 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 + \l {QDir}{QDir}, \l {QFile}{QFile}, and \l {QTextStream}{QTextStream} to + implement directory reading and input/output streams. + + \code + class Directory : public QObject{ + + Q_OBJECT + + Q_PROPERTY(int filesCount READ filesCount CONSTANT) + Q_PROPERTY(QString filename READ filename WRITE setFilename NOTIFY filenameChanged) + Q_PROPERTY(QString fileContent READ fileContent WRITE setFileContent NOTIFY fileContentChanged) + Q_PROPERTY(QDeclarativeListProperty<File> files READ files CONSTANT ) + + ... + \endcode + + The \c Directory class uses Qt's Meta-Object System to register properties it + needs to accomplish file handling. The \c Directory class is exported as a plugin + and is useable in QML as the \c Directory element. Each of the listed properties + using the \l {Q_PROPERTY()}{Q_PROPERTY} macro is a QML property. + + The \l {Q_PROPERTY()} {Q_PROPERTY} declares a property as well as its read and + write functions into Qt's Meta-Object System. For example, the \c filename + property, of type \l {QString}{QString}, is readable using the \c filename() + function and writable using the function \c setFilename(). Additionally, there + is a signal associated to the filename property called \c filenameChanged(), + which is emitted whenever the property changes. The read and write functions + are declared as \c public in the header file. + + Similarly, we have the other properties declared according to their uses. The + \c filesCount 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 \c fileContent property. + + \code + Q_PROPERTY(QDeclarativeListProperty<File> files READ files CONSTANT ) + \endcode + + The \c files list property is a list of all the filtered files in a directory. + The \c Directory class is implemented to filter out invalid text files; only + files with a \c .txt extension are valid. Further, \l {QLists}{QLists} can be + used in QML files by declaring them as a \c QDeclarativeListProperty in C++. + The templated object needs to inherit from a \l {QObject}{QObject}, therefore, + the \c File class must also inherit from \c QObject. In the \c Directory class, + the list of \c File objects is stored in a \c QList called \c m_fileList. + + \code + class File : public QObject{ + + Q_OBJECT + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + + ... + }; + \endcode + + The properties can then be used in QML as part of the \c Directory element's + properties. Note that we do not have to create an identifier \c id property + in our C++ code. + + \code + Directory{ + id: directory + + filesCount + filename + fileContent + files + + files[0].name + } + + \endcode + + 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 \c { files[0].name }. + + Regular C++ functions are also accessible from QML. The file loading and saving + functions are implemented in C++ and declared using the + \l {Q_INVOKABLE}{Q_INVOKABLE} macro. Alternatively, we can declare the functions + as a \c slot and the functions will be accessible from QML. + + \code + In Directory.h: + + Q_INVOKABLE void saveFile(); + Q_INVOKABLE void loadFile(); + \endcode + + The \c Directory class also has to notify other objects whenever the directory + contents change. This feature is performed using a \c signal. As previously + mentioned, QML signals have a corresponding handler with their names prepended + with \c on. The signal is called \c directoryChanged 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 \c onDirectoryChanged signal handler. + + The \c list 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 \c QDeclarativeListProperty<File>. Whenever the list + is accessed, the accessor function needs to return a + \c QDeclarativeListProperty<File>. The template type, \c File, needs to be a + \c QObject derivative. Further, to create the + \l {QDeclarativeListProperty}{QDeclarativeListProperty}, the list's accessor + and modifiers need to be passed to the consructor as function pointers. The list, + a \c QList in our case, also needs to be a list of \c File pointers. + + The constructor of \l {QDeclarativeListProperty}{QDeclarativeListProperty} + constructor and the \c Directory implementation: + \code + QDeclarativeListProperty ( QObject * object, void * data, AppendFunction append, CountFunction count = 0, AtFunction at = 0, ClearFunction clear = 0 ) + QDeclarativeListProperty<File>( this, &m_fileList, &appendFiles, &filesSize, &fileAt, &clearFilesPtr ); + \endcode + + The constructor passes pointers to functions that will append the list, count + the list, retrieve the item using an index, and empty the list. Only the append + function is mandatory. Note that the function pointers must match the definition + of \l {QDeclarativeListProperty::AppendFunction}{AppendFunction}, + \l {QDeclarativeListProperty::CountFunction}{CountFunction}, + \l {QDeclarativeListProperty::AtFunction}{AtFunction}, or + \l {QDeclarativeListProperty::ClearFunction}{ClearFunction}. + + \code + void appendFiles(QDeclarativeListProperty<File> * property, File * file) + File* fileAt(QDeclarativeListProperty<File> * property, int index) + int filesSize(QDeclarativeListProperty<File> * property) + void clearFilesPtr(QDeclarativeListProperty<File> *property) + \endcode + + To simplify our file dialog, the \c Directory class filters out invalid text + files, which are files that do not have a \c .txt extension. If a file name + doesn't have the \c .txt extension, then it won't be seen in our file dialog. + Also, the implementation makes sure that saved files have a \c .txt extension in + the file name. \c Directory uses \l {QTextStream}{QTextStream} to read the file + and to output the file contents to a file. + + With our \c Directory element, 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. + + To build the plugin, run \c qmake on the \c cppPlugins.pro project file, then run + \c make to build and transfer the plugin to the \c plugins directory. + + + \section2 Importing a Plugin in QML + + The qmlviewer tool imports files that are in the same directory as the + application. We can also create a \c qmldir file containing the locations of + QML files we wish to import. The \c qmldir file can also store locations of + plugins and other resources. + + \code + In qmldir: + + Button ./Button.qml + FileDialog ./FileDialog.qml + TextArea ./TextArea.qml + TextEditor ./TextEditor.qml + EditMenu ./EditMenu.qml + + plugin FileDialog plugins + \endcode + + The plugin we just created is called \c FileDialog, as indicated by the + \c TARGET field in the project file. The compiled plugin is in the \c plugins directory. + + + \section2 Integrating a File Dialog into the File Menu + + Our \c FileMenu needs to display the \c FileDialog element, 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. + + The \c Directory element is used in the \c FileMenu.qml file and it notifies the + \c FileDialog element that the directory refreshed its contents. This notification + is performed in the signal handler, \c onDirectoryChanged. + + \code + In FileMenu.qml: + + Directory{ + id:directory + filename: textInput.text + onDirectoryChanged: fileDialog.notifyRefresh() + } + \endcode + + 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 \c .txt + extension to their filenames. + + \code + In FileDialog.qml: + + signal notifyRefresh() + onNotifyRefresh: dirView.model = directory.files + \endcode + + The \c FileDialog element will display the contents of a directory by reading its + list property called \c files. The files are used as the model of a + \l {GridView}{GridView} element, 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 \c FileDialog is notified whenever the \c notifyRefresh signal is emitted, + reloading the files in the directory. + + \code + In FileMenu.qml: + + Button{ + id: newButton + label: "New" + onButtonClick:{ + textArea.textContent = "" + } + } + Button{ + id: loadButton + label: "Load" + onButtonClick:{ + directory.filename = textInput.text + directory.loadFile() + textArea.textContent = directory.fileContent + } + } + Button{ + id: saveButton + label: "Save" + onButtonClick:{ + directory.fileContent = textArea.textContent + directory.filename = textInput.text + directory.saveFile() + } + } + Button{ + id: exitButton + label: "Exit" + onButtonClick:{ + Qt.quit() + } + } + \endcode + + Our \c FileMenu can now connect to their respective actions. The \c saveButton + will transfer the text from the \c TextEdit onto the directory's \c fileContent + property, then copy its file name from the editable text input. Finally, the button + calls the \c saveFile() function, saving the file. The \c sloadButton has a similar + execution. Also, the \c New action will empty the contents of the \c TextEdit. + + Further, the \c EditMenu buttons are connected to the \c TextEdit functions to copy, + paste, and select all the text in the text editor. + + \image qml-texteditor5_filemenu.png + + \section1 Text Editor Completion + + \image qml-texteditor5_newfile.png + + The application can function as a simple text editor, able to accept text + and save the text into a file. The text editor can also load from a file and + perform text manipulation. +*/ diff --git a/doc/src/getting-started/gettingstartedqt.qdoc b/doc/src/getting-started/gettingstartedqt.qdoc index 1b3770f..25d0ccd 100644 --- a/doc/src/getting-started/gettingstartedqt.qdoc +++ b/doc/src/getting-started/gettingstartedqt.qdoc @@ -28,8 +28,8 @@ /*! \page gettingstartedqt.html - \title Getting Started programming with Qt - \ingroup gettingStarted + \title Getting Started Programming with Qt + \ingroup gettingStarted Welcome to the world of Qt--the cross-platform GUI toolkit. In this getting started guide, we teach basic Qt knowledge by @@ -85,7 +85,7 @@ other widgets), it is possible to show a single widget in its own window. Widgets are not visible by default; the function \l{QWidget::}{show()} makes the widget visible. - + Line 11 makes the QApplication enter its event loop. When a Qt application is running, events are generated and sent to the widgets of the application. Examples of events are mouse presses |