I'm trying to find any way to implement an transition when i navigate between tabs in an TabView in QML, but I can't find that, is there any way to do it ?
my code is:
TabView{
id : tbView
height: parent.height
width: parent.width
Tab{
HomePage{
id: home
height: tbView.height
width: tbView.width
onBtnConfigClicked: btnPlay()
}
}
Tab{
Rectangle{
anchors.fill: parent
color: "blue"
}
}
}
function btnPlay()
{
tbView.currentIndex = 1
}
the HomePage element has an signal btnConfigClick, then i attach it to the function btnPlay, it function change currentIndex property to 1, the first tab is 0, I would like an slide transition when a change the currentIndex.
Well, you can use the TabBar compontent together with a SwipeView:
From documentation:
TabBar {
id: bar
width: parent.width
TabButton {
text: qsTr("Home")
}
TabButton {
text: qsTr("Discover")
}
TabButton {
text: qsTr("Activity")
}
}
SwipeView {
width: parent.width
currentIndex: bar.currentIndex
Item {
id: homeTab
}
Item {
id: discoverTab
}
Item {
id: activityTab
}
}
So changing the currentIndex property of TabBar will automatically perform a SwipeView transition to corresponding item.
Because your question is not entirely clear to me, I do not know whether that is what you wanted to achieve.
Related
I am new to Qt. Wondering if there a possibility to make an item "unselectable" in ListView.
I see there are a lot of other things, e.g: collapsing , expanding, etc.
**
I have not find any simple example for this problem. **
Can you provide some minimalistic examples to make a specific item in the list unselectable?
I have the following minimalistic example. How can I set list item index 2 to be unselectable?
Window {
id: mainWindow
width: 130
height: 240
visible: truetitle: qsTr("Hello")
Rectangle {
id: bg
color: "#ffffff"
anchors.fill: parent
ListModel {
id: nameModel
ListElement { name: "Alice" }
ListElement { name: "Bob" }
ListElement { name: "Jay" }
ListElement { name: "Kate" }
}
Component {
id: nameDelegate
Text {
text: model.name
font.pixelSize: 24
}
}
ListView {
anchors.fill: parent
model: nameModel
delegate: nameDelegate
clip: true
highlight: Rectangle {
anchors { left: parent.left; right: parent.right }
//height: parent.height
color: "lightgrey"
}
}
}
}
I found numerous issues with your code snippet, so I attempted to address them all:
I made use of Page and set Page.background instead of declaring an outer Rectangle. This removes a level of indentation
I refactored NameComponent.qml to reduce the complexity of your main program
I change the delegate from Text to ItemDelegate so that it is clickable, and, it being clickable, I can (1) make the ListView have active focus so that it can receive keyboard events, (2) change the current item in the ListView => I think this achieves your criteria of being able to select a different item
I removed unnecessary anchoring from your highlight - your highlight will default anchor to your selected item
I set the width of your delegate to listView.width - I also made use of the ListView.view attached property so that your delegate and access properties from the ListView
Finally, I added a 20 pixel width vertical ScrollBar
import QtQuick
import QtQuick.Controls
Page {
background: Rectangle { color: "#ffffff" }
ListModel {
id: nameModel
ListElement { name: "Alice" }
ListElement { name: "Bob" }
ListElement { name: "Jay" }
ListElement { name: "Kate" }
}
ListView {
anchors.fill: parent
model: nameModel
delegate: NameDelegate { }
clip: true
highlight: Rectangle {
color: "lightgrey"
}
ScrollBar.vertical: ScrollBar {
width: 20
policy: ScrollBar.AlwaysOn
}
}
}
// NameDelegate.qml
import QtQuick
import QtQuick.Controls
ItemDelegate {
property ListView listView: ListView.view
width: listView.width - 20
text: model.name
font.pixelSize: 24
onClicked: {
listView.forceActiveFocus();
if (listView.currentIndex === index) {
listView.currentIndex = -1;
} else {
listView.currentIndex = index;
}
}
}
You can Try it Online!
I want to create Tabs. So using Tab bar and Tab buttons i am creating tabs and using stack layout i am loading the respecting screen.
Note: i dont want to use loader. Using only Stack layout how can i load the screen.
Please suggest how can i do that?
Item {
id:screenTabs
property var tabname : [qsTr("Tab1"),qsTr("Tab2"),qsTr("Tab3"),qsTr("Tab4"),qsTr("Tab5")]
property var tabScreen : ["qrc:/Tabscreen1.qml","qrc:/Tabscreen2.qml","qrc:/Tabscreen3.qml","qrc:/Tabscreen4.qml","qrc:/Tabscreen5.qml"]
width : parent.width
height : parent.height
TabBar
{
id: bar
width: parent.width*0.95
anchors {
top: parent.top
topMargin: 15
left: parent.left
leftMargin: 10
}
Repeater
{
model: tabname.length
TabButton
{
text: tabname[index]
}
}
}
StackLayout
{
id: stacklyt
width: parent.width
height: parent.height
currentIndex: bar.currentIndex
anchors {
top: bar.bottom
}
Repeater
{
model: tabScreen.length
Loader
{
width: parent.width
height: parent.height
source: tabScreen[index]
}
}
}
}
Also without using loader i am doing below shown way but this is not what i am expecting:
StackLayout {
id: stackLayout
width: parent.width
height: parent.height
currentIndex: bar.currentIndex
anchors.top: bar.bottom
Item {
}
Item {
}
Item {
}
Item {
}
Item {
}
}
If you don't want to use the Loader I think you have to instantiate the component given the name (and not the URI) and put them in a Container type (here the StackLayout) as you mention in your second solution.
without using loader i am doing below shown way but this is not what i am expecting
Why is this not what you expect? Did you replace Item with your components? You might have to add an import statement for your components if you are getting an import error.
StackLayout
{
id: stacklyt
width: parent.width
height: parent.height
currentIndex: bar.currentIndex
anchors.top: bar.bottom
Tabscreen1 {}
Tabscreen2 {}
Tabscreen3 {}
Tabscreen4 {}
Tabscreen5 {}
}
Is it possible to remove the animation from swipeviews? The one where you see the transition from the previous and the next page. I have many pages and I have a menu that selects the active item like:
mainContent.setCurrentIndex(0)
where mainContent is the swipeview.
// The content changes based on what is clicked on in the menu
SwipeView{
width: mainWindow.width - mainMenuId.width -anchors.leftMargin
id:mainContent
anchors.leftMargin: 20
anchors.topMargin: 20
clip:true
Component.onCompleted: contentItem.interactive = false
currentIndex: 0
Item{PageMain{}}
Item{PageTests{}}
Item{PageData{}}
Item{PageSavedFiles{}}
Item{PageProbe{}}
}
Either you can override the contentItem and disable ListView's animation, or, if you don't really need the swipe part of SwipeView, use e.g. StackLayout instead:
TabBar {
id: bar
width: parent.width
TabButton {
text: qsTr("Home")
}
TabButton {
text: qsTr("Discover")
}
TabButton {
text: qsTr("Activity")
}
}
StackLayout {
width: parent.width
currentIndex: bar.currentIndex
Item {
id: homeTab
}
Item {
id: discoverTab
}
Item {
id: activityTab
}
}
That code is using TabBar, but I think you get the idea. :)
Let us suppose I have a card made using Rectangle and I want to show buttons on top of it when clicked. I'm calling showMenu() function to do that and for buttons I'm using an ListView with dynamic ListModel. The problem with such is that the button gets added bellow the Rectangle instead of the top of it. The anchor is not updating after appending an item to the model. Here is my code
Item {
width: 120
height: 120
Rectangle {
id: card
width: 50
height: 100
color: "pink"
anchors.bottom: parent.bottom
Item {
id: rec
width: 50
anchors.bottom: parent.top // This anchor is not updating after appending an item to the list.
ListModel {
id: menuListModel
}
Component {
id: delegate
Rectangle {
width: 120
height: 20
color: "blue"
Text {
anchors.fill: parent
anchors.centerIn: parent
text: commandText
}
}
}
ListView {
anchors.fill: parent
model:menuListModel
delegate: delegate
interactive: false
}
}
MouseArea {
anchors.fill: parent
onClicked: menuListModel.append({"commandText" : "Normal Summon"});
}
}
}
This is more or less a duplicate of this question. The Item needs a height. As mentioned in the answer to that question, you can add debug statements to the code when things like this happen. In this situation, you can also add a Rectangle as a child of the Item and make sure that it's visible:
Rectangle {
anchors.fill: parent
color: "transparent"
border.color: "darkorange"
}
If it's not visible, you know that the problem lies with that (parent) item.
I am developing a QML application which basically contains two ListView. I would like to copy a QML item from one ListView to another. I tried to handle this by setting Drag property in the delegate but the item cannot go outside the view when I drag the item, I think the Flickable container handles mouse events.
So, I want to try the following:
create a mousearea which overlaps the to ListView
create a new object by calling **createComponent() / createObject()**
reparent this object to the mousearea
handle mouse events in the mousearea till drop
This solution seems to me a little complicated, so do you have a better way to achieve this ?
This was a bad idea and too much complicated. I think I got a way to achieve this:
each delegate of the ListView has a hidden Item which can be dragged,
as my ListView are in a reusable component, I use a property to pass a higher item (a Rectangle here and NOT a **MouseArea**) which can be used as parent for dragged items,
the higher item contains the two ListView (and maybe more in the future),
when the drag begins, the item is set to visible and reparented using a **State**
So, I missed the point that set the parent should solve my problem.
Next code is just an idea, but the key is to have a MouseArea inside a delegate for the first ListView so the user can drag the items and drop them into a DropArea which belongs to the second ListView.
In this example, model is very simple, just a number. And when the item is dropped, it is removed from the first ListView:
listView.model.remove(listView.dragItemIndex)
Just remove that line of code to copy the item instead of removing.
main.qml
import QtQuick 2.5
import QtQuick.Window 2.2
Window {
visible: true
width: 600
height: 600
Rectangle {
id: root
width: 400
height: 400
ListView {
id: listView
width: parent.width / 2
height: parent.height
property int dragItemIndex: -1
model: ListModel {
Component.onCompleted: {
for (var i = 0; i < 10; ++i) {
append({value: i});
}
}
}
delegate: Item {
id: delegateItem
width: listView.width
height: 50
Rectangle {
id: dragRect
width: listView.width
height: 50
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
color: "salmon"
border.color: Qt.darker(color)
Text {
anchors.centerIn: parent
text: modelData
}
MouseArea {
id: mouseArea
anchors.fill: parent
drag.target: dragRect
drag.onActiveChanged: {
if (mouseArea.drag.active) {
listView.dragItemIndex = index;
}
dragRect.Drag.drop();
}
}
states: [
State {
when: dragRect.Drag.active
ParentChange {
target: dragRect
parent: root
}
AnchorChanges {
target: dragRect
anchors.horizontalCenter: undefined
anchors.verticalCenter: undefined
}
}
]
Drag.active: mouseArea.drag.active
Drag.hotSpot.x: dragRect.width / 2
Drag.hotSpot.y: dragRect.height / 2
}
}
}
ListView {
id: listView2
width: parent.width / 2
height: parent.height
anchors.right: parent.right
property int dragItemIndex: -1
DropArea {
id: dropArea
anchors.fill: parent
onDropped: {
listView2.model.append(listView.model.get(listView.dragItemIndex))
listView.model.remove(listView.dragItemIndex)
listView.dragItemIndex = -1;
}
}
model: ListModel {
Component.onCompleted: {
for (var i = 0; i < 1; ++i) {
append({value: i});
}
}
}
delegate: Item {
id: delegateItem2
width: listView2.width
height: 50
Rectangle {
id: dragRect2
width: listView2.width
height: 50
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
color: "salmon"
border.color: Qt.darker(color)
Text {
anchors.centerIn: parent
text: modelData
}
}
}
}
}
}