QTableView printing - c++

I am new on QT an I try to print out from QTableView
How can I do this?
Thank a lot

Here is a variation of the first answer that gets rid of the intermediate file.
QString strStream;
QTextStream out(&strStream);
const int rowCount = pPublic->tableView->model()->rowCount();
const int columnCount = pPublic->tableView->model()->columnCount();
out << "<html>\n"
"<head>\n"
"<meta Content=\"Text/html; charset=Windows-1251\">\n"
<< QString("<title>%1</title>\n").arg(strTitle)
<< "</head>\n"
"<body bgcolor=#ffffff link=#5000A0>\n"
"<table border=1 cellspacing=0 cellpadding=2>\n";
// headers
out << "<thead><tr bgcolor=#f0f0f0>";
for (int column = 0; column < columnCount; column++)
if (!pPublic->tableView->isColumnHidden(column))
out << QString("<th>%1</th>").arg(pPublic->tableView->model()->headerData(column, Qt::Horizontal).toString());
out << "</tr></thead>\n";
// data table
for (int row = 0; row < rowCount; row++) {
out << "<tr>";
for (int column = 0; column < columnCount; column++) {
if (!pPublic->tableView->isColumnHidden(column)) {
QString data = pPublic->tableView->model()->data(pPublic->tableView->model()->index(row, column)).toString().simplified();
out << QString("<td bkcolor=0>%1</td>").arg((!data.isEmpty()) ? data : QString(" "));
}
}
out << "</tr>\n";
}
out << "</table>\n"
"</body>\n"
"</html>\n";
QTextDocument *document = new QTextDocument();
document->setHtml(strStream);
QPrinter printer;
QPrintDialog *dialog = new QPrintDialog(&printer, NULL);
if (dialog->exec() == QDialog::Accepted) {
document->print(&printer);
}
delete document;

here is my solution of a problem. May be it's too complex... But here you could find more solutions!
1). first I have saved table data to HTML page file:
bool CRefViewerDlg::createHtmlTableFromModel() {
// make a html-dump of table view
if (tableView) {
const QString htmlFileName = QString("%1/%2").arg(qApp->applicationDirPath()).arg("myTable.html");
QFile file(htmlFileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
MSG(QString("Can`t create file %1").arg(htmlFileName));
return false;
}
QTextStream out(&file);
const xbLong rowCount = tableView->model()->rowCount();
const xbLong columnCount = tableView->model()->columnCount();
out << "<html>\n"
"<head>\n"
"<meta Content=\"Text/html; charset=Windows-1251\">\n"
<< QString("<title>%1</title>\n").arg(refTitleName)
<< "</head>\n"
"<body bgcolor=#ffffff link=#5000A0>\n"
"<table border=1 cellspacing=0 cellpadding=2>\n";
// headers
out << "<tr bgcolor=#f0f0f0>";
for (xbLong column = 0; column < columnCount; column++)
if (!tableView->isColumnHidden(column))
out << QString("<th>%1</th>").arg(tableView->model()->headerData(column, Qt::Horizontal).toString());
out << "</tr>\n";
file.flush();
// data table
for (xbLong row = 0; row < rowCount; row++) {
out << "<tr>";
for (xbLong column = 0; column < columnCount; column++) {
if (!tableView->isColumnHidden(column)) {
QString data = tableView->model()->data(tableView->model()->index(row, column)).toString().simplified();
out << QString("<td bkcolor=0>%1</td>").arg((!data.isEmpty()) ? data : QString(" "));
}
}
out << "</tr>\n";
}
out << "</table>\n"
"</body>\n"
"</html>\n";
file.close();
}
return true;
}
2). after I have saved html content to file, it was opened in html view window, where I could print the document with QTextBrowser class:
void CLiveListDlg::on_printPageToolButton_clicked() {
#ifndef QT_NO_PRINTER
QTextBrowser *editor = static_cast<QTextBrowser* >(textBrowser);
QPrinter printer;
QPrintDialog *dialog = new QPrintDialog(&printer, this);
dialog->setWindowTitle(tr("Print Document"));
if (editor->textCursor().hasSelection())
dialog->addEnabledOption(QAbstractPrintDialog::PrintSelection);
if (dialog->exec() != QDialog::Accepted)
return;
editor->print(&printer);
#endif
}

