QML ListView, SwipeView etc. - avoid overlapping of other UI components - qt

I'm trying to avoid this annoying overlapping that both SideView and ListView seem to fancy. Here is an example which demonstrates the issue:
Note: Look at the green rectangle on the left when you swipe the SwipeView and also the tabs when you scroll down the ListView
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
return app.exec();
}
main.qml
import QtQuick 2.7
import QtQuick.Window 2.0
import QtQuick.Controls 2.0
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Layouts 1.2
Window {
id: window
visible: true
width: 600
height: 480
title: "Demo"
RowLayout {
id: layoutTopLevel
anchors.fill: parent
spacing: 0
Rectangle {
id: sidebarView
Layout.preferredWidth: layoutTopLevel.width * .3
Layout.fillHeight: true
color: "#453"
border.width: 1
}
ColumnLayout {
id: sideViewLayout
spacing: 0
SwipeView {
id: sideView
currentIndex: sideViewPageIndicator.currentIndex
Layout.fillWidth: true
Layout.preferredHeight: layoutTopLevel.height * .9
Page {
id: page1
header: Text {
text: "Page 1"
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 20
}
}
Page {
id: page2
header: Text {
text: "Page 2"
horizontalAlignment: Text.AlignHCenter
font.pixelSize: 20
}
TabView {
id: page2TabView
width: parent.width
height: parent.height
anchors.margins: 4
tabPosition: Qt.BottomEdge
Tab {
title: qsTr("Tab 1")
}
Tab {
title: qsTr("Tab 2")
ColumnLayout {
Text {
text: "Text 1"
Layout.alignment: Qt.AlignCenter
}
Text {
text: "Text 2"
Layout.alignment: Qt.AlignCenter
}
ListView {
width: parent.width
height: parent.height
model: ListModel {
ListElement {
name: "Element 1"
}
ListElement {
name: "Element 2"
}
ListElement {
name: "Element 3"
}
ListElement {
name: "Element 4"
}
ListElement {
name: "Element 5"
}
ListElement {
name: "Element 6"
}
}
delegate: Text {
text: name
}
}
}
}
style: TabViewStyle {
tabsAlignment: Qt.AlignHCenter
frameOverlap: 1
tab: Rectangle {
border.width: styleData.selected
implicitWidth: Math.max(text.width + 4, 80)
implicitHeight: 20
radius: 10
Text {
id: text
anchors.centerIn: parent
text: styleData.title
color: styleData.selected ? "white" : "black"
}
color: styleData.selected ? "#654" : "white"
}
frame: Rectangle {
color: "white"
}
}
}
}
}
PageIndicator {
id: sideViewPageIndicator
count: sideView.count
interactive: true
anchors.bottom: sideView.bottom
anchors.bottomMargin: -45
anchors.horizontalCenter: parent.horizontalCenter
delegate: Rectangle {
height: 30
width: 30
antialiasing: true
color: "#654"
radius: 10
opacity: index === sideView.currentIndex ? 0.95 : pressed ? 0.7 : 0.45
Behavior on opacity {
OpacityAnimator {
duration: 100
}
}
}
}
}
}
}

Use clip: true
Which clips the content which goes out of its boundaries.

I accidentally came across an example of a ListView while looking into another problem I had and I saw the clip property there. I have completely missed it while looking into the docs of both SideView and ListView. Basically when you set it to true the view no longer covers other components and this is exactly what I want. See comment by #Mitch on why this is not enabled by default.

Related

QML Wrap delegate inside Rectangle

