QTDemo-calqlatr (2) calqlatr. qml

Source: Internet
Author: User
Tags rewind
ImportQtQuick2.0importcontentimportcontentcalculator. jsasCalcEngine is the same. This time, the most common import part for the qml code is ignored, and at least basic understanding and use should be done. To use system components in Qml, you must declare them at the beginning. For custom components

Import QtQuick 2.0 import contentimport content/calculator. js as CalcEngine is the same. This time, the most common import part for qml Code has not been missed, so we must at least have a basic understanding and use. To use system components in Qml, you must declare them at the beginning. For custom components

import QtQuick 2.0import "content"import "content/calculator.js" as CalcEngine

Similarly, the most common import part for qml Code has not been missed this time, so we should at least have a basic understanding and use.

To use system components in Qml, you must declare them at the beginning. Custom components also need to be imported at the beginning. Note that system components can be directly imported by name. For custom components, you need to use "" to pack them.

QML supports three types of import:

  • Import Component (namespace ):The most common type of import is a module import. Clients can import QML modules which register QML object types and JavaScript resources into a given namespace.
  • Import directory:A directory which contains QML documents may also be imported directly in a QML document. This provides a simple way for QML types to be segmented into reusable groupings: directories on the filesystem.
  • Import js file:JavaScript resources may be imported directly in a QML document. Every JavaScript resource must have an identifier by which it is accessed.

Note: When only import js is used in the three types of import, you must use as to specify a unique Identifier. The other two are optional.

Main code structure of calqlatr. qml
Rectangle {    id: window    width: 320    height: 480    focus: true    color: "#272822"    onWidthChanged: controller.reload()    onHeightChanged: controller.reload()    function operatorPressed(operator) { CalcEngine.operatorPressed(operator) }    function digitPressed(digit) { CalcEngine.digitPressed(digit) }    Item {}    AnimationController {}    Display {}}

The basic properties of id/width/height and color do not need to be discussed. They have been used multiple times in the previous sample code. The new property used this time is focus, but we found that even if we change the focus value to false or remove the focus attribute (using the default value, there are no exceptions or differences in program running. This property is not used in this example,TODO: Later we will learn the specific role of the focus property..

OnWidthChanged and onHeightChanged

There are two lines in the Code:

    onWidthChanged: controller.reload()    onHeightChanged: controller.reload()

When width or height changes, the controller. reload () function is called to re-paint the UI. But what makes me Tangle is that the onWidthChanged and onHeightChanged Event Response functions are defined in there ???

When I tried to find these two functions or signal about width and height in the help document, the results were not found. At this time, I guess that Qt has done some built-in processing, but there is no documentation.

Is there a corresponding onXXXChanged Event Response Function for each property? The answer is yes. Therefore, in addition to the above onWidthChanged and onHeightChanged functions, there are also the following functions:

    onParentChanged: ;    onOpacityChanged: ;    onColorChanged: ;    onXChanged: ;    onYChanged: ;    onVisibleChanged: ;    onFocusChanged: ;

Of course, for the special property of id, there is no corresponding onIdChanged function.

DigitPressed (digit) and operatorPressed (operator) Functions

Then we define two more functions:

    function operatorPressed(operator) { CalcEngine.operatorPressed(operator) }    function digitPressed(digit) { CalcEngine.digitPressed(digit) }

In the previous article "how to define and use functions in QML", we learned how to define and call a function in Qml. The function body here is also very simple, direct passthrough calls content/calculator. the corresponding function in js. But where can these two functions be called ???

I am looking for it. I don't have it in the current file. I can't help but use grep for searching. I found the following function calls in Button. qml:

    MouseArea {        onClicked: {            if (operator)                window.operatorPressed(parent.text)            else                window.digitPressed(parent.text)        }    }

Objects are used across files.The system crashes.The pace.

Other child elements

The entire Rectangle has the following three child elements:

  • Item, number, and operator
  • AnimationController: UI initialization, as well as UI processing and animation when width/height is changed and dragged to the following control bar (a bit around, in fact, when the UI needs to be changed)
  • Display: the output result of the operation and the grip control bar at the bottom. The specific implementation is in the Display. qml file.

The following is a detailed analysis of each child element.

Item
    Item {        id: pad        width: 180        NumberPad { y: 10; anchors.horizontalCenter: parent.horizontalCenter }    }

The Code specifies that the width of an Item is 180. The numbers and operators are encapsulated in a separate NumberPad qml document. The position of NumberPad in the Item is a coordinate with a relative value of 10, and the horizontal direction is centered relative to the Item (PS: You can change the value and alignment here by yourself, see the running results respectively ).

NumberPad
Grid {    columns: 3    columnSpacing: 32    rowSpacing: 16    Button { text: "7" }    Button { text: "8" }    Button { text: "9" }    Button { text: "4" }    Button { text: "5" }    Button { text: "6" }    Button { text: "1" }    Button { text: "2" }    Button { text: "3" }    Button { text: "0" }    Button { text: "." }    Button { text: " " }    Button { text: "±"; color: "#6da43d"; operator: true }    Button { text: "?"; color: "#6da43d"; operator: true }    Button { text: "+"; color: "#6da43d"; operator: true }    Button { text: "√"; color: "#6da43d"; operator: true }    Button { text: "÷"; color: "#6da43d"; operator: true }    Button { text: "×"; color: "#6da43d"; operator: true }    Button { text: "C"; color: "#6da43d"; operator: true }    Button { text: " "; color: "#6da43d"; operator: true }    Button { text: "="; color: "#6da43d"; operator: true }}

Open the NumberPad. qml file and see the source code. I realized that the original layout was so simple that a Grid was done directly (columns: 3 specified three columns per line ). However, in ". as there is a blank space after "and" C ", you also need to add the corresponding" control "when using the Grid layout above:

    Button { text: "." }    Button { text: " " }...    Button { text: "C"; color: "#6da43d"; operator: true }    Button { text: " "; color: "#6da43d"; operator: true }

In the operator section above, "± ","? The operators "," √ "," Limit ", and" × "are not standard ASCII characters, the hexadecimal values are "C2B1", "E2889" 2, "E2889A", "C3B7", "C397", using "UTF-8 without BOM format" encoding.

Note that the text displayed by the Button and in calculator. the judgment in the js script file is one-to-one. That is to say, if you modify the text of the operator here, the original function cannot be completed when you click this button, the following describes calculator. js will talk about this part ).

