Extending TabViewStyle styleData - qt

I am currently trying to find a nicer way to do this, add an icon to a tab. Right now I am piggy backing off the styleData.title to include the icon source, but it would be nice to be able to extend the styleData so I can include other custom properties.
Here is my current hack:
Tab {
...
title: "Home|images/home-75.png"
...
}
style: TabViewStyle {
...
tab: Rectangle {
...
Text {
...
text: styleData.title.split("|")[0]
...
}
Image {
...
source: styleData.title.split("|")[1]
}
}
}
However it would be much nicer to just do this:
Tab {
...
title: "Home"
source: "images/home-75.png"
...
}
style: TabViewStyle {
...
tab: Rectangle {
...
Text {
...
text: styleData.title
...
}
Image {
...
source: styleData.source
}
}
}
Here is the application markup as is:
import QtQuick 2.2
import QtQuick.Window 2.1
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
ApplicationWindow {
visible: true
width: 320
height: 480
TabView {
id: tabwidget
x: 0
y: 0
tabPosition: Qt.BottomEdge
width: parent.width
height: parent.height
Tab {
id: homeTab
title: "Home|images/home-75.png"
source: "images/home-75.png"
component: Qt.createComponent("Page2.qml")
}
Tab {
id: inboxTab
title: "Inbox|images/home-75.png"
component: Qt.createComponent("Page3.qml")
}
Tab {
id: outboxTab
title: "Outbox"
source: "images/home-75.png"
component: Qt.createComponent("Page3.qml")
}
Tab {
id: settingTab
title: "Settings"
source: "images/home-75.png"
component: Qt.createComponent("Page3.qml")
}
style: TabViewStyle {
frameOverlap: 0
tab: Rectangle {
color: "#F6F6F7"
border.width: 0
implicitWidth: (parent.control.width + 3) / 4
implicitHeight: 88
radius: 0
CustomBorder
{
commonBorder: false
lBorderwidth: 0
rBorderwidth: 0
tBorderwidth: 1
bBorderwidth: 0
borderColor: "#bababc"
}
Text {
id: text
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
text: styleData.title.split("|")[0]
color: styleData.selected ? "#ff3b30" : "#8e8e8f"
}
Image {
id: img
width: 75
height: 75
source: styleData.title.split("|")[1]
}
}
}
}
}

Create component IconTab.qml
import QtQuick 2.2
import QtQuick.Controls 1.1
Tab {
property url iconSource
}
Then replace all your Tabs width IconTabs, e.g.
IconTab {
id: outboxTab
title: "Outbox"
iconSource: "images/home-75.png"
}
And get the icon's source in the TabViewStyle via:
Component.onCompleted: {
console.log("title: " + styleData.title)
console.log("title: " + tabwidget.getTab(styleData.index).title)
console.log("icon: " + tabwidget.getTab(styleData.index).iconSource)
}
Btw. check out the documentation for Tab.source and Tab.sourceComponent. Tab.component should not work. At least, it is not documented.

Related

QML Felgo - Pass parameter to previuos page when popping navigationStack (or Stackview)

