I can show current selection QML ListView but similar thing doesn't work in TreeView.
Part of the problem is for TreeView it doesn't recognize index which is passed to delegate in case of ListView. I tried styleData.indexbut that doesn't work either.
rowDelegate: Item {
id: row_delegate
height: 40
Rectangle {
id: rectid
anchors.fill: parent
MouseArea {
id: mouse_area
anchors.fill: parent
onClicked: {
console.log("Row clicked " + rectid.styleData.index)
}
}
}
}
The output is:
qml: Row clicked undefined
As stated by the documentation, you have a set of properties within the namespace styleData that can be used for almost the same purposes from within a delegate.
As an example, you can set the text property of a label that is part of your delegate as it follows:
text: styleData.value
Where styleData.value is (documentation excerpt):
the value or text for this item
Similarly, you have:
styleData.pressed - true when the item is pressed
styleData.index - the QModelIndex of the current item in the model
styleData.hasChildren - true if the model index of the current item has or can have children
And so on... Please, refer to the documentation for the full list.
Be aware also of the note at the end of the documentation:
Note: For performance reasons, created delegates can be recycled across multiple table rows. This implies that when you make use of implicit properties such as styleData.row or model, these values can change after the delegate has been constructed. This means that you should not assume that content is fixed whenComponent.onCompleted is called, but instead rely on bindings to such properties.
Related
I have this statement inside my QML item:
Rectangle {
// ...
anchors.right: someItemID.right
// ...
}
I'm receiving this warning for my Rectangle item:
QML Rectangle: Detected anchors on an item that is managed by a layout. This is undefined behavior; use Layout.alignment instead.
How can I use Layout.alignment to resolve the above warning? How can I pass another item ID to Layout.alignment? Is it possibe?
A layout manages the positions and sizes of all of its child items. Using anchors inside child items is not allowed as it could override these rules. You can only influence those properties provided by the layout in the Layout object attached to its children, which is hinted at in the warning message. Layout.alignment controls how the item is aligned within the cell created for it by the layout. You can therefore align an item to the edges of its adjacent cells, but you can't directly anchor to their items by ID.
If you need more precise control, you should position the items outside the layout using position and/or anchor properties.
I have the following code:
ListView {
delegate: MyDelegate {
MouseArea {
anchors.fill: parent
/*some other stuff*/
}
}
}
The problem is that MyDelegate contains checkboxes and MouseArea "steals" mouse events from them. They do not react on mouse events at all, i.e. do not work as expected.
I know about propagateComposedEvents property of MouseArea...but I'll have to implement all of its mouse events (clicked, pressed, released,...) and check whether the mouse cursor is in the checkbox or not to set mouse.accepted property accordingly.
This is how I understood all of these currently. Is there any easier way, i.e. a way to be able to process all of the mouse events for areas that does not handle mouse events explicitly? For instance static text, progress bars, etc.
You can apply negative values to the z property of the MouseArea.
From the documentation:
Items with a higher stacking value are drawn on top of siblings with a lower stacking order. Items with the same stacking value are drawn bottom up in the order they appear. Items with a negative stacking value are drawn under their parent's content.
I want to access delegate properties in ListView. I've tried with contentItem but sometimes it's undefined.
Here is my code:
ListModel{
id: modeldata
ListElement{
name:"don"
rank:1
}
ListElement{
name:"shan"
rank:2
}
ListElement{
name:"james"
rank:3
}
ListElement{
name:"jeggu"
rank:4
}
}
Component{
id: delegateitem
Row {
property int count: rank
Rectangle{
width: 100
height: 50
Text{
anchors.centerIn: parent
text: name
}
}
}
}
ListView{
id: listview
focus: true
anchors.fill: parent
model: modeldata
delegate: delegateitem
onCurrentIndexChanged: {
console.log("position",currentIndex)
console.log("property",contentItem.children[currentIndex].count);
}
}
Problem invalid output at position 1
qml: position 0
qml: property 1
qml: position 1
qml: property undefined
qml: position 2
qml: property 2
qml: position 3
qml: property 3
#Teimpz didn't really explain it well. Especially since there are bunch of qt project and ubuntu touch qml examples and use cases where you manage dynamically created list elements using javascript, and that is why they have javascript methods and properties
In QML there is more a notion of parent than a child, which is common in html. In bigger projects it is recommended (as you can also see in qt examples and in docs http://doc.qt.io/qt-5/qtqml-javascript-expressions.html#functions-in-imported-javascript-files) to have js logic separate from qml elements so you do access and manage elements from outside rather than pollute you qml elements with js logic, but not in a way of looking for children elements, but rather exposing children elements that you need.
In your case you should just use currentItem, same as you use currentIndex, so currentItem.count will give you what you need.
And if you don't need current item at all, you can access elements from model directly:
modelData.get(currentIndex).count, or listview.model.get(currentIndex).count
As for the hack that is mentioned by #Teimpz that is also one bad example. When you have more complex requirements and wanting specific elements inside delegate, every delegate has ListView.isCurrentItem property which you can attach and check. This would mean you can add property var myTargetItem to listview, and set it from child to whatever element you want if that delegate is current http://doc.qt.io/qt-5/qml-qtquick-listview.html#isCurrentItem-attached-prop
You can of course do that for any kind of event, maybe activeFocus so you could only reference activeFocused item.
This once again give you ability to expose only wanted elements without any advanced logic or lopping. Combining this with signals you can create very complex but clean interfaces without searching through children items.
So in the end maybe less nice but still better than searching for elements would be to add property int currentItemCount: 0 to listview. In delegate (Row element) you then add property bool isCurrentItem: ListView.isCurrentItem
so you get onIsCurrentItemChanged signal inside delegate, where you can do:
onIsCurrentItemChanged: if(isCurrentItem) listview.currentItemCount = count
so you have your current item count always set
The simple way is using itemAtIndex() like intemAt() in Repeater.
First of all: if you are trying to access list elements from outside your list, this is a good indicator that you should rethink your desing.
Now the solution: a listview has more children than only its items. You can filter them out by defining a property "property string type: "myType" " for example. Then find the items by looping over the children and only take those where the type property equals "myType".
Its somewhat of a hack but again you should really not be doing this in the first place.
myListView.itemAtIndex(currentIndex)).function_name()
Using QML, I’m writing a custom itemDelegate and rowDelegate that I want to be able to use across any number of different TableView instances. As the code to follows shows, I’ve been able to accomplish this—but only in a way that I’m extremely dubious about it working in future (or previous, for that matter) releases of Qt. I’m currently using Qt 5.2.
Component {
id: tableRowDelegate
Rectangle {
height: 16
color: styleData.selected ? "#448" : (styleData.alternate? "#eee" : "#fff")
property TableView tableView
// The view is 8 levels up for the rowDelegate
Component.onCompleted: {
if (styleData.row > -1) // Not entirely sure why this is needed -- worse, I don't know why it works; it just does
tableView = parent.parent.parent.parent.parent.parent.parent.parent
}
// Other delegate code omitted for brevity
}
}
Component {
id: tableCellDelegate
Rectangle {
width: parent.width
height: parent.height
color: "transparent"
border.color: "#a3b3b3"
border.width: 1
radius: 5
property TableView tableView
// The View is 9 levels up for the itemDelegate
Component.onCompleted: {
tableView = parent.parent.parent.parent.parent.parent.parent.parent.parent
}
// Other delegate code omitted for brevity
}
}
Once these delegates are constructed, access to the enclosing TableView is trivial
(and anonymous) by prefixing the property or signal name with ‘tableView.’; i.e.
tableView.alternatingRowColors
. . . just for example.
Is there really no better way to access the view from within a delegate without
hard-coding the ancestry, as in the above examples, or worse: without hard-binding
explicitly to the id of the TableView?
Caveat: I haven't actually tested this to make sure it'll work with a 2nd TableView.
It does work with the one I'm testing with.
Thanks for any thoughts!
Wayne
UPDATE with the answer. Thanks again, mlvljr, for helping me brainstorm this through.
Inline, at the TableView level, I can use a Loader element as kind of a wrapper delegate to create the loose-binding with the "real" delegate; as follows:
rowDelegate : Loader {
property TableView tableView : itemsAcquiredList
property QtObject styleDataExported: styleData
sourceComponent: tableRowDelegate
}
Those properties defined in the Loader are then available to
my "real" delegate. I can copy-paste just that block into any other
TableView, change just the id assigned to the tableView property, and
then use it with my reusable delegate.
It turns out that when I use a loader to get my delegate, styleData, and
model are no longer available directly in the loaded delegate; hence the
need for the 'styleDataExported' property in the Loader (the tableView
property now provides access to the model). So, for extra sugar-coating,
I can add two property bindings inside the loaded delegate, as follows:
property QtObject styleData: styleDataExported
property var model : tableView.model
And viola! Now my delegate's code looks just like a real one, and I
can get all the properties, signals, and methods from the TableView
ancestor without ever using its 'id', and without ever making any
assumptions about the internal ancestry of a delegate.
I don't know much about the loader, or whether I'll incur a performance
penalty for doing this, but it does give me a clean separation and
loose-binding between the view and the delegate. For now, this is
exactly what I was looking for.
Update II: I have tested this with both an itemDelegate, and a rowDelegate,
and they both work as expected.
I have one Textfield, Combo and a Radio. I want to get values of these 3 fields on clicking one button. How I can get the values of above 3 without using Ext.getCmp('id').getValue();
Is there any other method is their to get the values,
please let me know.
It depends on how you have contained your fields and the button you want to click to get their values.
You can navigate up and down your containers
var TheComponent = this.up('form').down('#MyTextField')
This climbs up your container hierarchy until it finds a 'form' container (doesn't matter what its Id or name is) and them climbs down until it finds a component with the id: 'MyTextField'
If your radio button is in a radio button group container you can retrieve an object that has all your 'on' key/values.
If your container is a form you can use the method proposed by lzhaki and retrieve an object that contains all the values on your form. Just remember that combo boxes behave differently to text boxes.
Each of these methods will return either a single value or an object containing a group of values.
In ExtJS 4.1, I found the prior example was close, but incorrect:
var TheComponent = this.up('form').down('#MyTextField')
There is no "down" method in the form object (apparently form fields aren't included in the down method's navigation logic).
Here's what worked for me to set initial focus on an edit field within a form.
var theForm = this.down('form').getForm();
var theField = theForm.findField('idEditVolname');
theField.focus();
You still must use getForm() to get the embedded form object, followed by findField() to locate the specific field - at least that's what works for me.
I don't know if this is still relevant, but here goes.
First of all, in Extjs4 and up, you use Ext.ComponentQuery.query() instead of Ext.getCmp().
What this allows you to do is access any xtype you have directly, just like the up, and down methods mentioned in other answers, but this method doesn't need any anchors as it searches the entire component hierarchy. Since you have only one of each element on the page that would be very easy to achieve without using id's.
I would name the main panel that contains the fields, but that's just for convenience.
Look at this fiddle
The code is really simple:
var panel = Ext.create('Ext.panel.Panel', {
renderTo: Ext.getBody(),
name: 'myForm',
title: 'Sample Test',
layout: 'anchor',
height: 200,
items: [{
xtype:'textfield',
fieldLabel: 'text',
value: 'Oh yeah!'
}]
});
var myVal = Ext.ComponentQuery.query('panel[name=myForm] textfield')[0];
alert (myVal.getValue());
The same can be done with the radio and combo fields, and you don't need a form for that, though it is more logical that way.