Qt / Necessitas – разумная замена QFileDialog / скин?

Я ищу хороший способ решения проблемы переноса Qt-приложений на Qt / Necessitas (Android).

Некоторые из виджетов QtGUI абсолютно ужасны – к сожалению, включая QFileDialog.

Знаете ли вы какие-либо замены с надлежащим внешним видом? Является ли QFileDialog пригодным для использования в любом месте с высоким приоритетом для разработчиков Necessitas?

#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

    У Android нет собственного встроенного диалогового окна файлов. Мы можем использовать QtAndroidExtras для вызова внешнего приложения, которое может выбрать файл:

    Использование внешнего приложения

    Я написал обертку, которая может быть использована для этого. Вот полный код:

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

    Вы должны добавить в свой файл * .pro:

     QT += androidextras 

    Используя пример:

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

    Пожалуйста, подтвердите, что это решение работает правильно на вашем устройстве.

    Вы можете легко создать собственный диалог с файлом либо с QtWidgets, либо с помощью QML, используя готовый класс QFileSystemModel .

    Что касается приоритета или нет, на данный момент кажется, что Necessitas будет поглощен усилиями Digia по поддержке Android. Я сомневаюсь, что будут прилагаться значительные усилия для правильного стиля QtWidgets, так как модуль отмечен как DONE, и все внимание для пользовательского интерфейса находится на QML. Поэтому, если бы я был вами, я бы не задерживал дыхание. Плюс запатентованные Qt-виджеты выглядят совершенно уродливыми на не-настольных платформах.

    Intereting Posts
    Изменение яркости экрана в программном обеспечении Android Мультимедийные помехи для Android Сброс хронометра Не может запускать приложение cordova на работе устройства или эмулятора Android contentprovider не возвращает Phone.NUMBER Получать координаты изображения растрового изображения из ImageView в два раза меньше Отчеты Crashlytics Не удалось получить настройки с https://settings.crashlytics.com/ Изящное обращение с ориентацией экрана во время начала работы MediaPlayer Framework на GingerBread и поддержка HTTP Live Streaming от Apple Воспроизведение Android MediaPlayer заикается по проводным наушникам, а не по Bluetooth Круглые формы кнопки искажаются с длиной текста внутри. Почему мой полноэкранный веб-просмотр постоянно закрывается сразу после открытия? Android-устройства не распознают подключенное оборудование с чипом FTDI Множество аргументов переменной длины Java Ручной ввод не сохранен в Android DatePicker (Dialog)