How can i wrap a custom delegate i made for my listview, inside of a rectangle in order to customize the background and add corner radius to my listview items? Currently i have what is shown on the left in the image below. My goal is the listview on the right, while maintaining the current TextWrapping and whatnot seen in the current solution.
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
Frame {
anchors.centerIn: parent
anchors.fill: parent
ListView {
implicitWidth: parent.width
implicitHeight: parent.height
clip: true
spacing: 12
model: ListModel {
ListElement {
description: "Wash the car this could be a really long message with some multiline support we will see how it works."
}
ListElement {
description: "Fix the car"
}
ListElement {
description: "Sell the car"
}
ListElement {
description: "Wash the car this could be a really long message with some multiline support we will see how it works. This should word wrap quite a lot of times."
}
ListElement {
description: "Fix the car"
}
ListElement {
description: "Sell the car"
}
ListElement {
description: "Wash the car"
}
ListElement {
description: "Fix the car"
}
ListElement {
description: "Sell the car"
}
}
delegate: RowLayout {
width: parent.width
Rectangle {
id: newsicon
width: 16
height: 16
color: "steelblue"
Layout.alignment: Qt.AlignTop
}
ColumnLayout {
Layout.fillWidth: true
spacing: 4
TextArea {
selectByMouse: true
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
id: messageText
text: model.description
wrapMode: TextEdit.WordWrap
readOnly: true
topPadding: 0
bottomPadding: 0
background: null
}
Label {
id: dateText
text: "Dec 20, 2019"
font.italic: true
font.pointSize: 8
color: "grey"
}
}
}
ScrollBar.vertical: ScrollBar {
active: true
}
}
}
Essentially all you need to do is encapsulate your delegate's RowLayout in a Rectangle that acts as the background color:
delegate: Rectangle {
id: delegateBackground
color:"lightgreen"
radius: 10
width: parent.width
height: contentContainer.height + 20
Item {
id: contentContainer
width: parent.width - 20
height: column.height
anchors.centerIn: delegateBackground
RowLayout {
width: parent.width
Rectangle {
id: newsicon
width: 16
height: 16
color: "steelblue"
Layout.alignment: Qt.AlignTop
}
ColumnLayout {
id: column
Layout.fillWidth: true
spacing: 4
TextEdit {
selectByMouse: true
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
id: messageText
text: model.description
wrapMode: TextEdit.WordWrap
readOnly: true
}
Label {
id: dateText
text: "Dec 20, 2019"
font.italic: true
font.pointSize: 8
color: "grey"
}
}
}
}
}
You'll notice that I also added an invisible Item as a container to hold the RowLayout inside the background so that there are margins around the edges as you have indicated in your graphic.

how to add a new component with another component as argument in qml

