QML Stylizing Button with singleton theme.qml - qt

I have a singleton .qml file for theme definitions: (theme/DarkTheme.qml)
pragma Singleton
import QtQuick 2.4
QtObject {
property var btn: {
"primary": {
color: "#21be2b",
downColor: "#7721be2b",
textColor: "#21be2b",
textDownColor: "#ffffff"
},
}
property color disableColor: "#999999"
property color transparent: "#00000000"
// Primary Button
property QtObject btn_bg: Rectangle {
color: parent ? parent.down ? btn.primary.downColor : transparent : transparent
opacity: enabled ? 1 : 0.7
border.color: enabled ? parent ? btn.primary.color : btn.primary.color : disableColor
border.width: 1
radius: 7
}
property QtObject btn_fg: Text {
text: parent ? parent.text : ""
font.pixelSize: 24
opacity: enabled ? 1.0 : 0.5
color: enabled ? parent ? parent.down ? btn.primary.textDownColor : btn.primary.textColor : btn.primary.textColor : disableColor
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
qmldir:
singleton Theme theme/DarkTheme.qml
Then I set the btn_bg and btn_fg to my buttons to stylize them:
Button {
width: 140
height: 60
text: "Button"
background: Theme.btn_bg
contentItem: Theme.btn_fg
}
Button {
x: 90
y: 90
width: 140
height: 60
text: "Button2"
background: Theme.btn_bg
contentItem: Theme.btn_fg
}
If I use one button only, it works perfectly, but when I use two buttons with same theme background and contentItems, it is not working.
How can I manage to achieve a easy system like this, Button{}s uses same background and foreground but clones the theme Rectangle not directly uses it?

I have managed to do it with making a new component called FButton.qml:
import QtQuick 2.4
import QtQuick.Controls 2.3
import "../"
Button {
property string theme: "primary"
property var themeObj: Theme.buttons[theme]
background: Rectangle {
color: parent.down ? themeObj.downColor : Theme.transparent
opacity: enabled ? 1 : 0.7
border.color: enabled ? themeObj.color : Theme.disableColor
border.width: 1
radius: 7
}
contentItem: Text {
text: parent.text
font.pixelSize: 24
opacity: enabled ? 1.0 : 0.5
color: enabled ? parent.down ? themeObj.textDownColor : themeObj.textColor : Theme.disableColor
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
and theme/DarkTheme.qml is now like this:
pragma Singleton
import QtQuick 2.4
QtObject {
property var buttons: {
"primary": {
color: "#21be2b",
downColor: "#7721be2b",
textColor: "#21be2b",
textDownColor: "#ffffff"
},
"warn": {
color: "#bebe2b",
downColor: "#77bebe2b",
textColor: "#FFbe2b",
textDownColor: "#ffffff"
},
"danger": {
color: "#be212b",
downColor: "#77be212b",
textColor: "#FF212b",
textDownColor: "#ffffff"
},
}
property color disableColor: "#999999"
property color transparent: "#00000000"
}
So, now I can use it like this:
FButton {
x: 20
y: 20
width: 140
height: 60
text: "Button"
theme: "primary"
}
FButton {
x: 20
y: 90
width: 140
height: 60
text: "Button2"
theme: "primary"
}

Related

QML: Change cursor color in TextField

How to change cursor color and probably width in QML TextField element? Let say we have following one:
import QtQuick 2.12
import QtQuick.Controls 2.12
TextField {
id: control
placeholderText: qsTr("Enter description")
background: Rectangle {
implicitWidth: 200
implicitHeight: 40
color: control.enabled ? "transparent" : "#353637"
border.color: control.enabled ? "#21be2b" : "transparent"
}
}
How to make cursor color green or blue or whatever? Thanks!
You have to set Rectangle with the color you want as the cursor through the cursorDelegate since TextField inherits from TextInput and therefore shares that property.
import QtQuick 2.12
import QtQuick.Controls 2.12
TextField {
id: control
placeholderText: qsTr("Enter description")
cursorDelegate: Rectangle {
visible: control.cursorVisible
color: "salmon"
width: control.cursorRectangle.width
}
background: Rectangle {
implicitWidth: 200
implicitHeight: 40
color: control.enabled ? "transparent" : "#353637"
border.color: control.enabled ? "#21be2b" : "transparent"
}
}
#eyllanesc provides a very good answer, but I want to point that the blinking behavior will not be preserved when you define a custom cursorDelegate.
If you want to have the blinking of the cursor. It can be done using an animation:
import QtQuick 2.12
import QtQuick.Controls 2.12
TextField {
id: control
placeholderText: qsTr("Enter description")
background: Rectangle {
implicitWidth: 200
implicitHeight: 40
color: control.enabled ? "transparent" : "#353637"
border.color: control.enabled ? "#21be2b" : "transparent"
}
cursorDelegate: Rectangle {
id: cursor
visible: false
color: "salmon"
width: control.cursorRectangle.width
SequentialAnimation {
loops: Animation.Infinite
running: control.cursorVisible
PropertyAction {
target: cursor
property: 'visible'
value: true
}
PauseAnimation {
duration: 600
}
PropertyAction {
target: cursor
property: 'visible'
value: false
}
PauseAnimation {
duration: 600
}
onStopped: {
cursor.visible = false
}
}
}
}

auto KeyNavigation.tab for custom components "rectangle or item" in QML

in Qml there is auto key navigation for already known components like checkbox,textfield,button and etc , i have my custom component which is a item or rectangle and i want same functionality for it,without writing
KeyNavigation.tab: componentid
here is one of my custom controls :
Rectangle {
signal clicked
property alias font : icoText.font.family
property alias icon : icoText.text
property alias size : icoText.font.pixelSize
property alias toolTip : tooltipText.text
property string colorEnter :"#0481ff"
property string colorExit :"#00171f"
id: root
implicitWidth: 50
implicitHeight: 50
//width: childrenRect.width
radius: 0
//height: childrenRect.height
color: colorExit
state: "default"
Text {
id: icoText
text: ""
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
font.pixelSize: 25
font.family: "fontawesome"
visible: text!= ""
color: "white"
}
ToolTip {
id:tooltipText
text: ""
delay: 500
timeout: 2000
visible: mouseArea.containsMouse && text!=""
font.family: "B Nazanin"
contentItem: Text {
text: tooltipText.text
font: tooltipText.font
color: "white"
}
background: Rectangle {
color: "#cc000000"
border.color: "black"
}
}
InnerShadow {
id:shadow
anchors.fill: icoText
radius: 1.0
samples: 17
horizontalOffset: 1
color: colorExit
source: icoText
visible: false
}
MouseArea{
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onEntered: root.color = colorEnter
onExited: root.color = root.state == "transparent"? "transparent" : root.colorExit
onPressed: {
shadow.visible = true
}
onReleased: {
shadow.visible = false
}
onClicked: {
root.clicked()
}
}
states: [
State {
name: "transparent"
PropertyChanges {
target: root
color:"transparent"
}
PropertyChanges {
target: icoText
color:colorExit
}
},
State{
name: "default"
PropertyChanges {
target: root
color:colorExit
}
PropertyChanges {
target: icoText
color:"white"
}
}
]
}
which will be inside a page like this :
Item{
myControl{
}
myControl{
}
}
this component by default does not loop through pressing tab what should i do?
i already tried this without success, i think this should be inside FocusScope but cause of poor documentation i did not get a simple example for this
set activeFocusOnTab on parent and focus:true in child you want to get focus
Rectangle{
activeFocusOnTab: true
Control{
focus: true
}
}
Focusable Qml Components (Focus My Control On Tab)
For my experience key navigation only works with native components like checkbox, textfield, button, etc.
To work arround this problem I used a fake native component hided with the same size of my custom component like the next example:
Rectangle {
id: myCustomComponent1
width: 100
height: 100
color: red
Button {
id: buttonFake1
text: "My Accessible text Component 1"
width: parent.width
height: parent.height
opacity: 0 // hide the fake component
Accessible.role: Accessible.defaultButton
Accessible.name: text
KeyNavigation.tab: buttonFake2
onClicked: {
console.log(index)
}
onFocusChanged: {
if(focus === true){
// Here do what you want with your custom component
// For example, change color, size, ...
Do_what_you_Want()
// And then set back the focus at the fake native component
// to key navigation keeps working from the same component
buttonFake1.focus = true
}
}
}
}
Rectangle {
id: myCustomComponent2
width: 100
height: 100
color: green
Button {
id: buttonFake2
text: "My Accessible text Component 2"
width: parent.width
height: parent.height
opacity: 0 // hide the fake component
Accessible.role: Accessible.defaultButton
Accessible.name: text
KeyNavigation.tab: buttonFake1
onClicked: {
console.log(index)
}
onFocusChanged: {
if(focus === true){
// Here do what you want with your custom component
// For example, change color, size, ...
Do_what_you_Want()
// And then set back the focus at the fake native component
// to key navigation keeps working from the same component
buttonFake2.focus = true
}
}
}
}

Spin box only works when up/down indicators are clicked, it does NOT works when it is edited by entering numbers

I have this Qt QML spinbox:
The problem is, it actually changes value only when up/down (+/-) indicators are clicked. When edited by entering numbers into spinbox, it does NOT change value. I have tried many things, but I cannot figure out why. Can anybody help?
QML code of the spinbox is this:
StyledSpinBox {
id: overhangAngleFactorSpinBox
implicitWidth: 120
implicitHeight: 30
to: 1 * 100
stepSize: 1
from: 0
Layout.leftMargin: 8
contentItem: StyledTextInput {
inputMethodHints: Qt.ImhFormattedNumbersOnly
}
value: 70
property int decimals: 2
property real realValue: value / 100.0
validator: DoubleValidator {
bottom: Math.min(overhangAngleFactorSpinBox.from, overhangAngleFactorSpinBox.to)
top: Math.max(overhangAngleFactorSpinBox.from, overhangAngleFactorSpinBox.to)
}
textFromValue: function(value, locale) {
return Number(value / 100.0).toLocaleString(locale, 'f', overhangAngleFactorSpinBox.decimals)
}
valueFromText: function(text, locale) {
return Number.fromLocaleString(locale, text) * 100.0
}
onValueChanged: {
editorScene.overhangAngleFactor = value / 100.0
}
}
StyledSpinBox.qml contains:
import QtQuick 2.5
import QtQuick.Controls 2.0 as QQC2
QQC2.SpinBox {
id: control
font.family: editorContent.labelFontFamily
font.weight: editorContent.labelFontWeight
font.pixelSize: editorContent.labelFontPixelSize
background: Rectangle {
border.color: editorContent.listHighlightColor
color: editorContent.paneBackgroundColor
}
down.indicator: Rectangle {
x: control.mirrored ? parent.width - width : 0
height: parent.height
implicitWidth: 40
implicitHeight: 40
border.color: editorContent.listHighlightColor
color: editorContent.listHighlightColor
Image {
anchors.centerIn: parent
source: "images/spinbox_down.png"
}
}
up.indicator: Rectangle {
x: control.mirrored ? 0 : parent.width - width
height: parent.height
implicitWidth: 40
implicitHeight: 40
border.color: editorContent.listHighlightColor
color: editorContent.listHighlightColor
Image {
anchors.centerIn: parent
source: "images/spinbox_up.png"
}
}
}
Problem solved by adding editable: true to spin box. According to documentation, the default value for editable is false:
editable : bool
This property holds whether the spinbox is editable. The default value is false.

How to add animation onPressed and onReleased in QML Slider?

http://doc.qt.io/qt-5/qml-qtquick-controls-styles-sliderstyle.html
Slider {
anchors.centerIn: parent
style: SliderStyle {
groove: Rectangle {
implicitWidth: 200
implicitHeight: 8
color: "gray"
radius: 8
}
handle: Rectangle {
anchors.centerIn: parent
color: control.pressed ? "white" : "lightgray"
border.color: "gray"
border.width: 2
implicitWidth: 34
implicitHeight: 34
radius: 12
}
}
How to access the onReleased and onPressed of the slider in order to start and stop some animation?
Here is what I tried:
import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Controls.Styles 1.4
import QtQuick.Controls 1.4
Window {
visible: true
Slider
{
id: head
property Rectangle thumb: thumb
anchors.centerIn: parent
style: SliderStyle {
groove: Rectangle {
implicitWidth: 200
implicitHeight: 8
color: "gray"
radius: 8
}
handle: Rectangle {
id: thumb
anchors.centerIn: parent
color: control.pressed ? "white" : "lightgray"
border.color: "gray"
border.width: 2
implicitWidth: 34
implicitHeight: 34
radius: 12
}
}
onPressedChanged:
{
if(pressed)
{
console.log("pressed")
returnAnimation.stop()
}
else
{
console.log("released")
returnAnimation.start()
}
}
ParallelAnimation {
id: returnAnimation
NumberAnimation { target: thumb.anchors; property: "horizontalCenterOffset";
to: 0; duration: 200; easing.type: Easing.OutSine }
NumberAnimation { target: thumb.anchors; property: "verticalCenterOffset";
to: 0; duration: 200; easing.type: Easing.OutSine }
}
}
}
Error:
ReferenceError: thumb is not defined
Here is a fully working example. You will have to create your own images referenced here since I can't attach them.
I have found scoping is tricky in QML with component objects. The ":style:handle" component in Slider can "see out" to the higher levels but the higher levels cannot "see in" to the ":style:handle" component.
General Strategy
Create a property in the Top Level Slider scope
Use the property inside the ":style:handle" component since it can "see out"
Use the higher level onPressedChanged handler and the pressed property to adjust the high level property which will be "seen" by the low level component.
Slider {
id: portVoltageSlider
width: 100; height: 27
maximumValue: 150; minimumValue: -150
value: 0.00
stepSize: 10
anchors { centerIn: parent }
// style:handle component will be able to see/access this property
// opacity value of style: SliderStyle:handle.sliderHover
property real hoverOpacity: 0
// adjust property on slider pressed
onPressedChanged: {
// show slider Hover when pressed, hide otherwise
if( pressed ) {
console.log("slider pressed. show hover.")
hoverShowAnimation.start()
}
else {
console.log("slider released. hide hover.")
hoverHideAnimation.start()
}
}
// gratuitous animation using opacity
PropertyAnimation {
id: hoverShowAnimation
target: portVoltageSlider; properties: "hoverOpacity"; from: portVoltageSlider.hoverOpacity; to: 1; duration: 500
}
PropertyAnimation {
id: hoverHideAnimation
target: portVoltageSlider; properties: "hoverOpacity"; from: portVoltageSlider.hoverOpacity; to: 0; duration: 500
}
style: SliderStyle {
id: sliderStyle
property bool hoverVisible: false
groove: Rectangle {
// x: slider1.leftPadding
y: portVoltageSlider.topPadding + portVoltageSlider.availableHeight / 2 - height / 2
implicitWidth: 200; implicitHeight: 4
width: portVoltageSlider.availableWidth; height: implicitHeight
radius: 2
color: "#bdbebf"
Rectangle {
width: portVoltageSlider.visualPosition * parent.width; height: parent.height
color: "yellow"
radius: 2
}
}
handle: Image {
id: sliderHandle
width: 22; height: 24
source: "sliderThumb.svg"
anchors { centerIn: parent }
Image {
id: sliderHover
width: 22; height: 24
source: "sliderValue.svg"
anchors { bottom: sliderHandle.top }
opacity: portVoltageSlider.hoverOpacity
Label {
id: check
anchors {centerIn: parent; verticalCenterOffset: -4 }
text: portVoltageSlider.value
font.pointSize: 6
font.bold: true
}
}
}
}
}
That what I meant in the comment above:
Slider {
...
onPressedChanged: {
if(pressed)
console.log("pressed")
else
console.log("released")
}
}
Would this work?
import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Controls.Styles 1.4
import QtQuick.Controls 1.4
Window {
visible: true
Slider
{
id: head
property Rectangle thumb: thumb
//Added these signals:
signal startAnim
signal stopAnim
anchors.centerIn: parent
style: SliderStyle {
groove: Rectangle {
implicitWidth: 200
implicitHeight: 8
color: "gray"
radius: 8
}
handle: Rectangle {
id: thumb
anchors.centerIn: parent
color: control.pressed ? "white" : "lightgray"
border.color: "gray"
border.width: 2
implicitWidth: 34
implicitHeight: 34
radius: 12
//Moved animation within the confines of the object that it actually pertains to
ParallelAnimation {
id: returnAnimation
NumberAnimation { target: thumb.anchors; property: "horizontalCenterOffset";
to: 0; duration: 200; easing.type: Easing.OutSine }
NumberAnimation { target: thumb.anchors; property: "verticalCenterOffset";
to: 0; duration: 200; easing.type: Easing.OutSine }
}
//Signal connections done here:
Component.onCompleted: {
head.startAnim.connect(returnAnimation.start)
head.stopAnim.connect(returnAnimation.stop)
}
}
}
onPressedChanged:
{
if(pressed)
{
console.log("pressed")
startAnim()
}
else
{
console.log("released")
stopAnim()
}
}
}
}

How to change the font color of a MenuBar?

How can I change the text color of the menu items of a QML MenuBar?
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
import QtQuick.Controls.Styles 1.3 as QtQuickControlStyle
ApplicationWindow {
title: qsTr("Test")
width: 640
height: 480
visible: true
property color menuBackgroundColor: "#3C3C3C"
property color menuBorderColor: "#282828"
menuBar: MenuBar {
style: QtQuickControlStyle.MenuBarStyle {
padding {
left: 8
right: 8
top: 3
bottom: 3
}
background: Rectangle {
border.color: menuBorderColor
color: menuBackgroundColor
}
// font: // how to set font color to red?
// textColor: "red" /* does not work - results in Cannot assign to non-existent property "textColor" */
TextField { // does also not work
style: TextFieldStyle {
textColor: "red"
}
}
}
}
}
A similar question has been asked here but it seems not to work with menu items.
You have to redefine itemDelegate and itemDelegate.label for menuStyle. The former defines the style of the MenuBar text whereas the latter defines the style of menu items text.
In the following example I defined a full style for MenuBar and Menus, not only for their text. scrollIndicator is the only missing piece here. It can be represented as a Text/Label or an Image.
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Controls.Styles 1.3
import QtQuick.Window 2.2
ApplicationWindow {
title: qsTr("Test")
width: 640
height: 480
visible: true
property color menuBackgroundColor: "#3C3C3C"
property color menuBorderColor: "#282828"
menuBar: MenuBar {
Menu {
title: "File"
MenuItem { text: "Open..." }
MenuItem { text: "Close" }
}
Menu {
title: "Edit"
MenuItem { text: "Cut"; checkable: true}
MenuItem { text: "Copy" }
MenuItem { text: "Paste" }
MenuSeparator {visible: true }
Menu {
title: "submenu"
}
}
style: MenuBarStyle {
padding {
left: 8
right: 8
top: 3
bottom: 3
}
background: Rectangle {
id: rect
border.color: menuBorderColor
color: menuBackgroundColor
}
itemDelegate: Rectangle { // the menus
implicitWidth: lab.contentWidth * 1.4 // adjust width the way you prefer it
implicitHeight: lab.contentHeight // adjust height the way you prefer it
color: styleData.selected || styleData.open ? "red" : "transparent"
Label {
id: lab
anchors.horizontalCenter: parent.horizontalCenter
color: styleData.selected || styleData.open ? "white" : "red"
font.wordSpacing: 10
text: styleData.text
}
}
menuStyle: MenuStyle { // the menus items
id: goreStyle
frame: Rectangle {
color: menuBackgroundColor
}
itemDelegate {
background: Rectangle {
color: styleData.selected || styleData.open ? "red" : menuBackgroundColor
radius: styleData.selected ? 3 : 0
}
label: Label {
color: styleData.selected ? "white" : "red"
text: styleData.text
}
submenuIndicator: Text {
text: "\u25ba"
font: goreStyle.font
color: styleData.selected || styleData.open ? "white" : "red"
styleColor: Qt.lighter(color, 4)
}
shortcut: Label {
color: styleData.selected ? "white" : "red"
text: styleData.shortcut
}
checkmarkIndicator: CheckBox { // not strinctly a Checkbox. A Rectangle is fine too
checked: styleData.checked
style: CheckBoxStyle {
indicator: Rectangle {
implicitWidth: goreStyle.font.pixelSize
implicitHeight: implicitWidth
radius: 2
color: control.checked ? "red" : menuBackgroundColor
border.color: control.activeFocus ? menuBackgroundColor : "red"
border.width: 2
Rectangle {
visible: control.checked
color: "red"
border.color: menuBackgroundColor
border.width: 2
radius: 2
anchors.fill: parent
}
}
spacing: 10
}
}
}
// scrollIndicator: // <--- could be an image
separator: Rectangle {
width: parent.width
implicitHeight: 2
color: "white"
}
}
}
}
}
And here is the resulting MenuBar and Menus:
You can also choose to set a MenuStyle directly inside a Menu, in the style property. Something like this:
Menu {
title: "File"
MenuItem { text: "Open..." }
MenuItem { text: "Close" }
style: MenuStyle {
itemDelegate.label: Label {
color: "blue"
text: styleData.text
// stuff above here
}
}
In this last example only the "File" Menu items are styled with a blue color for text. One can argue how much ugly that would be, though.

Resources