I want to use the ComboBox type in my project. Is it possible to change the appearance of the drop-down menu (color, shape, text style) or do I need to use a combination of rectangles, ListViews and other types?
The following code applies customizations but no modification is defined for the drop-down menu which remains gray:
ComboBox {
currentIndex: 2
activeFocusOnPress: true
style: ComboBoxStyle {
id: comboBox
background: Rectangle {
id: rectCategory
radius: 5
border.width: 2
color: "#fff"
Image {
source: "pics/corner.png"
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.bottomMargin: 5
anchors.rightMargin: 5
}
}
label: Text {
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font.pointSize: 15
font.family: "Courier"
font.capitalization: Font.SmallCaps
color: "black"
text: control.currentText
}
}
model: ListModel {
id: cbItems
ListElement { text: "Banana" }
ListElement { text: "Apple" }
ListElement { text: "Coconut" }
}
width: 200
}
The current public APIs does not allow customization of the drop-down menu as stated here. Qt 5.4, i.e. Styles 1.3, just introduced some properties to customize fonts and text (docs here) but still no public access to drop-down customization.
Also, the example provided in the link does not work with the newer versions of Qt. Here is a modified version I've tested with Qt 5.3, Qt 5.4 and Qt 5.5 (remember to add import QtQuick.Controls.Private 1.0 to the imports):
ComboBox {
id: box
currentIndex: 2
activeFocusOnPress: true
style: ComboBoxStyle {
id: comboBox
background: Rectangle {
id: rectCategory
radius: 5
border.width: 2
color: "#fff"
}
label: Text {
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font.pointSize: 15
font.family: "Courier"
font.capitalization: Font.SmallCaps
color: "black"
text: control.currentText
}
// drop-down customization here
property Component __dropDownStyle: MenuStyle {
__maxPopupHeight: 600
__menuItemType: "comboboxitem"
frame: Rectangle { // background
color: "#fff"
border.width: 2
radius: 5
}
itemDelegate.label: // an item text
Text {
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font.pointSize: 15
font.family: "Courier"
font.capitalization: Font.SmallCaps
color: styleData.selected ? "white" : "black"
text: styleData.text
}
itemDelegate.background: Rectangle { // selection of an item
radius: 2
color: styleData.selected ? "darkGray" : "transparent"
}
__scrollerStyle: ScrollViewStyle { }
}
property Component __popupStyle: Style {
property int __maxPopupHeight: 400
property int submenuOverlap: 0
property Component frame: Rectangle {
width: (parent ? parent.contentWidth : 0)
height: (parent ? parent.contentHeight : 0) + 2
border.color: "black"
property real maxHeight: 500
property int margin: 1
}
property Component menuItemPanel: Text {
text: "NOT IMPLEMENTED"
color: "red"
font {
pixelSize: 14
bold: true
}
}
property Component __scrollerStyle: null
}
}
model: ListModel {
id: cbItems
ListElement { text: "Banana" }
ListElement { text: "Apple" }
ListElement { text: "Coconut" }
}
width: 200
}
Here __dropDownStyle is assigned with a MenuStyle type. Some properties of such type are customized to obtain the desired style, in particular itemDelegate (which defines the appearance of an item inside the combobox) and frame (overall background). Refer to the linked MenuStyle APIs for more details. Overall result:
Note that this approach does perfectly work on Windows and Android whereas on OSX the code is completely ignored. One can check the qml style file inside the Qt installation (search for a subpath like qml/QtQuick/Controls/Styles/Desktop) to see what changes w.r.t. Windows and try to adapt the provided solution. This part is left up to the reader.
Thanks alot! I solved this by next code:
Item {
id: app
width: 200
height: 150
ListModel{
id: dataModel
ListElement{ name: "Day" }
ListElement{ name: "Week" }
ListElement{ name: "Month" }
ListElement{ name: "Year" }
}
Button {
id: comboButton
width: parent.width
height: parent.height / 5
checkable: true
style: ButtonStyle {
background: Rectangle {
color: control.pressed ? "#888" : "#fff"
smooth: true
radius: 5
border.width: 2
Image {
source: "pics/corner.png"
anchors.bottom: parent.bottom
anchors.right: parent.right
anchors.bottomMargin: 5
anchors.rightMargin: 5
}
}
label: Text {
renderType: Text.NativeRendering
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font.family: "Courier"
font.capitalization: Font.SmallCaps
font.pointSize: 15
color: "black"
text: "Day"
}
}
onVisibleChanged: {
if(!visible)
checked = false
}
}
TableView {
id: tableView
height: 120
width: parent.width
anchors.bottom: parent.bottom
highlightOnFocus: true
headerVisible: false
visible: comboButton.checked ? true : false
TableViewColumn {
role: "name"
}
model: dataModel
itemDelegate: Item {
Rectangle {
color: styleData.selected ? "#888" : "#fff"
height: comboButton.height - 0.5
border.width: 0.5
width: parent.width
Text {
renderType: Text.NativeRendering
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
font.family: "Courier"
font.capitalization: Font.SmallCaps
font.pointSize: 15
color: "black"
elide: styleData.elideMode
text: styleData.value
}
}
}
rowDelegate: Item {
height: comboButton.height - 0.5
}
onClicked: {
comboButton.checked = false
tableView.selection.clear()
}
}
}
With current Qt (as of 2020), ComboBox can be customized out-of-the box by specifying background, contentItem, indicator and delegate:
https://doc.qt.io/qt-5/qtquickcontrols2-customize.html#customizing-combobox
I've been using approaches like that, but they have a lot of limitations with focus management and z-index management.
I've end up with the implementation of ComboBox which consists of 2 parts: a header which you actually put somewhere and a dropdown component which you create dynamically. The latter consists of an Item covering everything (and intercepting mouse activity) and a dropdown which is carefully positioned below the header.
Code is pretty massive to included here so you can see details in my blogpost with all the code
Related
I have a QML component with a Flickable list and I need this Flickable to get activeFocus when I am clicking on it. I am trying to do it with MouseArea, but can't figure out how to make it work.
My tries:
FocusScope {
id: root
implicitHeight: 100
implicitWidth: 100
Flickable {
id: flickable
anchors.fill: parent
onActiveFocusChanged: console.log("Work!")
...
}
MouseArea {
anchors.fill: parent
onClicked: {
flickable.forceActiveFocus()
mouse.accepted = false
}
preventStealing: true
}
}
FocusScope {
id: root
implicitHeight: 100
implicitWidth: 100
MouseArea {
anchors.fill: parent
onClicked: flickable.forceActiveFocus()
Flickable {
id: flickable
anchors.fill: parent
onActiveFocusChanged: console.log("Work!")
...
}
}
}
In the first variant, my flickable is working, but MouseArea is not handling the click. In the second one, Flickable is not working, but MouseArea is handling the click.
So the question is how to correctly set activeFocus of Flickable on the click event?
Write id for your Flickable
and also Try this code :
import QtQuick 2.12
import QtQuick.Window 2.12
FocusScope {
id: root
width: 640
height: 480
Flickable {
id:flickable
width: parent.width
height: parent.height
contentHeight: mColumnId.implicitHeight
onActiveFocusChanged: console.log("Work!")
Column{
id : mColumnId
anchors.fill: parent
Rectangle {
color: "red"
width: parent.width
height: 200
Text {
anchors.centerIn: parent
text: "Element 1"
font.pointSize: 30
color : "white"
}
}
Rectangle {
color: "blue"
width: parent.width
height: 200
Text {
anchors.centerIn: parent
text: "Element 2"
font.pointSize: 30
color : "white"
}
}
Rectangle {
color: "yellow"
width: parent.width
height: 200
Text {
anchors.centerIn: parent
text: "Element 3"
font.pointSize: 30
color : "white"
}
}
}
MouseArea {
anchors.fill: parent
onClicked: {
flickable.forceActiveFocus()
mouse.accepted = false
preventStealing: true
}
}
}
}
I want to create a chart like this in qt. I already searched and can not find a way to do it.
I also can not find a way to customize Barchart and look like this in Widget Based Applications
Easy in QML!
import QtQuick 2.0
import QtQuick.Layouts 1.1
Rectangle
{
width: 600
height: 300
ListModel
{
id: dataModel
ListElement { label: "C.A"; value: 37 }
ListElement { label: "C.B"; value: 58 }
ListElement { label: "C.C"; value: 16 }
ListElement { label: "C.D"; value: 5 }
ListElement { label: "C.E"; value: 95 }
ListElement { label: "C.F"; value: 10 }
ListElement { label: "C.G"; value: 27 }
ListElement { label: "C.H"; value: 2 }
}
Rectangle
{
height: 4
width: layout.width
anchors.top: layout.bottom
anchors.horizontalCenter: layout.horizontalCenter
color: "#bbbdbe"
}
RowLayout
{
id: layout
width: 400
height: 200
spacing: 0
anchors.centerIn: parent
Repeater
{
id: rpt
property int barWidth: layout.width / count
model: dataModel
delegate:
Rectangle
{
width: rpt.barWidth
height: layout.height
color: "transparent"
Rectangle
{
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
width: 3
height: (parent.height * value) / 100
color: "#448bbe"
Rectangle
{
color: "#448bbe"
radius: width / 2
width: 8
height: 8
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
}
}
Text
{
y: parent.height + 3
anchors.horizontalCenter: parent.horizontalCenter
text: label
}
}
}
}
}
Screenshot
Since the OP didn't specify he wants a solution for a Qt widgets based application [he did after editing the question], the answer is:
Create your own QWidget class. Override the paintEvent and paint in it with a QPainter. I think there's plenty of examples if you google it.
Like this: http://doc.qt.io/qt-5/qtwidgets-painting-basicdrawing-example.html
Or this: http://programmingexamples.wikidot.com/qt-qpainter-example
Or this: Draw on QWidget
You can go for Custom QQuickPaintedItem here you can find an Example.
If I have the following:
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
ApplicationWindow {
title: qsTr("Hello World")
width: 800
height: 700
visible: true
property var myArray: [1, 2, 3, 4, 5, 6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
menuBar: MenuBar {
Menu {
title: qsTr("&File")
MenuItem {
text: qsTr("&Open")
onTriggered: messageDialog.show(qsTr("Open action triggered"));
}
MenuItem {
text: qsTr("E&xit")
onTriggered: Qt.quit();
}
}
}
Rectangle {
id: myButton
anchors.top: parent.top
anchors.topMargin: 5
color: "yellow"
width: 100
height: 25
radius: 3
anchors.horizontalCenter: parent.horizontalCenter
Text {
text: "Clear Selection"
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
MouseArea {
anchors.fill: parent
onClicked: {
myListView.currentIndex = -1
}
}
}
ListView {
id: myListView
width: 300
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: myButton.bottom
anchors.topMargin: 5
anchors.bottom: parent.bottom
currentIndex: -1
//highlightFollowsCurrentItem: false
highlight: Rectangle {
color: "pink"
radius: 3
width: parent.width - 10
height: 25
//y: myListView.currentItem.y
anchors.horizontalCenter: parent.horizontalCenter
}
clip: true
model: myArray
delegate: Rectangle {
width: parent.width - 10
height: 25
color: "transparent"
border.color: "cyan"
anchors.horizontalCenter: parent.horizontalCenter
Text {
text: myArray[index]
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
anchors.fill: parent
}
MouseArea {
anchors.fill: parent
onClicked: myListView.currentIndex = index
}
}
}
MessageDialog {
id: messageDialog
title: qsTr("May I have your attention, please?")
function show(caption) {
messageDialog.text = caption;
messageDialog.open();
}
}
}
When clicking the Clear Selection button I receive the following:
qrc:/main.qml:67: TypeError: Cannot read property of null
qrc:/main.qml:64: TypeError: Cannot read property of null
How can I clear the selection without getting the error? It doesn't appear to crash the application but I have a list view that changes based on another list view selection and the error occurs several times, cluttering up the debug output in Qt Creator. I have noticed this in Qt 5.4 and 5.5
The documentation for ListView says:
An instance of the highlight component is created for each list. The geometry of the resulting component instance is managed by the list so as to stay with the current item, unless the highlightFollowsCurrentItem property is false.
So you don't need to try to manage the position of the highlight item yourself. If you want to position the highlight, create an intermediate parent item instead:
highlight: Item {
Rectangle {
color: "pink"
radius: 3
width: parent.width - 10
height: 25
anchors.horizontalCenter: parent.horizontalCenter
}
}
As for why it happens, it's likely because the highlight item is reparented, leaving it in a state where its parent property is null. You can test this out with the following code:
anchors.horizontalCenter: { print(parent); parent.horizontalCenter }
The problem in general is that if you have a foo, which is supposed to have a bar, then you reference it as foo.bar, however, if foo was not properly initialized, then it cannot have a bar, since it does not exist (yet). In your case it seems that parent is not properly initialized, so it does not have a width and horizontalCenter (in the delegate, maybe), respectively. The solution is to initialize properly the object whose members are to be used, in our case, parent.
I had asked this question over on the Qt forum (https://forum.qt.io/topic/62328/clearing-a-qml-listview-selection) as well, but stack was quicker with a response. Checking the parent value works:
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2
ApplicationWindow {
title: qsTr("Hello World")
width: 800
height: 700
visible: true
property int myMargin: 5
menuBar: MenuBar {
Menu {
title: qsTr("&File")
MenuItem {
text: qsTr("&Open")
onTriggered: messageDialog.show(qsTr("Open action triggered"));
}
MenuItem {
text: qsTr("E&xit")
onTriggered: Qt.quit();
}
}
}
Rectangle {
id: myButton
anchors.top: parent.top
anchors.topMargin: myMargin
color: "yellow"
width: 100
height: 25
radius: 3
anchors.horizontalCenter: parent.horizontalCenter
Text {
text: "Clear Selection"
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
MouseArea {
anchors.fill: parent
onClicked: {
myListView.currentIndex = -1
}
}
}
Rectangle {
width: 300
anchors.top: myButton.bottom
anchors.topMargin: myMargin
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
ListView {
id: myListView
anchors.fill: parent
currentIndex: -1
spacing: 3
highlightMoveDuration: 25
highlight: Rectangle {
width: parent ? parent.width - 10 : 0
height: parent ? 25 : 0
color: "pink"
radius: 3
anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined
}
clip: true
model: ListModel {
id: myArray
Component.onCompleted: {
for (var i = 1; i < 46; i++)
append({number: i})
}
}
delegate: Rectangle {
width: parent ? parent.width - 10 : 0
height: parent ? 25 : 0
color: "transparent"
border.color: "cyan"
anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined
Text {
text: number
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
anchors.fill: parent
}
MouseArea {
anchors.fill: parent
onClicked: {
myListView.currentIndex = index
}
}
}
}
}
MessageDialog {
id: messageDialog
title: qsTr("May I have your attention, please?")
function show(caption) {
messageDialog.text = caption;
messageDialog.open();
}
}
}
I have created one qml list using listview, I require list height but when i try to get the height of list using List.height, the output is zero. but count and contentHeight is coming properly. please suggest how to proceed,please find the below code.
Rectangle{
id:displayarea
anchors.top:subTitle.bottom
anchors.margins: 5
width: parent.width-8
height: parent.height-30
x:4
anchors.topMargin: 2
Image {
id: fileInfoImage
width: parent.width
height: parent.height-15
source: Model.imagePath+Model.imageName
fillMode: Image.PreserveAspectFit
}
listView {
id: list
spacing: 1
interactive: true
width: parent.width
focus: true
anchors {
left: recstring.left;
top: fileInfoImage.bottom;
rightMargin: 1
topMargin: 2;
right: scrollBar.left
}
delegate: listDelegate
model: MainModel
cacheBuffer: 50
onContentHeightChanged: {
console.log("scrollbar visibility",scrollBar.visible,list.height,list.contentHeight,height);
scrollBar.visible = list.height
< list.contentHeight
thumb.height = list.height
/ (list.contentHeight / list.height)
console.log("thumb height",thumb.height,list.height);
}
}
Component{
id: listDelegate
Item{
width: parent.width
implicitHeight: descriptionText.implicitHeight
Rectangle{
id: faultCode
width: scrollBar.visible ? recstring.width-10 : recstring.width-7;
height: parent.height
Text{
id:descriptionText
width:parent.width
text:(strType == 1)?(" \u2022 " +qsTr(disString)):qsTr(disString)
wrapMode: Text.Wrap
font.pixelSize: (text.length === 0) ? 2: 8
anchors {
margins: 1;
}
}
}
}
}
Your ListView height property is not explicitly defined (even not defined at all).
So define height property.
Or, you can try to define the bottom property of your ListView's anchors.
A remark : your ListView's id is invalid:
IDs cannot start with an uppercase letter (M14)
I have to implement TreeView in qml. Basically because each subtree is just TreeView itself, i want to use TreeView component in TreeView definition (this is that Repeater on the end).
This is part of code where i reference the component i am defining.
You can see that rootDelegate is actually id of the Component.
Problem is Qt gives error Unable to assign QQuickRow to QQmlComponent
Repeater {
model: childrens
delegate: rootDelegate
}
TreeView.qml
import QtQuick 2.0
Component {
id: rootDelegate
Column {
Row {
id: itemControl
spacing: 2
Rectangle {
anchors.verticalCenter: parent.verticalCenter
gradient: Gradient {
GradientStop { position: 0.0; color: "#EEEEEE" }
GradientStop { position: 1.0; color: "#404040" }
}
width: openChar.implicitWidth
height: openChar.implicitHeight - 6
radius: 3
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
}
Text {
id: openChar
text: "+"
color: "black"
anchors.centerIn: parent
}
}
Rectangle {
height: 1
color: "#A0A0A0"
width: 10
anchors.verticalCenter: parent.verticalCenter
}
Text {
text: model.text
color: "white"
}
}
Repeater {
model: childrens
delegate: rootDelegate
}
}
}
You are trying to use a Сomponent recursively in itself, it is not allowed in Qml