I have a QML (Felgo) application and I would like to pass parameter to the previous page of the stack in navigationStack when popping. I would like to populate "myVar" property of Page2.qml (which is '0' by default) with the value '1' passed from Page3 when I call pop() in the Page3.qml. The example code is shown below. I tried that code but it doesn't work. What am I doing wrong? Thanks for all.
main.qml
Page1.qml
Page2.qml
Page3.qml
I created the following code snippet that has the following features:
Main.qml hosts a ListModel
Page1.qml is able to use the ListModel in a ListView since it sees because Page1.qml was pushed into Main.qml's StackView and has inherits access to everything in Main.qml
Page2.qml does nothing except provide navigation to either Page1.qml or Page3.qml
Page3.qml provides navigation back to Page2.qml as well as emitting a signal to Main.qml receives to update the ListModel
Page1.qml, Page2.qml and Page3.qml all emit signals which are handled in Main.qml
SVG graphics are supplied to polish the example
Here's the code snippet:
import QtQuick 2.15
import QtQuick.Controls 2.15
Page {
StackView {
id: stackView
anchors.fill: parent
initialItem: comp1
}
ListModel {
id: listModel
}
Component {
id: comp1
Page1 {
onGoForward: stackView.push(comp2)
}
}
Component {
id: comp2
Page2 {
onGoBack: stackView.pop()
onGoForward: stackView.push(comp3)
}
}
Component {
id: comp3
Page3 {
onGoBack: stackView.pop()
onNewNumber: number => listModel.append( { number } )
}
}
}
//Page1.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Page {
signal goForward()
header: Frame {
background: Rectangle { color: "#ccc" }
RowLayout {
width: parent.width
AppIconButton {
icon.source: "shapes-32.svg"
}
Text {
Layout.fillWidth: true
text: "Page1"
}
}
}
ListView {
anchors.fill: parent
model: listModel
delegate: Frame {
width: ListView.view.width
Text { text: number }
}
}
footer: Frame {
background: Rectangle { color: "#ccc" }
RowLayout {
width: parent.width
Button {
text: qsTr("Go Forward")
onClicked: goForward()
}
}
}
}
//Page2.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Page {
signal goForward()
signal goBack()
header: Frame {
background: Rectangle { color: "#ccc" }
RowLayout {
width: parent.width
AppIconButton {
icon.source: "chevron-left-32.svg"
onClicked: goBack()
}
AppIconButton {
icon.source: "shapes-32.svg"
}
Text {
Layout.fillWidth: true
text: "Page2"
}
}
}
footer: Frame {
background: Rectangle { color: "#ccc" }
RowLayout {
width: parent.width
Button {
text: qsTr("Go Forward")
onClicked: goForward()
}
}
}
}
//Page3.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Page {
signal newNumber(var number)
signal goBack()
header: Frame {
background: Rectangle { color: "#ccc" }
RowLayout {
width: parent.width
AppIconButton {
icon.source: "chevron-left-32.svg"
onClicked: goBack()
}
AppIconButton {
icon.source: "shapes-32.svg"
}
Text {
Layout.fillWidth: true
text: "Page3"
}
}
}
Text {
id: resultText
anchors.centerIn: parent
}
footer: Frame {
background: Rectangle { color: "#ccc" }
RowLayout {
width: parent.width
Button {
text: qsTr("New Number")
onClicked: {
let number = Math.random();
resultText.text = number;
newNumber(number);
}
}
}
}
}
//AppIconButton.qml
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Item {
property alias icon: btn.icon
Layout.preferredWidth: 32
Layout.preferredHeight: 32
clip: true
signal clicked()
Button {
id: btn
anchors.centerIn: parent
background: Item { }
icon.width: parent.width
icon.height: parent.height
onClicked: parent.clicked()
}
}
//shapes-32.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M8.45 18.367l-.564.855A8.795 8.795 0 1 1 18.832 7h-1.143A7.795 7.795 0 1 0 8.45 18.367zM14 8v6.429l1 1.53V9h14v14h-9.399l.654 1H30V8zm8.982 22h-21l10.544-16zm-10.46-14.177L3.838 29h17.295z"/><path fill="none" d="M0 0h32v32H0z"/></svg>
//chevron-left-32.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M18.793 25l-9-9 9-9h1.414l-9 9 9 9z"/><path fill="none" d="M0 0h32v32H0z"/></svg>
You can Try it Online!

QML, failed by using components of another qml file