How about this one?
Traverse through the model of your QTableView let's say QStandardItemModel. Obtain the each and individual texts of the items available in the QStandardItemModel.
Now using QTextCursor, insert the obtained texts from your model into QTextDocument. You can make use of the examples given here to insert text into QTextDocument.
After the completion of inserting into QTextDocument, you can print the contents available in the QTextDocument through
void QTextDocument::print ( QPrinter * printer ) const
The thing you have to make sure is that you should be able to traverse through each items so that you can able obtain all the item text from the model.
Hope it helps..

Related

Program not responding when export more than 10000 data to csv. QT C++

I'm exporting data to csv. I can export if datas around 8K or 10K but when I try to export data around 100K I get a warning "program not responding".
void MainWindow::exportArraysToCSV(QStringList labelList, QList < QList < double >> dataColums, QChar sep) {
QString filters("CSV files (*.csv);;All files (*.*)");
QString defaultFilter("CSVi files (*.csv)");
QString fileName = QFileDialog::getSaveFileName(0, "Save file", QCoreApplication::applicationDirPath(),
filters, & defaultFilter);
QFile file(fileName);
if (file.open(QFile::WriteOnly | QFile::Append)) {
QTextStream data( & file);
QStringList strList;
QString formula;
foreach(auto label, labelList) {
if (label.length() > 0){
strList.append("," + label + ",");
}
else
strList.append("");
}
data << strList.join(",") << "\n";
int maxRowCount = 0;
foreach(auto column, dataColums)
maxRowCount = qMax(maxRowCount, column.count());
for (int i = 5; i < maxRowCount; ++i) // rows
{
strList.clear();
for (int j = 0; j < 2; ++j) // columns
{
if (i < dataColums[j].count())
strList.append(QString::number(dataColums[j][i], 'f'));
else
strList.append("\"\" ");
}
data << strList.join(",") + "\n";
}
data << "=SUM(A2:A1255)";
file.close();
}
}

Error when try to read from a QFile

I want to read some data from a file with QT and then show data in a QTableWidget through a QComboBox.
void DemoDataView::on_comboBox_activated(const QString &arg1)
{
ui->tableWidget->setColumnCount(5);
ui->tableWidget->setRowCount(21);
ui->tableWidget->verticalHeader()->setVisible(false);
ui->tableWidget->setHorizontalHeaderLabels(QString("Age Range ; Male Population ; Male Percentage ; Female Population ; Female Percentage").split(";"));
ui->tableWidget->resizeColumnsToContents();
ui->tableWidget->resizeRowsToContents();
QFile inputFile("./data.txt");
if(!inputFile.open(QIODevice::ReadOnly))
{
QMessageBox::information(0, "Error", inputFile.errorString());
}
QTextStream in(&inputFile);
int rows = 0;
while(!in.atEnd()) {
QString mLine = in.readLine();
QStringList fields = mLine.split(" ");
QStringList::iterator it = fields.begin();
QString regName = *it;
ui->label->setText(arg1);
if(regName != "<END>" && QString::compare(regName, arg1) == 0) {
ui->label->setText(regName);
it++;
QString ageRange = *it;
it++;
QString nMale = *it;
double male = nMale.toDouble();
it++;
QString nFemale = *it;
double female = nFemale.toDouble();
ui->tableWidget->setItem(rows, 0, new QTableWidgetItem(ageRange));
ui->tableWidget->setItem(rows, 1, new QTableWidgetItem(nMale));
ui->tableWidget->setItem(rows, 3, new QTableWidgetItem(nFemale));
ui->tableWidget->setItem(rows, 2, new QTableWidgetItem(malePercCalc(male, female)));
ui->tableWidget->setItem(rows, 4, new QTableWidgetItem(femalePercCalc(male, female)));
rows++;
}
inputFile.close();
}
}
The file is in both the project folder and the build project folder.
When I run the application everything works good but in the Application Output tab I have this error message:
"QIODevice:: read (QFile, "./data.txt"): device not open"
Every time I click on a QComboBox item.
If it can be useful, this is the filling code of the QComboBox:
void DemoDataView::setComboBoxRegion() {
QFile inputFile("./data.txt");
if(!inputFile.open(QIODevice::ReadOnly))
{
QMessageBox::information(0, "Error", inputFile.errorString());
}
QTextStream in(&inputFile);
while(!in.atEnd()) {
QString mLine = in.readLine();
QStringList fields = mLine.split(" ");
QStringList::iterator it = fields.begin();
QString regName = *it;
if(regName != "<END>") {
if(ui->comboBox->findText(regName) == -1){
ui->comboBox->addItem(regName);
}
}
}
inputFile.close();
}
Your problem is that you are calling:
inputFile.close();
INSIDE of your loop, which means it is closed in the first loop. I can't really think of any cases that this would be the desired thing to happen;
To solve this, you should move it to the outside of the loop.

