Qt Qml Vertical Tabbar - qt

I would like to add Vertical TabBar to my app in a similar manner of what Qt Creater is doing in their app (as shown in picture).
I have been searching how to simple make the TabBar vertical, yet did not find proper answers (thought its common to have it vertical).
Question: How could I make a Vertical Tab to navigate through the different qml files I have? If there are more suitable options, please suggest.

A TabBar just uses a common ListView to display a bunch of TabButtons. You can customize it by overwriting the contentItem property and making the ListView vertical, like this:
// VertTabBar.qml
TabBar {
id: control
contentItem: ListView {
model: control.contentModel
currentIndex: control.currentIndex
spacing: control.spacing
orientation: ListView.Vertical // <<-- VERTICAL
boundsBehavior: Flickable.StopAtBounds
flickableDirection: Flickable.AutoFlickIfNeeded
snapMode: ListView.SnapToItem
highlightMoveDuration: 0
highlightRangeMode: ListView.ApplyRange
preferredHighlightBegin: 40
preferredHighlightEnd: height - 40
}
}

A complete example using Fusion theme.
It is important to set the width of the TabButton else the width is divided by the number of items.
Notice there is a light colour separator line, that comes from ???
Issue: first item can be partially clipped.
Well, there are a lot of things under the hood with QML...
Thus, we cannot really make a TabBar vertical...
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import QtQuick.Templates as T
// import QtQuick.Controls.impl
// import QtQuick.Controls.Fusion
// import QtQuick.Controls.Fusion.impl
Page {
id: root
width: 1800
height: 800
Row {
anchors.fill: parent
TabBar {
id: control
width: 200
height: parent.height
contentItem: ListView {
model: control.contentModel
currentIndex: control.currentIndex
spacing: control.spacing
orientation: ListView.Vertical
boundsBehavior: Flickable.StopAtBounds
flickableDirection: Flickable.AutoFlickIfNeeded
snapMode: ListView.SnapToItem
highlightMoveDuration: 0
highlightRangeMode: ListView.ApplyRange
preferredHighlightBegin: 40
preferredHighlightEnd: width - 40
}
Repeater {
model: 50
TabButton {
id: control2
width: control.width
text: "tab blabla blabla %1".arg(model.index)
contentItem: IconLabel {
spacing: control2.spacing
mirrored: control2.mirrored
display: control2.display
icon: control2.icon
text: control2.text
font: control2.font
color: control2.palette.buttonText
}
background: Rectangle {
y: control2.checked || control2.TabBar.position !== T.TabBar.Header ? 0 : 2
implicitHeight: 21
height: control2.height - (control2.checked ? 0 : 2)
border.color: Qt.lighter(Fusion.outline(control2.palette), 1.1)
border.width: 0
gradient: Gradient {
GradientStop {
position: 0
color: control2.checked ? Qt.lighter(Fusion.tabFrameColor(control2.palette), 1.04)
: Qt.darker(Fusion.tabFrameColor(control2.palette), 1.08)
}
GradientStop {
position: control2.checked ? 0 : 0.85
color: control2.checked ? Qt.lighter(Fusion.tabFrameColor(control2.palette), 1.04)
: Qt.darker(Fusion.tabFrameColor(control2.palette), 1.08)
}
GradientStop {
position: 1
color: control2.checked ? Fusion.tabFrameColor(control2.palette)
: Qt.darker(Fusion.tabFrameColor(control2.palette), 1.16)
}
}
}
}
}
}
StackLayout {
id: stack_layout
width: parent.width - 200
height: parent.height
currentIndex: control.currentIndex
Repeater {
model: 50
Item {
Label {
anchors.centerIn: parent
text: "tab %1".arg(model.index)
font.pixelSize: 50
}
}
}
}
}
}

Related

QML Scroll Bar doesn't update when it is at the bottom and window height is resized

