PDA

View Full Version : Non-comprehensive problem about Qwt in OO language



Momergil
24th July 2011, 18:11
Hello!

I'm having a problem about passing Qwt to a Object-oriented language style in my software. Let me explain.

My goal, now, is to create a software which receives data from a socket client, "translate it" and pass the y coordinates to three graphs simultaneously. in fact, I already have this software and it works fine.

The problem is that it is not written in traditional c++ object oriented style when it comes about using Qwt to create the 3 graphs, i.e. the instantiation of each graph is done "manually", not by simply creating the object from a class that create graphs.

So what I have today in my MainWindow, where the creation of the graphs is called, is this:


void MainWindow::on_Start_released()
{
ui->cmd->append("Start");

plot = new QwtPlot(QwtText("Graph 1"));
plot->setParent(ui->grafico); //Liga o grafico à widget

//Dimensões do gráfico dentro do widget
plot->setGeometry(0,0,1020,200);
plot->setAxisScale(QwtPlot::yLeft,0,300);
plot->setAxisScale(QwtPlot::xBottom,0.0,150);
//plot->setAxisTitle(QwtPlot::xBottom, "Tempo [s]"); //Falta espaço. Tentar colocar na borda do eixo, não embaixo
//plot->setAxisScale(QwtPlot::xBottom, d_interval.minValue(), d_interval.maxValue()); //faz a mudança dos números no eixo X

//Coloca grid
QwtPlotGrid *grid = new QwtPlotGrid();
grid->setPen(QPen(Qt::gray, 0.0, Qt::DotLine));
grid->enableX(true);
grid->enableXMin(true);
grid->enableY(true);
grid->enableYMin(false);
grid->attach(plot);

//plot->axisAutoScale(1);
//plot->axisAutoScale(1);
plot->show();

curva = new QwtPlotCurve("ECG"); //Antes: "Sine"
curva->setStyle(QwtPlotCurve::Lines);
curva->setPen(QPen(Qt::green)); //Cor da linha do gráfico (Cada um com sua cor?)
curva->attach(plot);
/************************************************** *****/
plot2 = new QwtPlot(QwtText("Graph 2"));
plot2->setParent(ui->grafico2); //Liga o grafico à widget

//Dimensões do gráfico dentro do widget
plot2->setGeometry(0,0,1020,200);
plot2->setAxisScale(QwtPlot::yLeft,0,300);
plot2->setAxisScale(QwtPlot::xBottom,0.0,150);
//plot->setAxisTitle(QwtPlot::xBottom, "Tempo [s]"); //Falta espaço. Tentar colocar na borda do eixo, não embaixo
//plot->setAxisScale(QwtPlot::xBottom, d_interval.minValue(), d_interval.maxValue()); //faz a mudança dos números no eixo X

//Coloca grid
QwtPlotGrid *grid2 = new QwtPlotGrid();
grid2->setPen(QPen(Qt::gray, 0.0, Qt::DotLine));
grid2->enableX(true);
grid2->enableXMin(true);
grid2->enableY(true);
grid2->enableYMin(false);
grid2->attach(plot2);

//plot->axisAutoScale(1);
//plot->axisAutoScale(1);
plot2->show();

curva2 = new QwtPlotCurve("ECG"); //Antes: "Sine"
curva2->setStyle(QwtPlotCurve::Lines);
curva2->setPen(QPen(Qt::green)); //Cor da linha do gráfico (Cada um com sua cor?)
curva2->attach(plot2);
/************************************************** *****/
plot3 = new QwtPlot(QwtText("Graph 3"));
plot3->setParent(ui->grafico3); //Liga o grafico à widget

//Dimensões do gráfico dentro do widget
plot3->setGeometry(0,0,1020,200);
plot3->setAxisScale(QwtPlot::yLeft,0,300);
plot3->setAxisScale(QwtPlot::xBottom,0.0,150);
//plot->setAxisTitle(QwtPlot::xBottom, "Tempo [s]"); //Falta espaço. Tentar colocar na borda do eixo, não embaixo
//plot->setAxisScale(QwtPlot::xBottom, d_interval.minValue(), d_interval.maxValue()); //faz a mudança dos números no eixo X

//Coloca grid
QwtPlotGrid *grid3 = new QwtPlotGrid();
grid3->setPen(QPen(Qt::gray, 0.0, Qt::DotLine));
grid3->enableX(true);
grid3->enableXMin(true);
grid3->enableY(true);
grid3->enableYMin(false);
grid3->attach(plot3);

//plot->axisAutoScale(1);
//plot->axisAutoScale(1);
plot3->show();

curva3 = new QwtPlotCurve("ECG"); //Antes: "Sine"
curva3->setStyle(QwtPlotCurve::Lines);
curva3->setPen(QPen(Qt::green)); //Cor da linha do gráfico (Cada um com sua cor?)
curva3->attach(plot3);

Server.StartServer();
}


