How to properly popup and resize Dialog from another .qml file - qt

Learning qml and trying to separate main window and settings in different files. I have a SettingsView.qml with simple Dialog and Have a main.qml where I call menu and call my settings dialog to popup. When I had a Dialog in main.qml it was fine and it had been resizing with whole window properly. But after I had moved it to different file the behaviour changed. Now also I recieve a message: "refSettingsDialog is not defined". I would be gratefull for any advices.
upd: Closed. No need in properties here etc just basics. And do not call id from another file. Atleast, as I understand it by now
SettingsView.qml
Dialog{
id: settingsDialog
modal: true
focus: true
title: "Settings"
standardButtons: Dialog.Ok | Dialog.Cancel
onAccepted: {
settingsDialog.close()
}
onRejected: {
settingsDialog.close()
}
}
main.qml
ApplicationWindow {
visible: true
id: screen
property alias mainScreen: screen
width: 640
height: 480
property alias screenWidth: screen.width
property alias screenHeight: screen.height
title: qsTr("McdtViewer")
Material.theme: Material.Dark
Material.accent: Material.Yellow
SystemPalette { id: activePalette }
//toolbar
header: ToolBar {
RowLayout {
spacing: 20
anchors.fill: parent
ToolButton {
icon.name: contentSwiper.currentIndex === 1 ? "Back" : "пустой"
onClicked: {
if (contentSwiper.currentIndex === 1){
contentSwiper.pop()
}
}
}
Label {
id: titleLabel
text: contentSwiper.currentIndex === 0? "ExpWatcher": "ExpView"
font.pixelSize: 20
elide: Label.ElideRight
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
Layout.fillWidth: true
}
ToolButton {
icon.name: "menu"
onClicked: optionsMenu.open()
Menu {
id: optionsMenu
x: parent.width - width
transformOrigin: Menu.TopRight
MenuItem {
text: "Settings"
//calling the instance of settingView which we declared in the bottom
onTriggered: {
settingsView.open()
}
}
}
}
}
}
}
// making instance of settingsDialog here so the width will be calculated properly.
SettingsView{
id: settingsView
x: Math.round((screenWidth - width) / 2)
y: Math.round(screenHeight / 6)
width: Math.round(Math.min(screenWidth, screenHeight) / 3 * 2)
}
}

Related

Update Text inside loaded qml file

We are having an ApplicationWindow based main.qml which is connected to our python backend via QmlElement Bridge. We have a view Slot-methods which directly return values to the qml frontend to change textfields which are children of the ApplicationWindow like the following:
ApplicationWindow {
id: mainFrame
width: 1280
height: 720
visible: true
title: qsTr("Test")
StackView {
id: stack
initialItem: loginFrame
anchors.fill: parent
}
Bridge {
id: bridge
}
Component{
id: loginFrame
ColumnLayout {
anchors.margins: 3
spacing: 3
Layout.columnSpan: 1
Layout.alignment: Qt.AlignHCenter
Text {
id: title
Layout.alignment: Qt.AlignHCenter
font.pointSize: 16
text: "Login Screen"
Layout.preferredHeight: 100
}
Button {
id: loginButton
Layout.alignment: Qt.AlignHCenter
text: "login"
highlighted: true
Material.accent: Material.Red
onClicked: {
title.text = bridge.login(username.text, password.text)
}
}
}
}
}
To reduce the size of our main.qml we decided to load the other Layouts, Components etc from different files with
Loader {
id: otherLoader
source: "other.qml"
}
How to access the Text Object inside of other.qml to update the text property from main.qml because the value is provided by the Bridge?
I already tried Accessing TextField from Another QML File but this hasn't worked.
The Loader creates items in not the same context as the statically create item use so cannot access the loaded item. You have several ways to access such an item.
The first and the most correct way is to use a declarative style:
Item {
id: container
anchors.fill: parent
property string someText: "press again"
Loader {
id: loader
active: false
sourceComponent: Text {
id: txt
text: container.someText
}
}
MouseArea {
anchors.fill: parent
onClicked: {
if(loader.active)
container.someText = "some text"
else
loader.active = true
}
}
}
You can create a binding in a Javascript code whenever you want:
Loader {
id: loader
active: false
sourceComponent: Text {
id: txt
Component.onCompleted: {
txt.text = Qt.binding(function() { return container.someText; })
}
}
}
Another option is using Loader.item property:
Item {
id: container
anchors.fill: parent
property string someText: "some text"
Loader {
id: loader
active: false
sourceComponent: Text {
id: txt
text: "press again"
}
}
MouseArea {
anchors.fill: parent
onClicked: {
if(loader.active)
loader.item.text = "some text"
else
loader.active = true
}
}
}