I have a problem with the usage qml components from another qml file. I have 2 files, main.qml and menu.qml (menu.qml is in another folder called menu). In the menu.qml I have my menu, which I want to use in main.qml
import QtQuick 2.9
import QtQuick.Controls 2.4
Menu {
id: routingMenu
width: maximumWidth
height: 200
y: 20
cascade: true
Rectangle {
Label {
x: (app_window.width / 8)
text: "FROM:"
font.pixelSize: 22
font.italic: true
color: "black"
}
Label {
y: routingMenu.height / 7
text: "Country:"
font.pixelSize: 22
font.italic: true
color: "black"
}
Label {
y: routingMenu.height / 2.5
text: "City:"
font.pixelSize: 22
font.italic: true
color: "black"
}
Label {
y: routingMenu.height / 1.6
text: "Street:"
font.pixelSize: 22
font.italic: true
color: "black"
}
Label {
y: routingMenu.height / 1.2
text: "Postal Code:"
font.pixelSize: 22
font.italic: true
color: "black"
}
} //Rectangle
Rectangle {
x: app_window.width / 2
Label {
x: (app_window.width / 4)
text: "TO:"
font.pixelSize: 22
font.italic: true
color: "black"
}
Label {
y: routingMenu.height / 7
text: "Country:"
font.pixelSize: 22
font.italic: true
color: "black"
}
Label {
y: routingMenu.height / 2.5
text: "City:"
font.pixelSize: 22
font.italic: true
color: "black"
}
Label {
y: routingMenu.height / 1.6
text: "Street:"
font.pixelSize: 22
font.italic: true
color: "black"
}
Label {
y: routingMenu.height / 1.2
text: "Postal Code:"
font.pixelSize: 22
font.italic: true
color: "black"
}
} //Rectangle
Button {
id: sendDataToItem
width: 100
height: 40
x: app_window.width / 2.7
text: "Send"
onClicked: {
//fromAddress.country: "";
//fromAddress.city: "";
//fromAddress.street: "";
//fromAddress.postalCode: "";
//toAddress.country: "";
//toAddress.city: "";
//toAddress.street: "";
//toAddress.postalCode: "";
}
} //sendDataToItem
} //Menu
I tried to use a Component, but it didn't helped me. That is code of my main.qml
import QtQuick 2.10
import QtQuick.Controls 2.2
import QtQuick.Window 2.0
import QtLocation 5.6
import QtPositioning 5.6
import "menu"
ApplicationWindow {
id: app_window
visible: true
width: maximumWidth
height: maximumHeight
title: qsTr("Navigation")
PositionSource {
active: true
onPositionChanged: {
//map_id.center = position.coordinate;
}
}
Plugin {
id: mapPlugin_
name: "osm"
}
/*Loader {
id: loadered
focus: true
source: "menu/menu.qml"
active: true
}*/
Rectangle {
id: mapRectangleID
width: 800
height: 800
x:0
y:20
Map {
id: map_
anchors.fill: parent
plugin: mapPlugin_
center: QtPositioning.coordinate(51.320729390711975,12.280097007751465)
zoomLevel: 15
MapQuickItem {
id: marker_id
coordinate: QtPositioning.coordinate(59.91, 10.75)
sourceItem: Image {
id: endPointImage
source: "assets/marker.png"
width: 100
height: 100
} //size and position of maker
anchorPoint.x: endPointImage.width / 2
anchorPoint.y: endPointImage.height
} //marker
RouteModel {
id: routeBetweenPoints
plugin: Plugin { name: "osm" }
query: RouteQuery {id: routeQuery }
Component.onCompleted: {
routeQuery.addWaypoint(QtPositioning.coordinate(51.318784,12.2773504 ));
routeQuery.addWaypoint(QtPositioning.coordinate(51.3117764,12.280909000000065 ));
//routeQuery.addWaypoint(endPointGeaocodeModel)
update();
}
} //start and end point
MapItemView {
model: routeBetweenPoints
delegate: Component {
MapRoute {
route: routeData
line.color: "red"
line.width: 10
}
} //Component
}//linie, die beide punkte verbindet
GeocodeModel{
id: endPointGeaocodeModel
plugin: Plugin { name: "osm" }
query: "Sandakerveien 116, Oslo"
onLocationsChanged: {
if (count> 0){
marker_id.coordinate = get(0).coordinate
map_id.center = get(0).coordinate
}
}
Component.onCompleted: update()
} //suche den platz mit strasse und stadt
//! [geocode0]
Address {
id: fromAddress
city: ""
country: ""
street: ""
postalCode: ""
} //fromAddress
//! [geocode0]
Address {
id: toAddress
country: ""
city: ""
street: ""
postalCode: ""
} //toAddress
} //Map
} //mapRectangleID
Button {
id: btn_close
width: 100
height: 20
text: "Close"
onClicked: {
Qt.quit();
}
}
Button {
id: btn_routing
width: 100
height: 20
x:100
text: "Routing"
onClicked: {
routingMenu.open();
}
}
Button {
id: btn_oldWay
width: 100
height: 20
x:200
text: "Old way"
onClicked: {
oldWayMenu.open();
}
}
Button {
id: rest
width: parent.width - x
height: 20
x:300
text: ""
onClicked: {
}
}
} //ApplicationWindow
I tried 2 ways to resolve the problem. One with the Loader, but I can't open my menu, and the another with example of QT which is in MapViewer Example. They import only the order and use the id of the component. But it doesn't work. I think, I do something wrong in my code, can someone tell me what I'm doing wrong or show me the right way to resolve my problem.
I think that the most important part of the code is:
Loader {
id: loadered
focus: true
source: "menu/menu.qml"
active: true
}
And then, how I'm using it:
Button {
id: btn_routing
width: 100
height: 20
x:100
text: "Routing"
onClicked: {
routingMenu.open();
}
}
By the button I'm using the component name, because I imported menu. But if I want to use the loader, I would set the visible in loader as false and then set onClicked as true. But I tried this and it didn't work.
Thanks for help
DC
The id is only valid within the .qml outside it has no meaning, for example let's say you're going to create 4 menus then if you would use the id routingMenu, which of the menus would you refer to? because that would cause confusion. So if you want to use the item loaded by Loader you must do it using the item property.
Loader {
id: loadered
focus: true
source: "menu/menu.qml"
active: true
}
// ...
Button {
id: btn_routing
width: 100
height: 20
x:100
text: "Routing"
onClicked: loadered.item.open()
}

