Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
QML Qt / Qml / 4_Текстовий редактор в QML.doc
Скачиваний:
82
Добавлен:
28.03.2016
Размер:
504.32 Кб
Скачать

Сочетание компонентов для текстового редактора

Теперь мы готовы создать компоновку текстового редатора используя QML. В текстовом редакторе имеется два компонента - созданная нами панель меню и текстовая область. QML позволяет повторно использовать компоненты, следовательно, делает наш код проще, с помощью импорта компонентов и настройки их при необходимости. Наш текстовый редактор разделяет окно на две части; треть экрана предназначена для панели меню, а две трети экрана отображают текстовую область. Панель меню отображается впереди любых других элементов.

Rectangle{

id: screen

width: 1000; height: 1000

//экран разделен на MenuBar и TextArea. 1/3 экрана назначена 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

}

}

Импортируя повторно используемые компоненты код нашего TextEditor выглядит проще. Затем мы можем настроить главное приложение, не беспокоясь о свойствах, поведение которых уже определено. Используя этот подход можно легко создавать компоновки приложения и компонентов пользовательского интерфейса.

Украшение текстового редактора

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 drawer, as well as the application, has two sates: the "drawer is open" state and the "drawer is closed" state. The drawer item is a strip of rectangle with a small height. There is a nested 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 screen, whenever a user clicks the mouse area.

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"

}

}

...

}

}

A state is simply a collection of configurations and it is declared in a State element. A list of states can be listed and bound to the states property. In our application, the two states are called DRAWER_CLOSED and DRAWER_OPEN. Item configurations are declared in PropertyChanges elements. In the DRAWER_OPEN state, there are four items that will receive property changes. The first target, menuBar, will change its y property to 0. Similarly, the textArea will lower to a new position when the state is DRAWER_OPEN. The textArea, the drawer, and the drawer's icon will undergo property changes to meet the current state.

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:-height; }

PropertyChanges { target: textArea; y: drawer.height; height: screen.height - drawer.height }

PropertyChanges { target: drawer; y: 0 }

PropertyChanges { target: arrowIcon; rotation: 0 }

}

]

State changes are abrupt and needs smoother transitions. Transitions between states are defined using the Transition element, which can then bind to the item's transitions property. Our text editor has a state transition whenever the state changes to either DRAWER_OPEN or DRAWER_CLOSED. Importantly, the transition needs a from and a to state but for our transitions, we can use the wild card * symbol to denote that the transition applies to all state changes.

During transitions, we can assign animations to the property changes. Our menuBar switches position from y:0 to y:-partition and we can animate this transition using the 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 Easing.OutQuint, which slows the movement near the end of the animation. Please read QML's Animation article.

transitions: [

Transition {

to: "*"

NumberAnimation { target: textArea; properties: "y, height"; duration: 100; easing.type:Easing.OutExpo }

NumberAnimation { target: menuBar; properties: "y"; duration: 100; easing.type: Easing.OutExpo }

NumberAnimation { target: drawer; properties: "y"; duration: 100; easing.type: Easing.OutExpo }

}

]

Another way of animating property changes is by declaring a Behavior element. A transition only works during state changes and Behavior can set an animation for a general property change. In the text editor, the arrow has a NumberAnimation animating its rotation property whenever the property changes.

В TextEditor.qml:

Behavior{

NumberAnimation{property: "rotation";easing.type: Easing.OutExpo }

}

Going back to our components with knowledge of states and animations, we can improve the appearances of the components. In Button.qml, we can add color and scale property changes when the button is clicked. Color types are animated using ColorAnimation and numbers are animated using NumberAnimation. The on propertyName syntax displayed below is helpful when targeting a single property.

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} }

Additionally, we can enhance the appearances of our QML components by adding color effects such as gradients and opacity effects. Declaring a Gradient element will override the color property of the element. You may declare a color in the gradient using the GradientStop element. The gradient is positioned using a scale, between 0.0 and 1.0.

В 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" }

}

This gradient is used by the menu bar to display a gradient simulating depth. The first color starts at 0.0 and the last color is at 1.0.

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.

Расширение QML с использованием 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 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 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.

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:

  1. Directory class that will handle directory related operations

  2. File class which is a QObject, simulating the list of files in a directory

  3. plugin class that will register the class to the QML context

  4. Qt project file that will compile the plugin

  5. A qmldir file telling the qmlviewer tool where to find the plugin

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 filedialog directory.

В filedialog.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

In particular, we compile Qt with the declarative module and configure it as a plugin, needing a lib template. We shall put the compiled plugin into the parent's plugins directory.