connect to a function
-
In MainWiondow.h I have
public: void button1(); void button5();
and in MainWiondow.cpp I have
connect(ui->button5, &QPushButton::clicked, button5); and void MainWindow::button5(){ ui->statusbar->showMessage("Button_5_Pressed", 0); }
I get an error about reference to non-static member. . . .
I have buttons 1..4 that work with new, and old and lambda. Know I am trying to connect to just a function.
What am I missing?
-
In MainWiondow.h I have
public: void button1(); void button5();
and in MainWiondow.cpp I have
connect(ui->button5, &QPushButton::clicked, button5); and void MainWindow::button5(){ ui->statusbar->showMessage("Button_5_Pressed", 0); }
I get an error about reference to non-static member. . . .
I have buttons 1..4 that work with new, and old and lambda. Know I am trying to connect to just a function.
What am I missing?
-
Please note that I stated that it "work(s) with new, old, and lambda" I had tried what you suggested, but the documentation states:
New: connecting to simple function
The new syntax can even connect to functions, not just QObjects:connect(
sender, &Sender::valueChanged,
someFunctionThat is what I am trying to accomplish thus:
connect(ui->button5, &QPushButton::clicked, button5);.What is required to make that work?
-
Please note that I stated that it "work(s) with new, old, and lambda" I had tried what you suggested, but the documentation states:
New: connecting to simple function
The new syntax can even connect to functions, not just QObjects:connect(
sender, &Sender::valueChanged,
someFunctionThat is what I am trying to accomplish thus:
connect(ui->button5, &QPushButton::clicked, button5);.What is required to make that work?
-
@ofmrew said in connect to a function:
What is required to make that work?
That
button5
be a free (or they called it "simple") function, which it is not in your case (MainWindow::button5()
).@JonB
I thought that I tried that, but apparently I broke the cardinal rule of debugging: make a single change and evaluate, never make more than one change! I must add, however, that it would be nice if the writers of documentation specified that the function must be a non- member (free) function. I included ```
void button5(){
// ui->statusbar->showMessage("Button_4_Pressed", 0);
qDebug() << "Button_5_Pressed";
}in mainwindow.cpp after the includes and ``` void button5();
before the connect statements. That worked, however, it was not what I desired: I wanted the text displayed in the statusbar as shown by the commented statement. What would be the best way to get what is desired? Is sending an event the best way?
-
@JonB
I thought that I tried that, but apparently I broke the cardinal rule of debugging: make a single change and evaluate, never make more than one change! I must add, however, that it would be nice if the writers of documentation specified that the function must be a non- member (free) function. I included ```
void button5(){
// ui->statusbar->showMessage("Button_4_Pressed", 0);
qDebug() << "Button_5_Pressed";
}in mainwindow.cpp after the includes and ``` void button5();
before the connect statements. That worked, however, it was not what I desired: I wanted the text displayed in the statusbar as shown by the commented statement. What would be the best way to get what is desired? Is sending an event the best way?
@ofmrew said in connect to a function:
would be nice if the writers of documentation specified that the function must be a non- member
Well, a function in C++ is a stand-alone function like in C. A member function is called method.
"I wanted the text displayed in the statusbar as shown by the commented statement" - then you need to connect to a slot which is a method (not stand-alone function).
-
@JonB
I thought that I tried that, but apparently I broke the cardinal rule of debugging: make a single change and evaluate, never make more than one change! I must add, however, that it would be nice if the writers of documentation specified that the function must be a non- member (free) function. I included ```
void button5(){
// ui->statusbar->showMessage("Button_4_Pressed", 0);
qDebug() << "Button_5_Pressed";
}in mainwindow.cpp after the includes and ``` void button5();
before the connect statements. That worked, however, it was not what I desired: I wanted the text displayed in the statusbar as shown by the commented statement. What would be the best way to get what is desired? Is sending an event the best way?
@ofmrew
As @jsulm has said, you do not want to connect to a non-member function and never did want to, I don't understand why you seemed to insist on it.Since you want to access
ui->statusbar
, andui
is a member variable inMainWindow
, what was wrong with my first:connect(ui->button5, &QPushButton::clicked, this, &MainWindow::button5);
which you immediately rejected?
-
@ofmrew
As @jsulm has said, you do not want to connect to a non-member function and never did want to, I don't understand why you seemed to insist on it.Since you want to access
ui->statusbar
, andui
is a member variable inMainWindow
, what was wrong with my first:connect(ui->button5, &QPushButton::clicked, this, &MainWindow::button5);
which you immediately rejected?
@JonB
Absolutely nothing! In fact I used exactly that with another button. Let me explain. I have five button each using a different kind of connection:connect(ui->button1, &QPushButton::clicked, this, &MainWindow::button1); connect(ui->button2, &QPushButton::clicked, this, &MainWindow::button2); connect(ui->button3, &QPushButton::clicked, [this](){ui->statusbar->showMessage("Button_3_Pressed", 0);}); connect(ui->button4, SIGNAL(clicked()), this, SLOT(button4())); connect(ui->button5, &QPushButton::clicked, button5);
To answer the question of why am I trying a free function: because is is allowed and I wanted to know the boundaries, which is that the function seems to be limited to free function. Why do I also what to now how to send text from a free function to the statusbar, because I am writing a book about graphics programming using Qt and this was to be an example of Signals and Slots. I wanted the example to be consistent, but the free function example is putting a crimp in that. Bottom line, I want to learn how to do it if it is possible. I hope that answers your question.
-
@JonB
Absolutely nothing! In fact I used exactly that with another button. Let me explain. I have five button each using a different kind of connection:connect(ui->button1, &QPushButton::clicked, this, &MainWindow::button1); connect(ui->button2, &QPushButton::clicked, this, &MainWindow::button2); connect(ui->button3, &QPushButton::clicked, [this](){ui->statusbar->showMessage("Button_3_Pressed", 0);}); connect(ui->button4, SIGNAL(clicked()), this, SLOT(button4())); connect(ui->button5, &QPushButton::clicked, button5);
To answer the question of why am I trying a free function: because is is allowed and I wanted to know the boundaries, which is that the function seems to be limited to free function. Why do I also what to now how to send text from a free function to the statusbar, because I am writing a book about graphics programming using Qt and this was to be an example of Signals and Slots. I wanted the example to be consistent, but the free function example is putting a crimp in that. Bottom line, I want to learn how to do it if it is possible. I hope that answers your question.
@ofmrew said in connect to a function:
Why do I also what to now how to send text from a free function to the statusbar,
Preferably you should not have a free function which wants to do this! Unless it is "outside of your code".
The problem will be: how can a free function get as far as accessing anything in the UI or the
MainWindow
where theui->stausbar
is located?and this was to be an example of Signals and Slots
Indeed so. What you have been trying to use is a
connect()
where there is no object for the slot. But what you are asking about is where there is no object for the signaller.In the example you have at present, the signaller is
ui->button1, &QPushButton::clicked
. If you have some independent function, which knows nothing about the UI, have itemit
a signal you invent. So that inMainWindow
you have something for the signalling side ofconnect()
, andthis, &MainWindow::putTextOnStatusbar
for the slot side.This means there has to be an object, which inherits from
QObject
, as the object which does theemit
of the desired text. If you truly are in a free function, you will have to have access to such an object, e.g. so that you can goemit thatObject->sendTextToStatusbar("Some text")
. AndMainWindow
must have sight of that to go:connect(thatObject, &ThatObject::sendTextToStatusbar, this, &MainWindow::putTextOnStatusbar);
-
To look at it from another angle - to access an object (statusbar in this case) you have to have a pointer or a reference to it. If you're inside a method of the MainWindow class you have access to it through
this->ui->statusbar
member.If you're in a free function there are basically two ways (well, there are more, but let's not make this difficult) you can get that pointer inside - through a global static variable or through that function parameter.
You can't use the parameter option here because the function signature must match the signal for the connect call to be possible, so that's out.
You can use a global static variable - assign it e.g. in the constructor of main window and then you can use it in the free function. But communication through global variables is a terrible application architecture and that's the last thing you should be considering. Also this is error prone, as there's nothing stopping someone from creating multiple instances of your main window class and they will all fight for that static variable to set their member pointer there. While possible to do that's just asking for trouble.
Qt widgets are an object oriented system and it is designed around objects and instances. You can work against it with globals and free functions, but that's just making things harder than they need to be. The intended usage of connections is for objects (QObjects specifically) to communicate, so the best option here is to go with the flow and use an object instance and a method, not a free function.
-
@ofmrew said in connect to a function:
Why do I also what to now how to send text from a free function to the statusbar,
Preferably you should not have a free function which wants to do this! Unless it is "outside of your code".
The problem will be: how can a free function get as far as accessing anything in the UI or the
MainWindow
where theui->stausbar
is located?and this was to be an example of Signals and Slots
Indeed so. What you have been trying to use is a
connect()
where there is no object for the slot. But what you are asking about is where there is no object for the signaller.In the example you have at present, the signaller is
ui->button1, &QPushButton::clicked
. If you have some independent function, which knows nothing about the UI, have itemit
a signal you invent. So that inMainWindow
you have something for the signalling side ofconnect()
, andthis, &MainWindow::putTextOnStatusbar
for the slot side.This means there has to be an object, which inherits from
QObject
, as the object which does theemit
of the desired text. If you truly are in a free function, you will have to have access to such an object, e.g. so that you can goemit thatObject->sendTextToStatusbar("Some text")
. AndMainWindow
must have sight of that to go:connect(thatObject, &ThatObject::sendTextToStatusbar, this, &MainWindow::putTextOnStatusbar);
-
@JonB
Thank you for the very detailed response. Give me some time to digest what you posted. Again thanks.@ofmrew
BTW. If, for whatever reason, you are determined to stick with a free function. There is an existing object which meets the criteria of being able to send a signal and being known toMainWindow
: it is theQApplication
object/instance of your program. If you subclass that for your application you can add new desired signal(s) for your use case(s). Any code you have which includes Qt, even if it is a free function, can access that to send a signal.MainWindow
can access it to connect the slot which updates its statusbar. So you are effectively sending "application signals". -
To look at it from another angle - to access an object (statusbar in this case) you have to have a pointer or a reference to it. If you're inside a method of the MainWindow class you have access to it through
this->ui->statusbar
member.If you're in a free function there are basically two ways (well, there are more, but let's not make this difficult) you can get that pointer inside - through a global static variable or through that function parameter.
You can't use the parameter option here because the function signature must match the signal for the connect call to be possible, so that's out.
You can use a global static variable - assign it e.g. in the constructor of main window and then you can use it in the free function. But communication through global variables is a terrible application architecture and that's the last thing you should be considering. Also this is error prone, as there's nothing stopping someone from creating multiple instances of your main window class and they will all fight for that static variable to set their member pointer there. While possible to do that's just asking for trouble.
Qt widgets are an object oriented system and it is designed around objects and instances. You can work against it with globals and free functions, but that's just making things harder than they need to be. The intended usage of connections is for objects (QObjects specifically) to communicate, so the best option here is to go with the flow and use an object instance and a method, not a free function.
@Chris-Kawa
Thank you for your reply, you and @JonB , have been very helpful. As an old assembler programmer, I knew that all that was needed was a pointer to both the statusbar and the displayMessage function, but then I had to consider the text message.And to answer why, the reason its purely pedagogical: this is not the first time I have wanted this type of linkage. I will take the information you provided and work on it some more. Again, thanks to both of you.
-
@Chris-Kawa
Thank you for your reply, you and @JonB , have been very helpful. As an old assembler programmer, I knew that all that was needed was a pointer to both the statusbar and the displayMessage function, but then I had to consider the text message.And to answer why, the reason its purely pedagogical: this is not the first time I have wanted this type of linkage. I will take the information you provided and work on it some more. Again, thanks to both of you.
-
@ofmrew said in connect to a function:
As an old assembler programmer
It was indeed all much simpler when we just wrote assembler... You didn't have to worry about this complex stuff because you simply didn't have it! :D
@JonB
The real complexity was not in what you were doing, but keeping clear were everything was being placed, We were, however, younger and our short term memory was better. The bottom line was you had total control, that is until you interacted with the OS--MVS, DOS, OS2, Windows, WindowsNT, etc. -
I want to thank JonB and Chris-Kawa for their input. I have decided not to pursue this issue further as there is not point because connecting to a free function seems to be of little use, being able to is interesting, but that is all. I must decide if consistency is important, if it is then switch all to Debug else be inconsistent.
Given that I started programming with FORTRAN II where all functions were free--recall "algorithms + data = programs". Even before C and the C++ preprocessor to convert C++ to C for compiling. Then came Object Oriented Programming where some languages eliminated the free function. I prefer not to use them.
-
I want to thank JonB and Chris-Kawa for their input. I have decided not to pursue this issue further as there is not point because connecting to a free function seems to be of little use, being able to is interesting, but that is all. I must decide if consistency is important, if it is then switch all to Debug else be inconsistent.
Given that I started programming with FORTRAN II where all functions were free--recall "algorithms + data = programs". Even before C and the C++ preprocessor to convert C++ to C for compiling. Then came Object Oriented Programming where some languages eliminated the free function. I prefer not to use them.
Thankfully C++ does not subscribe to single style of programming. One of its strengths is support for multiple paradigms. OOP is just one of many of them and it is suited for some tasks and detrimental to others.
It is quite a good fit for retained mode ui programming though, so Qt was designed to embrace it, while still allowing for other patterns if need be. Buttons, windows, events and such can just pretty naturally be described as classes and their instances.
Functional style of programming has its uses in ui too, especially in immediate mode ui libraries like ImGui.