Adjusting QML RowLayout attached properties

I am attempting a simple RowLayout of Rectangles. (See code below.) When I attempt to compile/run this in Qt Creator, I get:
qrc:/main.qml:31 Do not create objects of type Layout
when I attempt to use either Layout.minimumWidth:200 or Layout { minimumWidth:200 }
The Qt documentation for RowLayout shows the first form working. What am I missing?
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
ApplicationWindow {
id: window
title: "RB3Jay"
width:1280; height:960
minimumWidth:600; minimumHeight:300
visible: true
Rectangle {
id: pseudocontent
height: parent.height - (header.height + footer.height)
color:'orange'
anchors {
top:header.bottom
bottom:footer.top
left:parent.left
right:parent.right
}
}
header: RowLayout {
id: header
spacing: 0
height: 100
width: parent.width
Rectangle {
color:'red'
Layout {
minimumWidth:200; maximumWidth:200; preferredWidth:200
fillHeight:true
}
}
Rectangle {
color:'green'
Layout {
minimumWidth: 200
preferredWidth: parent.width*0.7
fillWidth:true; fillHeight:true
}
}
Rectangle {
color:'blue'
Layout {
minimumWidth: 200
preferredWidth: parent.width*0.3
fillWidth:true; fillHeight:true
}
}
}
footer: Inspector {
id: footer
height:100
}
}
While the foo { bar: 1; baz: 2 } -syntax works for grouped properties, Foo { } is reserved for creating an instance of QML type Foo. For attached properties, you must use the Foo.bar: 1 -syntax.
Layout is not a creatable type, it only provides attached properties. Therefore you must use the Foo.bar: 1 -syntax.
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
ApplicationWindow {
id: window
title: "RB3Jay"
width:1280; height:960
minimumWidth:600; minimumHeight:300
visible: true
Rectangle {
id: pseudocontent
height: parent.height - (header.height + footer.height)
color:'orange'
anchors {
top:header.bottom
bottom:footer.top
left:parent.left
right:parent.right
}
}
header: RowLayout {
id: header
spacing: 0
height: 100
width: parent.width
Rectangle {
color:'red'
Layout.minimumWidth:200
Layout.maximumWidth:200
Layout.preferredWidth:200
Layout.fillHeight:true
}
Rectangle {
color:'green'
Layout.minimumWidth: 200
Layout.preferredWidth: parent.width*0.7
Layout.fillWidth:true; Layout.fillHeight:true
}
Rectangle {
color:'blue'
Layout.minimumWidth: 200
Layout.preferredWidth: parent.width*0.3
Layout.fillWidth:true; Layout.fillHeight:true
}
}
footer: Inspector {
id: footer
height:100
}
}

Can a tableview have columns that take checkbox and image

