1

I want to write a QML app that adds the latest opened files from FileDialog to the main menu. I'm currently following this documentation example but the problem is that I can't understand how to pass the file name of an opened file.

import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.0

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    menuBar : MenuBar
    {
        Menu
        {
            id: recentFilesMenu
            Instantiator
                {
                    model: recentFilesMenu
                    MenuItem
                    {
                        text: model.fileName // I neeed to pass name of opned file here
                    }
                    onObjectAdded: recentFilesMenu.insertItem(index, object)
                }

            title: "File"
            MenuItem
            {
                text: "Open"
                onTriggered: fileDialog.visible = true

            }


            MenuItem
            {
                text: "Exit"
            }
        }


    }

    FileDialog
        {
            id: fileDialog
            title: "Oooopen"
            onAccepted:
            {
              // Here is problem
            recentFilesMenu.objectName = fileDialog.fileUrls
            }
        }
}
BaCaRoZzo
  • 7,502
  • 6
  • 51
  • 82
Dmitry Bubnenkov
  • 9,415
  • 19
  • 85
  • 145

3 Answers3

2

According to the documentation, Instantiator accepts the most common types of models - both C++ and QML ones. In the documentation example such an information is missing, probably to not force the usage of a specific one. An actual implementation can relay on ListModel. In this case the model would expose a fileName role used as the actual menu item.

Following this approach the result would be something like the following code. Mind that the urls are prepended with information which can be easily removed (see for instance this answer).

import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Dialogs 1.0

ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    menuBar : MenuBar {

        Menu {
            id: recentFilesMenu

            title: "File"

            MenuItem {
                text: "Open"
                onTriggered: fileDialog.visible = true
            }

            MenuSeparator { }

            Instantiator {
                model: ListModel { id: files }

                MenuItem { text: fileName }

                onObjectAdded: recentFilesMenu.insertItem(index, object)
                onObjectRemoved: recentFilesMenu.removeItem(object)
            }

            MenuSeparator { visible: files.count > 0 }

            MenuItem { text: "Exit" }
        }
    }

    FileDialog {
        id: fileDialog
        title: "Open"
        onAccepted: {
            for(var i = 0; i < fileDialog.fileUrls.length; ++i)
                files.append({fileName: fileDialog.fileUrls[i]})
        }
    }
}
Community
  • 1
  • 1
BaCaRoZzo
  • 7,502
  • 6
  • 51
  • 82
  • 1
    This should be the accepted answer. I was doing this with a Component and executing createObject and adding the object to the Menu I was using. Using an Instantiator is much cleaner process. – Demolishun Jul 17 '20 at 17:22
1

There is a widgets version of this kind of feature:

http://doc.qt.io/qt-5/qtwidgets-mainwindows-recentfiles-example.html

But the descriptive help is non-existent. Looking through the code here:

http://doc.qt.io/qt-5/qtwidgets-mainwindows-recentfiles-mainwindow-cpp.html

You will see that it stores a QStringList of a list of recent files in QSettings, and loads everything into an array of QActions.

Follow through the mainWindow.cpp for all the references to

enum { MaxRecentFiles = 5 };
QAction *recentFileActs[MaxRecentFiles];

And you should have some good ideas about how to do something similar in QML.

Hope that helps.

phyatt
  • 18,472
  • 5
  • 61
  • 80
0

You probably have a finite number of recent files that you want to display. That being said, you can implement x number of MenuItems and set the text to QStringList[i] implemented as a Q_PROPERTY in a C++ class. Then, you can manipulate the QStringList elements(size, order) on your C++ class.