Completely new to QT and QML. I'm trying to set the color of a rectangle based on the relationship between the two propery doubles callValue and handRaiseXBB, but I get the error
unexpected token if"
and
expected a qualified name id
Could anyone tell me what I am doing wrong?
import QtQuick 2.0
Item{
id: hand
property double callValue: 0.0
property double handRaiseXBB: 100
property string handCallColor: "green"
property string handFoldColor: "grey"
Rectangle {
anchors.fill: hand
if (hand.callValue >= hand.handRaiseXBB) {
color: hand.handFoldColor
}
else {
color: hand.handCallColor
}
}
}
You can do it like this:
color: (hand.callValue >= hand.handRaiseXBB) ? hand.handFoldColor : hand.handCallColor
You could also make a function to calculate it and then assign the color property with the return value of the function:
function getHandColor()
{
var handColor = hand.handCallColor
if(hand.callValue >= hand.handRaiseXBB)
{
handColor = hand.handFoldColor
}
return handColor
}
color: getHandColor()
Another form to solve this is the following:
Rectangle {
...
color: {
color = hand.handCallColor
if(hand.callValue >= hand.handRaiseXBB)
color = hand.handFoldColor
}
...
}
But the form with ternary operator is a better form!
QML is "based" in javascript, then i belive that all itens are javascript objects, how to:
var Rectangle: {
color: "red",
id: "id",
//then we can do this
setColor: function(_color) {this.color = _color}
}
Related
I'm having trouble overloading a parent function. Here is a simplified example trying to overload the getValue() function:
// MyGauge.qml
CircularGauge {
id: root
width: 235
height: 210
function getValue() {
return 100
}
value: getValue()
}
//main.qml
MyGauge {
function getValue() {
return 200
}
}
When running main.qml I would expect to see a value of 200, but 100 is shown. According to this answer, this should be working.
EDIT: I will provide a more complete example to show what I'm trying to accomplish. My CircularGauge has a complex CircularGaugeStyle. Most gauge's tick label text will just be the actual value of the tick. But ONE gauge should use different text; the values are too large so I want to make it an expression to divide by 1000. How do I do that for just this one gauge, without overriding the whole CircularGaugeStyle in the parent?
// MyGauge.qml
CircularGauge {
id: root
width: 235
height: 210
function tickmarkLabelText(value) {
return value
}
function getColor(value) {
return value >= 50 ? "#e34c22" : "#e5e5e5";
}
style: CircularGaugeStyle {
// LOTS OF OTHER STYLES HERE
tickmarkLabel: Text {
text: tickmarkLabelText(styleData.value) // I want to override just this function
color: getColor(styleData.value)
antialiasing: true
}
}
}
//main.qml
MyGauge {
function tickmarkLabelText(value) {
return value / 1000
}
}
What is the correct approach to insert dynamic properties to dynamically created ListElements in a ListModel using JS?
It's seems that i can't enter a variable reference between { } for supplying properties, it only works for values.model is a LisModel and this function should create the ListElements with both these properties.
function getReadings(model) {
var timeStr = "hour_0";
var temp = 11.9;
model.append({day: 1, timestr: 11.9}); //Error
model.append({day: 1, hour_0: 11.9}); //OK!
}
I'll appreciate any advice.
Keep in mind you're working with javascript. The { } is a JSON object, which is the parameter for the append( ) method.
This worked for me:
MouseArea {
anchors {top: parent.top; right: parent.right}
width: 100
height: 100
onClicked: {
var myKey = "day"
var myValue = "Saturday"
var json = { };
json[myKey] = myValue;
listModel.append(json)
}
}
In this qml code:
Component {
id: userdelegate
PictureBox {
...
icon: model.icon
icon.heigth: 50
}
}
PictureBox comes from the PictureBox.qml system file in this way:
...
Image {
id: icon
...
width: parent.width; height: 150
}
Running qml, I have the error in the title.
I need to use PictureBox.qml, but I can't change it.
How can I override default height value for PictureBox.qml icon?
You can try to bypass QML's scoping rules by traversing Item children until you can find the Image and manipulate it directly. It's possible it could break in the future, but item.toString() gives you something useful:
item.toString() -> "QQuickImage(0x114054350)"
So, you can try something like this (not tested):
function findItemOfType(type, item) {
if (item.toString().indexOf(type) != -1) {
return child;
}
for (var i=0;i < children.length;++i) {
var child = children[i];
var result = findItemOfType(type, child.children);
if (result != null) {
return result;
}
}
return null;
}
Using it like this:
findItemOfType("QQuickImage", pictureBoxId);
I want to select multiple items from a ListView. In C++ I would have done something like this
if (clicked_card->is_selected) {
clicked_card->is_selected = false;
int i = 0;
while(selected_cards[i] != clicked_card) i++;
selected_cards.erase(selected_cards.begin() + i);
} else {
clicked_card->is_selected = true;
selected_cards.push_back(clicked_card);
}
The above code uses pointer for comparison. So how to so such selection in QML. The solution I've come up with is something like this
Card.qml
Image {
id: delegate
property bool isSelected: false
...
MouseArea {
onClicked: {
if(isSelected === true) {
isSelected = false;
gameScene.deselectCard(selectSeq);
}
else {
isSelected = true;
gameScene.selectCard({'opParam': opParam, 'selectSeq': selectSeq});
}
}
}
}
GameScene.qml
Item {
id: gameScene
property var selectedCards: []
signal selectCard(variant userData)
onSelectCard: {
gameScene.selectedCards.push(userData)
}
signal deselectCard(variant userData)
onDeselectCard: {
for (var i = 0; i < gameScene.selectedCards.length; i += 1) {
if (gameScene.selectedCards[i].selectSeq == userData) {
gameScene.selectedCards.splice(i, 1);
break;
}
}
}
}
The problem with the above code is that I'm storing property isSelected in a delegate which is created and destroyed by the system. So this is giving me false solution. Is there any better way of multiple selection or any improvements in the solution ? I'm using model from C++ by subclassing QAbstractListModel.
I found the answer in Qt documentation. I simply have to use [DelegateModel][1]. It has a group property, for every group defined in a DelegateModel two attached properties are added to each delegate item. The first of the form DelegateModel.in*GroupName* holds whether the item belongs to the group and the second DelegateModel.*groupName*Index holds the index of the item in that group.
import QtQuick 2.0
import QtQml.Models 2.2
Rectangle {
width: 200; height: 100
DelegateModel {
id: visualModel
model: ListModel {
ListElement { name: "Apple" }
ListElement { name: "Orange" }
}
groups: [
DelegateModelGroup { name: "selected" }
]
delegate: Rectangle {
id: item
height: 25
width: 200
Text {
text: {
var text = "Name: " + name
if (item.DelegateModel.inSelected)
text += " (" + item.DelegateModel.selectedIndex + ")"
return text;
}
}
MouseArea {
anchors.fill: parent
onClicked: item.DelegateModel.inSelected = !item.DelegateModel.inSelected
}
}
}
ListView {
anchors.fill: parent
model: visualModel
}
}
Other solution would have been to move the property isSelected to C++ data model and use a getter and setter function to update the changes.
An easy solution. Use QPair or QPair to store the state of all of your item.
typedef QPair<int, bool> ItemState;
Enable multiple selection in your list o table:
ui->tableView->setSelectionMode(QAbstractItemView::MultiSelection);
And when you want to select a collection, just try something like this:
QList<ItemState> collection;
foreach (ItemState& el , collection) {
const int row = el.first;
const bool state = el.second;
const QModelIndex& index = ui->tableView->model()->index(row, 0);
ui->tableView->selectionModel()->select(index, state ? QItemSelectionModel::Select : QItemSelectionModel::Deselect );
}
You should update your collection data, everytime you modify the data in the model (add, remove o move elements). When the user clicks in a card, just handle the clicked event and modify your collection item state, and recall the loop.
I would like to know how to get the current item in the Pathview.
We do have have iscurrentItem property but how can we use it if its possible. With my present implementation I'm getting the current index but not the value of the item at that index
If you have the preferredHighlightBegin and preferredHighlightEnd properties defined you could use the childAt function to get the current item:
//example for vertical path
view.childAt(0, view.height * (preferredHighlightEnd + preferredHighlightBegin) / 2.0);
There is another approach where you can iterate all the children of the PathView and find which of the children is the current item:
for(var i = 0; i < view.children.length; ++i)
{
if(view.children[i].PathView.isCurrentItem){
console.log(i + " is current item")
//view.children[i] is your current item here
}
}
In your delegate Item you can set a Connection that updates a path custom property:
PathView {
id: myPathView
// ...
property Item currentItem
delegate: pathDelegate
}
Component {
id: pathDelegate
Item {
id: delegateItem
// ...
Connection {
target: myPathView
onCurrentIndexChanged: {
if (myPathView.currentIndex === delegateItem.index) {
myPathView.currentItem = delegateItem;
}
}
}
}
}
Not so efficient, but it works.