Как обрабатывать индикатор выполнения в QT/С++, когда значение обновления используется в качестве обратного вызова

Я пишу приложение для передачи файлов между устройством 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);

Я действительно застрял... пустой :-)


person Seb    schedule 17.01.2015    source источник
comment
поскольку это не код C, удалите тег C   -  person user3629249    schedule 17.01.2015


Ответы (1)


Для этого вам нужно будет передать указатель на класс в качестве аргумента обратного вызова в

LIBMTP_Send_File_From_File(device, path, genfile, MyProgress.ProgressBar, NULL);

аргумент NULL является аргументом обратного вызова

Dialog *MyProgress = new Dialog(parentWindow);
LIBMTP_Send_File_From_File(device, path, genfile, ProgressBar, MyProgress);
                                                              /* ^ here a pointer to */
                                                              /*   progress dialog   */

Примечание: parentWindow может быть вашим QMainWindow, и это очень важно, иначе у вас будет утечка памяти.

то в обратном вызове аргумент данных будет указывать на диалог, поэтому вы можете сделать

Dialog *dialog = reinterpret_cast<Dialog *>(data);
dialog->setValue((data_sent * 100) / data_total);
person Iharob Al Asimi    schedule 17.01.2015
comment
Я обновил свой код, но не вижу, куда добавить *dialog. Должен ли я делать это в вызывающей программе LIBMTP или в моем коде dialog.c? - person Seb; 17.01.2015
comment
@Себ, куда ты звонишь LIBMTP_Send_File_From_File()? - person Iharob Al Asimi; 17.01.2015
comment
в файле с именем mtp_wrapper.c диалоговое окно также вызывается здесь. и все data_sent. data, data_total определяются в диалоговом окне класса в dialog.h в приватном разделе - person Seb; 17.01.2015
comment
это файл c, как вы создаете там экземпляр диалога? - person Iharob Al Asimi; 17.01.2015
comment
позвольте мне добавить код. все это код C++, событие-оболочка. Оболочка включает вызов заголовка стека MTP. Я использую динамическую библиотеку, чтобы стек mtp был встроен в приложение. - person Seb; 17.01.2015
comment
код добавлен в описание, чтобы показать, как это называется - person Seb; 17.01.2015
comment
оболочка используется для создания класса/методов C++ для подключения стека C для MTP и приложения C++/Qt. - person Seb; 17.01.2015
comment
спасибо, но ProgressBar должен быть вызовом C или методом внутри класса Dialog? - person Seb; 17.01.2015
comment
не удалось построить: Диалог *диалог = реинтерпретировать_каст‹Диалог *›(данные); reinterpret_cast из 'const void *' в Dialog * отбрасывает квалификаторы. код добавляется в индикатор выполнения, который не находится внутри класса, но определяется внешним C - person Seb; 17.01.2015
comment
@Seb вместо этого используйте const_cast<Dialog *>. - person Iharob Al Asimi; 17.01.2015
comment
@Seb, не имеет значения, вы также можете попробовать изменить оба квалификатора const в сигнатуре функции ... - person Iharob Al Asimi; 17.01.2015