【问题标题】:How to handle progressbar in QT/C++ when update value is used as a callback更新值用作回调时如何处理 QT/C++ 中的进度条
【发布时间】:2015-01-17 00:45:38
【问题描述】:

我正在编写一个应用程序来在 Android 设备和 Mac 之间传输文件。 Tha 文件传输正在工作,但就用户体验而言,我想添加一个进度条,以便能够查看传输何时结束。

当我要转移到安卓设备时,我必须使用 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();
}

以及“ProgressBar”的 C 代码

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 拒绝使用班级。

我正在使用 MyProgress.ProgressBar 调用 LIBMTP_Send... 中的 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的实例,如下所示:

  Dialog MyProgress;
  MyProgress.CreateProgressBar();

  genfile = LIBMTP_new_file_t();
  ...

  ret = LIBMTP_Send_File_From_File(PulsDeviceMngr->device, strdup(AbsolutePath), genfile, MyProgress.ProgressBar, NULL);

我真的被困住了...空:-)

【问题讨论】:

  • 由于不是C代码,请去掉C标签

标签: c++ qt callback mtp


【解决方案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,它非常重要,否则您会出现内存泄漏。

然后在回调中 data 参数将指向对话框,所以你可以这样做

Dialog *dialog = reinterpret_cast<Dialog *>(data);
dialog->setValue((data_sent * 100) / data_total);

【讨论】:

  • 我已经更新了我的代码,但是我看不到在哪里添加 * 对话框。我必须在 LIBMTP 调用者或我的 dialog.c 代码中这样做吗?
  • @Seb 你在哪里打电话LIBMTP_Send_File_From_File()
  • 在名为 mtp_wrapper.c 的文件中,该对话框也在这里调用。和所有数据发送。 data、data_total 定义在类对话框中 dialog.h 的私有部分
  • 它是一个c文件,你如何在那里创建对话框的实例?
  • 让我添加代码。一切都是 C++ 代码事件的包装器。包装器包括对 MTP 堆栈标头的调用。我使用动态库将 mtp 堆栈嵌入到应用程序中
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-09
  • 1970-01-01
  • 2012-06-17
  • 2020-11-05
  • 1970-01-01
相关资源
最近更新 更多