Можно использовать форматы: JPG, PNG и SVG.
Этот элемент отображает файл изображения, указанный в свойстве source, файл может находится как локально так и в сети.
Есть интерактивный редактор для изменения свойств.
Свойствами можно подвергать изображение трансформациям, типа увеличение/уменьшение (scale), поворот (rotation), сглаживание (smooth).
import QtQuick 2.12; import QtQuick.Controls 2.2; import QtQuick.Layouts 1.12 ApplicationWindow { width: img.width; height: img.height; visible: true; Rectangle { anchors.fill: parent Image { id: img source: "qrc:/../../../../Downloads/11.jpg" x: 0; y: 0 smooth: true scale: 0.75 rotation: -30 } } }
Для более тонкой настройки трансформации, ее можно задавать списками (в квадратных скобках).
import QtQuick 2.12; import QtQuick.Controls 2.2; import QtQuick.Layouts 1.12 ApplicationWindow { width: img.width; height: img.height; visible: true; Rectangle { anchors.fill: parent Image { id: img source: "qrc:/../../../../Downloads/11.jpg" x: 0; y: 0 smooth: true transform: [ Scale { origin.x: width / 2 origin.y: width / 2 xScale: 0.75 yScale: 0.75 }, Rotation { origin.x: width / 2 origin.y: width / 2 angle: -30.0 } ] } } }
Добавим элемент загрузки BusyIndicator
import QtQuick 2.12; import QtQuick.Controls 2.2; import QtQuick.Layouts 1.12 ApplicationWindow { width: 640; height: 480; visible: true; Rectangle { anchors.fill: parent Image { id: img source: "http://qt-book.com/pic.jpg" anchors.fill: parent smooth: true Column { anchors.centerIn: parent visible: img.status == Image.Loading ? true:false Text { text: "Загрузка..." } BusyIndicator {} } } } }
Элемент для нормального масштабирования графики, особенно полезно при закругленных углах (кнопок и т.д.). Элемент разбивает изображение на девять частей.
import QtQuick 2.12 BorderImage { source: "" width: 100; height: 45 border {left: 30; top: 15; right: 30; bottom: 15} }
В QML есть только один градиент - линейный, если нужен другой, можно воспользоваться трансформацией.
Для создания, нужно свойству gradient присвоить элемент Gradient, он содержит точки останова (GradientStop) с позициями от 0 до 1.
Создание градиентов может потребовать много ресурсов, поэтому эффективнее использовать изображение градиента.
import QtQuick 2.12; import QtQuick.Controls 2.2; import QtQuick.Layouts 1.12 ApplicationWindow { width: 640; height: 480; visible: true; Rectangle { anchors.fill: parent gradient: Gradient { GradientStop{position: 0.0; color: "blue"} GradientStop{position: 0.7; color: "gold"} GradientStop{position: 1.0; color: "silver"} } rotation: 30 scale: 1.5 } }
Canvas представляет собой элемент холста, на котором можно выполнять растровые операции, по сути аналогичен QPaintDevice.
Сам QML описательный язык, поэтому алгоритмы рисования реализуются с использованием JavaScript, в свойстве обработки onPaint.
import QtQuick 2.12; import QtQuick.Controls 2.2; import QtQuick.Layouts 1.12 ApplicationWindow { width: 480; height: 480; visible: true; Rectangle { anchors.fill: parent Canvas { anchors.fill: parent; onPaint: { function drawFantasy() { ctx.beginPath(); ctx.translate(parent.width / 2, parent.height / 2); var fAngle = 91 * 3.14156 / 180 for(var i = 0; i < 300; ++i) { var n = i * 2; ctx.moveTo(0, 0); ctx.lineTo(n, 0); ctx.translate(n, 0); ctx.rotate(fAngle) } ctx.closePath(); } var ctx = getContext("2d"); ctx.clearRect(0, 0, parent.width, parent.height); ctx.save(); ctx.strokeStyle = "black"; ctx.lineWidth = 1; drawFantasy(); ctx.stroke(); ctx.restore(); } } } }
import QtQuick 2.12; import QtQuick.Controls 2.2; import QtQuick.Layouts 1.12 ApplicationWindow { width: 480; height: 480; visible: true; Rectangle { anchors.fill: parent Canvas { id: canv width: 320; height: 320; onPaint: { var ctx = getContext("2d"); ctx.strokeStyle= "blue"; ctx.lineWidth = 15; var gradient = ctx.createLinearGradient(canv.width, canv.height, 0, 0); gradient.addColorStop(0, "Indigo"); gradient.addColorStop(0.5, "Bisque"); gradient.addColorStop(1, "ForestGreen"); ctx.fillStyle = gradient; ctx.fillRect(0, 0, canv.width, canv.height); ctx.strokeRect(0, 0, canv.width, canv.height); } } } }
Для получения событий мыши служат специальные элементы - MouseArea, по сути просто прямоугольные области, в которых осуществляется ввод информации от мыши.
import QtQuick 2.12; import QtQuick.Controls 2.2; import QtQuick.Layouts 1.12 ApplicationWindow { width: 300; height: 300; visible: true; Rectangle { anchors.fill: parent color: "lightgreen" Text { id: txt anchors.centerIn: parent text: "<h1>This is text<br>Click here</h1>" horizontalAlignment: Text.AlignHCenter } MouseArea { anchors.fill: parent acceptedButtons: Qt.LeftButton | Qt.RightButton onPressed: { if(mouse.button == Qt.LeftButton) parent.color= "red" else parent.color= "blue" } onReleased: parent.color= "lightgreen" } } }
Так же, можно использовать свойство containsMouse, для обнаружения находится ли курсор над областью.
Аналогично можно использовать свойства onEntered и onExit.
import QtQuick 2.12; import QtQuick.Controls 2.2 ApplicationWindow { width: 300; height: 300; visible: true; Rectangle { anchors.fill: parent color: mousearea.containsMouse ? "red" : "lightgreen" Text { anchors.centerIn: parent text: "<h1>Hover me</h1>" } MouseArea { id: mousearea anchors.fill: parent hoverEnabled: true } } }
Сигналы в QML это события, которые уже прикреплены к свойствам, с кодом исполнения в них, эти свойства называются с префиксом on и являются по сути слотами.
Можно определять собственные сигналы:
signal <name>[(<type> <value>, …)]
К каждому такому сигналу автоматически создастся соответствующий обработчик (слот), с префиксом on.
Насколько я понимаю, вызвать наш сигнал может только какое то действие т.е. стандартный сигнал (точнее его обработчик on..), поэтому любой собственный сигнал будет так или иначе связан с уже существующим, стандартным сигналом.., плюс есть как минимум в том, что наши собственные сигналы будут доступны на уровнях выше т.е. извне, в случае например объявления объекта в отдельном файле.
import QtQuick 2.12; import QtQuick.Controls 2.2 ApplicationWindow { width: 300; height: 300; visible: true; Rectangle { anchors.fill: parent color: mousearea.containsMouse ? "red" : "lightgreen" signal myMouseSignal(int x, int y) onMyMouseSignal: { txt.text= "<h1>X:"+x +"; Y:"+y +"</h1>" } Text { id: txt anchors.centerIn: parent } MouseArea { anchors.fill: parent hoverEnabled: true onMouseXChanged: parent.myMouseSignal(mouseX, mouseY) onMouseYChanged: parent.myMouseSignal(mouseX, mouseY) } } }
// Файл button.qml import QtQuick 2.0 BorderImage { property alias text: txt.text signal clicked; source: "qrc:/button.png" width: txt.width +15 height: txt.height +15 border {left: 15; top: 12; right: 15; bottom: 15} Text { id: txt color: "white" anchors.centerIn: parent } MouseArea { anchors.fill: parent onClicked: parent.clicked(); onPressed: parent.source= "button-press.png" onReleased: parent.source= "button.png" } } // Основной файл import QtQuick 2.12; import QtQuick.Controls 2.2 ApplicationWindow { width: 150; height: 100; visible: true; Rectangle { anchors.fill: parent Button { anchors.centerIn: parent text: "Click this" onClicked: text= "Clicked" } } }
В основном ввод с клавиатуры обрабатывается двумя элементами: TextInput (однострочный) и TextEdit (многострочный).
Размер элемента будет соответствовать введенному тексту, что бы при пустом вводе элемент не исчезал, нужно задавать мин.ширину
import QtQuick 2.12; import QtQuick.Controls 2.2 ApplicationWindow { width: txt.width + 20; height: 100; visible: true; Rectangle { anchors.fill: parent TextInput { id: txt anchors.centerIn: parent color: "red" text: "Text in this" font.pixelSize: 32 focus: true } } }
Если на форме один элемент, он получает фокус автоматом, далее, фокус можно изменить ручным выбором мышкой либо табом. Програмно можно воспользоваться свойством focus.
Нетекстовые элементы так же могут иметь фокус.
Для управления порядком фокуса табом, используется т.н. прикрепляемое свойство «KeyNavigation.tab: <FocusThisElement>». В этом свойстве так же доступны клавиши типа KeyNavigation.left, KeyNavigation.right, KeyNavigation.up, KeyNavigation.down и т.д.
import QtQuick 2.12; import QtQuick.Controls 2.2 ApplicationWindow { width: 200; height: 80; visible: true; Rectangle { anchors.fill: parent TextEdit { anchors { left: parent.left right: parent.horizontalCenter top: parent.top bottom: parent.bottom } text: "Text1\nText1\nText1" font.pixelSize: 20 color: focus ? "red":"black" focus: true } TextEdit { anchors { left: parent.horizontalCenter right: parent.right top: parent.top bottom: parent.bottom } text: "Text2\nText2\nText2" font.pixelSize: 20 color: focus ? "red":"black" } } }
С помощью прикрепляемого свойства Keys можно получить доступ к событиям клавиатуры, с полной информацией о событии.
import QtQuick 2.12; import QtQuick.Controls 2.2 ApplicationWindow { width: 200; height: 80; visible: true; Rectangle { anchors.fill: parent Text { x: 20; y: 20; text: "Move this text" horizontalAlignment: Text.AlignHCenter Keys.onLeftPressed: x -= 3 Keys.onRightPressed: x += 3 Keys.onUpPressed: y -= 3 Keys.onDownPressed: y += 3 focus: true } } }
При помощи Keys.forwardTo можно пересылать события другим элементам, для дальнейшей обработки.
import QtQuick 2.12; import QtQuick.Controls 2.2 ApplicationWindow { width: 200; height: 80; visible: true; Rectangle { anchors.fill: parent Text { x: 20; y: 20; text: "Move this text" horizontalAlignment: Text.AlignHCenter focus: true Keys.onPressed: { if(event.key === Qt.Key_Left) { x -= 3; } else if(event.key === Qt.Key_Right) { x += 3; } else if(event.key === Qt.Key_Down) { y += 3; } else if(event.key === Qt.Key_Up) {y -= 3; } else if(event.key === Qt.Key_Plus) {font.pixelSize++; } else if(event.key === Qt.Key_Minus) {font.pixelSize--; } } } } }
Область региона- MultiPointTouchArea. Он содержит в себе элементы обработки события касания- TouchPoint, их должно быть столько, сколько одновременных касаний мы собираемся принимать, его можно сравнить с MouseArea.
import QtQuick 2.12; import QtQuick.Controls 2.2 ApplicationWindow { width: 400; height: 400; visible: true Rectangle { anchors.fill: parent color: "black" MultiPointTouchArea { anchors.fill: parent minimumTouchPoints: 1 maximumTouchPoints: 5 touchPoints: [ TouchPoint {}, TouchPoint {}, TouchPoint {}, TouchPoint {}, TouchPoint {} ] Repeater { model: parent.touchPoints Rectangle { color: "white" x: modelData.x; y: modelData.y width: 30; height: 30 visible: modelData.pressed } } } } }
Так же, у TouchPoint есть следующие св-ва:
pressed | При касании == true |
pressure | Сила нажатия (не все устр-ва поддерживают) |
previous{X,Y} | Пред координаты касания |
start{X,Y} | Начальные координаты касания |
x,y | Текущие координаты касания |
Для анимации свойств существует элемент PropertyAnimation, с ним можно менять сразу несколько свойств одновременно.
import QtQuick 2.12; import QtQuick.Controls 2.2 ApplicationWindow { width: 400; height: 400; visible: true Rectangle { anchors.fill: parent color: "lightgreen" Image { id: img x: 0; y: 0; source: "qrc:/button.png" } PropertyAnimation { target: img properties: "x,y" // Начальное и конечное значение для св-в from: 0; to: 400 - img.height // Длительность мс duration: 1500 running: true loops: Animation.Infinite // Режим. скорость и т.д. есть интерактивный редактор easing.type: Easing.OutExpo } } }
Более эффективная реализация для real и int.
import QtQuick 2.12; import QtQuick.Controls 2.2 ApplicationWindow { width: 300; height: 100; visible: true Rectangle { id: par anchors.fill: parent color: "lightgreen" Rectangle { x: 0; y: 0; height: 100 color: "red" NumberAnimation on width { id: anim1 from: 300; to: 0 duration: 2000 easing.type: Easing.InOutCubic onStopped: { anim2.start() } } NumberAnimation on width { id: anim2 from: 0; to: 300 duration: 2000 easing.type: Easing.InOutCubic running: false onStopped: { anim1.start() } } } } }
ColorAnimation управляет изменением цвета, так же используется from и to.
import QtQuick 2.12; import QtQuick.Controls 2.2 ApplicationWindow { width: 300; height: 100; visible: true Rectangle { anchors.fill: parent ColorAnimation on color { from: "lightgreen" to: "red" duration: 1500 running: true loops: Animation.Infinite } } }
RotationAnimation описывает поворот элемента.
Его свойство direction задает направление поворота:
RotationAnimation.Clockwise | по часовой (по умолчанию) |
RotationAnimation.Counterclockwise | против часовой |
RotationAnimationShortest | угол поворота в наименьшую сторону исходя из «from-to» |
import QtQuick 2.12; import QtQuick.Controls 2.2 ApplicationWindow { width: 150; height: 150; visible: true Rectangle { anchors.fill: parent Image { source: "qrc:/button.png" anchors.centerIn: parent smooth: true RotationAnimation on rotation { from: 0 to: 360 duration: 2000 loops: Animation.Infinite easing.type: Easing.InOutBack } } } }
Behavior реагирует на изменение свойств элементов, соответственно в эти моменты может вызывать другую анимацию и т.д.
В следующем примере, Behavior реагирует на изменение x и y у изображения, внутри другой элемент анимации, изменение же свойств изображения вызывается из событиями мыши в MouseArea
import QtQuick 2.12; import QtQuick.Controls 2.2 ApplicationWindow { width: 360; height: 360; visible: true Rectangle { id: rect anchors.fill: parent Image { id: img x: 10; y: 10; source: "qrc:/button.png" smooth: true Text { anchors.verticalCenter: img.verticalCenter anchors.top: img.bottom text: "Move cursor" } Behavior on x { NumberAnimation { duration: 500 easing.type: Easing.OutBack } } Behavior on y { NumberAnimation { duration: 500 easing.type: Easing.OutBack } } } MouseArea { anchors.fill: rect hoverEnabled: true onMouseXChanged: img.x= mouseX onMouseYChanged: img.y= mouseY } } }
Анимации могут быть объединены в группы, эти группы выполняются последовательно (SequentialAnimation) либо параллельно (ParallelAnimation). Группы могут быть вложенными друг в друга. Если элемент группы не указан, анимации выполняются параллельно.
import QtQuick 2.12; import QtQuick.Controls 2.2 ApplicationWindow { width: 360; height: 360; visible: true Rectangle { anchors.fill: parent Image { id: img source: "qrc:/button.png" smooth: true anchors.centerIn: parent } ParallelAnimation { NumberAnimation { target: img properties: "scale" from: 0.1 to: 3.0 duration: 2000 easing.type: Easing.InOutCubic } NumberAnimation { target: img properties: "opacity" from: 1.0 to: 0 duration: 2000 } running: true loops: Animation.Infinite } } }
import QtQuick 2.12; import QtQuick.Controls 2.2 ApplicationWindow { width: 360; height: 360; visible: true Rectangle { anchors.fill: parent Image { id: img source: "qrc:/button.png" smooth: true anchors.centerIn: parent NumberAnimation on scale { from: 0.1 to: 3.0 duration: 2000 easing.type: Easing.InOutCubic loops: Animation.Infinite } NumberAnimation on opacity { from: 1.0 to: 0 duration: 2000 loops: Animation.Infinite } } } }
Пример последовательной анимации: После нажатия мыши объект упадет вниз, повернется вокруг своей оси, полежит немного, затем поднимется обратно вверх:
import QtQuick 2.12; import QtQuick.Controls 2.2 ApplicationWindow { width: 130; height: 450; visible: true Rectangle { anchors.fill: parent Image { id: img source: "qrc:/button.png" smooth: true Text { anchors.horizontalCenter: parent.horizontalAlignment anchors.top: parent.bottom text: "Click for do it" } MouseArea { anchors.fill: img onClicked: anim.running= true } SequentialAnimation { id: anim NumberAnimation { target: img from: 20; to: 300; properties: "y" duration: 1000 easing.type: Easing.OutBounce } RotationAnimation { target: img from: 0; to: 360; properties: "rotation" duration: 1000 } PauseAnimation {duration: 500} NumberAnimation { target: img from: 300; to: 20; properties: "y" duration: 1000 easing.type: Easing.OutBounce } } } } }
Управлять состоянием можно при помощи элемента State, поддерживает наборы списков, описания элементов с набором их состояний.
Все объекты обязательно должны быть именованными.
Список состояний присваивается свойству states а необходимый набор присваивается свойству state, так и происходит смена состояний.
Изменение свойств внутри состояния перечисляется в в элементе PropertyChanges
import QtQuick 2.12; import QtQuick.Controls 2.2 ApplicationWindow { width: 360; height: 360; visible: true Rectangle { anchors.fill: parent Rectangle { id: rect state: "State2" Text { id: txt anchors.centerIn: parent } } states: [ State { name: "State1" PropertyChanges { target: rect color: "lightgreen" width: 150; height: 60; } PropertyChanges { target: txt text: "State2: Click" } }, State { name: "State2" PropertyChanges { target: rect color: "yellow" width: 200; height: 120; } PropertyChanges { target: txt text: "State1: Click" } } ] MouseArea { anchors.fill: parent onClicked: parent.state= (parent.state== "State1") ? "State2":"State1" } } }
Свойство transitions задает список переходов, в списке задаем элементы Transition, каждый элемент содержит два момента:
import QtQuick 2.12; import QtQuick.Controls 2.2 ApplicationWindow { width: 360; height: 360; visible: true Rectangle { anchors.fill: parent Rectangle { id: rect width: 100; height: 100 color: "magenta" state: "State1" Text { anchors.centerIn: parent text: "Click this" } MouseArea { anchors.fill: parent onClicked: rect.state = (rect.state == "State1") ? "State2":"State1" } states: [ State { name: "State1" PropertyChanges {target: rect; x: 0; y: 0} }, State { name: "State2" PropertyChanges {target: rect; x: 200; y: 200} } ] transitions: [ Transition { from: "State1"; to: "State2"; PropertyAnimation { target: rect; properties: "x,y"; duration: 1000 easing.type: Easing.OutBack } }, Transition { from: "State2"; to: "State1"; PropertyAnimation { target: rect; properties: "x,y"; duration: 1000 easing.type: Easing.InBounce } } ] } } }
Если свойства перехода будут одинаковыми, тогда можно использовать шаблонный переход:
import QtQuick 2.12; import QtQuick.Controls 2.2 ApplicationWindow { width: 300; height: 300; visible: true Rectangle { anchors.fill: parent Rectangle { id: rect width: 100; height: 100 color: "magenta" state: "State1" Text { anchors.centerIn: parent text: "Click this" } MouseArea { anchors.fill: parent onClicked: rect.state = (rect.state == "State1") ? "State2":"State1" } states: [ State { name: "State1" PropertyChanges {target: rect; x: 0; y: 0} }, State { name: "State2" PropertyChanges {target: rect; x: 200; y: 200} } ] transitions: [ Transition { from: "*"; to: "*"; PropertyAnimation { target: rect; properties: "x,y"; duration: 1000 easing.type: Easing.OutBack } } ] } } }
Движок для работы с частицами, в роли частиц могут выступать картинки и т.д.
import QtQuick 2.12; import QtQuick.Controls 2.2; import QtQuick.Particles 2.0 ApplicationWindow { width: 360; height: 360; visible: true Rectangle { anchors.fill: parent color: "MidnightBlue" ParticleSystem { anchors.fill: parent ImageParticle { source: "qrc:/button.png" } Emitter { width: parent.width height: parent.height anchors.bottom: parent.bottom lifeSpan: 10000 sizeVariation: 16 emitRate: 20 velocity: AngleDirection { angle: 90 angleVariation: 10 magnitude: 100 } } } } }