AnimationController
    AnimationController {        id: controller        animation: ParallelAnimation {            id: anim            NumberAnimation { target: display; property: "x"; duration: 400; from: -16; to: window.width - display.width; easing.type: Easing.InOutQuad }            NumberAnimation { target: pad; property: "x"; duration: 400; from: window.width - pad.width; to: 0; easing.type: Easing.InOutQuad }            SequentialAnimation {                NumberAnimation { target: pad; property: "scale"; duration: 200; from: 1; to: 0.97; easing.type: Easing.InOutQuad }                NumberAnimation { target: pad; property: "scale"; duration: 200; from: 0.97; to: 1; easing.type: Easing.InOutQuad }            }        }    }

The AnimationController we used here is something we have never met before. Let's take a look at the instructions in the official documentation:

Normally animations are driven by an internal timer, but the AnimationController allows the given animation to be driven by a progress value explicitly.

We learned from the document that the AnimationController is a control that manually controls the animation running mode.

AnimationController has two attributes and three functions:

Properties

  • Animation: Animation
  • Progress: real

Methods

  • CompleteToBeginning ()
  • CompleteToEnd ()
  • Reload ()

All the above attributes and functions are used in this example.

Animation attributes and ParallelAnimation controls

This property holds the animation to be controlled by the AnimationController.

The meaning of this field is well understood, that is, the specific animation in the AnimationController. Here we use the ParallelAnimation control, which we have not encountered before. In fact, ParallelAnimation is very easy to understand. The following is an official description:

The SequentialAnimation and inclutypes allow multiple animations to be run together. Animations defined in a SequentialAnimation are run one after the other, while animations defined in a few are run the same time.

From the description, we can see that SequentialAnimation and ParallelAnimation both encapsulate multiple sub-animations to execute the animation. However, the sub-animations in SequentialAnimation are executed one by one in order, while the sub-animation in ParallelAnimation is simultaneously. An official example shows how to execute multiple animations at the same time:

Rectangle {    id: rect    width: 100; height: 100    color: "red"    ParallelAnimation {        running: true        NumberAnimation { target: rect; property: "x"; to: 50; duration: 1000 }        NumberAnimation { target: rect; property: "y"; to: 50; duration: 1000 }    }}

The preceding example shows how to move a Rectangle in the diagonal line.

