dbzhang800 / QtXlsxWriter

.xlsx file reader and writer for Qt5
http://qtxlsx.debao.me
Other
1.22k stars 630 forks source link

Crash when using sheetmodel in qtableview #181

Closed bascyr closed 5 years ago

bascyr commented 5 years ago

Hi,

I try to extract xlsx sheets (microsoft) in a differents QTableView. One sheet (xlsx microsoft excel) for one QTableView which is in one tab of a QTabWidget. QTabWidget was placed with QTDesigner.

I strangely discover that windows crashes when I run this following code

        `QXlsx::Document xlsx(filename.toUtf8());
          foreach (QString sheetName, xlsx.sheetNames()) {
              Worksheet *sheet = dynamic_cast<Worksheet *>(xlsx.sheet(sheetName));
              if (sheet) {
                  QTableView *view = new QTableView(ui->tabWidget);
                  view->setModel(new SheetModel(sheet, view));
                  ui->tabWidget->addTab(view, sheetName);
              }
         }`            

Any ideas welcome to help understanding why it crashed. Thanks for answers.

VSRonin commented 5 years ago
bascyr commented 5 years ago

Hi,

22:15:10: Starting C:\Qt\Examples\Qt-5.12.0\test\build-3CABilan-Desktop_Qt_5_12_0_MSVC2017_32bit-Debug\debug\3CABilan.exe... 22:15:30: The process was ended forcefully. 22:15:30: C:/Qt/Examples/Qt-5.12.0/test/build-3CABilan-Desktop_Qt_5_12_0_MSVC2017_32bit-Debug/debug/3CABilan.exe crashed.

Surprisely, when I use your xlsxwidget example code in main.cpp file, all run pretty well. Tabs appear and contain datas. However, if the code is in a mainwindow constructor, tabs appear empty but with their names. When I click on them, it crashs.

include "mainwindow.h"

include "ui_mainwindow.h"

include

include "xlsxdocument.h"

include "xlsxworksheet.h"

include "xlsxcellrange.h"

include "xlsxsheetmodel.h"

using namespace QXlsx;

MainWindow::MainWindow(QWidget parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); //![0] QString filePath = QFileDialog::getOpenFileName(0, "Open xlsx file", QString(), ".xlsx"); if (filePath.isEmpty()) return; //![0]

    //![2]
    Document xlsx2(filePath);
    foreach (QString sheetName, xlsx2.sheetNames()) {
        Worksheet *sheet = dynamic_cast<Worksheet *>(xlsx2.sheet(sheetName));
        if (sheet) {
            QTableView *view = new QTableView(ui->tabWidget);
            view->setModel(new SheetModel(sheet, view));
            foreach (CellRange range, sheet->mergedCells())
                view->setSpan(range.firstRow()-1, range.firstColumn()-1, range.rowCount(), range.columnCount());
            ui->tabWidget->addTab(view, sheetName);
        }
    }
    //![2]

ui->tabWidget->show();

}

MainWindow::~MainWindow() { delete ui; }

VSRonin commented 5 years ago

Yes, you need to keep Document xlsx2(filePath); alive. Make it a member of MainWindow instead of a local variable

bascyr commented 5 years ago

Absolutely right ! Thanks for your help ! Even if I don't oversee why windows crashed...

Code which can help someone else :+1:

file mainwindow.cpp

MainWindow::MainWindow(QWidget parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); filePath = QFileDialog::getOpenFileName(0, "Open xlsx file", QString(), ".xlsx"); xlsx2=new QXlsx::Document(filePath); foreach (QString sheetName, xlsx2->sheetNames()) { Worksheet sheet = dynamic_cast<Worksheet >(xlsx2->sheet(sheetName)); if (sheet) { QTableView *view = new QTableView(ui->tabWidget); view->setModel(new SheetModel(sheet, view)); foreach (CellRange range, sheet->mergedCells()) view->setSpan(range.firstRow()-1, range.firstColumn()-1, range.rowCount(), range.columnCount()); ui->tabWidget->addTab(view, sheetName); } }

ui->tabWidget->show();

}

file mainwindow.h

class MainWindow : public QMainWindow { Q_OBJECT

public: explicit MainWindow(QWidget *parent = nullptr); ~MainWindow();

private: Ui::MainWindow ui; QString filePath; QXlsx::Document xlsx2; };

VSRonin commented 5 years ago

Even if I don't oversee why windows crashed...

SheetModel doesn't copy or takes ownership of the QXlsx::Document. If you delete it, the model will try to access a dangling pointer

In any case, your code above is leaking xlsx2, you should pass a parent (this?) to the constructor.

If your problem is solved please close the ticket

bascyr commented 5 years ago

Thanks for answers.