Cannot create certain QML types in a singleton - qml

I have a QML singleton for use in styling defined as follows:
pragma Singleton
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
QtObject {
property ProgressBarStyle progressBarErrorStyle: ProgressBarStyle {
background: Rectangle {
radius: 2
color: "lightgray"
border.color: "gray"
border.width: 1
implicitWidth: 200
implicitHeight: 20
}
progress: Rectangle {
color: "orangered"
border.color: "red"
}
}
}
I'm able to import the object and use it, however progressBarErrorStyle is always given the type ProgressBarStyle_QMLTYPE_17. If I change it to a Rectangle, then it is correctly typed as QQuickRectangle.
The QtQuick.Controls.Styles import defines ProgressBarStyle, and in QtCreator I'm not getting any syntax errors... so why is my object given the wrong type at runtime?

You should use Component as the property type:
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
Rectangle {
property Component progressBarErrorStyle: ProgressBarStyle {
background: Rectangle {
radius: 2
color: "lightgray"
border.color: "gray"
border.width: 1
implicitWidth: 200
implicitHeight: 20
}
progress: Rectangle {
color: "orangered"
border.color: "red"
}
}
ProgressBar {
id: progressBar
NumberAnimation {
target: progressBar
property: "value"
to: 1
running: true
duration: 2000
}
style: progressBarErrorStyle
}
}
The components for styles are used in Loader items internally, which create instances of the components when they need to, just like delegates in Qt Quick's ListView, for example.

Related

Opacity change on button hovered glitch QML

I have created a custom virtual keyboard where the components are buttons, whose attributes I have defined in the code below . When I rapidly move the mouse across the buttons, I find that there is a 'flashing' effect whereby the button opacity appears to momentarily drop to 0 and then return. How can I prevent this flashing effect?
import QtQuick 2.15
import QtQuick.Controls 2.12
import QtGraphicalEffects 1.0
import "definitions.js" as Defs
Button {
id: keyboardButton
property bool specialButton: false
contentItem: Text {
text: keyboardButton.text
font.family: Defs.font
font.pointSize: Defs.defaultTextSize
color: Defs.ivory
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}
background: Rectangle {
id: background
property double op: specialButton ? 0.7 : 0.5
color: Defs.b_blue
opacity: op
radius: 0
OpacityAnimator on opacity{
running: keyboardButton.hovered
from: background.opacity
to: background.op + 0.05
duration: 100
}
OpacityAnimator on opacity{
running: !keyboardButton.hovered
from: background.op + 0.05
to: background.op
duration: 100
}
}
}
Using one animator fixes it for me:
import QtQuick 2.15
import QtQuick.Controls 2.15
ApplicationWindow {
width: 640
height: 480
visible: true
Flow {
anchors.fill: parent
Repeater {
model: 100
Button {
id: keyboardButton
property bool specialButton: false
contentItem: Text {
text: keyboardButton.text
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}
background: Rectangle {
color: "steelblue"
opacity: hovered ? baseOpacity + 0.15 : baseOpacity
radius: 0
property double baseOpacity: keyboardButton.specialButton ? 0.7 : 0.5
Behavior on opacity {
OpacityAnimator {
duration: 100
}
}
}
}
}
}
}

QML Image size is ignored

I have a ToolButton in QML with an image with size 48x48 pixels:
ToolButton {
contentItem: Image {
source: "Icons/idea48.png"
}
}
if I set width and height nothing changes:
ToolButton {
contentItem: Image {
source: "Icons/idea48.png"
width: 5
height: 5
}
}
on the screen it is still 48x48.
And even adding fill Mode does not help:
ToolButton {
visible: scene.serviceMode
contentItem: Image {
source: "Icons/idea48.png"
width: 10
height: 10
fillMode: Image.Stretch
sourceSize: {
width: 48
height: 48
}
}
}
the sourceSize should be 48 to render image with high pixel density.
I also tried to put Image inside Item, but with no success:
ToolButton {
contentItem: Item {
width: 24
height: 24
Image {
source: "Icons/idea48.png"
fillMode: Image.Stretch
sourceSize: {
width: 48
height: 48
}
}
}
}
Qt Quick Controls 2.3 (Qt 5.10) adds built-in support for button icons. By default, different styles may request different icon sizes, according to their design guidelines, but you can easily override the icon size.
ToolButton {
icon.width: 24
icon.height: 24
icon.source: "Icons/idea48.png"
}
What comes to high-DPI support, consider providing #Nx versions like the Gallery example does: http://code.qt.io/cgit/qt/qtquickcontrols2.git/tree/examples/quickcontrols2/gallery/icons/gallery?h=5.10
Answer 1
Set the sourceSize of the Image in order to influence its implicitWidth and implicitHeight, which are used by the ToolButton to determine the size of the contentItem.
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
ApplicationWindow {
visible: true
width: 640
height: 480
header: ToolBar {
RowLayout {
anchors.fill: parent
ToolButton {
contentItem: Image {
source: "Icons/idea48.png"
sourceSize.width: 10
sourceSize.height: 10
fillMode: Image.Pad
}
}
}
}
}
Answer 2
Put the Image inside an Item so that the Image is not resized by the ToolButton and its dimensions remain exactly as specified by width and height.
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
ApplicationWindow {
visible: true
width: 640
height: 480
header: ToolBar {
RowLayout {
anchors.fill: parent
ToolButton {
contentItem: Item {
Image {
source: "Icons/idea48.png"
width: 10
height: 10
}
}
}
}
}
}
Answer 3
Force the size of the contentItem.
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
ApplicationWindow {
visible: true
width: 640
height: 480
header: ToolBar {
RowLayout {
anchors.fill: parent
ToolButton {
contentItem: Image {
source: "Icons/idea48.png"
}
Component.onCompleted: {
contentItem.width = 10
contentItem.height = 10
}
}
}
}
}