In the calqlatr example, what animation effects does the ParallelAnimation control play?

    AnimationController {        id: controller        animation: ParallelAnimation {            id: anim            NumberAnimation { target: display; property: "x"; duration: 400; from: -16; to: window.width - display.width; easing.type: Easing.InOutQuad }            NumberAnimation { target: pad; property: "x"; duration: 400; from: window.width - pad.width; to: 0; easing.type: Easing.InOutQuad }            SequentialAnimation {                NumberAnimation { target: pad; property: "scale"; duration: 200; from: 1; to: 0.97; easing.type: Easing.InOutQuad }                NumberAnimation { target: pad; property: "scale"; duration: 200; from: 0.97; to: 1; easing.type: Easing.InOutQuad }            }        }    }

Where:

  • The first NumberAnimation describes how to move the output result part from the position of-16 to the window. width-display. width; why is it from-16, because the left-side separator pattern is hidden at the beginning, and moved to the window. width-display. the separator bar on the right is hidden at the width. For details, seeDisplay part.
  • The second NumberAnimation describes the numbers and operators that move from window. width-pad. width to 0.
  • The third is a SequentialAnimation animation combination. In the first 200 ms, the pad part is reduced from 100% to 97%; in the last 200 ms, the pad part is restored from 97% to 100%. (If you do not understand, change 0.97 in the code to 0.5, the effect is very obvious)

In this way, because the above three animations are integrated into a ParallelAnimation control, the final effect is achieved by simultaneously performing the animation (see the running effect for details ).

SS attributes

Let's take a look at the description of the SS attribute:

This property holds the animation progress value.
The valid progress value is 0.0 to 1.0, setting values less than 0 will be converted to 0, setting values great than 1 will be converted to 1.

As we talked about the ParallelAnimation control, "AnimationController is a control that manually controls the animation running mode." How can we stop the animation at the specific frame? Here you need to use the progress attribute.

When the progress attribute is used in this example, it is slightly complicated. Then we can perform a special test and use the following code in the onClicked function of a Button:

    onClicked: controller.progress = 0.3    (or onClicked: controller.progress = 0.7)

After testing, When you click the Button, the UI will stay at the position of 30% (or 70%) according to the Animation Description in the AnimationController control.

In this example, progress is used to complete the process of slowly changing the UI along with the mouse position when the button at the lower part of the Display is dragged.

CompleteToBeginning () function

Finishes running the controlled animation in a backwards direction.
After calling this method, the animation runs normally from the current progress point in a backwards ction to the beginning state.
The animation controller's progress value will be automatically updated while the animation is running.

From the above description, we understand that the completeToBeginning () function is actually executed in reverse order from the current position of the animation and changes to the initial state.

In this example, the completeToBeginning () function is used to complete the process of dropping the mouse while dragging the button in the lower part of the Display from the right to the left, and the entire UI returns to the initial position, instead of staying at the position where the current mouse is released (there are only two kinds of UI effects for the UI of the calculator, and there is no effect to switch to half ).

CompleteToEnd () function

Finishes running the controlled animation in a forwards direction.
After calling this method, the animation runs normally from the current progress point in a forwards ction to the end state.
The animation controller's progress value will be automatically updated while the animation is running.

Its meaning and use effect are relative to the completeToBeginning () function.

Reload () function

Reloads the animation properties
If the animation properties changed, calling this method to reload the animation definations.

It can be seen from the description that when the animation attribute in the ParallelAnimation control changes, you need to call this function to re-paint the UI and create the state of the entire ParallelAnimation control.

Specifically, in the calqlatr example, when you use the mouse to change the width and height of the application, you need to re-layout the UI and refresh the ParallelAnimation control status (such as completeToEnd, ).

    onWidthChanged: controller.reload()    onHeightChanged: controller.reload()
Display part
    Display {        id: display        x: -16        width: window.width - pad.width        height: parent.height        MouseArea {...}    }

The Display control is a custom qml control. The specific implementation is in the Display. qml file. During the call, only the specific actions of x coordinates, width, height, and MouseArea are set.

Here, why is the x coordinate set to-16 because there is a 16-width image on both sides of the Display. Set to-16. In this way, only the right side pattern is displayed on the left side. When you move to the right side, only the left side pattern is displayed.

Implementation of the Display control
Item {    id: display    property bool enteringDigits: false    function displayOperator(operator){}    function newLine(operator, operand){}    function appendDigit(digit){}    function clear(){}    Item {        id: theItem        width: parent.width + 32        height: parent.height        Rectangle {}        Image {}        Image {}        Image {}        ListView {}    }}