I have a custom scrollbar QML type that I am working on. The problem I'm having is that if the scroll bar is all the way at the bottom of the page and the height of the main application window is increased, the translated contents stay in place and the size of the scroll bar is not updated. After this window resize occurs, clicking on the scroll bar causes the content to snap to its proper place and the scroll bar to snap to its proper size. What changes might could be made to the code below so the position of the contents (red blocks) and scroll bar size update while the window height is changing? Not afterwards when the scroll bar has been clicked again. To see the issue just open the code below, scroll the blue scroll bar all the way to the bottom, increase the height of the main window (observing the scroll bar size and the content position), and then click on the scroll bar after the resize. Here is my code:
main.qml
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Layouts 1.12
import QtQuick.Shapes 1.15
Window {
id: main_window
width: 640
height: 480
visible: true
title: qsTr("Hello World")
color: 'light blue'
// container
ColumnLayout {
id: my_column
anchors.centerIn: parent
width: main_window.width / 3
height: main_window.height / 3
spacing: 0
// contents
ColumnLayout {
id: repeater_element
Layout.fillWidth: true
Layout.fillHeight: false
spacing: 4
Repeater {
model: 7
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: false
Layout.preferredHeight: 75
Layout.alignment: Qt.AlignTop
color: 'red'
}
}
transform: Translate {
id: rect_translate
y: 0
}
}
}
// scroll bar type
Scroll_Bar {
x: 0
y: 0
height: parent.height
width: 20
container_element: my_column
content_element: repeater_element
translate_element: rect_translate
orientation: Qt.Vertical
}
// just a border for the container element
Shape {
ShapePath {
strokeWidth: 4
strokeColor: "black"
fillColor: Qt.rgba(.09, .05, .86, 0)
joinStyle: ShapePath.MiterJoin
startX: my_column.x
startY: my_column.y
PathLine {
relativeX: my_column.width
relativeY: 0
}
PathLine {
relativeX: 0
relativeY: my_column.height
}
PathLine {
relativeX: -my_column.width
relativeY: 0
}
PathLine {
relativeX: 0
relativeY: -my_column.height
}
}
}
}
Scroll_Bar.qml
import QtQuick 2.0
import QtQuick.Controls 2.5
ScrollBar {
property var container_element
property var content_element
property var translate_element
QtObject {
id: internal
property real vertical_size: container_element.height / content_element.height
property real horizontal_size: container_element.width / content_element.width
property real off_the_bottom: (content_element.height - container_element.height) + translate_element.y
}
id: scroll_bar_element
hoverEnabled: true
active: size
orientation: orientation
size: orientation === Qt.Vertical ? internal.vertical_size : internal.horizontal_size
padding: 0
contentItem: Rectangle {
id: ci
radius: 0
color: 'blue'
}
onSizeChanged: {
if(size > 1){
visible = false
}
else{
visible = true
}
}
onPositionChanged: {
if (orientation === Qt.Horizontal) {
translate_element.x = -scroll_bar_element.position * content_element.width
} else {
translate_element.y = -scroll_bar_element.position * content_element.height
}
}
Component.onCompleted: {
scroll_bar_element.onPositionChanged()
}
}
You can hardly write better scrollbar than the existing one, so I made the following code which does the same thing I saw in your example. ScrollBar can be the sibling of a flickable, so it won't take ownership and you can position it where you want. You can even make it rotated.
Is it something that solves your problem?
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Layouts 1.12
import QtQuick.Controls 2.12
Window {
id: main_window
width: 640
height: 480
visible: true
title: qsTr("Hello World")
color: 'light blue'
Flickable {
id: flickable
anchors.centerIn: parent
width: main_window.width / 3
height: main_window.height / 3
contentWidth: repeater_element.width
contentHeight: repeater_element.height
ScrollBar.vertical: scrollBar
// container
ColumnLayout {
id: my_column
width: main_window.width / 3
height: main_window.height / 3
spacing: 0
// contents
ColumnLayout {
id: repeater_element
Layout.fillWidth: true
Layout.fillHeight: false
spacing: 4
Repeater {
model: 7
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: false
Layout.preferredHeight: 75
Layout.alignment: Qt.AlignTop
color: 'red'
}
}
transform: Translate {
id: rect_translate
y: 0
}
}
}
}
ScrollBar {
id: scrollBar
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
//try this for fun
//rotation: 5
contentItem: Rectangle {
implicitWidth: 20
implicitHeight: 20
color: "blue"
}
}
Rectangle {
color: "transparent"
border.width: 4
anchors.fill: flickable
}
}

Checkbox becomes big when clicked on in QML tableview

