iterating a Qml across multiple screens - qt

It shows qml on main screen. I want to repeat the same image on other screens. They will all be exactly the same. It will be renewed on all screens according to the change in Main. Is something like this possible ?
code in main.qml
PlaybackControl {
id: playbackControl
anchors {
right: parent.right
left: parent.left
bottom: parent.bottom
}
mediaPlayer: mediaPlayer
mediaPlayer2: mediaPlayer2
}
Edit:
I want to run a qml to run concurrently on each window. I added new images. state1 main screen. There are 6 windows on the main screen. When I drag one of the screens out. I want the control bar below to appear on the screen that comes out. It will appear at the bottom of every screen that is removed. When I change the slider on one screen, it will change simultaneously on all screens. When I make the control bar a component and use it as an initial item in more than one stackview, it shows the last inial item I called without duplicating the source.

This is some simple test application that should dynamically create and show the same window on each available screen in its top-right corner
ApplicationWindow {
id: main
width: 640
height: 480
visible: true
title: qsTr("Multiple screens test")
property list<Window> windows;
Component {
id: windowComponent
Window {
id: window
width: 200
height: 50
visible: true
flags: Qt.FramelessWindowHint
property alias caption: txt.text
x: screen.width - window.width
y: 0
Text {
id: txt
anchors.centerIn: parent
text: ""
}
}
}
Component.onCompleted: {
var screens = Application.screens;
for(var s in screens)
{
var wnd = windowComponent.createObject(main.contentItem, { screen: screens[s], caption: "some text" });
main.windows.push(wnd);
wnd.show();
}
}
Button {
anchors.centerIn: parent
text: "change caption"
onClicked: {
for(var w in main.windows) {
main.windows[w].caption = "another text";
}
}
}
}
The each window is stored in an array so you can access that.

The pattern I have seen is:
StackView control used for Page navigation
The application declares a footer that is seen on all pages
Each page declares a unique header
The impact of this is that every page will see the same footer but a different header. I implement a media play and stop Button in the footer. The header shows which page you are on and there is inter-page navigation.
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Page {
property bool started: false
StackView {
id: stackView
anchors.fill: parent
initialItem: "MainPage.qml"
}
footer: Frame {
RowLayout {
AppIconButton {
icon.source: started ? "square-32.svg" : "play-32.svg"
onClicked: started = !started
}
}
}
}
//MainPage.qml
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Page {
header: Frame {
Text { text: "MainPage.qml" }
}
Button {
anchors.centerIn: parent
text: qsTr("Second Page")
onClicked: stackView.push("SecondPage.qml")
}
}
//SecondPage.qml
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Page {
header: Frame {
RowLayout {
AppIconButton {
icon.source: "chevron-left-32.svg"
onClicked: stackView.pop()
}
Text { text: "SecondPage.qml"
}
}
}
}
//AppIconButton.qml
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
Rectangle {
id: iconButton
Layout.preferredWidth: 32
Layout.preferredHeight: 32
property alias icon: btn.icon
clip: true
signal clicked()
Button {
id: btn
anchors.centerIn: parent
icon.width: parent.width
icon.height: parent.icon
onClicked: iconButton.clicked()
}
}
//play-32.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M8 3.045v25.91l19-12.952zm1 1.893l16.225 11.064L9 27.062z"/><path fill="none" d="M0 0h32v32H0z"/></svg>
//square-32.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M5.8 29h21.4a1.8 1.8 0 0 0 1.8-1.8V5.798A1.802 1.802 0 0 0 27.198 4h-21.4A1.8 1.8 0 0 0 4 5.798V27.2A1.8 1.8 0 0 0 5.8 29zM5 5.798A.798.798 0 0 1 5.798 5h21.4a.801.801 0 0 1 .802.798V27.2a.801.801 0 0 1-.8.8H5.8a.8.8 0 0 1-.8-.8z"/><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!

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!

Qt Qml Vertical Tabbar

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
}
}
}
}
}
}

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
}
}

QML RowLayout does not dynamically resize based on content

I have some experience with Qt Widgets, but only recently started to use QML.
The problem I face is that I'd like some layouts defined in QML to automatically adjust to fit their contents. This works, but not dynamically, i.e. if the content changes the layout does not adapt. With the old-style (non-QML) Layout/Widget approach, this happened automatically.
Here is an example (my code looks different and consists of different files, but I pasted this MWE together to demonstrate the problem):
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 1.0
import QtQuick.Layouts 1.2
Window {
id: root
visible: true
width: 640
height: 480
property var nbx: 3
Column {
RowLayout {
Repeater {
model: 3
Rectangle {
width: childrenRect.width
height: childrenRect.height
color: "green"
ColumnLayout {
Rectangle {
height: 10
}
RowLayout {
Repeater {
model: root.nbx
Rectangle {
width: 20
height: 20
color: "orange"
}
}
}
}
}
}
}
Button {
text: "5 boxes"
onClicked: root.nbx= 5;
}
Button {
text: "2 boxes"
onClicked: root.nbx = 2;
}
}
}
How can I achieve the same with QML?
You can make it work by setting the implicit size of the green Rectangle to the implicit size of the child ColumnLayout. I'm not exactly sure why, it seems the childrenRect properties are not propertly updated.
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 1.0
import QtQuick.Layouts 1.2
Window {
id: root
visible: true
width: 640
height: 480
property var nbx: 3
ColumnLayout {
RowLayout {
Repeater {
model: 3
Rectangle {
implicitHeight: col1.implicitHeight // <--- here is the change
implicitWidth: col1.implicitWidth
color: "green"
ColumnLayout {
id: col1
Rectangle {
height: 10
}
RowLayout {
Repeater {
model: root.nbx
Rectangle {
width: 20
height: 20
color: "orange"
}
}
}
}
}
}
}
Button {
text: "5 boxes"
onClicked: root.nbx= 5;
}
Button {
text: "2 boxes"
onClicked: root.nbx = 2;
}
}
}

