2013-02-26 124 views
5

我正在寻找一个很好的方式来解决Qt应用程序移植到Qt/Necessitas(Android)的问题。Qt/Necessitas - 合理的QFileDialog替换/皮肤?

一些QtGUI小部件绝对是非常残酷的 - 不幸的是,包括QFileDialog。

您是否知道任何具有适当外观和感觉的替换品? 让Necessitas开发人员可以在任何接近高优先级的地方使用QFileDialog?

#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

+0

什么意思 - 暴行?这个绝对是光滑的! – mlvljr 2013-06-23 10:39:56

回答

1

您可以轻松地通过使用外的开箱QFileSystemModel类建立自己的文件对话框要么QtWidgets或者QML。

至于是否优先,在这一点上,Necessitas似乎将被Digia支持Android的努力所吸收。我怀疑将会有相当大的努力来适当地设计QtWidgets,因为模块被标记为DONE,并且UI的所有焦点都在QML上。所以,如果我是你,我不会屏住呼吸。另外,在非桌面平台上,库存Qt小部件看起来完全难看。

3

Android没有自己的原生文件对话框。我们可以用QtAndroidExtras调用外部应用程序,它能够选择一个文件:

chosing external application

我写的包装,可能被用于这一点。下面是完整的代码:

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

请确认这个解决方案正常工作,您的设备上。