Qt / Necessitas - a reasonable replacement for QFileDialog / skin?

I am looking for a good way to address Qt applications for Qt / Necessitas (Android).

Some of the QtGUI widgets are absolutely terrible - unfortunately, including the QFileDialog.

Do you know any replacements with proper appearance? Is QFileDialog usable anywhere with high priority for Necessitas developers?

#include <QApplication> #include <QFileDialog> int main(int argc, char* argv[]) { QApplication a(argc, argv); QString fileName = QFileDialog::getOpenFileName(NULL, QObject::tr("Open Image"), "/home/jana", QObject::tr("Image Files (*.png *.jpg *.bmp)")); a.exec(); } 

QFileDialog

+5
source share
2 answers

Android does not have its own, own file dialog box. We can use QtAndroidExtras to call an external application that can select a file:

chosing external application

I wrote a wrapper that can be used for this. Here is the full code:

androidfiledialog.h

 #ifndef ANDROIDFILEDIALOG_H #define ANDROIDFILEDIALOG_H #include <QObject> #include <QAndroidJniObject> #include <QtAndroid> #include <QAndroidActivityResultReceiver> class AndroidFileDialog : public QObject { Q_OBJECT public: explicit AndroidFileDialog(QObject *parent = 0); virtual ~AndroidFileDialog(); bool provideExistingFileName(); private: class ResultReceiver : public QAndroidActivityResultReceiver { AndroidFileDialog *_dialog; public: ResultReceiver(AndroidFileDialog *dialog); virtual ~ResultReceiver(); void handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data); QString uriToPath(QAndroidJniObject uri); }; static const int EXISTING_FILE_NAME_REQUEST = 1; ResultReceiver *receiver; void emitExistingFileNameReady(QString result); signals: void existingFileNameReady(QString result); }; #endif // ANDROIDFILEDIALOG_H 

androidfiledialog.cpp

 #include "androidfiledialog.h" AndroidFileDialog::ResultReceiver::ResultReceiver(AndroidFileDialog *dialog) : _dialog(dialog) {} AndroidFileDialog::ResultReceiver::~ResultReceiver() {} void AndroidFileDialog::ResultReceiver::handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data) { jint RESULT_OK = QAndroidJniObject::getStaticField<jint>("android/app/Activity", "RESULT_OK"); if (receiverRequestCode == EXISTING_FILE_NAME_REQUEST && resultCode == RESULT_OK) { QAndroidJniObject uri = data.callObjectMethod("getData", "()Landroid/net/Uri;"); QString path = uriToPath(uri); _dialog->emitExistingFileNameReady(path); } else { _dialog->emitExistingFileNameReady(QString()); } } QString AndroidFileDialog::ResultReceiver::uriToPath(QAndroidJniObject uri) { if (uri.toString().startsWith("file:", Qt::CaseInsensitive)) { return uri.callObjectMethod("getPath", "()Ljava/lang/String;").toString(); } else { QAndroidJniObject contentResolver = QtAndroid::androidActivity().callObjectMethod("getContentResolver", "()Landroid/content/ContentResolver;"); QAndroidJniObject cursor = contentResolver.callObjectMethod("query", "(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;", uri.object<jobject>(), 0, 0, 0, 0); QAndroidJniObject DATA = QAndroidJniObject::fromString("_data"); jint columnIndex = cursor.callMethod<jint>("getColumnIndexOrThrow", "(Ljava/lang/String;)I", DATA.object<jstring>()); cursor.callMethod<jboolean>("moveToFirst", "()Z"); QAndroidJniObject result = cursor.callObjectMethod("getString", "(I)Ljava/lang/String;", columnIndex); return result.isValid() ? result.toString() : QString(); } } AndroidFileDialog::AndroidFileDialog(QObject *parent) : QObject(parent) { receiver = new ResultReceiver(this); } AndroidFileDialog::~AndroidFileDialog() { delete receiver; } bool AndroidFileDialog::provideExistingFileName() { QAndroidJniObject ACTION_GET_CONTENT = QAndroidJniObject::fromString("android.intent.action.GET_CONTENT"); QAndroidJniObject intent("android/content/Intent"); if (ACTION_GET_CONTENT.isValid() && intent.isValid()) { intent.callObjectMethod("setAction", "(Ljava/lang/String;)Landroid/content/Intent;", ACTION_GET_CONTENT.object<jstring>()); intent.callObjectMethod("setType", "(Ljava/lang/String;)Landroid/content/Intent;", QAndroidJniObject::fromString("file/*").object<jstring>()); QtAndroid::startActivity(intent.object<jobject>(), EXISTING_FILE_NAME_REQUEST, receiver); return true; } else { return false; } } void AndroidFileDialog::emitExistingFileNameReady(QString result) { emit existingFileNameReady(result); } 

You should add * .pro to your file:

 QT += androidextras 

using an example:

 AndroidFileDialog *fileDialog = new AndroidFileDialog(); connect(fileDialog, SIGNAL(existingFileNameReady(QString)), this, SLOT(openFileNameReady(QString))); bool success = fileDialog->provideExistingFileName(); if (!success) { qDebug() << "Problem with JNI or sth like that..."; disconnect(fileDialog, SIGNAL(existingFileNameReady(QString)), this, SLOT(openFileNameReady(QString))); //or just delete fileDialog instead of disconnect } 

:

 void MyClass::openFileNameReady(QString fileName) { if (!fileName.isNull()) { qDebug() << "FileName: " << fileName; } else { qDebug() << "User did not choose file"; } } 

Please confirm that this solution works correctly on your device.

+3
source

You can easily create your own dialog with a file, either with QtWidgets or using QML, using the ready-made QFileSystemModel class,

Regarding priority or not, at the moment it seems that Necessitas will be absorbed in Digia's efforts to support Android. I doubt that significant efforts will be made to ensure the correct QtWidgets style, as the module is marked as DONE, and all the attention for the user interface is on QML. Therefore, if I were you, I would not hold my breath. Plus, the patented Qt widgets look completely ugly on non-desktop platforms.

+1
source

All Articles