(Sorry for the Portuguese comments, by I imagine that you will understand the code anyway ;] )

So as you can see, I have to create each of the 3 graphs manually, which is not the OO style. And I want, therefore, to transform that code in this:



plot->createSimple(ui->grafico,"Graph 1","green");
plot2->createSimple(ui->grafico2,"Graph 2","blue");
plot3->createSimple(ui->grafico3,"Graph 3","red");


In this situation, I create the graphs from the "graf" class usign the function "createSimple", pointing each of the graphs to a specific QWidget, giving it a name and setting the color of line. Just to make things even more simple, here is the function createSimple as it is today:



void graf::createSimple(QWidget *a, QString b, QString c)
{

gra = new QwtPlot(QwtText(b));
gra->setParent(a); //Liga o grafico à widget

//Dimensões do gráfico dentro do widget
gra->setGeometry(0,0,1020,200);
gra->setAxisScale(QwtPlot::yLeft,0,300);
gra->setAxisScale(QwtPlot::xBottom,0.0,150);
//plot->setAxisTitle(QwtPlot::xBottom, "Tempo [s]"); //Falta espaço. Tentar colocar na borda do eixo, não embaixo
//plot->setAxisScale(QwtPlot::xBottom, d_interval.minValue(), d_interval.maxValue()); //faz a mudança dos números no eixo X
//plot->axisAutoScale(1);
//plot->axisAutoScale(1);

//Coloca grid
grid = new QwtPlotGrid();
grid->setPen(QPen(Qt::gray, 0.0, Qt::DotLine));
grid->enableX(true);
grid->enableXMin(true);
grid->enableY(true);
grid->enableYMin(false);
grid->attach(gra);

gra->show();

linha = new QwtPlotCurve("ECG");
linha->setStyle(QwtPlotCurve::Lines);
linha->setPen(QPen(c));
linha->attach(gra);
}


But here is where the problem begins, and they are two problems.

First, I simply can't understand why I can't instantiate (I hope this is the technical word for that) the variables "gra", "linha" [the line] and "grid"


QwtPlot *gra;
QwtPlotGrid *grid;
QwtPlotCurve *linha;

in the "graf.h" file; I have to instantiate them always in the "graph.cpp" file, which is not the correct way of doing it and, btw, its probably the source of all of my problems. If I try to instantiate the variables in the "graf.h" file, the compilation runs O.K., but when I start the program as soon as I click in the Start button to make the graphs appear, the software crash and it don't say what happened. So in order to make my software works to this point, I have always to instantiate in the .cpp file, what is wrong.

So, my first question: is there a official problem about instantiating Qwt variables in the .h file? Why can't and do that in my software?

---
Second and most annoying problem: once instantiating the variables in the .cpp file, I simply can't make the lines fit in the correct graph. Rather, they insist always to appear in the last graph in the window. Let me explain.

Here is the code I use to "translate" the string of data from the socket client to Y variables to each of the Qwt graph in the version that works fine:

.h file:

public:
std::vector<double> xs1;
std::vector<double> ys1;
std::vector<double> xs2;
std::vector<double> ys2;
std::vector<double> xs3;
std::vector<double> ys3;
double cur_x1, cur_x2, cur_x3;

QString str1, str2, str3;
int str1X, str2X, str3X;

.cpp file:



leitura = QString(socket->readLine());
str1 = leitura.section(' ',0,0);
str1X = str1.toInt(NULL);
qDebug() << "1 col:" << str1X << endl;
str2 = leitura.section(' ',1,1);
str2X = str2.toInt(NULL);
qDebug() << "2 col:" << str2X << endl;
str3 = leitura.section(' ',2,2);
str3X = str3.toInt(NULL);
qDebug() << "3 col:" << str3X << endl;

ys1.push_back(str1.toDouble(NULL));
xs1.push_back(cur_x1++);

pmw->curva->setData(&xs1[0],&ys1[0],xs1.size());
pmw->plot->replot();

ys2.push_back(str2.toDouble(NULL));
xs2.push_back(cur_x2++);

pmw->curva2->setData(&xs2[0],&ys2[0],xs2.size());
pmw->plot2->replot();

ys3.push_back(str3.toDouble(NULL));
xs3.push_back(cur_x3++);

pmw->curva3->setData(&xs3[0],&ys3[0],xs3.size());
pmw->plot3->replot();