Qt XML validation Errorhandling

I'm trying to find a solution that in case that a validation is not successful because there is more then one error in the XML file the Qt MessageHandler(line, column, description etc. ) is able to show every error in the XML data not just the first one that occurs in the XML file.
Example:
I have an error in line: 65 (see pic)
but there are also errors in line :78,83,95 but it dose not show it only shows the first one.
Is there a solution for this case? And if yes how?
My Code looks like this:
MessageHandler messageHandler;
QFile xsdfile("....xsd");
xsdfile.open(QIODevice::ReadOnly);
QXmlSchema schema;
schema.setMessageHandler(&messageHandler);
bool errorOccurred = false;
if (schema.load(&xsdfile, QUrl::fromLocalFile(xsdfile.fileName())) == false)
errorOccurred = true;
else
{
QXmlSchemaValidator xmlvalidator(schema);
QFile xmlfile("......xml");
xmlfile.open(QIODevice::ReadOnly);
if (!xmlvalidator.validate(&xmlfile, QUrl::fromLocalFile(xmlfile.fileName())))
errorOccurred = true;
xmlfile.close();
}
xsdfile.close();
if (errorOccurred) {
QString qs = messageHandler.statusMessage();
cout << "Line: " << messageHandler.line() << "\n" << "Row: " << messageHandler.column() << "\n" << "ErrorMessage: ";
std::cout << qs.toUtf8().constData() << std::endl;
return -1;
}
else {
return 0;
}
And my MessageHandler class looks like this:
class MessageHandler : public QAbstractMessageHandler
{
public:
MessageHandler()
: QAbstractMessageHandler(0)
{
}
QString statusMessage() const
{
return m_description;
}
int line() const
{
return m_sourceLocation.line();
}
int column() const
{
return m_sourceLocation.column();
}
protected:
virtual void handleMessage(QtMsgType type, const QString &description,
const QUrl &identifier, const QSourceLocation &sourceLocation)
{
Q_UNUSED(type);
Q_UNUSED(identifier);
m_description = description;
m_sourceLocation = sourceLocation;
}
private:
QString m_description;
QSourceLocation m_sourceLocation;
};
Thanks :)
I think you need to write a custom validator to catch all errors. You can modify this example code to catch all errors.
struct NodeProperties
{
NodeProperties()
{
values.resize(names.size());
}
std::vector<int> values;
static QStringList names;
static QString rootName;
static QString childName;
};
QString NodeProperties::rootName = "static_route";
QString NodeProperties::childName = "molenet";
QStringList NodeProperties::names = QList<QString>() << "node_id"
<< "nextHop_id"
<< "sink_id"
<< "delay_before_send"
<< "delay_before_sleep";
QList<NodeProperties> nodesProperties;
bool parseXMLFile()
{
QXmlStreamReader xmlStreamReader;
QString xmlFile;
xmlFile = QFileDialog::getOpenFileName(this,
tr("Open XML file"), QDir::currentPath(), tr("XML (*.xml)"));
if(xmlFile.isEmpty())
return false;
QFile file(xmlFile);
if (!file.open(QFile::ReadOnly | QFile::Text))
{
QMessageBox::warning(this,tr("Error: Cannot read file ..."),
(xmlFile+" " + file.errorString() ));
return false;
}
nodesProperties.clear();
xmlStreamReader.setDevice(&file);
xmlStreamReader.readNext();
while(!xmlStreamReader.atEnd())
{
if(xmlStreamReader.isStartElement())
{
if(xmlStreamReader.name() == NodeProperties::rootName)
xmlStreamReader.readNext();
if(xmlStreamReader.name() == NodeProperties::childName)
{
xmlStreamReader.readNext();
if(xmlStreamReader.isCharacters() )
xmlStreamReader.readNext();
if(xmlStreamReader.isStartElement())
{
NodeProperties prop;
for(int i = 0; i < NodeProperties::names.size(); ++i)
{
if(xmlStreamReader.isCharacters() )
{
xmlStreamReader.readNext();
--i;
continue;
}
if(xmlStreamReader.name() == NodeProperties::names[i])
{
prop.values[i] = xmlStreamReader.readElementText().toInt();
}
xmlStreamReader.readNext();
}
nodesProperties.push_back(prop);
}
}
}
xmlStreamReader.readNext();
}
file.close();
if (xmlStreamReader.hasError())
{
QMessageBox::warning(this,tr("Error: Failed to parse file "),
(xmlFile+" " + xmlStreamReader.errorString() ));
nodesProperties.pop_back();
}
else if (file.error() != QFile::NoError)
{
qDebug() << "Error: Cannot read file " << qPrintable(xmlFile)
<< ": " << qPrintable(file.errorString());
}
//createGraphVizFile(xmlFile);
this->xmlFile = xmlFile;
return true;
}
The XML file is:
<?xml version="1.0"?>
<static_route>
<molenet>
<node_id> 1 </node_id>
<nextHop_id> 2 </nextHop_id>
<sink_id> 254 </sink_id>
<delay_before_send> 2 </delay_before_send>
<delay_before_sleep> 30 </delay_before_sleep>
</molenet>
<molenet>
<node_id> 2 </node_id>
<nextHop_id> 3 </nextHop_id>
<sink_id> 254 </sink_id>
<delay_before_send> 4 </delay_before_send>
<delay_before_sleep> 30 </delay_before_sleep>
</molenet>
</static_route>