Displaying multiple images using QML in GridView

I've used the file dialog to select multiple images like this :
FileDialog{
id: uploadFiles
title: "Please choose images for dimple detection"
selectMultiple: true
nameFilters: [ "Image files (*.jpg *.png *.tif)", "All files (*)" ]
onAccepted: {}
}
I know I can reach the file paths using:
uplaodFile.fileUrls
but how can I display them in a Flickable item using GridView ?
Edit :
This the full code of the page ...
import QtQuick 2.15
import QtQuick.Controls 2.15
import "../controls"
import QtQuick.Dialogs 1.3
Item {
property bool isGridViewVisiable: false
Rectangle {
id: bgHome
color: "#2c313c"
anchors.fill: parent
Flickable{
id: flickableUpload
anchors.fill: parent
clip: true
Text {
id: titleResults
x: 249
width: 347
height: 141
color: "#ffffff"
text: qsTr("Upload the images to here please :)")
anchors.verticalCenter: parent.verticalCenter
anchors.top: parent.top
font.pixelSize: 25
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
anchors.verticalCenterOffset: -110
anchors.horizontalCenterOffset: 8
anchors.topMargin: 59
anchors.horizontalCenter: parent.horizontalCenter
font.family: "Arial"
font.bold: true
minimumPointSize: 15
minimumPixelSize: 16
fontSizeMode: Text.Fit
}
UploadBtn{
id:uploadBtn
x: 285
y: 220
anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenter: parent.horizontalCenter
btnIconSource: "../../images/svg_images/upload-icon.svg"
onPressed: {
uploadFiles.open()
}
// opening a file dialog in order to upload the images
FileDialog{
id: uploadFiles
title: "Please choose images for dimple detection"
selectMultiple: true
nameFilters: [ "Image files (*.jpg *.png *.tif)", "All files (*)" ]
onAccepted: {
isGridViewVisiable = true
}
}
Component {
id: nameDelegate
Column {
Image {
id: delegateImage
anchors.horizontalCenter: delegateText.horizontalCenter
source: model; width: 256; height: 256; smooth: true
fillMode: Image.PreserveAspectFit
}
Text {
id: delegateText
text: model.name; font.pixelSize: 24
}
}
}
GridView{
id:gridView
visible: isGridViewVisiable
anchors.fill: parent
model:uploadFiles.fileUrls
delegate: nameDelegate
clip: true
}
}
ScrollBar.vertical: ScrollBar{}
}
}
This the full page that I will add to a content loader in the main qml file
PS:
the upload button is a customized button
uploadFiles.fileUrls is an array of filenames. So you can use that as a model for your GridView.
GridView {
model: uploadFiles.fileUrls
delegate: Image {
source: modelData
}
}
UPDATE:
It turns out there was a problem with my original answer, as well as with the code that you were trying.
First of all, you're making your GridView a child of your UploadBtn. Did you intend that? I think that will be too small of a space to draw your images.
But more importantly, the part that I was wrong about is that fileUrls is not an array of strings. It's a list<url>. I assumed QML would be smart enough to treat that the same as an array, or maybe implicitly convert it to an array if needed. But apparently I was wrong. So we'll just have to use it a little differently.
Flickable{
...
UploadBtn {
id:uploadBtn
...
FileDialog{
...
}
Component {
id: nameDelegate
Column {
Image {
...
// Access the list by index
source: uploadFiles.fileUrls[index]
}
Text {
...
text: uploadFiles.fileUrls[index]
}
}
}
}
// Move GridView outside of UploadBtn
GridView {
...
// Just use the length of the list as our model
model: uploadFiles.fileUrls.length
}
}

How to implement swipeview QtQuick 2.5

I have QT 5.5 and it won't support SwipeView. I tried doing with listView but I am not getting what I expected. I want a similar functionality code in QT 5.5 like the code given below which is written in QT 5.6. Please help
import QtQuick 2.6
import QtQuick.Controls 2.0
import QtQuick.Window 2.0
Window {
visible: true
width: 200
height: 400
title: qsTr("Hello World")
id: page
SwipeView {
id: swipeView
anchors.fill: parent
currentIndex: 0
Page {
Label {
text: qsTr("First page")
anchors.centerIn: parent
}
}
Page {
Label {
text: qsTr("Second page")
anchors.centerIn: parent
}
}
Page {
Label {
text: qsTr("Third page")
anchors.centerIn: parent
}
}
Page {
Label {
text: qsTr("Fourth page")
anchors.centerIn: parent
}
}
Page {
Label {
text: qsTr("Fifth page")
anchors.centerIn: parent
}
}
}
Rectangle
{
id:minus
width:parent.width/2
height:100
anchors.left:parent.left
anchors.bottom:parent.bottom
color:"red"
MouseArea
{
anchors.fill:parent
onClicked:{
if(swipeView.currentIndex>0)
swipeView.currentIndex--
}
}
}
Rectangle
{
id:plus
width:parent.width/2
height:100
anchors.right:parent.right
anchors.bottom:parent.bottom
color:"green"
MouseArea
{
anchors.fill:parent
onClicked:{
if(swipeView.currentIndex<4)
swipeView.currentIndex++
}
}
}
}
If you cannot update your Qt version, you can indeed approximate a SwipeView using a ListView, a VisualItemModel, and a default qml property.
SwipeView.qml
ListView
{
id: root
// Allow to add pages as you would for a QtQuick.Controls 2 SwipeView
// Each item you declare in your SwipeView will be reparented to itemModel
default property alias items: itemModel.children
// SwipeView is horizontal
orientation: Qt.Horizontal
// Hide out of bounds pages
clip: true
// Do not stop between two pages
snapMode: ListView.SnapToItem
// Update currentIndex as you swipe through the pages
highlightRangeMode: ListView.StrictlyEnforceRange
model: VisualItemModel {
id: itemModel
// Used to bind the pages size to the swipeView size
onChildrenChanged: {
for(var i=0;i<children.length; i++)
{
children[i].width = Qt.binding(function(){return root.width})
children[i].height = Qt.binding(function(){return root.height})
}
}
}
}
Page.qml
Item {
property string title
Rectangle
{
anchors.fill: parent
border.width: 1
}
Text
{
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 20
text: title
}
}
PageIndicator.qml
Row
{
id: root
property int count
property int currentIndex
property Component delegate: bullet
property bool interactive
spacing: 5
Component
{
id: bullet
Rectangle
{
height: 10
width: height
radius: height/2
color:"black"
opacity: currentIndex==index?0.8:0.2
}
}
Repeater
{
model: root.count
Loader
{
property int index: model.index
sourceComponent: delegate
}
}
}
main.qml
import QtQuick 2.5
import QtQuick.Controls 1.4
ApplicationWindow
{
id: window
visible: true
width: 300
height: 300
SwipeView
{
id: swipeView
anchors.fill: parent
Page
{
title: "Page 1"
}
Page
{
title: "Page 2"
}
Page
{
title: "Page 3"
}
}
PageIndicator
{
id: pageIndicator
anchors.bottom: swipeView.bottom
anchors.bottomMargin: 10
anchors.horizontalCenter: swipeView.horizontalCenter
count: swipeView.count
currentIndex: swipeView.currentIndex
}
}
Qt Quick Controls 2 was introduced in Qt 5.7:
Qt Quick Controls 2 provides a set of controls that can be used to build complete interfaces in Qt Quick. The module was introduced in Qt 5.7.
Qt Labs Controls was introduced in Qt 5.6, so the code that you referenced would have to use the Qt.labs.controls 1.0 import in order to run with Qt 5.6.
You need to use a newer Qt version (5.6 or newer).

How to change the page to the next or previous item of a SwipeView by clicking on the right and left arrow respectively?

I have a SwipeView that loads its internal elements through a Repeater and a Loader.
I would like to swipe between the items forward and backward by just clicking the arrows on the right and left of the SwipeView.
How can I implement this behavior in QML?
SwipeView {
id: __swipeView
Layout.fillHeight: true
Layout.fillWidth: true
Repeater {
model: 3
Loader {
source: "qrc:/../SwipeDelegate.qml"
}
}
}
Within your delegate, you can access the SwipeView via the SwipeView attached property, and then increment or decrement the current index as necessary:
import QtQuick 2.6
import QtQuick.Controls 2.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
SwipeView {
anchors.fill: parent
Repeater {
model: 3
Item {
id: delegate
Button {
text: "<"
enabled: index > 0
onClicked: delegate.SwipeView.view.decrementCurrentIndex()
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
}
Label {
text: "Page " + (index + 1)
anchors.centerIn: parent
}
Button {
text: ">"
enabled: index < delegate.SwipeView.view.count - 1
onClicked: delegate.SwipeView.view.incrementCurrentIndex()
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
}
}
}
}
}
It's important to use the functions as opposed to setting currentIndex directly, for the reasons described here.