This code does produce checkboxes in a tableview but when I click on the checkbox it becomes big. I want it to remain of a constant size.
Please guide.
import QtQuick 2.0
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.1
Rectangle
{
id: rightside
anchors.fill: parent
height: parent.height
width: 1500
TableView
{
anchors.fill: parent
TableViewColumn
{
role: "selectall"
title: "Select All"
width: 100
delegate: CheckBox
{
anchors.fill: parent
checked: false
}
}
TableViewColumn {
role: "size"
title: "Size"
width: 100
}
TableViewColumn
{
role: "last_updated"
title: "Last Updated"
width: 100
delegate: Component
{
Rectangle
{
height: 100
width: 120
id: head
RowLayout
{
height: parent.height
width: parent.width
Rectangle
{
height: 20
width: 20
color: "red"
border.color: "black"
radius: 100
MouseArea
{
anchors.fill: parent
onClicked: parent.color = "grey"
}
}
}
}
}
}
model: ListModel
{
id: mymodel
ListElement { text: "Banana" }
ListElement { text: "Apple" }
ListElement { text: "Coconut" }
}
}
}
There are lots of way to solve your problem. But first, let's do proper distinction between Qt Qtuick Controls versions. To do it, use this import statement:
import QtQuick.Controls 1.4 as QC1
And respectively use all components that requires QC1, e.g.: QC1.TableView, QC1.TableViewColumn.
In your example you are getting overlapping of components. To avoid it in terms of QC1 you can define a higher row delegate for your TableView. But this discards the default style. Simple example of its usage with style goes here:
rowDelegate: Rectangle {
height: 30
SystemPalette {
id: myPalette
colorGroup: SystemPalette.Active
}
color: {
var baseColor = styleData.alternate ? myPalette.alternateBase : myPalette.base
return styleData.selected ? myPalette.highlight : baseColor
}
}
As result you'll get this:
Another option in terms of QC2 is to redefine indicator style of CheckBox. Below you'll find an example that could possibly fit your app, based on Customizing CheckBox documentation; so your CheckBox delegate will look like this:
delegate: CheckBox {
id: control
anchors.fill: parent
checked: false
indicator: Rectangle {
id: outer
readonly property int size: 18
implicitWidth: size
implicitHeight: size
x: control.leftPadding
y: parent.height / 2 - height / 2
radius: 4
border.color: control.down ? "orangered" : "orange"
Rectangle {
id: inner
anchors.centerIn: parent
width: outer.size/2
height: width
radius: 3
color: control.down ? "orangered" : "orange"
visible: control.checked
}
}
}
As result you'll get this:

How to make the listview align better?

