How to display model in QML with pages? - qt

I have problem with displaying model with pages, and I can't find what is proper way to do this.
I have ListView which has model of 15 rectangles like in the picture below.
There is property currentPage which is changed when clicking the buttons. I want to be able to display:
0-4 elements in the first page
5-9 in the second
And last 5 on the third page.
I know that I can create them for example FirstPage.qml, SecondPage.qml... And use them directly, but I want to display Items from model. The ListView is not important it can be any component but I want to use model.
What is the best way to achieve this? Any idea suggestion is welcome.

ListView has a method called positionViewAtIndex() that will allow you to specify which item to scroll to. So for your case, you could do something like this:
Button {
id: previousBtn
onClicked: {
listView.positionViewAtIndex(listView.currentIndex - 5);
}
}
Button {
id: nextBtn
onClicked: {
listView.positionViewAtIndex(listView.currentIndex + 5);
}
}

Related

Trying to style Qt QML items by inserting child styling item

I'm trying different approaches to styling a QT's app QML items. My goal is to:
limit the amount of code in the main files (hide all styling stuff in styling files, unlike in the Style Singleton approach)
not have to define every single type of item I'm going to use (unlike in the Custom Component approach)
possibly be able to mix and match different pre-defined styles in a single item.
Maybe there is a clear strategy to get this, I just didn't read about it yet. And maybe it doesn't make any sense anyway :-)
I've been playing with the idea of defining different components, one for each style type I want to define. The idea is to:
- define a component which is going to modify its parent
- insert that component where I want to adopt that specific style
A first approach relies on some javascript calls:
MyStyle.qml:
Item {
Component.onCompleted: {
parent.color = "lightblue"
parent.radius = 5
parent.border.width = 3
parent.border.color = "black"
}
}
And in my main code:
Rectangle {
id: testRectangle
anchors.fill: parent
MyStyle {}
}
This gives me the result I want, but it doesn't feel right:
I'd like for the styling to be applied statically, once and for all
if I start using this all over the place, won't I see artifacts when objects get created, and slow down my interface?
So I tried this too:
MyRectangleStyle.qml:
Item {
property Rectangle styleTarget
styleTarget.color: "lightblue"
styleTarget.radius: 5
styleTarget.border.width: 3
styleTarget.border.color: "black"
}
and in my main code:
Rectangle {
id: testRectangle
anchors.fill: parent
MyStyle {styleTarget: testRectangle}
}
But:
well, it doesn't work :-) (no warnings though, qml simply doesn't load)
and I'm sort of back to having to define every single type of items I'm going to use.
So, is there a better way to achieve what I'm trying to do here? Thanks!
Your second method does not work because your Component sets properties to an item that does not necessarily exist at the time of creating the Component, instead it sets the property when the styleTarget changes. On the other hand, it is not necessary for MyStyle to be an Item since it is not shown, instead use QtObject, and finally to generalize your method change property Item styleTarget toproperty Rectangle styleTarget:
QtObject {
property Item styleTarget
onStyleTargetChanged: {
styleTarget.color = "lightblue"
styleTarget.radius = 5
styleTarget.border.width = 3
styleTarget.border.color= "black"
}
}

How to clear QML Menu correctly

I have a dynamicaly created Menu. The code below is just to understand the hierarchy
Menu {
id: mainMenu
MenuItem {
text: "item"
}
Menu {
title: "submenu"
MenuItem {
text: "submenuitem"
}
}
}
Now I need to remove all mainMenu's content. As I can see in the documentation, Menu have methods removeItem, takeItem and takeMenu. Using takeMenu and count property I can access menu's children and remove them recursively. But what if I don't know the order and type of menu items? Item has not property count. I need some universal solution that can remove the item itself, and if it is a menu then remove all it's children.
I don't know if it's the cleanest solution, but it works well to clear your example.
while(mainMenu.items.length > 0)
mainMenu.removeItem(mainMenu.items[0]);
You don't need to go recursively because when you remove an Item, all its childItems are removed with it.

Setting activeFocus by clicking anywhere within an Item