How to make image to fill qml controls button

I want icon to fill Button. Here is code:
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.1
import QtQuick.Window 2.2
Window{
id: root
title: "settings"
flags: Qt.Dialog
minimumHeight: 700
minimumWidth: 700
maximumHeight: 700
maximumWidth: 700
ColumnLayout{
id: columnLayout
anchors.fill: parent
RowLayout{
Button{
iconSource: "images/1x1.png"
checkable: true
checked: true
Layout.minimumWidth: 100
Layout.minimumHeight: 100
}
Button{
iconSource: "images/1x2.png"
checkable: true
checked: false
Layout.minimumWidth: 100
Layout.minimumHeight: 100
}
Button{
iconSource: "images/2x1.png"
checkable: true
checked: false
Layout.minimumWidth: 100
Layout.minimumHeight: 100
}
Button{
iconSource: "images/2x2.png"
checkable: true
checked: false
Layout.minimumWidth: 100
Layout.minimumHeight: 100
}
}
Rectangle{
visible: true
implicitHeight: 600
implicitWidth: 700
color: "red"
}
}
}
Button size is 100*100 pixels but image size is much lower. How to make image to be as big as button
It really depends on what you want to achieve. IMO, there are three solutions here:
1) If you need an image as a button, just use Image with a MouseArea filling it:
Image {
source: "http://images5.fanpop.com/image/photos/27500000/Cool-beans-azkaban-27533920-200-200.gif"
MouseArea {
anchors.fill: parent
onClicked: {
console.info("image clicked!")
}
}
}
2) If you want to use a button with an image, redefine the label property of the style, as follows:
Button{
width: 200
height: 200
style: ButtonStyle {
label: Image {
source: "http://images5.fanpop.com/image/photos/27500000/Cool-beans-azkaban-27533920-200-200.gif"
fillMode: Image.PreserveAspectFit // ensure it fits
}
}
}
This way you can fit any image in the Button and the small padding to the borders allows you to see when the button is clicked/checked. Mind that, by using ButtonStyle, you lose the platform style.
3) If you really want to use the Button and make it look like an Image follow the smart approach proposed by Mitch.
If you don't mind using private API, there's the padding property:
import QtQuick 2.4
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
Item {
width: 200
height: 200
Button {
iconSource: "http://www.sfweekly.com/imager/the-exhikittenist-cattown-cat-pics-and-m/b/square/3069319/58c8/WikiCat.jpg"
anchors.centerIn: parent
style: ButtonStyle {
padding {
left: 0
right: 0
top: 0
bottom: 0
}
}
Rectangle {
anchors.fill: parent
color: "black"
opacity: parent.pressed ? 0.5 : 0
}
}
}
Looking at ButtonStyle.qml:
/*! The padding between the background and the label components. */
padding {
top: 4
left: 4
right: control.menu !== null ? Math.round(TextSingleton.implicitHeight * 0.5) : 4
bottom: 4
}
If you want the image will fill the button :
Button{
Image {
anchors.fill: parent
source: "images/1x1.png"
fillMode: Image.Tile
}
checkable: true
checked: true
Layout.minimumWidth: 100
Layout.minimumHeight: 100
}
or some another fillMode, as you need
I have gone through same problem stated here. thanks a lot for different solutions. But the one that #folibis suggested finally gave a platform looked (flat in windows 10) button with my svg image. But it does work directly well. three reasons:
1. The image was tightly fit with button.To keep like an icon, I used a FLAT groupbox.
2. fillmode tile is not appropriate when we look for simple iconic image on a button. I have changed it to PreserveASpectFit.
3. checkable and checked properties were not intended for normal action buttons. But surely the question's code sample has got these.
pl see my code here. may be useful. Once again Thanks to #Folibis
Button {
id: nextButton
GroupBox {
flat: true
anchors.fill: parent
Image {
anchors.fill: parent
source: "qrc:/next.svg"
fillMode: Image.PreserveAspectFit
}
}
Layout.minimumWidth: 100
Layout.minimumHeight: 100
}

Resources