QML How could i set default option to null of combobox? - qt

My combobox like this:
but i want this:
My combobox default is first currentText,but i don not want it show any thing when i have not pitch on noting.
if i set:
displayText: " "
It doesn't work which one I choose.
the value is null.
what should i do?

You can set currentIndex: -1:
ComboBox {
currentIndex: -1
model: [ ... ]
}
Note: if it user be able to place own text put editable: true

If you just want an empty option, put an empty string in your model:
ComboBox {
model: [
"",
"During transport",
"Before cutting",
"During cutting",
"After cutting"
]
}

Related

How to programmatically append text to a QML TextArea?

I am trying to pass log data to my QML front end, one line at a time, and have it append to the end of a TextArea. I've considered several approaches. The following is the most promising. I have created a QAbstractListModel (in Python) and pass this model into a repeater where it arrives as a single item (rowCount =1) which I append to the TextArea using the line
text: terminal_text.text + display
This works but I get this warning everytime the text is updated.
file://.../TextArea.qml:728:9: QML QQuickTextEdit*: Binding loop detected for property "text"
See below for the code of the repeater.
Repeater {
model: TerminalFeed { }
delegate: TextArea {
id: terminal_text
font.family: "Courier"
width: parent.width
height: parent.height
readOnly: true
selectByMouse: true
wrapMode: TextEdit.NoWrap
horizontalScrollBarPolicy: Qt.ScrollBarAsNeeded
verticalScrollBarPolicy: Qt.ScrollBarAsNeeded
text: terminal_text.text + display
}
}
How can I stop this happening? Alternatively does anyone have a better way of achieving the same result?
Technically, that is indeed a binding loop because text is dependent on its own value. If QML didn't detect it and break it, an infinite loop of updating would result.
Instead of using a binding, you can do something like this:
Repeater {
model: TerminalFeed { }
delegate: TextArea {
id: terminal_text
font.family: "Courier"
width: parent.width
height: parent.height
readOnly: true
selectByMouse: true
wrapMode: TextEdit.NoWrap
horizontalScrollBarPolicy: Qt.ScrollBarAsNeeded
verticalScrollBarPolicy: Qt.ScrollBarAsNeeded
onDisplayChanged: {
text = text + display;
}
}
}
With the original binding approach, it will try and update whenever either display or text changes. With this approach, it will only try and update whenever display changes – which is what you really want.
I had a similar problem where I wanted to show logged data in a QML window.
I use the insert() method, which is inherited from QML TextField. The insertion position is the length of the TextArea.
TextArea {
id: outputTextArea
}
Component.onCompleted: {
data = "dummyString"
outputTextArea.insert(outputTextArea.length, data)
}

How to update ListElement (QML) value field with dynamically updating property