So let me explain: "leitura" reads the entire line that the socket client receives, and str1, str2 and str3 receives the three columns of data from "leitura", each of them with the Y coordinates for each of the graphs. Later each of the "ys" receives the data from "str1, str2 and str3" converted to double. Finally, a MainWindow vector called "*pmw" acess the varibles "curva" and "plot" from MainWindow (see first code) and ask them to execute the functions "setData()" and "replot()".


As I sad earlier, this code is fine. The problem is when I try to execute a similar version using OO for the Qwt plot.

Theorically, everything that I should do of different, if the variables "gra" and "linha" were instantiated in the "graf.h", would be to change the pmw path to something like this:



pmw->plot->linha->setData(&xs1[0],&ys1[0],xs1.size());
pmw->plot->replot();

pmw->plot2->linha->setData(&xs2[0],&ys2[0],xs2.size());
pmw->plot2->replot();

pmw->plot3->linha->setData(&xs3[0],&ys3[0],xs3.size());
pmw->plot3->replot();


[continue in the next post]

[continuing]

But if the variables are not instantiated in the "graf.h", they are not found by the "pmw" and this code is found useless. What I tried to do, than, was to create functions in "graph.cpp" that were capable of changing the value of this variables despite they were instantiated in the .cpp file (see first problem). But always when I try to do so, the software confuses itself and begin to plot only the last of the graphs that was instantiated.


So for example, if the code is put entirely as it should, instead each of the graphs receives each of the data and show the curve, only the third graph plots the curve receiving its values. The other two remain "silent". Now if I create only two graphs in the MainWindow.cpp:



plot->createSimple(ui->grafico,"Graph 1","green");
plot2->createSimple(ui->grafico2,"Graph 2","blue");
//plot3->createSimple(ui->grafico3,"Graph 3","red");


but I lat the code for reading the column the same (including the changes to plot3, that was not instantiaded), than the graph3 do'nt appear in the software, the graph1 doesn't show anything and the graph2 plots the data from graph3!!

And so on, doesn't matter how many different functions I use to call setData(), it will always plot only the last graph while the others will remain clear.



Do anybody know how to solve my 2 problems? Probably by solving the first one the second goes away too.

Sorry for the immense post, but I think it was necessary to explain my problem exactly. I spend more than 6 hours by now trying to solve it and I'm beginning to become borrowed :P


Thanks for your time! =]

Uwe
24th July 2011, 21:21
So as you can see, I have to create each of the 3 graphs manually, which is not the OO style.
There is nothing wrong with the original code and it absolutely not against OO. But even if - OO is not a synonym for good.



If I try to instantiate the variables in the "graf.h" file, the compilation runs O.K., but when I start the program as soon as I click in the Start button to make the graphs appear, the software crash and it don't say what happened.
Implementing methods in a .h file doesn't make any sense beside if you want to inline a method. So I guess you want to do some sort of instantiation together with the declaration of a class members - but this is not C++ ( constructors are intended for this ). But this is a detail of the language and also has nothing to do with the OO paradigm.

Sorry for not giving you a more detailed answer for your second question, but you didn't post the deciding parts of your code - general thoughts about OO are not important here.

Uwe

Momergil
24th July 2011, 23:18
Hello, Uwe!

First, thanks for the reply. Let me see what I can do for you:


There is nothing wrong with the original code and it absolutely not against OO. But even if - OO is not a synonym for good.

Well, I agree that the code itself is fine and that it is not necessary for me to create it using only OO. In fact, theorically the unique thing that really matters in a software is that it works fine, independent of the code that it uses. But, you know, when you are doing a software not for free, but being payed by a company that gives you money to do a good work, it is at least expected that I'm gonna do something correct. And, by the way that I learned C++ some time ago, the correct way of doing this would be by using OO. Imagine if my boss (who is also an engineering and therefore has an idea of what is a good, organized code programming) decides to see my software and he sees a mess. That certainly wouldn't be good for me! More than that, it's still a way of learning something more, makes to code become more organized (what in programming is always good) and so on. So I really thing it would be a good think if I change the code to a OO standart.



Implementing methods in a .h file doesn't make any sense beside if you want to inline a method. So I guess you want to do some sort of instantiation together with the declaration of a class members - but this is not C++ ( constructors are intended for this ). But this is a detail of the language and also has nothing to do with the OO paradigm.

I'm not sure if I understood what you wanted to say with this comment, so I'm not able to reply it appropriately. But giving the few that I think I understood, I may say that I have the impression that you didn't understand my point. So let me revise what I want:

In OO languages we have a .h and a .cpp (in case of C++). In the header, we instantiate the methods and variables that we specify and with which we are gonna work with in the .cpp. So for example, here comes a .h of my software:


#ifndef MYSERVER_H
#define MYSERVER_H
#include "myclient.h"
#include <iostream>
#include <QTcpServer>
#include <QTcpSocket>
#include <QAbstractSocket>
#include <QtCore>
#include <QtGui>

class myserver : public QTcpServer
{

Q_OBJECT
public:
explicit myserver(QObject *parent = 0);
void StartServer();
void CloseServer();

protected:
void incomingConnection(int handle);
signals:
};

#endif // MYSERVER_H

and part of its .cpp:


#include "myserver.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QTextEdit>
extern MainWindow *pmw;

myserver::myserver(QObject *parent) :
QTcpServer(parent)
{
}

void myserver::StartServer()
{
//Aguarda conexão de qualquer IP na porta 1234
if(listen(QHostAddress::Any,1234))
{
qDebug() << "Server Started";
}
else
{
qDebug() << "Server Not Started";
}
}

void myserver::CloseServer()
{
pmw->ui->cmd->append("Server Stoped");
}

void myserver::incomingConnection(int handle)
{
myclient *client = new myclient(this);
client->SetSocket(handle);
}


Now its true that I can instantiate the variables directly in the .cpp and work with them from there. But in this case, the Qt is incapable of recognizing those variables as part of the class, and its not any miracle: that is not how standard C++ OO language is supposed to be.

When it comes about my Qwt "graf" class, I only can instantiate my variables QwtPlot, QwtGrid and so forth in the .cpp, because when I do it as it should be, in the header file, it compiles O.K. but crashes when the graphs are created (when I click a "Start" button).


Sorry for not giving you a more detailed answer for your second question, but you didn't post the deciding parts of your code - general thoughts about OO are not important here.

Uwe
About not putting the "deciding parts of your code" regarding the second question, well, I must confess that I'm lost. Giving what I know about my problem, the parts that I put are the ones that really mater; everything else is in the description. So which exactly are this parts that you are talking about? If you thing it will be fine, I may preset the entire "graf" class, but giving the hundreds of changes that I did trying to make it work, it would probably give more problems than helps.

I must go now so I can't give more details.

Thank you anyway.

Martin/Momergil

Uwe
25th July 2011, 07:25
Well, I agree that the code itself is fine and that it is not necessary for me to create it using only OO. In fact, theorically the unique thing that really matters in a software is that it works fine, independent of the code that it uses. But, you know, when you are doing a software not for free, but being payed by a company that gives you money to do a good work, it is at least expected that I'm gonna do something correct.
You also have to do things "right", when you are doing free software. In case of a long term project like Qwt with many thousands of unknown users and applications a good class design is even much more important as in any application code, that is running in a limited and well known environment.

But this has mot much to do with your problem.



In OO languages we have a .h and a .cpp (in case of C++). In the header, we instantiate the methods and variables that we specify and with which we are gonna work with in the .cpp.
No this is declaration - instantiation is something completely different. Maybe this is the reason for your confused posting. Is it possible, that your question is simply about class members vs. global variables ?

The original code ( the one you don't like ) instantiates the plot widgets and its items in MainWindow::on_Start_released - in your code they are instantiated in graf::createSimple. The difference is, that MainWindow::on_Start_released instantiates 3 plots in advance and your code instantiates the plots on demand one by one.

The first solution definitely makes sense when you want to have a fixed layout - yours will be better if you want to have a user interface with an unknown number of plots, that dynamically appear ( and maybe disappear ).



Now its true that I can instantiate the variables directly in the .cpp and work with them from there. But in this case, the Qt is incapable of recognizing those variables as part of the class, and its not any miracle: that is not how standard C++ OO language is supposed to be.

Before you get lost in whatever terminology - what about posting a small piece of code demonstrating what you mean by "instantiation" and what doesn't work for you ?


So which exactly are this parts that you are talking about?
Your application crashes not because of OO, but because of very basic things like your are running on uninitialized pointers. So, when you start your debugger you will see what pointer it is and then you can show your code dealing with this pointer. From the discussion above I guess it's enough to show the declaration and the instantiation of this pointer in your code.

Uwe

Momergil
25th July 2011, 18:54
Hello, Uwe!

First, thanks for your time in trying to help me once again.

But second, I would like to happily say that, despite I don't know how, now my code is working - in exactly the way that it wasn't working before! For a unknown reason now I'm able to do declaration in the header file and the graph is running O.K. in the way that I wanted and, as I predicted, it was just a matter of declarating the variables in the header and than everything else would run O.K.. About how I did it, it was just a matter of knowing what could be done with a simpler software, than change the older, correct version in accord to it.

About your comments, I thank you once again for them. Sorry if my confusion between "declaration" and "instantiation" made my comments confusing, and I agree with you about the issue on having organized programs.

Once again thank you for everything.

Martin/Momergil