I am trying to create a component in QML as shown in the attached screenshot
AFAIK, TableView is the component that I should use to create something like this using QML. Looking at the example here it seems that it can support multiple columns and the style is configurable. However, I am not sure how to add the checkbox control and an image element in the columns.
You can start from here:
import QtQuick 2.3
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
Window {
visible: true
width:1000; height: 500
ListModel {
id: mymodel
ListElement {
title: "my_name.mp4"
check: true
img: "1450465860217s.jpg" //your own img url here
filesize: "1.5GB"
lenght: "20:00"
lastMod: "12/02/2014"
}
ListElement {
title: "my_nam2.mp4"
check: false
img: "1450465860217s.jpg" //your own img url here
filesize: "400MB"
lenght: "8:00"
lastMod: "01/01/2015"
}
ListElement {
title: "my_nam2.mp4"
check: false
img: "1450465860217s.jpg" //your own img url here
filesize: "1.5GB"
lenght: "1:20:00"
lastMod: "12/13/2016"
}
}
TableView {
width: 1000; height: 500
anchors.centerIn: parent
TableViewColumn {
role: "title"
title: "Title"
width: 200
}
TableViewColumn {
role: "filesize"
title: "FileSize"
}
TableViewColumn {
role: "lenght"
title: "Lenght"
}
TableViewColumn {
role: "lastMod"
title: "Last Modified"
}
model: mymodel
rowDelegate: Rectangle{
color: "white"
height: 40
}
itemDelegate: RowLayout {
width: parent == null? 0 : parent.width
Loader{
sourceComponent: styleData.column == 0 ?
things : null
}
Component {
id: things
RowLayout{
height: 30
CheckBox{
id: itemCheckBox
checked: mymodel.get(styleData.row).check
}
Image{
Layout.preferredWidth: 80
Layout.preferredHeight: 40
source: mymodel.get(styleData.row).img
}
}
}
Text {
//anchors.centerIn: parent
text: styleData.value
}
}
}
}
You'll need to code your model in c++ and polish the interface, but its a good starting point.

ListView items don't get highlighted

Here's the code:
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick.Controls.Styles 1.1
import QtQuick.Window 2.1
import QtGraphicalEffects 1.0
import QtQuick.Layouts 1.1
Window {
id: window
/* Interface */
Rectangle {
id: dataView
anchors.topMargin: 10
height: 30 * model.count
width: 600
radius: 5
border.color: "#333"
border.width: 1
color: "black"
opacity: 0.6
clip: true
ListView {
anchors.fill: parent
anchors.topMargin: 7
model: model
delegate: delegate
interactive: false
spacing: 6
highlight: Rectangle {
color: "#333"
border.width: 1
border.color: "red"
}
onHighlightItemChanged: {
console.debug(1);
}
}
}
/* Model */
ListModel {
id: model
ListElement {
name: "Google Chrome"
icon: ""
}
ListElement {
name: "Google Chrome"
icon: ""
}
ListElement {
name: "Google Chrome"
icon: ""
}
}
Component {
id: delegate
Rectangle {
id: wrapper
height: 24
anchors.topMargin: 7
anchors.bottomMargin: 7
Row {
anchors.fill: parent
spacing: 0
Image {
id: delegateIcon
fillMode: Image.Stretch
source: icon
width: 24
height: 24
}
Text {
text: name
font.pixelSize: 12
font.family: "Segoe UI"
color: "#fff"
}
}
}
}
}
The problem is described in the headline: when I hover an item with a mouse, nothing happens. Moreover, onHighlightItemChanged only emits at the start of the application.
What am I doing wrong?
1) You need to add a width to your delegate
id: wrapper
height: 24
becomes
id: wrapper
height: 24
width: parent.width // or 100
2) You need to trigger the action "click -> item changed", by adding this
MouseArea {
anchors.fill: parent
z: 1
onClicked:
{
list.currentIndex = index
}
}
under the delegate's Row { }
Note: onHighlightItemChanged: isn't doing what you think (it checks if the delegate component is changed, as if you have 2 possible delegates). This is better:
onCurrentIndexChanged: {
console.debug("New index : "+ currentIndex);
}

Resources