I want to set the activeFocus for a FocusScope by clicking anywhere within an Item.
Is there a way to achieve this without having a MouseArea over the entire Item? Because it would have to overlay all elements within the Item, making them unclickable.
I'm pretty new to QtQuick/QML and have troubles understanding how to properly implement FocusScopes. I've read about propagating click signals, but couldn't get it to work.
Assuming I have something like this (no FocusScopes for readability):
Rectangle
{
id: outerRectangle
width: 1000
height: 1000
// various controls in here
Rectangle
{
id: innerRectangle
anchors.centerIn: parent
width: 200
height: 200
// even more controls in here
}
}
I want the outerRectangle to get the activeFocus when I click anywhere on the outerRectangle and vice-versa for the innerRectangle. But all controls on both Rectangles still have to work properly.
How can I achieve this?
Surround your Item with FocusScope:
FocusScope {
Item {
focus: true
}
}
See Qt Doc

ReferenceError in qt quick controls tabview

My code consistently gives me a ReferenceError. I have tried to fix this by using
tv.b1Text = " XD "
as in the example, but it didn't work. How can I fix this error? I believe there's a similar problem here.
Here's my code:
Button {
id: b0
text:"b1's text"
onClicked: {
b1.text = " XD "
}
}
TabView {
id: tv
Tab {
id: tab1
grid {
Button{
id: b1
text:"b1's text"
onClicked: {
//console.log(b1.text)
show_text()
}
}
}
}
}
You have a hierarchy in place here and specific scopes. You cannot access ids without exposing them to higher scopes or without going through the hierarchy, but in the correct way.
Let's examine your TabView: it has a single Tab element which contains a Grid (I'm assuming the grid element is actually a Grid!) which in turns contains the Button you want to modify. If you want to access it from Button b0 you have to:
Select the tab in tv
Select the contained item (via the property of the same name) --> it is Grid
Select the first item of the Grid (which is the only one, our Button)
Hence, in the current setting, a correct code to modify your b1 text from b0 clicked signal handler, is the following:
tv.getTab(0).item.children[0].text = " XD "
Note that data[0] can be used in place of children[0] (see the Item element docs). As you can see here you navigate the hierarchy to reach the QML element to be modified.
As you have seen, the previous code is tedious and error prone. A much better approach would be using the aliasing feature as well as Javascript to improve the overall result; other users already kindly advised you about that.

Get index of the delegate currently displayed - QML ListView

I created a ListView, which displays a couple of pages of content defined by the user (plain text). The page displayed is a delegate. Only one page is visible at a time. I decided to use it to get snapping to one item, in the same way the iOS' launcher works. The user simply flicks between the pages. (this is to be used on touch screens)
I need to have the index of the currently displayed page for some operation. currentIndex of the ListView always stays == 0. How can I get it?
For those who prefer code:
ListView
{
onCurrentIndexChanged: console.log(currentIndex) // this gets called only once - at startup
delegate: Column
{
// The page displayed, only one page at a time
}
}
Thanks
There are many ways to get the index of current item that is displayed in the screen. If you can get the x-y coordinate of current page, you can use indexAt method in ListView.
And in each delegate, you can find the index using index role within the scope of the delegate. The index is like a role you declared in your model, and is automatically assigned by ListView. For example,
ListView
{
delegate: Column
{
property int indexOfThisDelegate: index
//...
}
}
The index role is introduced here:
A special index role containing the index of the item in the model is also available to the delegate. Note this index is set to -1 if the item is removed from the model...
Another way is to explicitly assign value to the currentItem property in ListView, so the view can scroll by itself. Here is an simple example in Qt documentation, which is similar to your application.
I know this is quite old but I had the same problem and spend some time trying to find a way to get currentIndex that would work for me. In my case sometimes I need to change the width of my ListView so I have to recalculte currentIndex manualy every time I resize it.
But I found a highlightRangeMode property. When it's set to ListView.StrictlyEnforceRange then currentIndex is always updated automaticly and contains correct index of the currently visible item.
ListView {
highlightRangeMode: ListView.StrictlyEnforceRange
// ...
}
You can do like that:
QModelIndex index =this->indexAt(event->pos());
this ->setCurrentIndex(index);
You can use attached properties of ListView class (ListView). They are attached to each instance of the delegate.
See ListView.isCurrentItem or ListView.view example:
ListView {
width: 180; height: 200
Component {
id: contactsDelegate
Rectangle {
id: wrapper
width: 180
height: contactInfo.height
color: ListView.isCurrentItem ? "black" : "red"
Text {
id: contactInfo
text: name + ": " + number
color: wrapper.ListView.isCurrentItem ? "red" : "black"
}
}
}
model: ContactModel {}
delegate: contactsDelegate
focus: true
}

Resources