enum values in a class - Qt Creator - c++

I made a functions class that contains enumerated values but when called in my main.cpp, I get a "has not been declared" error. I'm trying to figure out where I'm going wrong but not having much luck. My class header, currently (reduced to fit here):
class main_funcs : public QObject
{
Q_OBJECT
public:
main_funcs(QObject *parent, QQuickView *view)
: QObject(parent), myDialog(view){
IP_is_set = false;
newIP = null;
newIP.resize(50);
local_IPv4 = null;
enum direction {up, down};
enum sys_sides {left, right};
enum sys_control {analog, digital};
public slots:
void myfunc1();
void myfunc2(sys_sides side);
void myfunc3(direction dir);
void myfunc4(sys_control type);
private:
...
...
}
and in my main.cpp, I'm connecting signals to slots:
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
// MAIN CONTROL WINDOW:
QQuickView* view = new QQuickView(QUrl("main.qml"));
view->show();
QQuickItem *rect = view->rootObject();
main_funcs *funcs = new main_funcs(0, view);
QObject::connect(rect, SIGNAL(onClicked_func1()), funcs, SLOT(myfunc1()));
QObject::connect(rect, SIGNAL(onClicked_func2()), funcs, SLOT(myfunc2(funcs::up)));
QObject::connect(rect, SIGNAL(onClicked_func3()), funcs, SLOT(myfunc3(funcs::left)));
QObject::connect(rect, SIGNAL(onClicked_func4()), funcs, SLOT(myfunc4(funcs::analog)));
The error appears in the class header at the functions that require enumerated values. The error is that the enumerated value "has not been declared" -It's declared in the public heading just above it. I'm still a C/C++ newb, and definitely new to Qt as I haven't done much with it. Can anyone point me in the right direction at the very least? Thanks!

Your call to your enums is wrong. They are scoped by the class, not the class object.
Try this:
QObject::connect(rect, SIGNAL(onClicked_func2()), funcs, SLOT(myfunc2(main_funcs::up)));
QObject::connect(rect, SIGNAL(onClicked_func3()), funcs, SLOT(myfunc3(main_funcs::left)));
QObject::connect(rect, SIGNAL(onClicked_func4()), funcs, SLOT(myfunc4(main_funcs::analog)));
EDIT:
That'll solve the "has not been declared" error, but I realize that you'll then get another error. You're trying to pass arguments into a function pointer, that won't work.
A signal will take an argument, the parameter that you pass in there will be passed, by Qt, to your slot. You do not control the arguments to your slot in the connection. You control your arguments to the slot by what you pass to the signal.
Read through this for more info: http://doc.qt.io/qt-5/signalsandslots.html

There are some major issues with your code. You should not define values when connecting signal and slots. Only the types should be provided in the old style connecting syntax.
Also when connecting a signal to some slot, the signal should provide the arguments for the slots. So here you cal not connect any of the signals onClicked_func2,.. to the slots as they do not have any argument apparently. (In case onClicked_func2 is really a signal, it looks like a slot)
Also if you want to use the enumeration types, you should use the enumeration in the class scope by following the class name like :
main_funcs::up

First of all, I suggest to put constructor definition in the cpp file, not in the class definition file, it will help keeping things tidy and not to forget closing curly brackets of the constructor like in this case.
Second I suggest also to keep your enums outside the class definition so you will be able to use them in other classes, as they seem to be very general logic enums.
Thirds signals and slots do not work that way, you need to connect SIGNAL signatures with identical slot signatures you cannot be passing actual parameters during connect I do not thing that will ever work, and you should be getting also a lot of connect errors during start up.

Related

C++ Qt Signals and Slots

I have difficulty connecting to SLOTs defined in a different class. I have 2 classes - Computations and MainWindow. MainWindow is supposed to handle the GUI part of the program only and Computations handles the calculations. I am creating a calculator.
Basically, I want to understand how I can connect to SLOTs in the Computations Class from the MainWindow Class.
I guess you already checked the Qt Signals & Slots page. To implement what you want you need to have an instance of your class in the other one.
So for example in your MainWindow class, you can include the Computations class and create a member variable of it:
#include "computations.h"
class MainWindow : public QMainWindow
{
Q_ObBJECT
public:
//..
private:
Computations *_computation;
};
and then in the constructor of MainWindow after initializing the _computation object (_computation = new Computations();) you do the connections like this (works for Qt5):
QObject::connect(_computation, &Computations::somethingHappened, this, &MainWindow::doSomeGuiStuff);
QObject::connect(this, &MainWindow::guiThingHappened, _computation, &Computations::doSomeComputation);
depending on which way it should go.
I hope this helps.
This is another version how to use, I think can be easier to understand for beginners
You need define signal and slots in your classes.
Add to header of your class, for example signals to MainWindow, slots to Computations
public slots:
void something();
signals:
void something_happend();
Then, in anywhere, where you want use it, in your example in mainwindow.cpp, you need to connect signal and slot. Do this by QObject::connect :
QObject::connect(who_emit,SIGNAL(what_signal),who_receive,SLOT(what_slot))
Example:
mainwindow.h
signals:
void something_happend();
computations.h
public slots:
void something_happend();
mainwindow.cpp
Computations *c = new Computations(this);
QObject::connect(this,SIGNAL(something_happend()),c,SLOT(something()));
If you want to pass some arguments, SIGNAL and SLOT that you want to connect need have same types of arguments:
public slots:
void something(int c);
signals:
void something_happend(int c);
QObject::connect(this,SIGNAL(something_happend(int)),c,SLOT(something(int)));
Such connections belong at a level where both the UI and the controller (computation object) are available. Thus, either in the body of main, or in a class that composes that various elements of the application at a high level (such a class usually shouldn't derive from QApplication, though).
It is almost always too tight of a coupling if the UI class knows of the existence of the computation object, or is somehow tied to its details. I usually design the UI to have an interface composed of signals and slots of as generic a nature as practicable, and then tie it to one or more controller objects via signal/slot connections. I also leverage the property system to expose UI-relevant properties in a generic manner, often using viewmodel objects to interface a UI-agnostic controller to a concrete kind of a UI.
In your case, I'd suggest that neither MainWindow know of Computations, nor vice versa:
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
Computations comp;
MainWindow ui;
QObject::connect(&comp, ..., &ui, ...);
/* more connections here */
ui.show();
return app.exec();
}
For more concrete examples, see answer #1 or answer #2.
you need slots and signals because those work together, like this:
your file.h
public slots:
void start();
signals:
void levelChanged(int level);
implementing:
void MainBoard::start()
{
isStarted = true;
clearBoard();
emit levelChanged(1);
}
now you need to link a button
startButton = new QPushButton(tr("&Start"));
startButton->setFocusPolicy(Qt::NoFocus);
connect(startButton, &QPushButton::clicked, board, &MainBoard::start);

How do I get ui from a widget in order to connect it in another class?

I need to connect a QPushButton (startListeningPushButton) from my StartWindow to a slot in my MainController. I still have a few questions:
Should I make a pointer of Ui::startWidget ui, because by default Qt created it as a normal variable?
Is getStartWindow() the right way to get the StartWindow from ViewController?
What would be the right way to get startListeningPushButton from StartWindow (is my getter right)?
This is my code:
MainController.cpp:
MainController::MainController()
{
connect(m_viewController.getStartWindow()->getStartListeningPushButton, &QPushButton::clicked, this, &MainController::bla)
}
ViewController.cpp:
StartWindow* ViewController::getStartWindow()
{
return &startWindow;
}
StartWindow.cpp:
QPushButton* StartWindow::getStartListeningPushButton()
{
return ui->fStartListeningPushButton;
}
StartWindow.h:
#ifndef STARTWINDOW_H
#define STARTWINDOW_H
#include "ui_startwindow.h"
class StartWindow : public QWidget
{
Q_OBJECT
public:
StartWindow(QWidget *parent = 0);
~StartWindow();
QPushButton* getStartListeningPushButton();
private:
Ui::startWidget *ui;
};
#endif // STARTWINDOW_H
If you are using Qt Designer and Qt IDE generated such code that it's object not a pointer I don't think that you should make it pointer.
Yeah, returning a pointer to QWidget (StartWindow in your case) is pretty OK.
Your getter is OK.
Seems like you have mistype in your connect, it should look like this:
QObject::connect(m_viewController.getStartWindow()->getStartListeningPushButton(), SIGNAL(clicked()),
this, SLOT(bla()));
It's unclear if you have and then what is your problem.
The only thing I doubt would work is the first parameter of your call to connect:
m_viewController.getStartWindow()->getStartListeningPushButton should actually be m_viewController.getStartWindow()->getStartListeningPushButton() (to have the function be called so that you get the pointer to expected QPushButton and pass it to the connect function).
In the connect function:
First and third parameter must be of type QObject*. So this can either be this pointer (if current class is derived from QObject), or any class attribute of type QObject* (ui->fStartListeningPushButton) or a function call returning QObject* (m_viewController.getStartWindow()->getStartListeningPushButton()). But m_viewController.getStartWindow()->getStartListeningPushButton (with no ()) does not make sense here).
Second parameter must be a signal (declared in header file class using signals: keyword. You don't need implement any code here, you just declare the signal and Qt MOC mechanism implements it silently). Valid syntax for this parameter is &QPushButton::clicked or SIGNAL(clicked()) (Qt4 syntax, still valid in Qt5).
Fourth parameter must be a slot (declared in header file class using slots: keyword, and implemented by you). Valid syntax for this parameter is &MainController::bla or SLOT(bla()) (Qt4 syntax, still valid in Qt5).
There's actually a fifth optional parameter to use when you'll start dealing with threads.

Passing different classes in connect() in Qt

I'm working on a image editing software which includes a few classes. But I need my code to be more generic. But I've got a big problem with my classes when it comes to connections.
QObject::connect(actionSmartContrast, SIGNAL(triggered(bool)), effectsWindow, SLOT(addSmartContrast()));
QObject::connect(actionSaturation, SIGNAL(triggered(bool)), effectsWindow, SLOT(addSaturation()));
I've got a Menu called "Effects", and when the user clicks the QAction actionSmartContrast, then the effect Smart Contrast is added to my effects window. The thing is, given that each effect has its own class, I have to create a function for each class as you can see in the code above. And this is very repetitive. I would like to avoid this problem by doing something like this:
QObject::connect(actionSmartContrast, SIGNAL(triggered(bool)), effectsWindow, SLOT(addEffect(new SmartContrast())));
QObject::connect(actionSaturation, SIGNAL(triggered(bool)), effectsWindow, SLOT(addEffect(new Saturation())));
Everything would be fine for the function addEffect() because it expects a pointer to an Effect object and both SmartContrast and Saturation inherit from Effect. The only problem is that it is impossible to pass variables in connect() like this. So I thought of subclassing QAction and creating a signal which would return the class I like everytime but again, how to tell my new Action class what class it should return? If I have a thousand effects, I won't subclass QAction a thousand times! I need to create a function which would take for example a pointer to a SmartContrast object and it will guess that it has to return a SmartContrast pointer everytime the Action is clicked. And that would still be possible to do it because of the inheritance from the class Effect. But I really can't figure out how to do that. Any help would be much appreciated. Thanks in advance!
Looks like QSignalMapper is exactly what you're looking for.
UPDATED:
Another way is to use lambda (if Qt version and c++ compiler allows):
QObject::connect(actionSmartContrast, &QAction::triggered, [effectsWindow](){ effectsWindow->addEffect(new SmartContrast()) });
There are several options.
If it is enough to have the base class pointer of the effects because you use e.g. virtual methods following solution should do:
You can create an intermedite class:
class Intermediate : public QObject
{
Q_OBJECT
public:
Intermediate(QObject* parent = 0) : QObject(parent){}
signals:
void triggerEffect(Effect*);
public slots:
void effectTriggered()
{
QAction* action = qobject_cast<QAction*>(QObject::sender());
if ( action ) {
std::map<QAction*,Effect*>::iterator it = m_mapping.find(action);
if ( it != m_mapping.end() )
{ emit triggerEffect( it->second ); }
}
}
public:
void registerActionEffectPair(QAction* action,Effect* effect)
{ m_mapping[action]=effect; }
private:
std::map<QAction*,Effect*> m_mapping;
};
To use your Effect base class as type for signals and slots, you have to register it as a metatype:
qRegisterMetaType<Effect*>();
Connect it:
QObject::connect(intermediateInstancePtr, SIGNAL(triggerEffect(Effect*),
effectsWindow, SLOT(addEffect(Effect*)));
And the connections of each action would look like:
intermediateInstancePtr->registerActionEffectPair( yourEffectAction, theEffectPtr );
QObject::connect(yourEffectAction, SIGNAL(triggered(bool)),
intermediateInstancePtr, SLOT(effectTriggered()));
Another one could be to use QObjects properties:
setProperty( "property", "value" )
Call this for each effect QAction and read the property in the slot "addEffect".
The property can be read by calling
QAction* action = qobject_cast<QAction*>(QObject::sender());
if ( action ){
QVariant val = action->property("property");
if ( val.isValid() )
{
//TODO
}
}
since Object::sender returns the sender which is responsible for the slot call.
Afterwards you can do a switch case or stuff like this to distinguish between the different effects.
I finally solved my problem! I subclassed QAction and added a signal to my new class which creates a new effect from the class I want depending on the property text(). Simple if blocks are enough. Thank you all for your answers!

Unable to add slot and connect it to a button

I gathered a code of an application called calendar from the base of examples of the Qt Framework. I am trying to learn from it and add there some functionality. The problem right now that I've got is that I want to implement two function to the two button that I created ( one for increase counting of the days and the second for decrease ).
The code that I added to the function for increasing the days is:
void MainWindow::forward(int *click_forward)
{
click_forward++;
}
and the code added to the function for decreasing the days:
void MainWindow::backwards(int *click_backwards)
{
click_backwards--;
}
In the constructor I defined a variable named click which of the int
type, and I sent this variable to the both function by reference:
forward(&click);
backward(&click);
In the header file, in the public slosts area these both functions are
defined as:
void forward(int *click_forward);
void backwards(int *click_backwards);
I also implemented two SIGNAL-SLOT connections:
QObject::connect(nextbtn, SIGNAL(clicked()), this, SLOT(forward(int
&click)));
QObject::connect(beforebtn, SIGNAL(clicked()), this,
SLOT(backwards(int &clickt)));
But for some reasons when I compile the project I receive an information that:
QObject::connect: No such slot MainWindow::forward(int &click)
QObject::connect: No such slot MainWindow::backwards(int &clickt)
I wanted to use pointers in these two functions, just to work on the original variable itself not on the copy.
Could I please ask you to point me out what I am doing wrong.
Thank you,
The problem is that your signal and slot(s) have different signatures: signal has no arguments, but slot has an argument of pointer type. Besides, even if your signals connections would work, the execution of such code wouldn't do anything useful (at least) as you modify the temporary defined variables click_backwards etc.
I would solve this in the following way:
Define the class member variables and slots:
class MainWindow
{
[..]
private slots:
void forward();
void backwards();
private:
int click_forward;
int click_backwards;
}
Define slots:
void MainWindow::forward()
{
click_forward++;
}
void MainWindow::backwards()
{
click_backwards--;
}
And finally establish connections:
QObject::connect(nextbtn, SIGNAL(clicked()), this, SLOT(forward()));
QObject::connect(beforebtn, SIGNAL(clicked()), this, SLOT(backwards()));
if you do your signals and slots like this, then you get a compiler error instead of a run time error, which i personally find very helpful since it will just tell you that they wont connect because of incompatible signals/slots
QObject::connect(nextbtn, &QPushButton::clicked, this, &MainWindow::forward);
By the way, you're not increasing the value of the integer, you're increasing the pointer.
That's a bug waiting to happen.

Pointer to a slot function

I have some slot function defined in my class which do some actions. I wanted to create a possibility to allow the user of my class to define his own slot function (replacing the function from my class for his own). I tried to achieve it by pointer to a slot function this way:
class asd {
Q_OBJECT
private:
void ( asd::*m_funcTrigger )( QAction* );
public:
asd();
// and some method to pass the pointer
private slots:
void actionTrigger( QAction* );
};
the constructor:
asd::asd() {
// set the slot function from class as default
m_funcTrigger = &asd::actionTrigger;
// m is a QMenu object
connect(m, SIGNAL(triggered(QAction*)), this, SLOT(m_funcTrigger(QAction*)));
}
actionTrigger's implementation is not important I think.
So, when I put actionTrigger into the SLOT() it works ok. When I put there the m_funcTrigger it doesn't - nothing happens (the slot is not found by the Qt). I was sure that it is beacuse the pointer is not in the slots section in the class, so I just put it there:
private slots:
void ( asd::*m_funcTrigger )( QAction* );
void actionTrigger( QAction* );
but I got strange error:
C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppCommon.targets(151,5): error MSB6006: "cmd.exe" exited with code 1.
I completely don't know how to deal with this.
EDIT:
I think the reason why it's not found by the Qt:
From what I have read over the Internet, the SLOT() just returns a simple const char* which includes identifier name of the method passed to the SLOT, Therefore the Qt completely doesn't know what the pointer is pointing at. It just looks after the m_funcTrigger( QAction* ) function.
I created another solution (which works I will put it here later I'm currently at work) that requires the user of the class to pass a SLOT(hisOwnFunction()) into the function which sets the slot function. Because the class uses signal-slots idea, so it's Qt dependent and I think because of that it's ok to pass SLOT there instead of a pointer. What do you think?
You can make your slot virtual, so derived class can override it.
You can call m_funcTrigger in your slot by yourself:
private slots:
void actionTrigger_slot( QAction* a)
{
m_funcTrigger(a);
}