Я пишу приложение для передачи файлов между устройством Android и Mac. Передача файлов работает, но с точки зрения пользовательского опыта я хотел бы добавить индикатор выполнения, чтобы видеть, когда передача завершена.
Поскольку я перехожу на устройство Android, мне пришлось использовать стек mtp. Функция, используемая для копирования файла,
LIBMTP_Send_File_From_File(device, path, genfile, ProgressBar, NULL);
ProgressBar — это функция обратного вызова, а стек MTP написан на C.
Мое приложение написано на C++/Qt.
Сначала я разработал индикатор выполнения и ожидал, что с помощью механизма CONNECT/SIGNAL/SLOT он обновит индикатор выполнения, но он не работает.
Что я сделал, так это в dialog.h определил мой обратный вызов:
extern "C" int ProgressBar(const uint64_t data_sent, const uint64_t data_total, void const * const data);
и класс для разработки диалогового окна.
class Dialog : public QWidget
{
Q_OBJECT
public:
Dialog();
void CreateProgressBar();
void DestroyProgressBar();
private:
QWidget *ProgressDialog;
QProgressBar *ProgressIndicator;
QVBoxLayout *ProgressLayout;
QPushButton *CancelButton;
private slots:
void onCancelButtonAction();
};
В Dialog.c,
Dialog::Dialog()
{
}
void Dialog::CreateProgressBar() {
ProgressDialog = new QWidget(this);
ProgressDialog->setWindowTitle("Progress");
ProgressLayout = new QVBoxLayout(this);
ProgressIndicator = new QProgressBar();
ProgressIndicator->resize(200,25);
//ProgressIndicator->setrange(0,100);
ProgressIndicator->setValue(0);
ProgressIndicator->setOrientation(Qt::Horizontal);
connect(ProgressIndicator,SIGNAL(ProgressBar(const uint64_t, const uint64_t, void const * const)),ProgressIndicator,SLOT(setValue(int)));
CancelButton = new QPushButton();
CancelButton->setFixedSize(25,25);
CancelButton->setText("Cancel");
CancelButton->setFlat(true);
CancelButton->setAutoFillBackground(true);
CancelButton->setStyleSheet("QPushButton { background-color : white;}");
connect(CancelButton, SIGNAL(clicked()), this, SLOT(onCancelButtonAction()));
ProgressLayout->addWidget(ProgressIndicator);
ProgressLayout->addWidget(CancelButton);
ProgressDialog->setLayout(ProgressLayout);
ProgressDialog->show();
}
void Dialog::DestroyProgressBar() {
ProgressDialog->close();
}
void Dialog::onCancelButtonAction() {
DestroyProgressBar();
}
и код C для "ProgressBar"
int ProgressBar(const uint64_t data_sent, const uint64_t data_total, void const * const data) {
return (data_sent * 100) / data_total;
}
Это в основном не работает, потому что подключение отклоняет подключение SIGNAL к ProgressBar, потому что это не часть класса.
С другой стороны, если я перемещаю ProgressBar в своем классе, подключение выполняется, но код не создается, потому что LIBMTP_Send отклоняет использование класса.
Я вызываю ProgressBar в LIBMTP_Send... с помощью MyProgress.ProgressBar
Dialog MyProgress;
MyProgress.CreateProgressBar();
LIBMTP_Send_File_From_File(device, path, genfile, MyProgress.ProgressBar, NULL);
Это не работает, потому что я использую вызов метода, если мой класс вместо обратного вызова C
Мой метод при попытке использовать класс вместо кода C определяется следующим образом:
int Dialog::ProgressBar(const uint64_t data_sent, const uint64_t data_total, void const * const data) {
char* tmp_string;
char* tmp_sent;
char* tmp_total;
if(ProgressIndicator.destroyed() == true)
return true;
if (ProgressIndicator != NULL) {
ProgressIndicator->setValue();
}
if (progressDialog != NULL) {
return (data_sent * 100) / data_total;
}
return 0;
}
В этом случае я делаю:
ret = LIBMTP_Send_File_From_File(PulsDeviceMngr->device, strdup(AbsolutePath), genfile, MyProgress.ProgressBar, NULL);
но ошибка сборки: должна быть вызвана ссылка на нестатическую функцию-член
Я создаю экземпляр диалогового окна в коде, который вызывает функцию LIBMTP, как показано ниже:
Dialog MyProgress;
MyProgress.CreateProgressBar();
genfile = LIBMTP_new_file_t();
...
ret = LIBMTP_Send_File_From_File(PulsDeviceMngr->device, strdup(AbsolutePath), genfile, MyProgress.ProgressBar, NULL);
Я действительно застрял... пустой :-)