How to save a table in a file
-
I'm developing a library that includes this feature: https://github.com/VSRonin/QtModelUtilities
I still need to get it to stable and fully documented but should be good enough for rock and roll.
Saving to csv is done via theCsvModelSerialiser
class -
@Daesos Are you sure it does not save the file? You're using a relative path, that means the file will be located in the current working directory of your app, most probably in the build directory. Also did you check whether MainWindow::on_pushButton_2_clicked() was actually called?
-
The image above is the directory of my project. If I click on save button, the cell corresponding to log_activity.csv and Event changes into modified.
It shows "Modified" when the date of the previous directory is different from the current one.
So I guess the save_button works.Also, if the file doesn't exit, the program create the file with the given name.
-
@Daesos said in How to save a table in a file:
I want to resolve this only with given libraries by Qt
Then copy-paste my code. I only use Qt in those and license is apache 2 so you can basically do what you want with it.
In your code above you are not:
- Writing any new line to separate rows.
- Writing any column separator
- Escaping column separators inside the data
-
@Daesos
Assuming the file is opened for write, you are saying you end up with nothing in it, and your table does indeed contain desired text (ui->tableWidget->item(i, j)->text()
). You stream all your data toQTextStream out
but you only close theQFile csv
. I don't know if that knows to fetch all remaining data out of the stream. Tryout.flush()
prior to thecsv.close()
? -
@jsulm I'm trying, but it stops with this message: Stopped "end-stepping-range". I've put a breakpoint at "out<<ui->tableWidget->item(i, j)->text();" and as i can see, this returns "main.window.cpp", which is correct. Then, I don't what happen.
-
@Daesos Try calling http://doc.qt.io/qt-5/qtextstream.html#flush before closing the file
-
@Daesos Last idea I have: is it possible that you open same file somewhere else in your app, or that there is still an instance of your app running?
Oh, one more idea: try to write the file using an absolute path to some other location. -
@jsulm I checked and there is no other instance opened. Also, I used another path. The program created the file.csv (empty), then quitted. Application Output: "The program has unexpectedly finished."
Since I don't know if I have mistaken something I will post all the mainwindow.cpp code:
#include "mainwindow.h" #include "ui_mainwindow.h" #include <QFileDialog> #include <QFileInfo> #include <QTimer> #include <QDateTime> #include <QFile> #include <QTextStream> MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); setWindowTitle("DirectoryMonitor"); ui->tableWidget->setColumnCount(4); ui->tableWidget->setHorizontalHeaderLabels(QStringList() << "" << "Filename" << "Event" << "Time"); f_name = "log_activity.csv"; } MainWindow::~MainWindow() { delete ui; } void MainWindow::on_pushButton_clicked() { ui->tableWidget->clearContents(); path = QFileDialog::getExistingDirectory(this, tr("Open Directory"), ".", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); ui->lineEdit->setText(path); QDir dir(path); dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); dir.setSorting(QDir::Time); list = dir.entryInfoList(); for(int i = 0; i < list.size(); ++i){ ui->tableWidget->insertRow(ui->tableWidget->rowCount()); ui->tableWidget->setItem(i, 1, new QTableWidgetItem(list.at(i).fileName())); ui->tableWidget->setItem(i, 3, new QTableWidgetItem(list.at(i).lastModified().toString())); } int count = 0; for(int i = 0; i < ui->tableWidget->rowCount(); ++i){ QTableWidgetItem *itm = ui->tableWidget->item(i, 1); if(itm != 0) ++count; } //rimuovi righe vuote ui->tableWidget->setRowCount(count); QTimer *time = new QTimer(this); connect(time, SIGNAL(timeout()), this, SLOT(changes())); time->start(3000); } void MainWindow::changes() { QDir dir(path); dir.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot); dir.setSorting(QDir::Time); QFileInfoList newlist = dir.entryInfoList(); int index_delete = -1; //caso modified e delete file for(int i = 0; i < list.size(); ++i){ int count = 0; for(int j = 0; j < newlist.size(); ++j){ if(list.at(i).fileName() == newlist.at(j).fileName()){ ++count; if(list.at(i).lastModified() != newlist.at(j).lastModified()){ QTableWidgetItem *itm = new QTableWidgetItem(""); itm->setBackground(QColor(109, 158, 235)); ui->tableWidget->setItem(i, 0, itm); ui->tableWidget->setItem(i, 2, new QTableWidgetItem("Modified")); ui->tableWidget->setItem(i, 3, new QTableWidgetItem(newlist.at(j).lastModified().toString())); } } } if(count == 0){ index_delete = i; } } if(index_delete != -1){ QTableWidgetItem *itm = new QTableWidgetItem(""); itm->setBackground(QColor(224, 102, 99)); ui->tableWidget->setItem(index_delete, 0, itm); if(ui->tableWidget->item(index_delete, 2)->text() != "Deleted") ui->tableWidget->setItem(index_delete, 3, new QTableWidgetItem(QDateTime::currentDateTime().toString())); ui->tableWidget->setItem(index_delete, 2, new QTableWidgetItem("Deleted")); } //caso new file int index_new = -1; for(int i = 0; i < newlist.size(); ++i){ int count = 0; for(int j = 0; (j < list.size() && count == 0); ++j){ if(newlist.at(i).fileName() == list.at(j).fileName()) ++count; } if(count == 0) index_new = i; } if(index_new != -1){ ui->tableWidget->insertRow(ui->tableWidget->rowCount()); QTableWidgetItem *itm = new QTableWidgetItem(""); itm->setBackground(QColor(148, 195, 123)); ui->tableWidget->setItem(ui->tableWidget->rowCount() - 1, 0, itm); ui->tableWidget->setItem(ui->tableWidget->rowCount() - 1, 1, new QTableWidgetItem(newlist.at(index_new).fileName())); ui->tableWidget->setItem(ui->tableWidget->rowCount() - 1, 2, new QTableWidgetItem("Created")); ui->tableWidget->setItem(ui->tableWidget->rowCount() - 1, 3, new QTableWidgetItem(newlist.at(index_new).lastModified().toString())); list.append(newlist.at(index_new)); } } void MainWindow::on_pushButton_2_clicked() { QFile csv(f_name); if(!csv.open(QFile::WriteOnly)) return; QTextStream out(&csv); for(int i = 0; i < ui->tableWidget->rowCount(); ++i) for (int j = 1; j < ui->tableWidget->columnCount(); j++){ QString txt(ui->tableWidget->item(i, j)->text()); out<<txt; } out.flush(); csv.close(); }
Sorry for the indentation.
This is the declaration of the global variables in mainwindow.hQString path, f_name; QFileInfoList list;
-
@Daesos
If you're still having problems with the file (once you've solved the "crash"), try replacing yourQFile
with aQString
, and use https://doc.qt.io/Qt-5/qtextstream.html#QTextStream-3. You should be successfully building up the string of the file content. If that doesn't work, nor will write to file. -
I used debugger and when i click on pushButton_2 (save on interface) it returns a Segmentation Fault at "QTableWidgetItem::text".
@J.Hilk, I didn't even notice. I edited the increment.Segmentation Fault occurs when I try to access to a NULL pointer, right? So, it might be out of bound.
-
@Daesos
I don't seesave_button
in the code you've posted?I notice you have:
ui->tableWidget->setItem(i, 0, itm); ui->tableWidget->setItem(i, 2, new QTableWidgetItem("Modified")); ui->tableWidget->setItem(i, 3, new QTableWidgetItem(newlist.at(j).lastModified().toString()));
Where do you
setItem()
oni, 1
?for(int i = 0; i < ui->tableWidget->rowCount(); ++i) for (int j = 1; j < ui->tableWidget->columnCount(); j++){ QString txt(ui->tableWidget->item(i, j)->text()); out<<txt; }
Check your accesses on every
i, j
here. Somewhere you do not have an item atitem(i, j)
! -
I've edited the increment:
for(int i = 0; i < ui->tableWidget->rowCount(); ++i) for (int j = 1; j < ui->tableWidget->columnCount(); ++j) out<<ui->tableWidget->item(i, j)->text();
@JonB said in How to save a table in a file:
I notice you have:
ui->tableWidget->setItem(i, 0, itm); ui->tableWidget->setItem(i, 2, new QTableWidgetItem("Modified")); ui->tableWidget->setItem(i, 3, new QTableWidgetItem(newlist.at(j).lastModified().toString()));
Where do you
setItem()
oni, 1
?I've inizialized item at (i, 1) before. Once inizialized the name of the file must not be modified. So I didn't use setItem on i, 1 again.
@Daesos
ui->tableWidget->setItem(ui->tableWidget->rowCount() - 1, 1, new QTableWidgetItem(newlist.at(index_new).fileName())); -
@Daesos said in How to save a table in a file:
for(int i = 0; i < ui->tableWidget->rowCount(); ++i)
for (int j = 1; j < ui->tableWidget->columnCount(); ++j)
out<<ui->tableWidget->item(i, j)->text();Maybe it's time to
#include
good old<QDebug>
for(int i = 0; i < ui->tableWidget->rowCount(); ++i) for (int j = 1; j < ui->tableWidget->columnCount(); ++j){ qDebug() << i << "of" << ui->tableWidget->rowCount() << endl << j << "of" << ui->tableWidget->columnCount(); out<<ui->tableWidget->item(i, j)->text(); qDebug() << QString("Found text at %1 | %2").arg(i).arg(j); }
-
Replace
out<<ui->tableWidget->item(i, j)->text();
without<<ui->tableWidget->model()->index(i, j).data().tostring();
to prevent segfaultsThe problems I highlighted are still present though
@VRonin said in How to save a table in a file:
In your code above you are not:
- Writing any new line to separate rows.
- Writing any column separator
- Escaping column separators inside the data