The Code shows that the Display control has the following elements:

  • A Rectangle is used to change the background color of the Display part to white to Display the operation process and result.
  • The two images display the left and right sides of the bar respectively.
  • The third Image Displays the drag button at the bottom.
  • The final ListView is used to display the calculation result by row.
  • Four operators are defined, including the display operator, adding new lines, adding numbers, and clearing

The changes to these functions and the content in ListView are detailed during the analysis of calculator. js. This chapter focuses on the changes to the qml control.

Button action at the bottom of Display
        MouseArea {            property real startX: 0            property real oldP: 0            property bool rewind: false            anchors {}            height: 50            onPositionChanged: {}            onPressed: startX = mapToItem(window, mouse.x).x            onReleased: {}        }

This MouseArea defines the overall UI changes when you operate the buttons at the bottom of the Display.

First look at the anchors and height sections:

Anchors {bottom: parent. bottom left: parent. left right: parent. right}
            height: 50

You can set the bottom, left, and right values of anchors to be the corresponding values of parent. The height is 50 because the distance between the button and the bottom is 20, and the height of the button is 30. The final result is that the click range of the button is expanded to the entire area at the bottom of the Display to facilitate user operations.

We will continue to analyze the onPositionChanged section of MouseArea:

            onPositionChanged: {                var reverse = startX > window.width / 2                var mx = mapToItem(window, mouse.x).x                var p = Math.abs((mx - startX) / (window.width - display.width))                if (p < oldP)                    rewind = reverse ? false : true                else                    rewind = reverse ? true : false                controller.progress = reverse ? 1 - p : p                oldP = p            }

Note that the startX variable is used here, which is the mouse position obtained when you click the mouse:

            onPressed: startX = mapToItem(window, mouse.x).x

The mapToItem function has been learned in the previous "MouseArea of QT Demo". Its function is to map coordinates in the current space to the position in the window space, to put it simply, you can obtain the position of the current mouse based on the entire window.

After getting startX, compare it with the horizontal center of the window to see whether the operation is performed on the left or right.

When you move the mouse, use mapToItem (window, mouse. x). x again to get the current position of the mouse and assign it to the mx temporary variable. Because moving the mouse is a process and the onPositionChanged callback function is triggered multiple times in the middle, you can constantly compare the interval between the current coordinate and the initial coordinate and the position of the initial mouse, you can get the operation direction when the mouse is finally released. However, during the entire process, the UI animation and the mouse are synchronized by setting the controller. progress attribute.

The above explanation is complex and the description is not very clear. The following uses the scenario to describe it:

  1. Move the button to the left with the mouse to the right: if the reverse value is false and the P value is always greater than the oldP value, the rewind and reverse values are both false, that is, the mouse moves to the right.
  2. On the left side of the button, return again when the coordinates are shifted to the right: if reverse is false, the start P value is greater than oldP. If the P value after turning back begins to light rain oldP, the reverse returns true to rewind and reverse, that is, the mouse moves to the left
  3. On the right side of the button, move the mouse to the left: If reverse is true and the P value is always greater than oldP, the rewind and reverse are both true, that is, the move of the mouse is eventually left

  4. On the right side of the button, return again when the coordinates are moved to the left: the reverse is true, and the start p value is greater than the oldP. After the return, the P value starts to rain oldP, and the opposite of the rewind and reverse is false, that is, the mouse moves to the right.

However, there are two scenarios that are not taken into account, that is:

  • The button is on the left, move the mouse to the left
  • Move the button to the right with the mouse

In fact, conditions can be added to limit the use of p, but note the absolute value of p here. It is convenient to process the above four scenarios, but cannot cover all scenarios. As for how to optimize the code here, we will not detail the above two scenarios. If you are not sure about this, you can communicate with us.


According to the above scenario analysis, after determining the final movement direction of the mouse, when releasing the mouse button, you need to switch the UI animation to the start or end state, but cannot stay in a certain state in the middle.

OnReleased: {if (rewind) // move the cursor to the left controller. completeToBeginning () else // move the cursor to the right controller. completeToEnd ()}
Summary

New knowledge learned in this section:

  1. OnPropertyChanged series Functions
  2. Learning and using the AnimationController Control

When I first started to contact Qml, The qml code of calqlatr was completely confused. Based on the previous analysis, now the code for learning calqlatr is not that complicated and difficult to understand.

This blog has a long length and I will spend nearly a week in my spare time. Compared with the previous sample code, although various qml controls are used, this example, especially the processing part of Mousearea, adds a lot of business logic, in addition, it is not straightforward to understand.

I don't know the specific efficiency, but from the code writing, I feel that Qt's Qml is quite operational for the UI.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.