How to save a table in a file
-
@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 Start your app with debugger (F5) and when it crashes check the stack trace to see where it crashes (use debug build of your app).
-
@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
Going through your code, I noticed, you're mixing postfix, prefix in your nested loop to access the Tablewidget Item. I would search there for an out of bounds error. -
@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;
wrote on 10 Jul 2018, 11:38 last edited by JonB 7 Oct 2018, 11:39@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. -
wrote on 10 Jul 2018, 11:39 last edited by Daesos 7 Oct 2018, 11:52
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.
-
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.
wrote on 10 Jul 2018, 11:40 last edited by JonB 7 Oct 2018, 11:46@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)
! -
wrote on 10 Jul 2018, 11:50 last edited by Daesos 7 Oct 2018, 11:53
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())); -
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); }
-
wrote on 10 Jul 2018, 12:00 last edited by VRonin 7 Oct 2018, 12:00
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
-
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
wrote on 10 Jul 2018, 12:53 last edited by Daesos 7 Oct 2018, 12:56@VRonin In a previous version I've added both ";" and "\n", but I forgot to write them again.
However I forgot one case: what happen if I did not create/delete/modify any file, folder, or other?
The cells (i, 2) might be empty and here is where the program fails.
I resolved by editing some code:void MainWindow::on_pushButton_2_clicked() { QFile csv(f_name); if(!csv.open(QFile::WriteOnly)) return; QTextStream out(&csv); int tmp_column = 0; for(int i = 0; i < ui->tableWidget->rowCount(); ++i){ for (int j = 1; j < ui->tableWidget->columnCount(); ++j){ if(ui->tableWidget->item(i, j) != 0) out<<ui->tableWidget->item(i, j)->text(); out<<";"; tmp_column = j; } if(ui->tableWidget->item(i, tmp_column) != 0) out<<"\n"; } out.flush(); csv.close(); }
It may not be quite good-looking but it works:
I've also prevented segmentation faults like this for example:
ui->tableWidget->setItem(index_delete, 0, itm); if(ui->tableWidget->item(index_delete, 2) != 0 && ui->tableWidget->item(index_delete, 2)->text() != "Deleted") ui->tableWidget->setItem(index_delete, 3, new QTableWidgetItem(QDateTime::currentDateTime().toString()));
-
wrote on 10 Jul 2018, 12:58 last edited by VRonin 7 Oct 2018, 12:58
Try naming a folder
Ugly; Name
and save your model -
wrote on 10 Jul 2018, 13:04 last edited by VRonin 7 Oct 2018, 13:04
P.S.
new QTableWidgetItem(QDateTime::currentDateTime().toString())
see https://bugreports.qt.io/browse/QTBUG-65555this should be separated in 3 lines:
QTableWidgetItem* tableItem = new QTableWidgetItem; tableItem->setData(Qt::EditRole,QDateTime::currentDateTime()); ui->tableWidget->setItem(index_delete, 3,tableItem);
-
wrote on 10 Jul 2018, 14:57 last edited by Daesos 7 Oct 2018, 15:03
Say I want to order the items of the table by name or date once I push Save, but without sorting the table itself (just the output in the file.csv). What can I do? Should I create a temporary table, order it and then store in the file?
Tell me if the question is not clear. -
wrote on 11 Jul 2018, 07:30 last edited by VRonin 7 Nov 2018, 08:08
Not a temporary table, you can use a
QSortFilterProxyModel
and then serialise the proxy rather than the original model.
Since your current architecture relies on theQStandardItem
interface rether than theQAbstractItemModel
one you'll need to do some rewriting.To give you an idea, being
QString m_csvSeparator
the column separator:#include <QStringBuilder> QString escapedCSV(QString unexc) const { if (!unexc.contains(m_csvSeparator)) return unexc; unexc.replace(QLatin1Char('\"'), QStringLiteral("\"\"")); return '\"' % unexc % '\"'; } bool writeCsv(QTextStream& writer, const QAbstractItemModel* constModel) const { if (!constModel) return false; for (int i = 0, maxRow = constModel->rowCount(); i < maxRow ; ++i) { for (int j = 0, maxCol = constModel->columnCount(); j < maxCol ; ++j) { const QString roleData = constModel->index(i, j).data().toString(); if (j>0) writer << m_csvSeparator; if (!roleData.isEmpty()) writer << escapedCSV(roleData); } writer << '\n'; } return writer.status() == QTextStream::Ok; }
23/27