Progress bar for copying files

I am trying to create a progress bar for a file copy in Qt. This is as close as I could find, however I believe this doesn't work because according to the Qt class documentation:
Unlike other QIODevice implementations, such as QTcpSocket, QFile does
not emit the aboutToClose(), bytesWritten(), or readyRead() signals.
This implementation detail means that QFile is not suitable for
reading and writing certain types of files, such as device files on
Unix platforms.
How can I do something like this? I don't know how to implement my own signals.
Here is my code:
void Replicator::anotbaandbFile(QDir source, QDir target)
{
source.setFilter(QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks);
target.setFilter(QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks);
qDebug() << "Scanning: " << source.path();
QStringList sourceFileList = source.entryList();
QStringList targetFileList = target.entryList();
for (int aCount = 0; aCount < sourceFileList.count(); aCount++)
{
bool found = false;
for (int bCount = 0; bCount < targetFileList.count(); bCount++)
if (sourceFileList.at(aCount) == targetFileList.at(bCount))
found = true;
if (found == false)
{
sourceFile = new QFile(source.absolutePath()+"/"+sourceFileList.at(aCount));
targetFile = new QFile(target.absolutePath()+"/"+sourceFileList.at(aCount));
progressBar->setMinimum(0);
progressBar->setMaximum(sourceFile->size());
written = 0;
connect(sourceFile,SIGNAL(bytesWritten(qint64)),SLOT(onWrite(qint64)));
sourceFile->copy(targetFile->fileName());
//QFile::copy(source.absolutePath()+"/"+sourceFileList.at(aCount), target.absolutePath()+"/"+sourceFileList.at(aCount));
qDebug() << source.absolutePath()+"/"+sourceFileList.at(aCount) << " " << target.absolutePath()+"/"+sourceFileList.at(aCount);
}
}
}
and
void Replicator::onWrite(qint64 w)
{
written += w;
progressBar->setValue( written );
}
new code modified from above
if (found == false)
{
sourceFile = new QFile(source.absolutePath()+"/"+sourceFileList.at(aCount));
targetFile = new QFile(target.absolutePath()+"/"+sourceFileList.at(aCount));
progressBar->setMinimum(0);
progressBar->setMaximum(sourceFile->size());
QByteArray buffer;
for (int count = 0; !(buffer = sourceFile->read(1000000)).isEmpty(); count+=1000000)
{
targetFile->write(buffer);
progressBar->setValue(count);
}
//targetFile->write(buffer);
//QFile::copy(source.absolutePath()+"/"+sourceFileList.at(aCount), target.absolutePath()+"/"+sourceFileList.at(aCount));
qDebug() << "copying " << sourceFile->fileName() << " to " << targetFile->fileName();
}
You can simply copy large files by portions of fixed size, than count portions already copied and callculate of percentage of work by dividing it to overal count of portions.
int iWorkPercentage = (int)(((float)iPortionsProcessed / (float)iOveralPortions) * 100);