How to Connect two qml files?

I am making a music player application. i have a DownRect which has a slider and a playSection which has a button. this button has a audio. when button is clicked audio is played and i want the slider to set it's value by the audio duration. (the button is add dynamically from ButtonD.qml file). what i want to do is to connect DownRect's slider to playSection's button.
//DownRect.qml
Rectangle{
id: downRectangle
width: parent.width
height: parent.height
x:0
y:750
color: "#c62828"
smooth: true
Slider{
id: sliderDownRect
x: 300
y: 25
width: 650
from: 0
// to: play.duration
stepSize: 100
value: 0
Material.accent : Material.background
Material.foreground: Material.background
onValueChanged:{
}
}
}
and here is the ButtonD.qml file which i'd like to connect to DownRect.qml
//ButtonD.qml
Button{
id: buttonD
width:900
height: 46
flat: true
Audio{
id: playing
}
}
You make sure that the duration (and other relevant properties of Audio) are exposed in ButtonD.qml, e.g. by adding aliases like such:
Button {
id: buttonD
property alias duration: playing.duration
...
}
The same goes for the Slider's value.
Rectangle {
id: downRectangle
property alias duration: sliderDownRect.to
...
}
In the file that instantiates both, you use Binding-objects to create a bidirectional binding between the both. Those Binding-objects excell at working with dynamically instantiated objects.
Basically, if you'd include the files into one file, this should look something like this:
main.qml
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtMultimedia 5.5
ApplicationWindow {
id: myWindow
visible: true
width: 600
height: 600
color: 'white'
property Item dynamicallyCreatedItem
Button {
x: 102
text: 'create'
onClicked: {
dynamicallyCreatedItem = Qt.createComponent('AudioButton.qml').createObject(myWindow.contentItem)
}
}
DownRect {
y: 50
id: rect
}
Binding {
target: rect
property: 'maxValue'
value: dynamicallyCreatedItem ? dynamicallyCreatedItem.duration : 0
when: dynamicallyCreatedItem
}
Binding {
target: rect
property: 'value'
value: dynamicallyCreatedItem ? dynamicallyCreatedItem.position : 0
when: dynamicallyCreatedItem
}
}
AudioButton.qml
import QtQuick 2.0
import QtQuick.Controls 2.0
import QtMultimedia 5.5
Button {
id: audioButton
onClicked: audio.play()
property alias duration: audio.duration
property alias position: audio.position
Audio {
id: audio
source: 'airhorn.wav'
}
}
DownRect.qml
import QtQuick 2.0
import QtQuick.Controls 2.0
Rectangle {
id: rect
width: parent.width
height: 50
property alias value: slider.value
property alias maxValue: slider.to
Slider {
id: slider
anchors.fill: parent
}
}

Center the label in a ComboBox element with a custom ComboBoxStyle

I am using QtQuick.Controls 1.0 and QtQuick.Controls.Styles 1.0 and I can't find a way to properly align the label of the ComboBox vertically and on the right.
This is my current code
import QtQuick 2.0
import QtQuick.Controls 1.0
import QtQuick.Controls.Styles 1.0
ComboBox {
id: comboCategories
width: 230
height: 30
style: ComboBoxStyle {
background: Rectangle {
id: rectCategory
width: comboCategories.width
height: comboCategories.height
color: "white"
}
label: Text {
anchors.verticalCenter: parent.verticalCenter
anchors.right: background.right
font.pointSize: 12
color: "#808080"
text: control.currentText
}
}
}
But the label stays in the top left of my element and does not seem to be affected by the anchors. I also tried to replace parent with control or background with no effect
I don't exactly know the reasoning behind this but if I wrap my Text element in an Item then I can properly
import QtQuick 2.0
import QtQuick.Controls 1.0
import QtQuick.Controls.Styles 1.0
ComboBox {
id: comboCategories
width: 230
height: 30
style: ComboBoxStyle {
background: Rectangle {
id: rectCategory
width: comboCategories.width
height: comboCategories.height
color: "white"
}
label: Item {
anchors.fill: parent
Text {
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: 5
font.pointSize: 12
color: "#808080"
text: control.currentText
}
}
}

item inside component access

I have the following qml file:
import QtQuick 1.0
Component{
Column{
id: interHeader;
Item{
id:interItem
height: 300
width: 200
Text{
id:title
text:"Text"
anchors.centerIn: parent
font.bold: true
elide:"ElideRight"
color: "Black"
}
}
Item {
width: parent.width
height: 100
//onClick event
MouseArea {
anchors.fill: parent
onClicked:{
console.log("Ok");
}
}
}
}
}
The problem is that I need to assign some KeyNavigation to the interItem.
I want to access the interItem from another qml file.
How can this be done?
There really is no benefit of using Component in a completely separate QML file. Remove Component and name your Qml file with a capital letter - e.g. InterHeader
Then define a property under your root item. For example:
import QtQuick 1.0
Item {
id: interHeader
property variant keyActionUp
Keys.onUpPressed: keyActionUp
}
OR
You can use the Connections function to execute callbacks for signals from interHeader.
http://doc.qt.nokia.com/4.7-snapshot/qml-connections.html