How to change triangle in ComboBox qml? - qt

How do I change the size and color of the triangle in a ComboBox? And also flip the triangle?
Now it looks like this

I'm assuming you're using the Material style.
Without declaring your own indicator:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Window {
id: window
width: 640
height: 480
visible: true
ComboBox {
id: comboBox
model: 10
Binding {
target: comboBox.indicator
property: "rotation"
value: 180
}
Binding {
target: comboBox.indicator
property: "color"
value: "tomato"
}
}
}
Declaring your own indicator:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Window {
id: window
width: 640
height: 480
visible: true
ComboBox {
id: comboBox
model: 10
indicator: ColorImage {
x: comboBox.mirrored ? comboBox.padding : comboBox.width - width - comboBox.padding
y: comboBox.topPadding + (comboBox.availableHeight - height) / 2
color: "tomato"
rotation: 180
source: "qrc:/qt-project.org/imports/QtQuick/Controls/Material/images/drop-indicator.png"
}
}
}
Both approaches assume something about the QML implementation of the style in use:
The first approach assumes that the indicator has a color property. This could change in a future version (although it's very unlikely).
The second approach uses an internal resource URL (for convenience, since it's an image that everyone testing this code should have available on their machines), but I wouldn't generally encourage doing so yourself. If you're sure that your application will use the Material style, then it should be fine, but again, this path could change in a future version. If you want a more future-proof option, use your own image for the indicator.
If you want a completely future-proof option, implement your own style:
https://doc.qt.io/qt-5/qtquickcontrols2-customize.html#definition-of-a-style
Qt 6 version of that page:
https://doc.qt.io/qt-6/qtquickcontrols2-customize.html#definition-of-a-style

Related

Custom QML Quick 2 Control with TabBar Inside

I am creating a custom QML Quick 2 TabBar control in Qt 5.15. If I make a simple control (CustomTabBarSimple.qml) as
import QtQuick 2.0
import QtQuick.Controls 2.15
TabBar {
}
Then I can use it with
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Window {
visible: true
width: 640; height: 480
color:"silver"
CustomTabBarSimple
{
id:bar
TabButton { text:"Button1" }
TabButton { text:"Button2" }
}
StackLayout {
anchors.top: bar.bottom
currentIndex: bar.currentIndex
Text {text: "First Stack"}
Text {text: "Second Stack"}
}
}
But if instead I wrap the TabBar in another control like this is no longer functions:
import QtQuick 2.0
import QtQuick.Controls 2.15
Rectangle
{
default property alias contents: bar.data
width: 300; height:50
color: "red"
TabBar {
id: bar
}
}
You can see I tried to use default property alias contents: bar.data to put the TabButton inside the custom control's TabBar but it appears that the TabBar no longer organizes the buttons properly and they no longer change the currentIndex when clicked---likely because the data field is overwriting critical elements.
Is it possible to inject the TabButton into the proper place using a default alias? Second, how would I be able to discover this for myself from the documentation?
There's two problems with your code:
You're trying to access currentIndex from the TabBar, but you're not exposing that property in your CustomTabBarSimple. You can fix that by adding this:
property alias currentIndex: bar.currentIndex
The list of TabButtons are not direct children of the TabBar. TabBar is derived from a Container, which has a list of child objects in contentData. You can read about that here.
default property alias contents: bar.contentData

QML Glow Inside a RowLayout

I am using Qt 5.15 Quick 2 QML to create a row of custom buttons in a window. When I have a standalone custom button things appear to work fine, but when I put them in a RowLayout there appears to be severe clipping and artifacting issues.
A minimum reproducible example might look like:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Layouts 1.15
import QtQuick.Controls 2.15
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
RowLayout
{
anchors.fill:parent
anchors.margins: 25
Button
{
text: "Click Me"
Layout.fillWidth: true
}
CustomButton
{
text: "That Boy Don't Glow Right"
}
Button
{
x: 100; y:100
text: "Click Me"
Layout.fillWidth: true
}
}
}
with the custom control
import QtQuick 2.0
import QtQuick.Controls 2.15
import QtGraphicalEffects 1.15
Button {
id: control
text: "Click Me"
Glow {
anchors.fill: control
radius: 64
spread: 0
samples: 128
color: "red"
source: control
visible: true
}
}
with example output:
One potential fix is to add change the Glow to
Glow {
anchors.fill: control
width: parent.width
height:parent.height
x:control.x
y:control.y
parent: control.parent
...
But this doesn't seem right. First, it's not obvious to me where parent.width and control.x and control.parent are bound from and what happens in single and multiple nesting. If a CustomButton is placed inside another control with id control, would it rebind the property? And it appears if a RowLayout is placed inside a RowLayout, then it would require parent: control.parent.parent. In my actual code there is some non-trivial positioning to allow margins for a drop shadow, too, and the CustomButton is in another container so the actual code that works is: x:control.x + parent.pad/2 and parent:control.parent.parent.parent which is, frankly, ridiculous and assumes that non-standard fields in the parent are always available.
Is there a better way? Was hoping I could keep the button's ability to glow itself.
According to the docs:
"Note: It is not supported to let the effect include itself, for instance by setting source to the effect's parent."
So it's fortunate that you were able to get your example to work at all. One way to avoid using the parent as a source is to point the Glow object at the Button's background object:
Button {
id: control
Glow {
source: control.background
}
}

qml - Referencing top.<property> does not work from ListView?

Can anyone tell me why the following fails?
The Rectangles specify border.width: top.bw where bw is a property in the top Window which has id:top. But the result is zero.
If I replace top.bw with just bw it works in this demo but not in the real application which might have a bw defined in an intermediate object. So I need to specify top.bw somehow.
What's wong with this?
import QtQuick 2.14
import QtQuick.Window 2.14
Window {
id: top
width:800; height: 800
property double bw: 15
ListView {
anchors.fill:parent
model: 3
delegate: Rectangle {
width: 100; height: 100
border.width: top.bw
}
}
}
To understand the problem you must add the following:
Component.onCompleted: console.log(top)
And you will get the following:
qml: QVariant(QQuickAnchorLine, )
So it appears that "top" is an undocumented property in Item(This property is for the use of anchors, for more information read Positioning with Anchors) causing a variable name conflict. The solution is to use another id like "root".
import QtQuick 2.14
import QtQuick.Window 2.14
Window {
id: root
width:800; height: 800
property double bw: 15
ListView {
anchors.fill:parent
model: 3
delegate: Rectangle {
width: 100; height: 100
border.width: root.bw
}
}
}

QT QML how to change only one feature of a, say, button style

changing the style of a component, seems to replace all the features of the default style. is there a way to change only one feature?
For example, suppose i want a red button;
import QtQuick 2.7
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
ApplicationWindow
{
visible: true
width: 640
height: 480
Button
{
height: 200
width: 200
text: "Press me"
style: ButtonStyle
{
// changes background but also throws away everything else
// in standard button style
background: Rectangle { color: "red" }
}
}
}
re-defining ButtonStyle with a background works fine for changing the color of the button, but then everything else within the system default ButtonStyle is gone. For example, the border and the click highlight.
How to just change one feature and keep the rest?
Sorry if this has been asked before.
thanks,
Update
The above question was for Controls 1, but the same problem exists for Controls 2. Here's the same example code for Controls 2.
import QtQuick 2.7
import QtQuick.Controls 2.1
ApplicationWindow
{
visible: true
width: 640
height: 480
Button
{
height: 200
width: 200
text: "Press me"
// changes background but also throws away everything else
// in standard button style
background: Rectangle { color: "red" }
}
}
Preface
The purpose of QtQuick.Controls 1.4 was, to offer controls with native look and feel. If you want to have easier adjustable controls, and don't need the native look, you should consider the newer and faster QtQuick.Controls 2.0.
Main
What you desire is - afaik - impossible, as the default style consists out of two Rectangles and one Image where the Image seems to be the most important. You can find the images in the mingw-package at this location:
Qt\Qt5.7.0\5.7\mingw53_32\qml\QtQuick\Controls\Styles\Base\images
To access the objects of the control, you find them here:
Button {
id: but2
x: 50
onClicked: console.log(this.children[1].item.children[0].item.children[0], this.children[1].item.children[0].item.children[1], this.children[1].item.children[0].item.children[2])
}
So, the easiest solution, to pop into my mind is to use Colorize
import QtQuick 2.0
import QtQuick.Window 2.0
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtGraphicalEffects 1.0
Window {
width: 1024
height: 800
visible: true
Button {
id: but
text: 'test'
}
Colorize {
source: but
anchors.fill: but
// values from the documentation example.
hue: 0.0
saturation: 0.5
lightness: -0.2
}
}
Or to be more general: To just adjust the styling, go for shaders.
QtQuick.Controls 2.0
There you have another case: the background is a Rectangle not just the Component. But if you do not assign one your self, it is only created after the Button.
Button {
id: but1
background.color: 'red'
}
is impossible, as the background is not instantiated when you try to assign the color.
You could use the Component.onCompleted handler to do this:
Button {
id: but1
Component.onCompleted: background.color = 'red'
}
But of course you overwrite the Binding of the original style, that handles the color-change while the Button is beeing pressed
Button {
id: but1
Component.onCompleted: background.color = Qt.binding(function() { return (but1.pressed ? 'red' : 'green') }
}
would enable the color-change again, but you won't have the original color.
You might retrive the orignal color by trying it out:
Button {
id: but1
onPressed: console.log(this.background.color)
onReleased: console.log(this.background.color)
}
This will output you the colors of the two states for pressed. But maybe there are more! So the easiest solution is to use a conditional Binding as this:
Button {
id: but1
}
Binding {
when: but1.pressed
target: but1
property: 'background.color'
value: 'red'
}
All QC2 types that derive from a Control have a member called palette. (See here) For some reason they don't mention this in the docs when they're describing how to customize the different controls. But you can look in the source code to see which palette colors you need to modify for your object. For instance, to change a Button's background to be red, you just need this:
Button
{
id: btn1
palette.button: "red"
}
You can change all buttons in your application by changing the palette in your ApplicationWindow, like this:
ApplicationWindow
{
id: mainWin
// Change default button background to be red
palette.button: "red"
Button
{
id: btn1
// Background will be red
}
Button
{
id: btn2
// You can of course override the default
palette.button: "green"
}
}

Element inheritance not working

I want to achieve some kind of inheritance, like - I have base frame, and then modify it. Here is code sample.
BaseFrame.qml:
Rectangle {
id: base
anchors.fill: parent
function setButtonY (y) {
console.log("Down to ", y)
requestButton.y = y
}
Button {
id: requestButton
width: 200
x: (parent.width / 2) - 100
y: 100
}
}
DerivedFrame.qml:
BaseFrame{
anchors.fill: parent
onVisibleChanged: {
setButtonY(300)
}
Button{
x: 100
y: 100
width: 200
height: 200
visible: true
}
}
The problem is, when I use DerivedFrame - only BaseFrame is shown. If I add some buttons like below, they are never shown:
DerivedFrame {
Button {
// some stuff here + visible: true
}
}
Also - setButtonY correctly show log with correct y, but requestButton never move to the required y. Is there a way to achieve this?
Using absolute positioning is not advised. You can exploit a positioning type (e.g. Column) to automatically lay out your items. However you have to ensure that, while added to BaseFrame.qml, Items are correctly inserted in the positioning item.
When Items are added to a parent, they are inserted inside the default property. In each Item-derived type, data property is the default one. Then we alias the data of the positioning Item and then make that alias the default property. This way we obtain the result searched in the previous paragraph. The BaseFrame.qml could look like this:
import QtQuick 2.0
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
Item {
id: base
anchors.fill: parent
default property alias hook: rowContainer.data //aliasing
Column {
id: rowContainer
anchors.fill: parent
Button {
id: requestButton
width: 300
height: 100
text: "1"
}
}
}
This is a DerivedFrame.qml possible implementation:
import QtQuick 2.0
import QtQuick.Controls 1.2
BaseFrame{
anchors.fill: parent
Button{
anchors.right: parent.right
width: 200
height: 200
text: "2"
}
}
And finally here is the main.qml code:
import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Controls 1.2
ApplicationWindow {
visible: true
width: 500
height: 500
DerivedFrame {
Button {
anchors.horizontalCenter: parent.horizontalCenter
text: "3"
}
}
}
Obviously this is just one of the possible ways to create a dynamic type. You can also have a look to this video, whereas this answer deals with dynamic addition. Finally this answer provides another example usage of default alias.

Resources