What I want to do is create a new object inside a component, which can be done with the Component component of qml, but as an argument I want to pass another component which will be in a different .qmlfile.
I'm going to illustrate what I'm trying to do.
I have a tab bar accordion component I've done:
When I click on the button I want a new tab to be created which will have its own contents!
I provide the code I've used below:
import QtQuick 2.7
import QtQuick.Dialogs 1.2
import QtQuick.Layouts 1.3
import QtQuick.Controls 2.3
import QtQuick.Window 2.3
ApplicationWindow {
visible: true
width: 640
height: 500
title: qsTr("Tabbars")
Button{
id: button
text: "add new tab dynamically"
onClicked: item.createPanelItem()
anchors.top:parent.top
anchors.left:parent.left
height: 20
width: parent.width
}
Item{
id:item
//anchors.fill:parent
anchors.top: button.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
ScrollView{
anchors.fill:parent
Column {
id: column
width:item.width
property int currentItem: 0
PanelItem {
id:panel1
index:0
title: "Panel 1"
width:parent.width
content: Item {
property string title: "teste"
height: configContent.implicitHeight
width: configContent.implicitWidth
ColumnLayout{
id:configContent
anchors.topMargin: 10
anchors.bottomMargin: 10
anchors.fill:parent
TextField {
id: companyNameText1
placeholderText: qsTr("Company name")
Layout.fillWidth: true
selectByMouse: true
}
ComboBox {
id: languagesComboBox1
textRole: "text"
objectName: "language"
Layout.fillWidth: true
model: ListModel {
ListElement {text: QT_TR_NOOP("English"); oid: 0}
ListElement {text: QT_TR_NOOP("Portuguese"); oid: 1}
ListElement {text: QT_TR_NOOP("Spanish"); oid: 2}
ListElement {text: QT_TR_NOOP("Italian"); oid: 3}
ListElement {text: QT_TR_NOOP("French"); oid: 4}
ListElement {text: QT_TR_NOOP("Portuguese(Brasil)"); oid: 5}
}
}
ComboBox {
id: devSndrModeComboBox1
textRole: "text"
objectName: "test_dev_sndr_mode"
Layout.fillWidth: true
model: ListModel {
Component.onCompleted: {
append({ text: QT_TR_NOOP("None"), oid: 0 })
append({ text: QT_TR_NOOP("Subpanel"), oid: 1 })
append({ text: QT_TR_NOOP("All"), oid: 2 })
}
}
}
}
}
// onResetOtherPanels: function(indexClicked){
// if()
// }
}
PanelItem {
id:panel2
index:1
title: "Panel 2"
width:parent.width
content: Item {
property string title: "teste"
height: configContent2.implicitHeight
width: configContent2.implicitWidth
ColumnLayout{
id:configContent2
anchors.fill:parent
ComboBox {
id: sndrModeComboBox1
textRole: "text"
Layout.fillWidth: true
model: ListModel {
Component.onCompleted: {
append({ text: QT_TR_NOOP("Preset"), oid: 0 })
append({ text: QT_TR_NOOP("Programmed"), oid: 1 })
}
}
}
}
}
Component.onCompleted: {
//resetOtherAccordions.connect(panel1.resetHeight)
console.log("panel 2 height "+panel2.height)
}
}
PanelItem {
id:panel3
index:2
title: "Panel 3"
width:parent.width
content: Item {
property string title: "teste"
height: configContent3.implicitHeight
width: configContent3.implicitWidth
ColumnLayout{
id:configContent3
anchors.fill:parent
ComboBox {
id: sndrModeComboBox2
textRole: "text"
Layout.fillWidth: true
model: ListModel {
Component.onCompleted: {
append({ text: QT_TR_NOOP("Preset"), oid: 0 })
append({ text: QT_TR_NOOP("Programmed"), oid: 1 })
}
}
}
}
}
Component.onCompleted: {
console.log("panel 3 height "+panel2.height)
}
}
}
}
function createPanelItem(){
panelItem.createObject(column,{title:qsTr("newTest"),index:4 /*,content: Item{}*/ })
}
Component {
id: panelItem
PanelItem {
title: qsTr("Teste")
width: parent.width
}
}
}
}
PanelItem.qml:
import QtQuick 2.7
import QtQuick.Layouts 1.2
Item {
id: root
property Component content
property string title: "panel"
property bool isSelected: false
property int index: 0
function toggleSelected() {
root.isSelected = !root.isSelected
if(root.isSelected){
parent.currentItem = index
for(var i = 0;i<parent.children.length;i++)
{
if(parent.children[i].index !== parent.currentItem && parent.children[i].isSelected)
{
parent.children[i].toggleSelected()
}
}
}
}
clip: true
height: container.height + bar.height
Rectangle{
id: bar
anchors {
top: parent.top
left: parent.left
right: parent.right
}
height: 30
color: root.isSelected ? "#81BEF7" : "#CEECF5"
Text {
anchors.fill: parent
anchors.margins: 10
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
text: root.title
}
Text {
anchors{
right: parent.right
top: parent.top
bottom: parent.bottom
margins: 10
}
horizontalAlignment: Text.AlignRight
verticalAlignment: Text.AlignVCenter
text: "^"
rotation: root.isSelected ? "180" : 0
}
MouseArea {
id:panelAreaClick
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: function(){
toggleSelected()
}
}
}
Rectangle{
id: container
anchors.top: bar.bottom
anchors.left: parent.left
anchors.right: parent.right
height: loader.item && isSelected ? loader.item.height : 0
Loader {
id: loader
visible: isSelected
sourceComponent: content
anchors.top: container.top
}
Behavior on height {
PropertyAnimation { duration: 1000 }
}
}
}
My big problem here, is I can't find a way to provide something to content in the createObject function.
I know that I can pass dynamically content to content doing something like:
"content": "import QtQuick 2.0; Rectangle{}"
but this is not I want to do, because I will have a component created on a file something like panellog.qml that is what I want to pass to the contentargument of the new tab that will be created.
It would be easiest to simply specify that in your inline component:
Component {
id: panelItem
PanelItem {
title: qsTr("Teste")
width: parent.width
content: Item {}
}
}
Or you can set the type of content to be Component so you can pass some other inline component to it, which ... is pretty much the same thing really. This might seem a bit too laborious, but is actually quite handy to customize stuff in a way that also gives you access to the current component scope.
The problem here is that Qt has a two way limitation that is kinda impeding:
you cannot use declarative component syntax in imperative (JS) code
you cannot declaratively instantiate inline components
Which means that:
if you want to reference a declarative object, you have to do so using its id or a property - it will only work with an identifier, not with an object literal/instance
if you want to decalratively create an object, it has to be in a dedicated qml file

