How to Correctly Clear Qml ListView Selection - c++

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();
}
}
}

Related

Provide activeFocus to Flickable

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
}
}
}
}

how to take more than one photo in QML?

I have to take 4 continues pictures using the webcamera in QML i can take only one picture after that
I get an error from the QML debugger which states "Camera not ready for capture" how do i get the camera to be in ready state after the first capture this is the code i have tried
even if i set the ready state to true: it does not seem to be working? is there an easy way to get my way around this?
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Rectangle{
width: parent.width
height: parent.height
ColumnLayout{
width: parent.width;height: parent.height
spacing: 15;
Camera{
id:cam
captureMode: Camera.CaptureStillImage
imageCapture {
onImageCaptured: {
ready:true
console.log(ready)
}
}
}
VideoOutput{
id:vid1
source: cam
height:parent.height
width: 800
Layout.fillWidth: true
Layout.fillHeight: true
}
Rectangle{
id:rect1
width: 100
height: 30
Layout.fillWidth: true
Layout.alignment:bottom
color: "#365688"
Text {
id: text1
anchors.centerIn: parent
text:"capture"
font.pointSize: 10
}
MouseArea{
anchors.fill:parent
onClicked: {
console.log("clicked");
for(var i=0;i<=3;i++){
cam.start()
cam.imageCapture.captureToLocation("C:/Users/vinay/Documents")
console.log(cam.cameraStatus)
}
}
}
}
}
}
}

how can i create or achieve a chart like this in Qt?

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.

QML ComboBox item DropDownMenu style

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

Qt5 QtQuick 2.0 (Qt Quick Application) switching views (qml files) in one window

In traditional Qt (QWidget) I have one QMainWindow and some dynamically created QWidgets with the content and I change them that one was seen in main windows. What are the ways of achieving when I have couple qml files and I wants to be able to switch between them when eg clicking a button.
There are at least 3 options for solving this problem:
You can use the ready for this purpose component StackView. The point is that you will create 2 components at once and you'll be able to change them by clicking on the button.
Example:
import QtQuick 2.12
import QtQuick.Controls 2.5
ApplicationWindow {
id: window
visible: true
width: 640
height: 480
title: qsTr("Stack")
header: ToolBar {
contentHeight: toolButton.implicitHeight
ToolButton {
id: toolButton
text: stackView.depth > 1 ? "\u25C0" : "\u2630"
font.pixelSize: Qt.application.font.pixelSize * 1.6
onClicked: {
if (stackView.depth > 1) {
stackView.pop()
} else {
drawer.open()
}
}
}
Label {
text: stackView.currentItem.title
anchors.centerIn: parent
}
}
Drawer {
id: drawer
width: window.width * 0.66
height: window.height
Column {
anchors.fill: parent
ItemDelegate {
text: qsTr("Page 1")
width: parent.width
onClicked: {
stackView.push("Page1Form.qml")
drawer.close()
}
}
ItemDelegate {
text: qsTr("Page 2")
width: parent.width
onClicked: {
stackView.push("Page2Form.qml")
drawer.close()
}
}
}
}
StackView {
id: stackView
initialItem: "HomeForm.qml"
anchors.fill: parent
}
}
Use the Loader here you will dynamically load files during execution, the disadvantage of this method is that if you switch often, it will be time consuming.
Example:
import QtQuick 2.0
Item {
width: 200; height: 200
Loader { id: pageLoader }
MouseArea {
anchors.fill: parent
onClicked: pageLoader.source = "Page1.qml"
}
}
You can create a class in C++ that will be given to an already initialized QML object to an empty qml form. thus, mono place individual components into libraries and use them as plugins (use qqmlcomponent).
I would use a simple Loader, with a button that when is clicked, changes the source file of the Loader. Like so :
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Window {
id: root
Rectangle {
id: page_main
color: "#202020"
anchors.fill : parent
Button {
id: button_page_1
width: 105
text: qsTr("Page 1")
anchors {
left: parent.left
top: parent.top
leftMargin: 6
topMargin: 0
}
checkable: true
onClicked: {
if (loader_main.source == "/page_1.qml") {
loader_main.source = ""
} else {
loader_main.source = "/page_1.qml"
button_page_2.checked = false
button_page_3.checked = false
}
}
}
Button {
id: button_page_2
width: 105
text: qsTr("Page 2")
anchors {
left: button_auto.right
top: parent.top
leftMargin: 6
topMargin: 0
}
checkable: true
onClicked: {
if (loader_main.source == "/page_2.qml") {
loader_main.source = ""
} else {
loader_main.source = "/page_2.qml"
button_page_1.checked = false
button_page_3.checked = false
}
}
}
Button {
id: button_page_3
width: 105
text: qsTr("Page 3")
anchors {
left: button_manual.right
top: parent.top
leftMargin: 6
topMargin: 0
}
checkable: true
onClicked: {
if (loader_main.source == "/page_page_3.qml") {
loader_main.source = ""
} else {
loader_main.source = "/page_page_3.qml"
button_page_1.checked = false
button_page_2.checked = false
}
}
}
}
Loader {
id: loader_main
y: 60
visible: true
anchors {
top: parent.top
bottom: parent.bottom
right: parent.right
left: parent.left
topMargin: 48
bottomMargin: 0
leftMargin: 0
rightMargin: 0
}
}
}