I have an application which use C++ and QML.
In my C++ : I read the value and i send it to QML in order to show it in a slider.
My value change when i press in my hardware.
My problem is in the QML part:
In QML :
I need to trigger an animation for few seconds when this value change. I only need to show this animation when the value from c++ part Change.
if someone could help ?
I already tried the QML timer but not showing animation when value changed ?
Some code in QML part for the animation :
VolumeRemote.QML
Rectangle {
id: item1
width: 550
height: 110
color: "#0a0a07"
border.color: "#ffffff"
opacity: 1
SliderComponent{
id:slider
x: 34
y: 79
width: 466
height: 5
minimumValue: 0
//here i give the value from C++ to my slider
//Controller is a global Qobject where i define some stuff
value: Controller.volume_radio
onValueChanged: {
animation.running=true;
}
PropertyAnimation {
id:myanimation
running: true
target:item1
property: 'visible'
to: false
duration: 10000
}
}
Text {
id: text1
x: 93
y: 16
width: 170
height: 41
color: "#ffffff"
text: qsTr("Radio Volume :")
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 24
font.family: regular.name
}
Text {
id: valeurslider
x: 277
y: 16
// x: 618
//y: 45
width: 24
height: 41
color: "#ffffff"
text: slider.value
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
opacity: 0.45
font.pixelSize: 30
font.family: regular.name
}
Image {
id: image1
x: 34
y: 16
width: 44
height: 41
source: "assets/ic_sound_popup_on.png"
}
}
You have two options
A local property and its change signal
readonly property qreal valueFromCpp: Controller.volume_radio
onValueFromCppChanged: // trigger animation
A Connections element
Connections {
target: Controller
onNameOfThePropertyNotifySignal: // trigger animation
}
if you use this in the C++ part: Q_PROPERTY(int RadioVolume READ getval NOTIFY val_signal ), you have to add a write function to change RadioVolume. Tha is to say:
Q_PROPERTY(int RadioVolume READ getval WRITE setVal NOTIFY val_signal ) and in the function setVal(), you have to change the RadioValume variable value and you have to emit the val_signal everytime the value changes. Instead of setting the value directly, call the setVal() function everywehre you set RadioVolume value and then in the QML part you have to put this: onVal_Signal: put the animation here
If you have any question regarding my answer do not hesitate to ask. If you have the code, i will be glad to help you change it
I use #Beloqui and #KevinKrammar second answer :
1 - Declare simple animation with property visible
2 - SliderCompenent and give the value : Controller.volume_radio
3 - use of connections in order to get the signal notified from C++ : OnVolumesignal
Then i can trigger the animation when signal is emitted from c++ part
Here a small piece of code :
import QtQuick 2.0
import QtQuick 2.0
import Controllers 1.0
import "Logic.js" as Controller_Js
Rectangle {
id: item1
width: 550
height: 110
color: "#0a0a07"
border.color: "#ffffff"
opacity: 1
visible: Controller.stateVol
SliderComponent{
id:slider
x: 34
y: 79
width: 466
height: 5
minimumValue: 0
maximumValue: 100
value: Controller.volume_radio
NumberAnimation {
id: animation
target: item1
property: "visible"
duration: 1000
easing.type: Easing.InOutQuad
}
//gestion du signal
Connections{
target:commodo
onVolumesignal:{
if (commodo.RadioVolume !==100){
Controller.stateVol=true
animation.start();
console.log("state of controller :", Controller.stateVol)
} else if (commodo.RadioVolume>100){
animation.stop();
Controller.stateVol=false
console.log("state", Controller.stateVol)
}
}
}
Cobntroller.stateVol is defined to false in my controller.qml
Thanks guys, it really helped me.
Related
I'm developping an app using QT 5.15 LTS (5.15.2). I have the following QML item that I use to handle virtual keyboard interactions :
//InputScreen.qml
import QtQuick 2.3
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.2
import QtQuick.VirtualKeyboard 2.3
Rectangle
{
id: inputScreen
property var target: undefined
width: app.width
height: app.height
color: "#44000000"
z: 200
onVisibleChanged:
{
if (inputScreen.visible == true)
{
fld.text = target.text;
inputPanel.forceActiveFocus();
fld.forceActiveFocus();
fld.clicked(); //Tried to force a click here. Explanation below
}
}
Rectangle
{
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
height: 40
width: 600
z: 201
TextField
{
id: fld
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
width: 400
height: 40
font.pixelSize: 24
focus: true
}
Button
{
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
width: 200
height: 40
font.pixelSize: 24
text: "Valider"
onClicked:
{
if (target != undefined)
{
target.text = fld.text;
inputScreen.visible = false;
}
}
}
}
InputPanel
{
id: inputPanel
height: 400
width: app.width - 40
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
focus: true
z: 201
}
MouseArea
{
anchors.fill: parent
onClicked:
{
target.text = fld.text;
inputScreen.visible = false;
}
}
}
When my item becomes visible, the textField gets the focus correctly and I can start typing through the InputPanel virtual keyboard. There's however one single problem : the shift key does not work !
In order to make that shift key enable itself, I need to click on the TextField, which beats the purpose of forcing the active focus on it to begin with.
Is there any way to fix that problem ? Or at the very least, is there any kind of workaround I can use to enable that shift key ?
I have already tried to force a click inside my TextField (as seen in the code above), but it didn't work.
For context : here's the content of main.qml as well, in order to give out a working example :
import QtQuick 2.6
import QtQuick.Window 2.2
import QtQuick.Layouts 1.3
import QtQuick.Controls 1.4
import QtQuick.VirtualKeyboard 2.3
Window
{
id: app
visible: true
width: 640
height: 480
title: qsTr("Example")
InputScreen
{
id: inputScreen
visible: false
}
Rectangle
{
id: rect
height: parent.height * 0.8
width: parent.width * 0.8
anchors.centerIn: parent
border.color: "#FF0000"
z: 1
TextField
{
id: myField
anchors.centerIn: parent
width: 200
height: 24
MouseArea
{
anchors.fill: parent
onClicked:
{
inputScreen.target = myField;
inputScreen.visible = true;
}
}
}
}
}
I finally managed to find a trick that enabled that shift key without requiring to click on my already focused TextField, and it's actually very simple.
I simply added the following line in the onClicked event of the MouseArea inside the "myField" TextField :
MouseArea
{
anchors.fill: parent
onClicked:
{
parent.focus = true; //This line solved the issue !
//...
}
}
I have no idea why, but somehow this was enough to actually unlock the shift key from my InputPanel virtual keyboard without requiring me to click a second time on the TextField from my InputScreen item. I suppose it has probably something to do with the fact that my MouseArea is hijacking the focus of the "myField" TextField, which triggers some sort of odd behaviour on the InputPanel item despite having another TextField item focused.
In any case, I hope this will help someone.
I am trying to make a Gomoku game using qml and c++. I have created a 10 * 10 board using qml grid and repeater. like this....
Window {
width: 640
height: 480
visible: true
color: "#241d2b"
title: qsTr("Hello World")
Grid {
x: 10; y: 10
width: 418
height: 418
property bool defineColor: true
rows: 10; columns: 10; spacing: 2
Repeater {
model: 100
Rectangle {
width: 40; height: 40
color: "white"
MouseArea{
anchors.fill: parent
TapHandler{
id:tapped
onTapped: ghuti.visible = uiBridge.showLog(index)
}
}
Rectangle {
id: ghuti
visible: false
radius: width*0.5
anchors.fill: parent
anchors.rightMargin: 5
anchors.leftMargin: 5
anchors.bottomMargin: 5
anchors.topMargin: 5
//anchors.fill: parent
color: "red"
}
Rectangle {
id: ghuti2
visible: false
radius: width*0.5
anchors.fill: parent
property string property0: "none.none"
anchors.rightMargin: 5
anchors.leftMargin: 5
anchors.bottomMargin: 5
anchors.topMargin: 5
//anchors.fill: parent
color: "black"
}
}
}
}
}
The human input can be easily captured by mouse click...but in reply, computer need to turn. But I do not find and clue for automatic computer turn in right place. The two rectangles inside the loop ...one is for human input and other is for computer input.`
I want to create a custom Scrollbar.Like this.
This is my code, i want to use ScrollBar component in Qml.
Rectangle {
id: frame
clip: true
width: 160
height: 160
border.color: "black"
anchors.centerIn: parent
Text {
id: content
text: "ABC"
font.pixelSize: 160
x: -hbar.position * width
y: -vbar.position * height
}
ScrollBar {
id: vbar
hoverEnabled: true
active: hovered || pressed
orientation: Qt.Vertical
size: frame.height / content.height
anchors.top: parent.top
anchors.right: parent.right
anchors.bottom: parent.bottom
}
}
In my case, i want to create with my Scrollbar image.
I tried「source: "./bar.bng" 」,but it said ScrollBar haven't have the parameter "source". How can i use custom image.
Stylesheets (in a form of .qss files, as used for QWidget's) are not used for QML.
Here are examples of how you can implement them though.
For your exact use-case, check out Customizing ScrollBar
I'm rendering a custom OpenGL Item, and on top of that I would like to add some widgets.
So far, it's working fine. This is what it looks like.
However, now I am trying to add a Text item to the OpenGL via:
Rectangle{
id: logoTextBox
x: logoButton.x + logoButton.width
y: logoButton.y
width: 200
height: logoButton.height
color: "#EEEEEE"
Text{
id: logoVersionBlurb
y: 10
x: 10
font.pointSize: 8
text: "Ver 1.0"
color: "black"
}
Text{
id: logoNameBlurb
y: 20
x: 10
font.pointSize: 14
font.bold: true
text: "Please work"
}
}
and It looks like this:
I still want the OpenGL to render, but I want the Text to appear overlayed above it. Any ideas?
I'm creating my GLContext like this in QML:
MyGLWidget{
id: glWidget
}
And here is the relevant method from the C++ file
void MyGLWidget::sync()
{
if (!m_renderer) {
m_renderer = new MyGLRenderer();
connect(window(), SIGNAL(beforeRendering()), m_renderer, SLOT(paint()), Qt::DirectConnection);
}
m_renderer->setViewportSize(window()->size() * window()->devicePixelRatio());
}
Okay, I've found a solution. I set the text's renderType to NativeRendering, and that caused the Triangle to render correctly.
Text{
id:sizeDialogXText
color: "white"
y: sizeDialogTitleText.y + 20
x: sizeDialogTitleText.x
text: "X"
font.pointSize: 12
renderType: Text.NativeRendering //This is the important line
}
In OpenGL terms, what I want to do is modify the projection matrix of a Qt GUI.
Pretend the window is 480x640. It is displayed as normal, and rendered to a texture.
I then take that texture, and stretch it across the entire screen.
Does Qt have something like that? I don't want the GUI looking fine and having appropriately-sized text on a 480x640 tablet, but then it gets loaded up on a 1536x2048 tablet and you need a magnifying glass for the text.
I've written my own GUI in OpenGL before, calculating a vid.width/BASEWIDTH, vid.height/BASEHEIGHT ratio and multiplying the modelview matrix of elements to ensure that a GUI always fills a screen and stays the same size -- obviously this only works perfectly providing the aspect ratio is the same, but I digress.
I messed with layouts in Qt Quick for awhile, and it offers some nice anchoring options, but nothing for stuff like scaling up the text if the parent window is larger. Or am I missing something here?
An OpenGL GUI I wrote had a few options for control position coordinates:
Origin for transforms (Top, Center, Bottom, Left, Center, Right)
PosIsPercentage (specified whether the position coordinates were to be interpreted as a percentage of screen width/height)
This allowed you to set the position as a distance from any edge of the screen, or you could set PosIsPercentage = true and set the X value to 75 to have the coordinate always be at 3/4ths of whatever the screen size was.
There was also a SizeIsPercentage value, so you could set a button to be 10% of the screen width.
I see some of these options in the Qt Quick designer, but they aren't behaving as I expect.
I know this is hard to explain, so here is an image to demonstrate:
http://www.spaddlewit.com/QtLayoutProblem.png
(not what I'm using Qt for, but a good example of the problem I'm having)
Scaling items based on the width and height of the screen works well enough, except when you move to a high DPI device. A better method is to scale items based on the height of the default font. The default font size of a Text item, for example, will always be legible on platforms supported by Qt, no matter the DPI. You can use the same principle to scale font sizes; multiply the default font size by some amount.
Below I've done a quick mock up of the screenshot you linked to:
import QtQuick 2.3
import QtQuick.Controls 1.2
ApplicationWindow {
id: window
contentItem.implicitWidth: 640
contentItem.implicitHeight: 480
contentItem.minimumWidth: 640
contentItem.minimumHeight: 480
contentItem.maximumWidth: 1024
contentItem.maximumHeight: 768
/*
With Qt 5.4, you can also use the new FontMetrics item,
which saves you the overhead of creating a Text item:
For example:
FontMetrics {
id: fontMetrics
}
Then:
font.pixelSize: fontMetrics.font.pixelSize * 4
anchors.margins: fontMetrics.implicitHeight * 2
*/
Text {
id: defaultText
}
Image {
source: "http://cdn2.landscapehdwalls.com/wallpapers/1/perfect-green-hills-1197-1280x800.jpg"
}
Item {
id: container
anchors.fill: parent
anchors.margins: defaultText.implicitHeight * 2
Column {
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
spacing: container.anchors.margins
Text {
id: yourGameText
text: "Your Game!"
font.pixelSize: defaultText.font.pixelSize * 4
wrapMode: Text.Wrap
}
ListView {
interactive: false
anchors.right: parent.right
width: yourGameText.width
height: container.height * 0.3
model: ["Play Game!", "Options", "Exit"]
delegate: Button {
text: modelData
width: ListView.view.width
}
}
}
Row {
anchors.left: parent.left
anchors.bottom: parent.bottom
spacing: container.anchors.margins
Image {
source: "http://www.facebookbrand.com/img/assets/asset.f.logo.lg.png"
width: defaultText.implicitHeight * 3
height: width
}
Image {
source: "http://g.twimg.com/Twitter_logo_white.png"
width: defaultText.implicitHeight * 3
height: width
}
Image {
source: "http://www.youtube.com/yt/brand/media/image/YouTube-logo-full_color.png"
width: defaultText.implicitHeight * 3
height: width
}
}
}
}
Window Size
The first thing I did was set the default, minimum and maximum size of the window.
Scaling
Next, I created an empty Text item which items and text sizes will be based off. It might seem hackish, and it is a bit, but it also works really well. As mentioned in the comment, in Qt 5.4 there will be a FontMetrics type which you can use instead of creating a Text item that will never actually be shown.
Another alternative is to use Screen's pixelDensity property.
Margins
You said you wanted to:
set the position as a distance from any edge of the screen
I did that by creating an Item that fills the window, and then setting the margins from the edges of the window as some factor of the default font's implicit height. This ensures that the content within the item will be the same physical distance (e.g., in millimetres) from the edge of the window regardless of the DPI of the device you're viewing it on. If you'd rather the distance be larger if the window is larger, you can do this instead:
anchors.margins: window.width * 0.1
Font Sizes
Take a look at the Text item within the Column. If you want to ensure the text is also the same physical size on the screen, you can set font.pixelSize to be the default font's size multiplied by some amount. Again, if you'd rather base it off the size of the screen rather than the DPI, you can do this instead:
font.pixelSize: window.height * 0.05
More Information
The Scalability documentation also gives a nice overview on this topic.
Below is a screenshot of the application running:
The following works, but it's annoying -- you have to create a scaleWidth and scaleHeight function and wrap any constant coordinates in them.
Font sizes scale along the shortest edge of the screen -- this application is a Portrait-only orientation, so it uses scaleWidth(pointSize) for font sizes.
Would be nice to find a solution that's compatible with the QML designer.. is there any way to automatically insert this calculation, maybe afterwards in C++ code at runtime?
import QtQuick 2.2
import QtQuick.Window 2.1
import QtQuick.Controls 1.2
ApplicationWindow {
id:window
visible: true
width: 480
height: 640
function scaleWidth(w)
{
return w * (width / 480.0)
}
function scaleHeight(h)
{
return h * (height / 640.0)
}
Text {
id: defaultText
}
Image {
id: image1
x: 0
y: 0
width: window.width
height: window.height
fillMode: Image.Stretch
source: "http://cdn2.landscapehdwalls.com/wallpapers/1/perfect-green-hills-1197-1280x800.jpg"
Label {
id: lblTitle
x: 0
y: scaleHeight(8)
text: qsTr("Welcome to the App")
anchors.horizontalCenter: parent.horizontalCenter
font.pointSize: scaleWidth(36)
horizontalAlignment: Text.AlignHCenter
}
Label {
id: lblSubtitle
x: 0
text: qsTr("Login to Continue")
font.pointSize: scaleWidth(24)
anchors.top: lblTitle.bottom
anchors.topMargin: scaleHeight(8)
anchors.horizontalCenter: lblTitle.horizontalCenter
}
Item {
id: itemCenterAlign
x: 0
y: 0
width: 0
height: 200
anchors.horizontalCenter: parent.horizontalCenter
}
Label {
id: lblUsername
x: 0
text: qsTr("Username:")
anchors.top: lblSubtitle.bottom
anchors.topMargin: scaleHeight(64)
font.bold: true
font.pointSize: scaleWidth(24)
anchors.right: itemCenterAlign.left
anchors.rightMargin: scaleWidth(8)
}
TextField {
id: txtUsername
width: scaleWidth(224)
height: scaleHeight(43)
anchors.left: itemCenterAlign.right
anchors.leftMargin: scaleWidth(8)
anchors.top: lblSubtitle.bottom
anchors.topMargin: scaleHeight(64)
font.pointSize: scaleWidth(24)
placeholderText: qsTr("Username")
}
Label {
id: lblPIN
x: 0
y: scaleWidth(-8)
text: qsTr("PIN:")
font.bold: true
font.pointSize: scaleWidth(24)
anchors.topMargin: scaleHeight(12)
anchors.right: itemCenterAlign.left
anchors.rightMargin: scaleWidth(8)
anchors.top: lblUsername.bottom
}
TextField {
id: txtPIN
x: 0
y: 0
width: scaleWidth(224)
height: scaleHeight(43)
placeholderText: qsTr("PIN")
font.pointSize: scaleWidth(24)
anchors.topMargin: scaleHeight(8)
anchors.leftMargin: scaleWidth(8)
anchors.left: itemCenterAlign.right
anchors.top: txtUsername.bottom
}
Row {
id: row1
x: 0
y: scaleHeight(277)
width: scaleWidth(464)
height: scaleHeight(115)
spacing: scaleWidth(8)
anchors.horizontalCenter: parent.horizontalCenter
Button {
id: cmdQuit
text: qsTr("Quit")
width: row1.width / 3 - row1.spacing / 2
height: row1.height
}
Button {
id: cmdGPSOnly
text: qsTr("GPS Only")
width: row1.width / 3 - row1.spacing / 2
height: row1.height
}
Button {
id: cmdLogin
text: qsTr("Login")
width: row1.width / 3 - row1.spacing / 2
height: row1.height
}
}
Button {
id: cmdAbout
width: cmdQuit.width
height: scaleHeight(44)
text: qsTr("About")
anchors.top: row1.bottom
anchors.topMargin: scaleHeight(8)
anchors.left: row1.left
anchors.leftMargin: 0
}
Label {
id: lblVersion
y: 619
text: qsTr("v3.0.0.0")
font.pointSize: scaleWidth(16)
anchors.bottom: parent.bottom
anchors.bottomMargin: scaleHeight(8)
anchors.left: parent.left
anchors.leftMargin: scaleWidth(8)
}
Label {
id: lblBooks
x: 0
y: lvBooks.y
text: qsTr("Books Loaded:")
horizontalAlignment: Text.AlignRight
font.pointSize: scaleWidth(24)
anchors.right: lvBooks.left
anchors.rightMargin: scaleWidth(8)
}
Rectangle
{
x: lvBooks.x
y: lvBooks.y
width: lvBooks.width
height: lvBooks.height
color: "white"
border.color: "black"
}
ListView {
id: lvBooks
x: 0
y: 0
width: scaleWidth(224)
height: scaleHeight(160)
anchors.bottom: parent.bottom
anchors.bottomMargin: scaleHeight(8)
anchors.right: parent.right
anchors.rightMargin: scaleWidth(8)
model: ListModel {
ListElement {
name: "Book1"
}
ListElement {
name: "Book2"
}
}
delegate: Item {
x: 5
width: scaleWidth(80)
height: scaleHeight(40)
Row {
Text {
text: name
font.bold: true
font.pointSize: scaleWidth(24)
anchors.verticalCenter: parent.verticalCenter
}
spacing: 0
}
}
}
}
}