How to hide menu items in QML

I'm using Qt Quick Controls 2 and write this code for context menu:
Menu{
id: contextmenu
x: ( parent.width - contextmenu.width ) / 2
y: ( parent.height - contextmenu.height ) / 2
modal: true
property int selid
MenuItem {
text: "Compare"
visible: isexp
}
Divider{ visible: isexp }
MenuItem {
text: "Send..."
visible: isexp
}
Divider{ visible: isexp }
MenuItem {
text: "Edit..."
}
Divider{}
MenuItem {
text: "Delete"
}
}
Divider - it is my component. isexp is is property of object. When isexp false menu is shows wrong. See screenshot:
https://s31.postimg.org/c608kdtbv/qqq.png
How to change visibility of menu items and show menu properly. Thank for advice.
Setting the height to 0 in addition to hiding the items works:
import QtQuick 2.6
import QtQuick.Controls 2.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
property bool itemsVisible: true
Menu {
id: contextmenu
x: (parent.width - contextmenu.width) / 2
y: (parent.height - contextmenu.height) / 2
modal: true
MenuItem {
text: "Compare"
visible: itemsVisible
height: visible ? implicitHeight : 0
}
MenuItem {
text: "Send..."
visible: itemsVisible
height: visible ? implicitHeight : 0
}
MenuItem {
text: "Edit..."
}
MenuItem {
text: "Delete"
}
}
Button {
text: "Open"
onClicked: {
itemsVisible = !itemsVisible
contextmenu.open()
}
}
}
This is because the height of the menu is based off the contentHeight of the internal ListView.
I found workaround but it is not so good:
Menu{
id: contextmenu
x: ( parent.width - contextmenu.width ) / 2
y: ( parent.height - contextmenu.height ) / 2
modal: true
MenuItem {
text: "Compare"
}
Divider{ }
MenuItem {
text: "Send..."
}
Divider{ }
MenuItem {
text: "Edit..."
}
Divider{}
MenuItem {
text: "Delete"
}
Component.onCompleted: {
if( !isexp )
{
contextmenu.removeItem(0)
contextmenu.removeItem(0)
contextmenu.removeItem(0)
contextmenu.removeItem(0)
}
}
}
In early Qt quick version, like Controls 1.4, you can use the private method of the menu object: __closeAndDestroy().
But there is no guarantee for this private method.

Resources