In the below code, the property __operatingModus_season updating every 30 seconds. But in frontend, I dont see any value or changes. Please give some heads up if i am wrong.
ListModel{
id: tileListModelBetriebsmodus
Component.onCompleted: {
if(__is_automatik_mode_ON){
tileListModelBetriebsmodus.append({"tileListSource": "../../images/HausScreen/operatingModeAuto.png",
"tileListText": getFrontendText("AUTO"),
"tileListValue": __operatingModus_season
})
}else{
tileListModelBetriebsmodus.append({"tileListSource": "../../images/HausScreen/hamburgerfinger.png",
"tileListText": getFrontendText("MANUAL"),
"tileListValue": __operatingModus_season
})
}
}
}
This way of adding items to the ListModel doesn't make them dynamic, the values are stored on the spot.
You might be able to Create Property Bindings like this:
ListModel{
id: tileListModelBetriebsmodus
Component.onCompleted: {
if(__is_automatik_mode_ON){
tileListModelBetriebsmodus.append({"tileListSource": "../../images/HausScreen/operatingModeAuto.png",
"tileListText": getFrontendText("AUTO"),
"tileListValue": Qt.binding(function() { return __operatingModus_season })
})
}else{
tileListModelBetriebsmodus.append({"tileListSource": "../../images/HausScreen/hamburgerfinger.png",
"tileListText": getFrontendText("MANUAL"),
"tileListValue": Qt.binding(function() { return __operatingModus_season }
})
}
}
}
Note I did not test this, if you would add a minimal working example I could have done so.
Amfasis' answer suggesting the use of Qt.binding() is on the right track, except Qt won't allow assigning a binding object directly to a ListElement. However, it allows assigning plain JS function objects. So you have to do it in two steps instead:
Step 1: Define your dynamically evaluated ListElement role as a JS function (tip: you can also use the arrow syntax to make this more readable), for example:
ListElement {
dynamicLabel: () => config.useLabelA ? labelA : labelB
}
Step 2: Set up a binding inside your delegate between the target item and the model role:
ListView {
delegate: Text {
Component.onCompleted: {
text: Qt.binding(model.dynamicLabel)
}
}
}
Note the need to go through Component.onCompleted as you can't do text: Qt.binding(model.dynamicLabel) directly (QML spits out an error "Invalid use of Qt.binding() in a binding declaration.").
You can't just do text: model.dynamicLabel either as that would only evaluate the JS function once at initial assignment, but not update if e.g. config.useLabelA changed. That's what you need the Qt.binding() wrapper for.
Building on Romain Pokrzywka's answer:
text: valuedUpdated() ? model.dynamicLabel : "" will be evaluated whenever value is updated. valuedUpdated() is a Q_PROPERTY, which returns true. Notify signal can be emitted whenever value is updated.

Presetting currentIndex in QML TreeView

I'm using QML TreeView to list some categorized options for user to select.
Using property TreeView.selection I have assigned SlectionModel to the treeview.
I have a problem with preselecting the item. Using
treeView.selection.setCurrentIndex(idx,3)
I only set the properties of the selection model(the item gets correctly selected/higlighted), but treeView.currentIndex is still invalid. And when using key up/down, it will jump to the first item.
What am I missing?
ItemSelectionModel {
id: treeViewSelectionModel
objectName: "treeViewSelectionModel"
model: myModel
onCurrentChanged:{console.log("Selectio - current changed from ",previous, " to ", current)}
}
TreeView {
focus: true
id: treeView
objectName: "treeView"
headerVisible: false //to hide the header
TableViewColumn {
title: "Name"
role: "name"
}
model: myModel
selectionMode: SelectionMode.SingleSelection
selection: treeViewSelectionModel
Component.onCompleted: {
var idx = treeView.model.getPreselected();
console.log("preselected",idx);
treeView.selection.setCurrentIndex(idx,ItemSelectionModel.Select);
treeView.selection = treeView.selection
//These logged current indexes does not match
console.log("treeView.currentIndex",treeView.currentIndex);
console.log("treeView.selection.currentIndex",treeView.selection.currentIndex);
updateGuiSize();
treeView.forceActiveFocus();
}
}
The problem is that the treeView.currentIndex and treeView.selection.currentIndex are not the same. If you go to set the value of the treeView.currentIndex, it is accessible only through the hidden variable __listView.
__listView.currentIndex = idx.row
EDIT:
I found another option
treeView.__currentRow = idx.row

selectedRows() in Qml TreeView with ExtendedSelection is one step behind

I have a treeview in the qml, the selection mode is ExtendedSelection. Whenever the selected index changes by the user I need to exactly know which tree rows are selected. Here is the TreeView:
Controls.TreeView {
id: myTreeView
Controls.TableViewColumn {
title: "Name"
role: "name"
}
headerVisible: false
anchors.fill: parent
selection: ItemSelectionModel {
onCurrentIndexChanged: {
console.log(myTreeView.selection.selectedRows(0))
console.log(currentIndex)
}
}
selectionMode: Controls.SelectionMode.ExtendedSelection
onDoubleClicked: {
if (isExpanded(index))
collapse(index);
else
expand(index);
}
}
In the example above I just try to print the selected rows to the console to make sure I have the right selection. currentIndex always holds the last selected index(as expected), but the selection.selectedRows() which is supposed to hold all the rows that are currently selected, is always one step behind. For example:
if user (while holding Ctrl) selects rows 1, 2, 3 one by one the selection.selectedRows() will be null, "1", "1,2" and currentIndex will be 1, 2, 3 respectively. Combining these two together, one can get the list of all indexes that are in selected state.
My problem is that if the user releases the Ctrl and selects row 4, then the selection.selectedRows() will be "1,2,3" although it should be null.
To summarize it is not possible to distinguish between the case that the user selects (holding Ctrl) rows 1,2,3,4 and the case in which user first selects rows (holding Ctrl) 1,2,3 and then releases Ctrl and just selects row 4.
I have also tested with myTreeView.selection.selectedIndexes, but still the same behaviour.
It looks like a bug in TreeView to me, please advice how to solve.
Thanks.
You should use onSelectionChanged instead of onCurrentIndexChanged. With that signal you can get a list of selected indexes.
I don't know your whole code, but using the File System Browser example provided by Qt you can check the difference.
In that example, replace
ItemSelectionModel {
id: sel
model: fileSystemModel
}
by
ItemSelectionModel {
id: sel
model: fileSystemModel
onSelectionChanged: {
console.log("onSelectionChanged - selectedRows: " + selectedIndexes)
}
onCurrentIndexChanged: {
console.log("onCurrentIndexChanged - selectedRows: " + selectedIndexes)
}
}
To see how both signals work.

State.when vs Item.state property

The when property of a QML State type can be used to control when the state should be applied by a boolean expression.
When I set the state property of an QML Item explicitly that seems to override the when properties of all state objects as in the following code:
Item {
id: item
anchors.fill: parent
states: [
State {
name: "when state"
when: 1 === 1
},
State {
name: "explicit state"
}
]
onStateChanged: console.log("state = " + state)
MouseArea {
anchors.fill: parent
onPressed: item.state = "explicit state"
onReleased: item.state = ""
}
}
The initial state of item is the "when state" as it is determined by the when expression. When the MouseArea is pressed the state turns to the "explicit state". After release of the mouse button the state turns to the default state (""). It seems that the when state evaluation is ceased.
Is there any way to "recover" to the "when" state evaluation somehow?
The when properties on states are evaluated:
When a group of states is initially created
When a state's when is altered (either by being set, or when any of the properties that one of the when bindings rely on change)
So no, you can't really "reset" it. I'd suggest not mixing the two methods if you can avoid it.

Resources