Displaying multiple images using QML in GridView - qt

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

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

How to call data from elsewhere when I click a button in QML

When I click a button in QML, I want the data from another place that I created before to come to the textfields in my table, how can I do it? Can I do this in QML or do I need to create a separate backend cpp file? Can you help me please?
For example this below code is one row of my table
Rectangle{
border.width: 2
border.color: "black"
id:rectangle_mov_mean_nokta_sayisi
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: mainWindow.width/8
Layout.preferredHeight: mainWindow.height/22
Layout.margins: -3
Layout.fillWidth: true
color: row_even
Text{
color:normal_text
id:text_rectangle_mov_mean_nokta_sayisi
text:"Mov Mean Nokta Sayısı"
anchors.centerIn: parent
}
}
Rectangle{
border.width: 2
border.color: "black"
id:rectangle_mov_mean_nokta_sayisi_deger
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: mainWindow.width/8
Layout.preferredHeight: mainWindow.height/22
Layout.margins: -3
Layout.fillWidth: true
color:row_even
TextField {
id:textfield_rectangle_mov_mean_nokta_sayisi_deger
anchors.centerIn: parent
placeholderText: qsTr("")
color:normal_text
}
}
There are 20 of these rectangles. When I click a button, a separate value will be displayed for each text field. I need to create these values elsewhere.
you should read Signal and Slots in QML.
For example :
If you have 3 separate QML files:
In main.qml:
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
visible: true
width: 640
height: 480
title: qsTr("External Components with signals and slots")
Notifier{
id : notifierId
rectColor: "yellowgreen"
target: receiverId
}
Receiver {
id : receiverId
rectColor: "dodgerblue"
anchors.right: parent.right
}
Component.onCompleted: {
notifierId.notify.connect(receiverId.receiveInfo)//Connect signal to slot
}
}
and in Receiver.qml :
import QtQuick 2.12
Item {
property alias rectColor: receiverRectId.color
width: receiverRectId.width
height: receiverRectId.height
function receiveInfo( count){
receiverDisplayTextId.text = count
console.log("Receiver received number : "+ count)
}
Rectangle {
id : receiverRectId
width: 200
height: 200
color: "red"
Text {
id : receiverDisplayTextId
anchors.centerIn: parent
font.pointSize: 20
text : "0"
}
}
}
and in Notifier.qml:
import QtQuick 2.12
Item {
property alias rectColor: notifierRectId.color
width: notifierRectId.width
height: notifierRectId.height
property int count: 0
signal notify( string count)//Declare signal
property Receiver target : null
onTargetChanged: {
notify.connect(target.receiveInfo)
}
Rectangle {
id : notifierRectId
width: 200
height: 200
color: "red"
Text {
id : displayTextId
anchors.centerIn: parent
font.pointSize: 20
text : count
}
MouseArea{
anchors.fill: parent
onClicked: {
count++
notify(count)
}
}
}
}
you can see that by using signals and slots you can send data from Notifier.qml to Receiver.qml.

How can I read listmodel role property in main.qml?

In main.qml, I am updating listModel dynamically on every function addItem() call. Herein, I am setting two role; buttonTypeRole and source. OneText.qml file has a Text field. Actually, after inserting buttonTypeRole and source into listModel, I want to know whether source is being truncated or not.
IS ANY WAY TO READ OneText.qml TEXT TRUNCATED PROPERTY IN main.qml FILE?
main.qml
function additem()
{
listModel.insert(tlist.listModel.count , {"buttonTypeRole":"OneText.qml", "source":editText})
console.log("model-- "+tlist.listModel.get(sourceIndex).t)
}
listModel and ListView snapshot:
Item
{
property alias listModel: listModel
ListModel
{
id:listModel
}
Rectangle
{
id:listHolder
border.color: "transparent"
border.width: 3
color:"transparent"
height:560
width:600
focus:true
ListView
{
//id:listview
x:5
y:5
spacing:10
width:700
height:listHolder.height - 20
id:list
boundsBehavior: ListView.StopAtBounds
model:listModel
delegate:listComponent
clip: true
snapMode:ListView.SnapToItem
}
}
Component
{
id:listComponent
Rectangle
{
//color:"grey"
width:obj.width
height:obj.height
border.color: "red"
Loader
{
id:itemDisplay
source:buttonTypeRole
}
}
}
}
buttonTypeRole :OneText.qml snapshot
import QtQuick 2.0
import QtQuick.Controls 2.0
Item
{
id:one
height:obj.height
width:obj.width
Text
{
id:textOne
height:obj.height
width:obj.width
anchors.verticalCenter: parent.verticalCenter
verticalAlignment: "AlignVCenter"
anchors.leftMargin: 10
font.family: obj.fontFamily
font.bold: obj.fontBoldStyle == "true" ? true : false
font.pixelSize: obj.fontSize
text:source
elide: Text.ElideRight
}
}

How to have a numerical model start at 1 in a combobox from QML

In the combobox from qml we can give them a model with a numerical value.
The options of the combobox then start from 0 to the model value minus 1.
What i want is to show the values on the combobox plus 1.
But still, if i try to access, with qml javascript, the value that is selected in that combobox is the original value, what i mean is, if it's the first option it's the value 0. The numbers shall only start from 1 in the display part of combobox.
I'm going to give an example (with a model=32):
display of the combobox
the options:
what i want is them to start at one, like this:
The code used was the following:
import QtQuick 2.9
import QtQuick.Controls 2.0
ApplicationWindow {
id: window
title: "Stack"
visible: true
height: 200
width: 400
Item {
id: page
anchors.fill: parent
width:parent.width
height: parent.height
Column{
width:parent.width
spacing:10
ComboBox {
id:comboBox
model: 32
objectName: "test"
implicitHeight: 30
displayText: currentText
// delegate:
// Button {
// id:buttonCombo
// width: parent.width
// text: index+1
// height:40
// contentItem: Text {
// text: buttonCombo.text
// font: comboBoxCustom.font
// leftPadding: 5
// horizontalAlignment: Text.AlignLeft
// verticalAlignment: Text.AlignVCenter
// elide: Text.ElideRight
// }
// background: Rectangle {
// color: buttonCombo.hovered ? (buttonCombo.pressed ? "#d8d8d8" : "#e8e8e8" ) : "#fff"
// }
// }
anchors.topMargin: 10
}
}
}
}
Maybe this could be done:
displayText: Number(currentText)+1
but i don't know if its the best solution...

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

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

Resources