How to customize ScrollView from qtquick controls 2.3

I'm using using ScrollView control from import QtQuick.Controls 2.3version because it looks better that prior ones.
The problem is that if i try to customize it with ScrollBar.vertical it looses some functionality. I can't press it and drag it up and down like it does by default.
I've searched and i've find a way to do the drag functionality.
The code i've used is:
import QtQuick 2.9
import QtQuick.Controls 1.4
import QtQuick.Controls 2.3
ApplicationWindow {
id: window
title: "Stack"
visible: true
height: 200
width: 400
ListModel {
id: libraryModel
ListElement {
text: "A Masterpiece"
}
ListElement {
text: "Brilliance"
}
ListElement {
text: "Outstanding"
}
}
Item {
id: page
anchors.fill: parent
width:parent.width
height: parent.height
ScrollView {
id:scrollView
anchors.fill:parent
ScrollBar.vertical: ScrollBar {
parent: scrollView
x: scrollView.mirrored ? 0 : scrollView.width - width
y: scrollView.topPadding
height: scrollView.availableHeight
active: scrollView.ScrollBar.horizontal.active
contentItem: Rectangle {
implicitWidth: 6
implicitHeight: 100
radius: width/2
color: scrollView.pressed ? "orange" : "green"
}
}
Column{
width:parent.width
spacing:10
TextField {
id:textField
implicitHeight: 30
font.bold: true
}
ComboBox {
id:comboBox
anchors.topMargin: 10
textRole: "text"
model: libraryModel
}
TextField {
id:textField2
anchors.topMargin: 10
implicitHeight: 30
font.bold: true
}
ComboBox {
id:comboBox2
anchors.topMargin: 10
textRole: "text"
model: libraryModel
}
TextField {
id:textField3
anchors.topMargin: 10
implicitHeight: 30
font.bold: true
}
ComboBox {
id:comboBox3
anchors.topMargin: 10
textRole: "text"
model: libraryModel
}
TextField {
id:textField4
anchors.topMargin: 10
implicitHeight: 30
font.bold: true
}
ComboBox {
id:comboBox4
anchors.topMargin: 10
textRole: "text"
model: libraryModel
}
}
}
}
}
What did i missed on the code? Maybe on ScrollBar?
I've fixed it by setting a different parent for ScrollBar (link). Also, to change the color you need to check ScrollBar property instead of ScrollView:
ScrollBar.vertical: ScrollBar {
id: scrollBar
parent: scrollView.parent
policy: ScrollBar.AlwaysOn
x: scrollView.mirrored ? 0 : scrollView.width - width
y: scrollView.topPadding
height: scrollView.availableHeight
active: scrollView.ScrollBar.horizontal.active
contentItem: Rectangle {
implicitWidth: 6
implicitHeight: 100
radius: width/2
color: scrollBar.pressed ? "orange" : "green"
}
}
If you set z: 1 (or any value > 0) to your ScrollBar the problem should be fixed.
I am not sure about the reason but it looks like it is related to the scrollbar attached by default to the ScrollView, that prevents you to access the custom scrollbar in this 10px zone.
cf Why is there a dead zone on the right side of my flipable?

QML pieMenu on draggable object

