Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Solved QProgressBar and ActiveX

    General and Desktop
    2
    3
    79
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • N
      neo_qt last edited by

      With Qt Creator, I have inserted a progress bar using the QProgressBar object. I would like the progress bar displaying the busy mode while doing some operations in Excel ( called via ActiveX)

      If I am not wrong QAxObject will start another thread so the GUI should not hang out during the ActiveX call/operations. Could you tell me what I did wrong ?

      Here is my code

      // progressBar busy mode 
      ui->progressBar->setMinimum(0);
      ui->progressBar->setMaximum(0);
      ui->progressBar->show();
      
      // Kick Excel using ActiveX
      CoInitialize(0);
      QAxObject excel( "Excel.Application", 0 );
      
      //Some Excel operations... during few seconds
      
      // Quit Excel
      excel.dynamicCall("Quit()");
      
      // Revert to normal mode
      ui->progressBar->setMaximum(100);
      
      1 Reply Last reply Reply Quote 0
      • hskoglund
        hskoglund last edited by hskoglund

        Hi, while QAxObject can do many fancy things, starting another thread outside of the GUI is not of them :-(

        But if you add some QThread/worker code and move the QAxObject stuff in there, it will work nicely with the GUI.
        Here's an example that updates a progress bar: create an empty vanilla Widget app, add axcontainer to the QT line in the .pro file, then change mainwindow.h to this:

        #include <QMainWindow>
        #include "windows.h"    // for the CoInitialize() call
        #include "QAxObject"
        #include <QThread>
        
        namespace Ui { class MainWindow; }
        
        class ExcelWorker : public QObject
        {
            Q_OBJECT
        
        public slots:
            void doWork(int n)
            {
                CoInitialize(0);
                auto excel = new QAxObject("Excel.Application",0);
                if (nullptr == excel)
                    return;
        
                excel->setProperty("Visible",true);
                auto workbooks = excel->querySubObject("Workbooks");
                auto workbook  = workbooks->querySubObject("Add");
                auto sheets    = workbook->querySubObject("Worksheets");
                auto sheet     = sheets->querySubObject("Item(int)",1);
        
                for (int i = 0; (i < n); ++i)
                {
                    sheet->querySubObject("Cells(int,int)",i % 10 + 1,i / 10 + 1)->setProperty("Value",i);
                    QThread::msleep(100);  // simulate some heavy munging
        
                    emit oneReady(i);
                }
            }
        
        signals:
            void oneReady(int i);
        };
        
        class MainWindow : public QMainWindow
        {
            Q_OBJECT
            QThread excelThread;
        
        public:
            MainWindow(QWidget *parent = nullptr);
            ~MainWindow();
        
        private slots:
            void oneReadyFromExcel(int i);
            void on_pushButton_clicked();
        
        signals:
            void doExcelWork(int n);
        
        private:
            Ui::MainWindow *ui;
        };
        

        and change the mainwindow.cpp to this:

        #include "mainwindow.h"
        #include "ui_mainwindow.h"
        #include "qtimer.h"
        
        MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
        {
            ui->setupUi(this);
        
            auto ew = new ExcelWorker;
            ew->moveToThread(&excelThread);
            connect(this,&MainWindow::doExcelWork,ew,&ExcelWorker::doWork);
            connect(ew,&ExcelWorker::oneReady,this,&MainWindow::oneReadyFromExcel);
        
            excelThread.start();
        }
        
        MainWindow::~MainWindow()
        {
            delete ui;
        }
        
        void MainWindow::on_pushButton_clicked()
        {
            emit doExcelWork(100);
        }
        
        void MainWindow::oneReadyFromExcel(int i)
        {
            ui->progressBar->setValue(i);
        }
        

        Finally add one progress bar and a push button and connect the clicked() signal from the push button to starting Excel and you're good to go.

        Edit: I just tested it, it runs ok but crashes when exiting the app, the example is missing the cleanup of the worker thread and quitting Excel, but I think you'll get the idea anyhow..

        N 1 Reply Last reply Reply Quote 1
        • hskoglund
          hskoglund last edited by hskoglund

          Hi, while QAxObject can do many fancy things, starting another thread outside of the GUI is not of them :-(

          But if you add some QThread/worker code and move the QAxObject stuff in there, it will work nicely with the GUI.
          Here's an example that updates a progress bar: create an empty vanilla Widget app, add axcontainer to the QT line in the .pro file, then change mainwindow.h to this:

          #include <QMainWindow>
          #include "windows.h"    // for the CoInitialize() call
          #include "QAxObject"
          #include <QThread>
          
          namespace Ui { class MainWindow; }
          
          class ExcelWorker : public QObject
          {
              Q_OBJECT
          
          public slots:
              void doWork(int n)
              {
                  CoInitialize(0);
                  auto excel = new QAxObject("Excel.Application",0);
                  if (nullptr == excel)
                      return;
          
                  excel->setProperty("Visible",true);
                  auto workbooks = excel->querySubObject("Workbooks");
                  auto workbook  = workbooks->querySubObject("Add");
                  auto sheets    = workbook->querySubObject("Worksheets");
                  auto sheet     = sheets->querySubObject("Item(int)",1);
          
                  for (int i = 0; (i < n); ++i)
                  {
                      sheet->querySubObject("Cells(int,int)",i % 10 + 1,i / 10 + 1)->setProperty("Value",i);
                      QThread::msleep(100);  // simulate some heavy munging
          
                      emit oneReady(i);
                  }
              }
          
          signals:
              void oneReady(int i);
          };
          
          class MainWindow : public QMainWindow
          {
              Q_OBJECT
              QThread excelThread;
          
          public:
              MainWindow(QWidget *parent = nullptr);
              ~MainWindow();
          
          private slots:
              void oneReadyFromExcel(int i);
              void on_pushButton_clicked();
          
          signals:
              void doExcelWork(int n);
          
          private:
              Ui::MainWindow *ui;
          };
          

          and change the mainwindow.cpp to this:

          #include "mainwindow.h"
          #include "ui_mainwindow.h"
          #include "qtimer.h"
          
          MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
          {
              ui->setupUi(this);
          
              auto ew = new ExcelWorker;
              ew->moveToThread(&excelThread);
              connect(this,&MainWindow::doExcelWork,ew,&ExcelWorker::doWork);
              connect(ew,&ExcelWorker::oneReady,this,&MainWindow::oneReadyFromExcel);
          
              excelThread.start();
          }
          
          MainWindow::~MainWindow()
          {
              delete ui;
          }
          
          void MainWindow::on_pushButton_clicked()
          {
              emit doExcelWork(100);
          }
          
          void MainWindow::oneReadyFromExcel(int i)
          {
              ui->progressBar->setValue(i);
          }
          

          Finally add one progress bar and a push button and connect the clicked() signal from the push button to starting Excel and you're good to go.

          Edit: I just tested it, it runs ok but crashes when exiting the app, the example is missing the cleanup of the worker thread and quitting Excel, but I think you'll get the idea anyhow..

          N 1 Reply Last reply Reply Quote 1
          • N
            neo_qt @hskoglund last edited by

            @hskoglund Thank you very much for the explanation and the code. I have not tested fully your code yet but now I understand why my code did not work as I expect.

            1 Reply Last reply Reply Quote 0
            • First post
              Last post