QTableView output save as .csv or .txt

I wrote the below code for a qt gui to view the query output in a QTableView(Model oriented). now i want to save this output as a .csv or .txt file. There were suggestions to use QTableWidget(Item oriented) but I would like to stick to the model based approach.
void MainWindow::on_pushButton_clicked()
{
db = QSqlDatabase::addDatabase("QOCI");
db.setHostName("host");
db.setDatabaseName("db");
db.setUserName("uid");
db.setPassword("pw");
db.setPort(port);
QString MyQuery = ui->lineEdit->text();
if (db.open())
{
qDebug()<<QDateTime::currentDateTime()<<"QUERY DONE SUCCESSFULLY ";
this->model=new QSqlQueryModel();
model->setQuery(MyQuery);
ui->tableView->setModel(model);
}
else
{
qDebug()<<QDateTime::currentDateTime()<<"YOU FORGOT THE QUERY "<<db.lastError().text();
}
}
any guidelines ???
You may customize it according to your actual needs:
// [Collect model data to QString]
QString textData;
int rows = model->rowCount();
int columns = model->columnCount();
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
textData += model->data(model->index(i,j)).toString();
textData += ", " // for .csv file format
}
textData += "\n"; // (optional: for new line segmentation)
}
// [Save to file] (header file <QFile> needed)
// .csv
QFile csvFile("test.csv");
if(csvFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
QTextStream out(&csvFile);
out << textData;
csvFile.close();
}
// .txt
QFile txtFile("test.txt");
if(txtFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
QTextStream out(&txtFile);
out << textData;
txtFile.close();
}
You can save your model to a text file by :
QFile f( "table.txt" );
if( f.open( QIODevice::WriteOnly ) )
{
QTextStream ts( &f );
QStringList strList;
for (int i=0; i<model->rowCount(); i++)
{
strList.clear();
for (int j=0; j<model->columnCount(); j++)
strList << model->data(model->index(i,j)).toString();
ts << strList.join(" ") + "\n";
}
f.close();
}
Here the model data are saved one row in each line separated by space. If you want to separate them by some other character like comma you can just replace the parameter on the join like :
ts << strList.join(",") + "\n";
here is a way to export a qtableview to a csv, including the column names using qt
void staticmethods::exportTableViewToCSV(QTableView *table) {
QString filters("CSV files (*.csv);;All files (*.*)");
QString defaultFilter("CSV files (*.csv)");
QString fileName = QFileDialog::getSaveFileName(0, "Save file", QCoreApplication::applicationDirPath(),
filters, &defaultFilter);
QFile file(fileName);
QAbstractItemModel *model = table->model();
if (file.open(QFile::WriteOnly | QFile::Truncate)) {
QTextStream data(&file);
QStringList strList;
for (int i = 0; i < model->columnCount(); i++) {
if (model->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString().length() > 0)
strList.append("\"" + model->headerData(i, Qt::Horizontal, Qt::DisplayRole).toString() + "\"");
else
strList.append("");
}
data << strList.join(";") << "\n";
for (int i = 0; i < model->rowCount(); i++) {
strList.clear();
for (int j = 0; j < model->columnCount(); j++) {
if (model->data(model->index(i, j)).toString().length() > 0)
strList.append("\"" + model->data(model->index(i, j)).toString() + "\"");
else
strList.append("");
}
data << strList.join(";") + "\n";
}
file.close();
}
}