Question

I implemented a native File Picker on BlackBerry 10, after a bit of messing around it finally recognised the class, it opens fine and returns the file Address on the console but it looks like two signals are not working properly, baring in mind this is pretty much a straight copy of code from BlackBerry 10 docs.

    using namespace bb::cascades::pickers;
void Utils::getFile() const{

     FilePicker* filePicker = new FilePicker();
    filePicker->setType(FileType::Music);
    filePicker->setTitle("Select Sound");
    filePicker->setMode(FilePickerMode::Picker);
    filePicker->open();

    // Connect the fileSelected() signal with the slot.
    QObject::connect(filePicker,
        SIGNAL(fileSelected(const QStringList&)),
        this,
        SLOT(onFileSelected(const QStringList&)));

    // Connect the canceled() signal with the slot.
    QObject::connect(filePicker,
        SIGNAL(canceled()),
        this,
        SLOT(onCanceled()));
}

I wanted it to return the file url to qml with this (works fine with QFileDialog but that wouldn't recognise on my SDK) var test=utils.getFile() if(test=="") console.debug("empty") else console.debug(test)

But I'm getting these messages from the console: Object::connect: No such slot Utils::onFileSelected(const QStringList&) in ../src/Utils.cpp:27 Object::connect: No such slot Utils::onCanceled() in ../src/Utils.cpp:33

It is returning undefined from the else in the qml function when it opens, Does anyone know where I cocked up or how I could get QFileDialog class to be found by the SDK?

Was it helpful?

Solution

I just wanted to give you a bit of an explanation in case you're still having some troubles. The concept's in Qt were a little foreign to me when I started in on it as well.

There are a couple ways you can do this. The easiest would probably be the pure QML route:

import bb.cascades 1.2
import bb.cascades.pickers 1.0

Page {
    attachedObjects: [
        FilePicker {
            id: filePicker
            type: FileType.Other
            onFileSelected: {
                console.log("selected files: " + selectedFiles)
            }
        }
    ]

    Container {
        layout: DockLayout {

        }
        Button {
            id: launchFilePicker
            text: qsTr("Open FilePicker")
            onClicked: {
                filePicker.open();
            }
        }
    }
}

When you click the launchFilePicker button, it will invoke a FilePicker. Once a file is selected, the fileSelected signal will be fired. The slot in this case is the onFileSelected function (predefined), which logs the filepaths of the files that were selected (a parameter from the signal) to the console.


The C++ route is a little more work, but still doable.

If your class file was called Util, then you'd have a Util.h that looks something like this:

#ifndef UTIL_H_
#define UTIL_H_

#include <QObject>

class QStringList;

class Util : public QObject
{
    Q_OBJECT
public:
    Util(QObject *parent = 0);

    Q_INVOKABLE
    void getFile() const;

private Q_SLOTS:
    void onFileSelected(const QStringList&);
    void onCanceled();
};

#endif /* UTIL_H_ */

Note the Q_INVOKABLE getFile() method. Q_INVOKABLE will eventually allow us to call this method directly from QML.

The corresponding Util.cpp would look like:

#include "Util.h"

#include <QDebug>
#include <QStringList>
#include <bb/cascades/pickers/FilePicker>

using namespace bb::cascades;
using namespace bb::cascades::pickers;

Util::Util(QObject *parent) : QObject(parent)
{
}

void Util::getFile() const
{
    FilePicker* filePicker = new FilePicker();
    filePicker->setType(FileType::Other);
    filePicker->setTitle("Select a file");
    filePicker->setMode(FilePickerMode::Picker);
    filePicker->open();

    QObject::connect(
            filePicker,
            SIGNAL(fileSelected(const QStringList&)),
            this,
            SLOT(onFileSelected(const QStringList&)));

    QObject::connect(
            filePicker,
            SIGNAL(canceled()),
            this,
            SLOT(onCanceled()));
}

void Util::onFileSelected(const QStringList &stringList)
{
    qDebug() << "selected files: " << stringList;
}

void Util::onCanceled()
{
    qDebug() << "onCanceled";
}

To make your Q_INVOKABLE getFile() method available to QML, you'd need to create an instance and set it as a ContextProperty. I do so in my applicationui.cpp like so:

Util *util = new Util(app);
QmlDocument *qml = QmlDocument::create("asset:///main.qml").parent(this);
qml->setContextProperty("_util", util);

Then, you can call this Q_INVOKABLE getFile() method from QML:

Page {
    Container {
        layout: DockLayout {}
        Button {
            id: launchFilePicker
            text: qsTr("Open FilePicker")
            onClicked: {
                _util.getFile();
            }
        }
    }
}

Like Richard says, most of the documentation covers how to create signals/slots, so you could review that, but also have a look at some Cascades-Samples on Git.

Hope that helps!!!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top