My program consisted of a tabbar and stackLayout. I face a layout problem that the tab button is too close to the head of the listview as shown below. They are horizontally aligned together.
But I want the listview to be under the tab button. I tried adding the topMargin in the listview, but it doesn't have any effect at all. Please help.
The code:
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtMultimedia 5.8
import QtQuick.Layouts 1.3
import com.contentplayermod.filemodel 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Tabs")
property int idx: 0
property bool isActive: true
TabBar {
id: bar
width: parent.width
TabButton {
text: qsTr("Main")
}
TabButton {
text: qsTr("View")
}
}
StackLayout {
id: stackLayout
height:parent.height
width: parent.width
currentIndex: bar.currentIndex
Item {
id: mainTab
anchors {
topMargin:60
}
width: 500
height:800
ListView {
id: lv
anchors.margins: 50
width: 200; height: 400
highlight: Rectangle { color: "lightsteelblue"; radius: 5 }
focus: true
currentIndex: 0
Component {
id: fileDelegate
Text {
text: fileName
font.pointSize: 20
anchors {
topMargin:60
}
MouseArea{
anchors.fill: parent
}
}
}
model: FileModel{
id: myModel
folder: "c:\\folder"
nameFilters: ["*.mp4","*.jpg"]
}
delegate: fileDelegate
highlightFollowsCurrentItem: true
}
}
Item {
id: viewTab
width: 500
height:800
}
}
}
You can either anchors your stack-top to the bottom of the tab bar like this :
...
StackLayout {
id: stackLayout
height:parent.height - bar.height
anchors.top: bar.bottom
width: parent.width
...
Or much simpler, put everything in a ColumnLayout :
ColumnLayout {
anchors.fill: parent
TabBar {
id: bar
Layout.fillWidth: true
...
}
StackLayout {
id: stackLayout
Layout.fillHeight: true
Layout.fillWidth: true
...
}
}
So you don't have to deal with width and height, and it's more easy to insert new widgets in your window.
You can add spacing to the ColumnLayout to put some space between the TabBar and the content. Or manage this inside the Items displayed by the StackLayout for more flexibility.

How to make a horizontal pagination?

I'm developing a BlackBerry 10 mobile application using the Momentics IDE 2.1.2 (native SDK).
I'm looking for a sample that shows how to build a horizontal pagination like in the image below that I will put it inside a container replacing with that a listview with a grid display.
Can anyone help me with this ?
You can easy build simple pagination using ListView only. Hope the example below will be usefull:
import QtQuick 2.4
Item {
width: 600
height: 800
ListView {
id: listView
anchors.fill: parent
orientation: ListView.Horizontal
snapMode: ListView.SnapToItem
highlightRangeMode: ListView.StrictlyEnforceRange
model: 5
clip: true
delegate: Rectangle {
width: listView.width
height: listView.height
color: Qt.rgba(Math.random(),Math.random(),Math.random(),1);
Text {
anchors.centerIn: parent
text: "page " + index
}
}
}
Item {
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
height: 30
Row {
anchors.centerIn: parent
Repeater {
model: listView.model
Rectangle {
width: 20
height: 20
border.width:2
border.color: "white"
color: index == listView.currentIndex ? "orange" : "white"
Text {
anchors.centerIn: parent
text: index
}
}
}
}
}
}

Nested ScrollView in QML doesn't respond to mousewheel

I have a nested ScrollView, similar to the following QML:
import QtQuick 2.0
import QtQuick.Controls 1.1
Rectangle {
width: 200
height: 600
ScrollView {
id: sView
anchors.fill: parent
ListView {
id: list
boundsBehavior: Flickable.StopAtBounds
clip: true
focus: true
interactive: true
model: 5
delegate: Component {
MouseArea {
id: hoverArea
width: 100
height: 200
onClicked: list.currentIndex = index;
Rectangle {
id: fauxParent
anchors.fill: parent
border.width: 1
border.color: "black"
Rectangle {
anchors.top: parent.top
anchors.left: parent.left
height: parent.height
width: parent.width / 2
border.width: 1
border.color: "purple"
color: "green"
Text {
anchors.centerIn: parent
text: "stuff"
}
}
ScrollView {
//parent: sView
anchors.top: fauxParent.top
anchors.right: fauxParent.right
height: fauxParent.height
width: fauxParent.width / 2
ListView {
model: 3
delegate: Component {
Rectangle {
radius: 10
height: 100
width: 100
color: "blue"
}
}
}
}
}
}
}
}
}
}
It seems to run correctly, except that the inner ScrollView won't respond to the mousewheel: the outer ScrollView intercepts that event. The only fix I've found in research for this, is to set the inner scrollview's parent directly to the outer scrollview (uncomment the parent: sView line). Unfortunately, this re-positions all five scrollview delegates onto the top right corner of the outer scrollview. It seems that ScrollView positions itself based on its parent?
For the record, my actual application is wrapping a large section of the page in a scrollview so as to allow the user to access sections of it that may be out of bounds for the current window size. The content of this section, though, has a variety of different controls for a variety of different purposes, including some scrollviews. So I'd also accept an alternate way of moving around a set of generic content that's too large for the window.
This is a Windows desktop app, so I don't need to consider mobile-specific issues.
You nested four elements that handle scroll Events.
Why do you put a ScrollView arround a ListView?
If you remove the ScrollViews the Mousewheel work fine.
Rectangle {
width: 200
height: 600
ListView {
anchors.fill: parent
id: list
boundsBehavior: Flickable.StopAtBounds
clip: true
focus: true
interactive: true
model: 5
delegate: Component {
MouseArea {
id: hoverArea
width: 100
height: 200
onClicked: list.currentIndex = index;
Rectangle {
id: fauxParent
anchors.fill: parent
border.width: 1
border.color: "black"
Rectangle {
anchors.top: parent.top
anchors.left: parent.left
height: parent.height
width: parent.width / 2
border.width: 1
border.color: "purple"
color: "green"
Text {
anchors.centerIn: parent
text: "stuff"
}
}
ListView {
anchors.top: fauxParent.top
anchors.right: fauxParent.right
height: fauxParent.height
width: fauxParent.width / 2
model: 3
delegate: Component {
Rectangle {
radius: 10
height: 100
width: 100
color: "blue"
}
}
}
}
}
}
}
}
If you miss the Scrollbar look at this:
How to create scrollbar in QtQuick 2.0?

Resources