I've got a draggable object that is created by a Javascript, which is working fine. But when I create a PieMenu inside it, the object isn't created/visible in the Javascript context:
import QtQuick 2.8
import QtQuick.Controls.Styles 1.4
import QtQuick.Extras 1.4
import QtQml.Models 2.2
Rectangle {
id: rev
width: 100
height: 80
color: "transparent"
antialiasing: false
Drag.active: dragArea.drag.active
MouseArea {
id: dragArea
width: parent.width
height: parent.height + 10 // easier to get
anchors.centerIn: parent
drag.target: parent
drag.axis: Drag.XAndYAxis
onClicked: pieMenu.popup(mouseX, mouseY), console.log("clicked")
}
PieMenu {
id: pieMenu
MenuItem {
text: "Add vertical bar"
onTriggered: print("Action 2")
}
}
Gauge {
id: revgauge
anchors.fill: parent
anchors.margins: 10
orientation : Qt.Horizontal
minorTickmarkCount: 4
tickmarkStepSize : 5000
minimumValue: 0
maximumValue: 10000
Behavior on value {
NumberAnimation {
duration: 5
}
}
Text {
font.pixelSize: (parent.height / 3)
anchors.top : parent.top
font.bold: true
font.family: "Eurostile"
color: "white"
anchors.horizontalCenter: parent.horizontalCenter
}
style: GaugeStyle {
valueBar: Rectangle {
implicitWidth: rev.height /3
color: Qt.rgba(revgauge.value / revgauge.maximumValue, 0, 1 - revgauge.value / revgauge.maximumValue, 1)
}
}
}
}
Can Mousearea handle dragging and a PieMenu at once? If not how can it be solved?
Consider QML PieMenu boundingItem. It addresses an exact issue with MouseArea you presented.

Error of 'TypeError: Cannot read property 'name' of undefined', it comes start to end or vice-versa of application window by moving mouse wheel scroll

I am working on qml, found found an error during moving mouse wheel scrolling i.e.
"TypeError: Cannot read property 'name' of undefined".
It only appear when either mouse wheel scrolling or close the application while during execution and beginning of the application didn't show this error.
One more thing, I am getting accurate data/result whatever I want but due to this error the performance of application get affected.
Please let me know how can I get rid of this issue?
also find below example to see error.
My code is..
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Layouts 1.1
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
menuBar: MenuBar {
Menu {
title: qsTr("File")
MenuItem {
text: qsTr("Exit")
onTriggered: Qt.quit();
}
}
}
TableView {
anchors.fill: parent
visible: true
backgroundVisible: false
alternatingRowColors: false
sortIndicatorVisible: true
clip: true
highlightOnFocus: false
width: parent.width
height: parent.height
TableViewColumn{ role: "code" ; title: "cde" ; width: 200;
delegate: Component {
id: codeDelegate
Item{
Text {
color: "lightgray"
elide: styleData.elideMode
text: styleData.value //modelSettingData.get(styleData.row).name
font.family: "Arial"
font.pixelSize: 18
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
Text {
id: metaData
color: "red"
width: parent.width
// height: 20
anchors.bottom: parent.bottom
anchors.bottomMargin: -parent.height/1.5
font.weight: Font.ExtraLight
//elide: Text.ElideMiddle
text: "Time: " + modelSettingData.get(styleData.row).name //Error comes when this part added but I need to use it with the same form
}
}
}
}
}
TableViewColumn{ role: "name" ; title: "nme" ; width: 200
delegate: Component {
id: nameDelegate
Text {
color: "yellow"
elide: styleData.elideMode
text: styleData.value
font.family: "Arial"
font.pixelSize: 18
}
}
}
model: ListModel {
id: modelSettingData
ListElement {
name: "aaaaaaaaaa"
code: "3042666666666"
}
ListElement {
name: "bbbbbb"
code: "32235"
}
ListElement {
name: "ccccccc"
code: "32638"
}
ListElement {
name: "ddddddddddd"
code: "00000000000"
}
ListElement {
name: "eeeeeeeeeeee"
code: "111111111111"
}
ListElement {
name: "ffffffffffff"
code: "222222222222"
}
ListElement {
name: "ggggggggggggg"
code: "3333333333333"
}
ListElement {
name: "hhhhhhhhhhhhh"
code: "4444444444444"
}
ListElement {
name: "iiiiiiiiiiiii"
code: "5555555555555"
}
}
rowDelegate: Rectangle {
property bool selected : styleData.selected
width: parent.width-2
height: 100
color: styleData.selected? "black" : "black"
Rectangle {
width: parent.width
height: 1
anchors.bottom: parent.bottom
visible: parent.selected
color: "yellow"
}
}
}
}

Resources