PDA

View Full Version : Passing data between MainWindow and my class



r2com
25th July 2016, 23:41
So I have a simple class with one variable called param1, constructor, and two functions to set/get that parameter:

So here are the sources of ctester.h and ctester.cpp

#ifndef CTESTER_H
#define CTESTER_H


class CTester {

public:
CTester(); // constructor
void SetParam1(int value);
int GetParam1(void);

private:
int param1;

};

#endif // CTESTER_H




CTester::CTester(void)
{
// initializing all the parameters
param1 = 0;
}

void CTester::SetParam1(int value)
{
param1 = value;
}

int CTester::GetParam1(void)
{
return param1;
}


My main.cpp and mainwindow.cpp files are rather simple, since I just started a QMainWindow application in QtCreator:


#include "mainwindow.h"
#include <QApplication>


int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();

return a.exec();
}





#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}

MainWindow::~MainWindow()
{
delete ui;
}



What I am not quite sure is, what is the most proper way of getting/setting that param1 variable in my class through that MainWindow form?
The search on QtCentre gives tons of similar threads BUT about sharing data between dialogs or dialogs and main window, but I did not see any description in docs or the forum threads about reading/writing to own class.

In other words, I have my Qt GUI interface, but what I want to achieve now is create now personal c++ class which is "tied" to that GUI and updated by it. I do have two buttons on the MainWindow form, Set and get, and the editbox for setting the value and label for showing the value of param1 when get button is clicked.

Keep in mind that I want to keep ctester.h and ctester.cpp as c++ source files only, i.e. no Qt related macros/keywords there.
Now, does it mean that I need another "intermediate" wrapper class for this mechanism to work? Or there is a better, more elegant approach to achieve what I just described?

d_stranz
26th July 2016, 00:02
So where does your instance of the CTester class live? Have you even declared an instance of it anywhere? If you haven't declared an instance of it, then how do you expect to call its Get and Set methods from any other class at all?

There is no magic to mixing pure C++ and Qt classes; the Qt libraries -are- C++ and the macros (like Q_OBJECT) are just aids to paste a lot of boilerplate code into header files and elsewhere. Signals and slots are just ordinary C++ methods and are called from within the Qt framework just like any other C++ method.

Of course, you have to have an instance of a class first before you can call any of its non-static members. Where do you want your instance of CTester to live?

r2com
26th July 2016, 00:13
I declared instance of CTester inside private section of QMainWindow:


private:
Ui::MainWindow *ui;
CTester aa;


Then on the form designer I right click on the Get button and choose "GoTo SLot->clicked()" and enter this code:


void MainWindow::on_param1Get_clicked()
{
aa.GetParam1();
QString s = QString::number(aa.GetParam1());
ui->param1Label->setText(s);
}


It does give me a LNK2019 error on compile.
And also, I have a feeling that I'm trying to achieve this in an ugly way and there gotta be an elegant solution.

d_stranz
26th July 2016, 00:54
LNK2019

And what else does it say besides "LNK2019"? Probably something about can't find a CTester constructor or a CTester:: GetParam() method, right? So did you add "Tester.cpp" or whatever you called the source file to the project? Did you add the paths to and names of your Qt library ".lib" files to the link properties? (Qt5Core, Qt5Gui, and Qt5Widgets, at a minimum for a GUI project).

By the way, you -do- realize that the code in your line 3 does nothing, right? Gets the parameter value, doesn't assign it to anything, then throws it away once the statment is done.

anda_skoa
26th July 2016, 11:34
And also, I have a feeling that I'm trying to achieve this in an ugly way and there gotta be an elegant solution.

Aside from the linker error and the unnecessary line that d_stranz mentioned this looks fine.

Cheers,
_

r2com
26th July 2016, 20:50
OK, nevermind, it turns out that I had to run Build->Run qmake
And after that include header file in ctester.cpp, now it all works.

but my another question still holds, can you show me any other similar or good methods to achieve what I am trying to achieve? I just want to know all proper solutions available to me.

Also, I want to know methods to achieve this without adding any Qt related syntax to ctester.cpp/ctester.h

Because in a way how i got it to work now, its strange...there is now a "private slots" but who is a signal then? signal comes from user? from OS?

anda_skoa
26th July 2016, 21:52
but my another question still holds, can you show me any other similar or good methods to achieve what I am trying to achieve? I just want to know all proper solutions available to me.

Well, C++ offers you two options:

1) public members in CTester which the other class can directly access
2) setter/getter methods



Also, I want to know methods to achieve this without adding any Qt related syntax to ctester.cpp/ctester.h

That's what you have right now, no?



Because in a way how i got it to work now, its strange...there is now a "private slots" but who is a signal then? signal comes from user? from OS?

The only slot I see in your code is the one connected to the button that you want to use to read the data.
What other private slot are you referring to?

Cheers,
_

r2com
26th July 2016, 22:08
Alright, so according to your response, here is what I understand is available to a programmer to achieve task:

Flow A:
1) public members in CTester which the other class can directly access
2) setter/getter methods

Flow B:
1)Modify CTester class to be derived from QObject, insert slots there,a nd tie signal/slots to my MainWindow ui.

Correct?

In my case I used Flow A, method #2

anda_skoa
27th July 2016, 00:19
Yes, that's about it.

Cheers,
_

d_stranz
27th July 2016, 00:41
There is nothing wrong with "Flow A" and public getter / setter methods. I use non-Qt C++ classes everywhere in my code.

I need the algorithms I write to be portable, not just to a different OS, but to a different GUI platform (like Windows MFC). So I embed them in Qt GUI classes either as member variables or in some cases as stack variables in a method if I don't need to have a persistent instance in my Qt class. I use signals and slots in the Qt class so that other parts of my GUI can communicate with the Qt class that owns the C++ instance.

If I have a GUI element (a QLineEdit for example) that the user can edit to change the temperature, the form where the edit lives listens for the "editingFinished()" signal from the line edit, and if the value is OK, emits a signal "temperatureChanged( double )". The MainWindow has a slot, "onTemperatureChanged( double )" that is connected to this signal. In that slot, it calls the C++ method "setTemperature( double )" of the CTemperatureControl instance it owns. CTemperatureControl doesn't know anything about Qt, but it does know what to do when someone sets a new temperature on it.

As an aside, there are a few things about what I have just described that I think are part of a good design that encapsulates things locally and doesn't spread knowledge of what each part of the program is doing all over the rest of it:

1 - The QLineEdit is owned by a form of some kind (based on QWidget, usually). The QLineEdit tells the form its value has changed. It is up to the form to relay that information to whomever is listening. And it does so in an application-specific way: a "temperatureChanged()" signal, not a "lineEdit_1_text_changed()" signal.

2 - So a revised design suggested by the project manager says to replace QLineEdit with a QDoubleSpinBox because the stupid testers were typing negative temperatures and their dog's names into the edit box to see if they could break the system. No problem, all you do is update the form to listen for the slider's valueChanged() signal then emit "temperatureChanged()" and the rest of the program doesn't care.

3 - The MainWindow is just listening for a "temperatureChanged()" signal from some QObject. It doesn't know it's a form with an edit or spin box. So you could replace that form with a widget that listens to a feed sent from your Nest thermostat and which emits "temperatureChanged()" every time the user presses the Up or Down button.

4 - And because the MainWindow talks to the CTemperatureControl instance through a plain old C++ method call, you could throw that whole GUI away and replace it with something that did the same thing, and the temperature control wouldn't know anything different, either.

(Why doesn't this forum have and tags? I've been watching too much politics here in the US).

r2com
27th July 2016, 17:04
thanks anda_skoa and d_stranz for explanations