I have a problem with MathGL library and creating MathGL instance in the application. Every time I try to run it there is an error saying that QApplication must be constructed before QWidget (from which the class QMathGL inherits). Below you can find my code of main and all the functions connected with the MainWindow class:
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "functions.h"
#include "surface.h"
#include "error.h"
#include <QString>
#include <QFileDialog>
#include <GL/glut.h>
#include <cmath>
#include <fstream>
#include <mgl2/qmathgl.h>
surface graph;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_draw_clicked()
{
string s;
bool correct = 1;
error *errorWindow = new error(this);
s = ui->eqEdit->text().toStdString();
period fPeriod = period(ui->upEdit->text().toDouble(),ui->lowEdit->text().toDouble());
functionSum fSum = functionSum(s,fPeriod,ui->accEdit->text().toDouble());
for (int i = 0; i < fSum.accuracy; i++)
{
for (int j = 0; j < fSum.accuracy; j++)
{
if(isnan(fSum.zValues[i][j]) || isinf(fSum.zValues[i][j]))
{
correct = 0;
}
}
}
if(!correct)
{
errorWindow->show();
}
graph = surface(fSum);
}
void MainWindow::on_save_clicked()
{
QString plik;
string splik;
plik = QFileDialog::getSaveFileName(this,"Zapisz plik",QString(),"Pliki tekstowe (*.txt)");
splik = plik.toStdString();
ofstream saver;
saver.open(splik.c_str());
if (saver.is_open())
{
for(int i = 0; i < graph.points.size(); i++)
{
saver << graph.points[i].x << " " << graph.points[i].y << " " << graph.points[i].z << endl;
}
saver.close();
}
}
void MainWindow::on_load_clicked()
{
QString plik;
string splik;
plik = QFileDialog::getOpenFileName(this,"Otwórz plik",QString(),"Pliki tekstowe (*.txt)");
splik = plik.toStdString();
ifstream loader;
loader.open(splik.c_str());
graph.points.clear();
if(loader.is_open())
{
while(!loader.eof())
{
point a(0,0,0);
loader >> a.x >> a.y >> a.z;
graph.points.push_back(a);
}
loader.close();
}
}
void MainWindow::on_plot_clicked()
{
int a = sqrt(graph.points.size());
mglData x(a,a);
mglData y(a,a);
mglData z(a,a);
long long int k = 0;
for (long long int i = 0;i<sqrt(graph.points.size());i++)
{
for (long long int j = 0;j<sqrt(graph.points.size());j++)
{
x.a[i+a*j] = graph.points[k].x;
y.a[i+a*j] = graph.points[k].y;
z.a[i+a*j] = graph.points[k].z;
k++;
}
}
mglGraph plot;
plot.Rotate(50,60);
plot.Light(true);
plot.Surf(x,y,z);
QMathGL plotter;
plotter.setGraph(&plot);
plotter.show();
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Related
I have established a connection with the slot, the function is called, and the values via qDebug () are output, but the table does not change, what is wrong?
mainwindow.cpp
<pre>MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->tableWidget->horizontalHeader()->hide();
ui->tableWidget->verticalHeader()->hide();
//Matrix *matr=new Matrix;
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_updateTbl(int **mas, int n){
for(int i=0;i<n;i++){
ui->tableWidget->insertRow(ui->tableWidget->rowCount());
for(int j=0;j<n;j++){
ui->tableWidget->insertColumn(ui->tableWidget->columnCount());
ui->tableWidget->setItem(i,j,new QTableWidgetItem( QString::number(mas[i][j])));
}
}
}
</pre>
main.cpp
<pre>
#include "mainwindow.h"
#include <QApplication>
#include "matrix.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
Matrix matr;
MainWindow mywnd;
QObject::connect(&matr,SIGNAL(updateTbl(int**,int)), &mywnd, SLOT(on_updateTbl(int**,int)));
matr.upTable();
return a.exec();
}
</pre>
matrix.cpp
<pre>
#include "matrix.h"
#include <QFile>
#include <QDebug>
#include <QString>
#include <QTextStream>
Matrix::Matrix()
{
QFile file("mas.txt");
this->mas=alloc_mem(n,n);
array_to_file(file,n,n);
fill_array(file,mas,n,n);
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if (mas[i][j]!=mas[n-j-1][n-i-1]) {
symmetrical=false;
break;
}
}
}
if(symmetrical){
for(int i=0;i<n;i++){
mas[i][i]=0;
mas[i][n-i-1]=0;
}
//print(mas,n,"Измененная");
}
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(mas[i][j]) vec.append(mas[i][j]);
}
}
}
int** Matrix::alloc_mem(int height, int width){
int** mas = new int*[height];
for (int i = 0; i < height; i++) {
mas[i] = new int[width];
}
return mas;
}
void Matrix::array_to_file(QFile &file, int height, int width){
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
return;
int to_mas;
QTextStream out(&file);
for (int i = 0; i < height; i++){
for (int j = i + 1; j < width; j++){
to_mas=rand()%100-50;
out<<to_mas<<" ";
}
out<<1<<" ";
out<<"\n";
}
file.close();
}
void Matrix::fill_array(QFile &file, int **mas, int height, int width){
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
QTextStream in(&file);
QStringList matr = in.readAll().split("\n");
for (int i = 0; i < height; i++){
for (int j = 0; j < width-i; j++){
mas[i][j]=matr.at(i).split(" ").at(j).toInt();
mas[height-1-j][width-1-i]=mas[i][j];
}
}
file.close();
}
void Matrix::print(int **mas, int n, QString name){
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
}
}
}
void Matrix::upTable(){
emit updateTbl(mas,n);
}
</pre>
mainwindow.h
<pre>
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
private slots:
void on_updateTbl(int**,int);
};
#endif // MAINWINDOW_H
</pre>
matrix.h
<pre>
#ifndef MATRIX_H
#define MATRIX_H
#include <QVector>
#include <QFile>
#include <QString>
#include <QObject>
class Matrix:public QObject
{
Q_OBJECT
public:
Matrix();
~Matrix(){}
//bool check_symmetrical(int **mas,int n);
void print_vector(QVector<int> vector);
int** alloc_mem(int height,int width);
void array_to_file(QFile& file,int height,int width);
void fill_array(QFile& file,int **mas,int height,int width);
void print(int** mas,int n,QString name);
void upTable();
private:
int n=10;
int **mas;
bool symmetrical=true;
QVector<int> vec;
signals:
void updateTbl(int**,int);
};
#endif // MATRIX_H
</pre>
If I copy this code into the constructor, then everything is fine and everything changes, but nothing works from the function
How do you want to see table with values when widget with updated table is not displayed?
MainWindow w;
w.show(); // <--- w is displayed, tableWidget is not modified in this widget
Matrix matr;
MainWindow mywnd; // <--- mywnd is not displayed
QObject::connect(&matr,SIGNAL(updateTbl(int**,int)), &mywnd, SLOT(on_updateTbl(int**,int)));
// mywnd is updated
matr.upTable();
add
mywnd.show();
you will see the other widget with updated content.
I am working on a matrix calculator and I encountered a really annoying problem, have been trying to fix it for 3 hours now, but it's getting worse instead of getting better. Maybe you will be able to help.
This is my MainWindow class:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPushButton>
#include <QGridLayout>
#include <QLabel>
#include "addmatrix.h"
#include "memory.h"
#include "matrixcreation.h"
#include <QMap>
#include "matrix.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(MainWindow *parent = 0);
~MainWindow();
private slots:
void on_createButton_clicked();
void setMatrix(Matrix *matrix);
private:
Matrix getMatrixFromMemory(QString &name);
void addMatrixToMemory();
Ui::MainWindow *ui;
AddMatrix *add;
MatrixCreation *matrixCreate;
QMap <QString, Matrix> matrixMap;
};
#endif // MAINWINDOW_H
.cpp file
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(MainWindow *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setWindowTitle("Matrix Calculator");
add = NULL;
matrixCreate = NULL;
}
MainWindow::~MainWindow()
{
delete ui;
delete add;
delete matrixCreate;
matrixMap.clear();
}
void MainWindow::on_createButton_clicked()
{
if (add != NULL)
{
delete add;
add = new AddMatrix;
}
else
add = new AddMatrix;
if (matrixCreate != NULL)
{
ui->label->setText(getMatrixFromMemory(matrixCreate->getMatrix()->getName()).getName());
delete matrixCreate;
matrixCreate = new MatrixCreation;
}
else
matrixCreate = new MatrixCreation;
// Polaczenie sygnalow ze slotami
// Sluzy ustawieniu liczby wierszy w matrixCreate
connect(add->getCombo1(), SIGNAL(currentIndexChanged(QString)), matrixCreate, SLOT(setRows(QString)));
// Jak wyzej, tylko kolumn
connect(add->getCombo2(), SIGNAL(currentIndexChanged(QString)), matrixCreate, SLOT(setColumns(QString)));
// Ustawienie pola name w matrixCreate
connect(add->getEdit(), SIGNAL(textChanged(QString)), matrixCreate, SLOT(setName(QString)));
// Po ustawieniu liczby wierszy i kolumn oraz nazwy macierzy - wywola sie slot updateTable
// ktory sluzy do ustawienia rozmiaru okna i tabeli
connect(add, SIGNAL(setupSuccessful()), matrixCreate, SLOT(updateTable()));
// Po ustawieniu wierszy, kolumn, ustawieniu nazwy, rozmiarow, wywola sie slot show matrixCreate
connect(add, SIGNAL(setupSuccessful()), matrixCreate, SLOT(show()));
// Sluzy dodaniu macierzy do pamieci (mapy)
connect(matrixCreate, SIGNAL(matrixReady(Matrix*)), this, SLOT(setMatrix(Matrix*)));
add->show();
}
void MainWindow::setMatrix(Matrix *matrix)
{
matrixMap[matrix->getName()] = *matrix;
}
Matrix MainWindow::getMatrixFromMemory(QString &name)
{
return matrixMap[name];
}
As you can see I have a QMap in my MainWindow. I also have a an instance of MatrixCreation class called matrixCreate.
Here is MatrixCreation class:
#ifndef MATRIXCREATION_H
#define MATRIXCREATION_H
#include <QDialog>
#include <QTableView>
#include <QPushButton>
#include <QStandardItem>
#include <QTableWidget>
#include <QMainWindow>
#include "matrix.h"
#include "memory.h"
#include "addmatrix.h"
#include <windows.h>
namespace Ui {
class MatrixCreation;
}
class MatrixCreation : public QWidget
{
Q_OBJECT
public:
explicit MatrixCreation(QWidget *parent = 0);
~MatrixCreation();
QTableWidget *getTable();
Matrix *getMatrix();
private slots:
void on_okButton_clicked();
void updateTable();
void setRows(QString rows);
void setColumns(QString columns);
void setName(QString name);
signals:
void matrixReady(Matrix *matrix);
private:
Ui::MatrixCreation *ui;
int rows;
int columns;
int **matrix;
QString name;
Matrix *newMatrix;
};
#endif // MATRIXCREATION_H
.cpp file
#include "matrixcreation.h"
#include "ui_matrixcreation.h"
MatrixCreation::MatrixCreation(QWidget *parent) :
QWidget(parent),
ui(new Ui::MatrixCreation)
{
ui->setupUi(this);
this->resize(150, 50);
// Ustawienie rozmiaru wysokosci wiersza na 40 piksele
ui->tableWidget->verticalHeader()->setDefaultSectionSize(40);
// Ustawienie rozmiaru szerokosci kolumny na 94 piksele
ui->tableWidget->horizontalHeader()->setDefaultSectionSize(94);
// Dopasowanie rozmiaru kolumn do rozmiaru tabeli
ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
ui->tableWidget->verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
// Wylaczenie scrollbarow tabeli
ui->tableWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
ui->tableWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
rows = 1;
columns = 1;
matrix = NULL;
newMatrix = new Matrix;
}
MatrixCreation::~MatrixCreation()
{
delete ui;
if (matrix != NULL)
{
for (int i = 0; i < rows; i++)
delete matrix[i];
}
delete newMatrix;
}
void MatrixCreation::setRows(QString rows)
{
this->rows = rows.toInt();
}
void MatrixCreation::setColumns(QString columns)
{
this->columns = columns.toInt();
}
// Metoda odpowiedzialna za utworzenie odpowiedniej ilosci wierszy i kolumn
// oraz ustawienie odpowiedniej wielkosci okna i rozmiaru tabeli
void MatrixCreation::updateTable()
{
// stale roznice miedzy szerokoscia i wysokoscia okna i tabeli
int w = 323 - 305;
int h = 300 - 227 + 15;
for(int i = 0; i < rows; i++)
{
ui->tableWidget->insertRow(i);
h += 35;
}
for(int j = 0; j < columns; j++)
{
ui->tableWidget->insertColumn(j);
w += 50;
}
this->resize(w, h);
this->setMinimumSize(w, h);
ui->retranslateUi(this);
this->setWindowTitle("Matrix Creation");
}
QTableWidget *MatrixCreation::getTable()
{
return ui->tableWidget;
}
void MatrixCreation::on_okButton_clicked()
{
matrix = new int *[rows];
for(int j = 0; j < rows; j++)
{
matrix[j] = new int[columns];
}
for(int i = 0; i<rows; i++)
{
for(int j = 0; j<columns; j++)
{
matrix[i][j] = ui->tableWidget->item(i, j)->text().toInt();
}
}
// Ustawienie pol skladowych w zmiennej newMatrix klasy Matrix
newMatrix->setColumns(columns);
newMatrix->setRows(rows);
newMatrix->setName(name);
newMatrix->setMatrix(matrix);
emit matrixReady(newMatrix);
this->close();
}
void MatrixCreation::setName(QString name)
{
this->name = name;
}
Matrix *MatrixCreation::getMatrix()
{
return newMatrix;
}
What is the problem:
I want to add a created matrix to a QMap by emiting this signal:
emit matrixReady(newMatrix);
a Matrix class is used to hold all the elements of matrix (rows, cols, values of cells and name).
However, Matrix objects are not being added to QMap. But, when I delete this line in MatrixCreation destructor:
delete newMatrix;
It works.
Second problem:
When I am closing my application and MainWindow destructor gets called, while destroying a map it shows an error : BLOC_TYPE_IS_VALID bla bla...
I don't know how to fix it, however I will keep on trying. Any help will be appreciated.
void MainWindow::setMatrix(Matrix *matrix)
{
matrixMap[matrix->getName()] = *matrix;
}
You're adding copy of the matrix to your map. So here you have a leak.
void MainWindow::setMatrix(Matrix *matrix)
{
matrixMap[matrix->getName()] = *matrix;
delete matrix;
}
This should fix your problem.
Use valgrind to profile your application and find memory leaks: http://valgrind.org/docs/manual/quick-start.html
So, there is a library on the Internet to handle bitmap files: "bitmap_image.hpp". It seems nice and it works well for my project, until when I try to include "Windows.h" in my project as well. The compiler can't identify both the "bitmap_image" class and "POINT" structure which come from "bitmap_image.hpp" and "Windows.h" respectively.
I tried everything I know but the problem is still not solved. Also, when try to compile another project which includes ONLY cstdio, bitmap_image.hpp and Windows.h, it works.
I uses Qt and here are all the code:
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtDebug>
#include "bitmap_image.hpp"
#include <Windows.h>
using namespace std;
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
double compare_bitmap(bitmap_image& large, bitmap_image& small, unsigned int top_left_x, unsigned int top_left_y)
{
/*
Purpose:
compare two bitmaps and return the percentage of matched pixels
Description:
this function concerns the pixels in "large" only if it falls in this square--
top-left: (top_left_x, top_left_y)
bottom-right: (top_left_x+small.width()-1, top_left_y+small.height()-1)
while all pixels in "small" will be concerned
Rules:
"large" should not be smaller than "small" in either dimensions
top_left_x should be ranged from 0 to (large.width()-small.width())
top_left_y should be ranged from 0 to (large.height()-small.height())
*/
if(large.width()<small.width() || large.height()<small.height()) return -1;
if(top_left_x<0 || top_left_x>(large.width()-small.width()) || top_left_y<0 || top_left_y>(large.height()-small.height())) return -2;
double pixel_count = 0;
double matched_count = 0;
for(unsigned int y=0; y<small.height(); ++y)
{
for(unsigned int x=0; x<small.width(); ++x)
{
if(large.get_pixel(top_left_x+x, top_left_y+y)==small.get_pixel(x,y)) ++matched_count;
++pixel_count;
}
}
return matched_count/pixel_count;
}
bool identify_bitmap(bitmap_image& large, bitmap_image& small, POINT& result_point, double min_match_percent = 1.0)
{
if(large.width()<small.width() || large.height()<small.height()) return false;
unsigned int p_x, p_y;
double match_percent = 0;
for(unsigned int y=0; y<(large.height()-small.height()+1); ++y)
{
for(unsigned int x=0; x<(large.width()-small.width()+1); ++x)
{
double percent = compare_bitmap(large, small, x, y);
if(percent>match_percent)
{
p_x = x;
p_y = y;
match_percent = percent;
}
}
}
if(match_percent<min_match_percent) return false;
result_point.x = p_x;
result_point.y = p_y;
return true;
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
string s = "capture_2.bmp";
bitmap_image image(s);
if(!image) qDebug()<<"failed";
else qDebug()<<"succeed";
}
MainWindow::~MainWindow()
{
delete ui;
}
Update: I just find the solution for myself. Sorry for the post.
Solution: The first post to this thread stated that we can #define WIN32_LEAN_AND_MEAN just prior to #include <Windows.h>
Although I don't fully understand the reasons...
This question already has an answer here:
Qt/C++ Convert QString to Decimal
(1 answer)
Closed 8 years ago.
I am trying to make a program that takes 3 user inputs and a calculate button that puts them all into an equation and prints out the answer. The problem I am having right now is that the inputs seem to not be able to convert to numbers and I can't figure out why.
Error reads on line (int numN0 = QString::number(N0);):
error: no matching function for call to 'QString::number(QString&)'
Here's my code:
Header
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_NtButton_clicked();
void on_N0Button_clicked();
void on_kButton_clicked();
void on_tButton_clicked();
void on_quitButton_clicked();
void on_pushButton_5_clicked();
void on_equation_linkActivated(const QString &link);
private:
Ui::MainWindow *ui;
int N;
int N0;
int k;
int t;
};
Main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
/*QPushButton *button = new QPushButton("Quit the program!");
QObject::connect(button, SIGNAL(clicked()), &app, SLOT(quit()));
button->show();
*/
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtCore>
#include <QtGui>
#include <QMessageBox>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_N0Button_clicked()
{
QString N0 = ui->lineEdit_2->text();
int numN0 = QString::number(N0);
if (numN0 < 1000){
QMessageBox::information(this,"Error","Can't be over 1000");
}
if (ui->lineEdit_2->text() > 0)
{
QMessageBox::information(this,"Error","Can't be under 0");
}
}
void MainWindow::on_kButton_clicked()
{
int k = ui->lineEdit_3->text();
if (QString::number(k) > 1)
{
QMessageBox::information(this,"Error","Can't be over 1");
}
if (ui->lineEdit_3->text() < 0)
{
QMessageBox::information(this,"Error","Can't be under 0");
}
}
void MainWindow::on_tButton_clicked()
{
QString t = ui->lineEdit_4->text();
}
void MainWindow::on_pushButton_5_clicked()
{
for (int x = 0; x < t; x++)
{
int ans = N*x == N0*10^(k*x);
ui->equation->setText(QString::number(ans));
}
}
You should use:
QString N0 = ui->lineEdit_2->text();
int numN0 = N0.toInt();
QString::number(N0) takes int and return QString, but you need conversion to int. Also you can use bool ok if you want to know is conversion was successful.
For example:
QString str = "FF";
bool ok;
int hex = str.toInt(&ok, 16); // hex == 255, ok == true
int dec = str.toInt(&ok, 10); // dec == 0, ok == false
Information
In my program I am reading a lot of data from a text file & putting it to a QTableWidget.
Initially it was all done in the GUI thread & then I decided to multi thread it to have better performance. But on the contrary the performance was significantly slow i.e. 8x slower!
So I decided to benchmark it. Here are my files:
main.cpp
#include <QtGui/QApplication>
#include <QMutex>
#include <QDir>
#include <string>
#include <QDebug>
#include "mainwindow.h"
QFile *logFile = NULL;
QTextStream *logStream = NULL;
QMutex *mutex = NULL;
bool *debugMode = NULL;
void myMessageOutput(QtMsgType type, const char *msg)
{
if(((logFile != NULL) && (debugMode != NULL)))
{
mutex->lock();
switch (type)
{
case QtDebugMsg:
if(!*debugMode)
{
mutex->unlock();
return;
}
*logStream << msg;
logStream->flush();
break;
case QtWarningMsg:
*logStream << "\n*** Warning ***\n";
*logStream << msg;
*logStream << "\n*** Warning Complete ***\n";
logStream->flush();
break;
case QtCriticalMsg:
*logStream << "\n*** Critical ***\n";
*logStream << msg;
*logStream << "\n*** Critical Complete ***\n";
logStream->flush();
break;
case QtFatalMsg:
*logStream << "\n*** Fatal ***\n";
*logStream << msg;
*logStream << "\n*** Fatal Complete ***\n";
logStream->flush();
abort();
}
mutex->unlock();
}
}
void CreateLogFile()
{
QString path = "C:\\Users\\abcd\\Documents\\QT\\benchmark\\output.log";
QFile *file = new QFile(path);
if(file->exists())
file->remove();
if(!file->open(QFile::WriteOnly | QFile::Text))
{
qFatal("Could not create log file.");
}
logStream = new QTextStream(file);
logStream->setRealNumberNotation(QTextStream::FixedNotation);
logStream->setRealNumberPrecision(16);
logFile = file;
}
int main(int argc, char *argv[])
{
mutex = new QMutex();
qInstallMsgHandler(myMessageOutput);
debugMode = new bool;
CreateLogFile();
*debugMode = true;
QApplication a(argc, argv);
MainWindow w;
w.show();
w.bench2();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QThread>
#include "multi_thread.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void bench2();
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QList>
#include <QTime>
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::bench2()
{
QTableWidget *table = new QTableWidget();
table->setRowCount(1000);
table->setColumnCount(1000);
for(int i = 0; i < 1000; i++)
{
for(int j = 0; j < 1000; j++)
table->setItem(i, j, new QTableWidgetItem());
}
Multi_Thread **multis = new Multi_Thread *[4];
QThread **thrs = new QThread *[4];
int from;
int to = -1;
QTime time;
time.start();
for(int i = 0; i < 4; i++)
{
from = to + 1;
to = from + 250;
if(i == 3)
to = 999;
multis[i] = new Multi_Thread();
multis[i]->setTable(table, from, to);
thrs[i] = new QThread();
connect(thrs[i], SIGNAL(started()), multis[i], SLOT(bench2_1()));
multis[i]->moveToThread(thrs[i]);
}
for(int i = 0; i < 4; i++)
{
if(!i)
time.start();
thrs[i]->start();
}
for(int i = 0; i < 4; i++)
{
thrs[i]->wait();
}
qDebug() << "\nbench2 1 " << time.elapsed();
for(int i = 0; i < 4; i++)
{
delete multis[i];
delete thrs[i];
}
delete[] multis;
delete[] thrs;
table->clear();
table->setRowCount(1000);
table->setColumnCount(1000);
for(int i = 0; i < 1000; i++)
{
for(int j = 0; j < 1000; j++)
table->setItem(i, j, new QTableWidgetItem());
}
time.start();
for(int i = 0; i < 1000; i++)
{
for(int j = 0; j < 1000; j++)
table->item(i, j)->setText("0");
}
qDebug() << "\nbench2 2 " << time.elapsed();
table->clear();
table->setRowCount(1000);
table->setColumnCount(1000);
QTableWidgetItem ***items = new QTableWidgetItem **[1000];
for(int i = 0; i < 1000; i++)
{
items[i] = new QTableWidgetItem *[1000];
for(int j = 0; j < 1000; j++)
{
QTableWidgetItem *item = new QTableWidgetItem();
table->setItem(i, j, item);
items[i][j] = item;
}
}
multis = new Multi_Thread *[4];
thrs = new QThread *[4];
to = -1;
for(int i = 0; i < 4; i++)
{
from = to + 1;
to = from + 250;
if(i == 3)
to = 999;
multis[i] = new Multi_Thread();
multis[i]->setItems(items, from, to);
thrs[i] = new QThread();
connect(thrs[i], SIGNAL(started()), multis[i], SLOT(bench2_2()));
multis[i]->moveToThread(thrs[i]);
}
table->blockSignals(true);
table->setUpdatesEnabled(false);
table->setWordWrap(false);
for(int i = 0; i < 4; i++)
{
if(!i)
time.start();
thrs[i]->start();
}
for(int i = 0; i < 4; i++)
{
thrs[i]->wait();
}
qDebug() << "\nbench2 3 " << time.elapsed();
table->blockSignals(false);
table->setUpdatesEnabled(true);
table->setWordWrap(true);
for(int i = 0; i < 4; i++)
{
delete multis[i];
delete thrs[i];
}
delete[] multis;
delete[] thrs;
table->clear();
for(int i = 0; i < 1000; i++)
{
delete[] items[i];
}
delete[] items;
}
multi_thread.h
#ifndef MULTI_THREAD_H
#define MULTI_THREAD_H
#include <QObject>
#include <QThread>
#include <QTableWidget>
class Multi_Thread : public QObject
{
Q_OBJECT
public:
explicit Multi_Thread();
void setTable(QTableWidget *tab, int f, int t);
void setItems(QTableWidgetItem ***i, int f, int t);
private:
QTableWidget *table;
QTableWidgetItem ***items;
int from;
int to;
signals:
public slots:
void bench2_1();
void bench2_2();
};
#endif // MULTI_THREAD_H
multi_thread.cpp
#include "multi_thread.h"
Multi_Thread::Multi_Thread() : QObject()
{
}
void Multi_Thread::setTable(QTableWidget *tab, int f, int t)
{
table = tab;
from = f;
to = t;
}
void Multi_Thread::setItems(QTableWidgetItem ***i, int f, int t)
{
items = i;
from = f;
to = t;
}
void Multi_Thread::bench2_1()
{
for(int i = from; i <= to; i++)
{
for(int j = 0; j < 1000; j++)
{
table->item(i, j)->setText("0");
}
}
QThread::currentThread()->exit(0);
}
void Multi_Thread::bench2_2()
{
for(int i = from; i <= to; i++)
{
for(int j = 0; j < 1000; j++)
{
items[i][j]->setText("0");
}
}
QThread::currentThread()->exit(0);
}
output.log
bench2 1 7654
bench2 2 1160
bench2 3 8021
What is strange is that I was expecting "bench2 3" to be faster than "bench2 1".
PS: My laptop hardware can needs 4 threads to reach 100% usage. Please edit it as per your hardware requirements. Can be known from Environment variables.
Calling table->item(...)->setText() from any thread other than the GUI thread is undefined behavior. Don't do it. It's nice that you're using a QObject in a QThread to do the job, but you must not directly call methods on objects that live in other threads.
The internal model will call the view's dataChanged() slot for each of your updates. This is the likely source of the slow-down, apart from the memory allocations for each item.
The typical way of preparing a data model in a separate thread would be to:
Instantiate the model in a separate thread. The model must not yet be connected to any views at this point. Initialize the model with data. It can be a QStandardItemModel or a custom model. Custom models are not that hard, and can often be much more efficient if you don't need to perform a memory allocation per each item.
Connect the model to the view (QTableView, not QTableWidget). You can move it to the gui thread for convenience, although you don't have to.
Only access the model from the thread it lives in, unless you use queued method invocations or queued signal-slot connections. The view uses the latter and thus can live in a thread separate from the model.
A QTableWidget bundles an internal QStandardItemModel with a QTableView. If you want to deal with the model separately, you simply use the the model class in isolation from the view class.
This answer has a different strategy for getting large amounts of data into a QTableView very efficiently (time and memory). I also cached a parsed row of data for successive requests to the same row.