PDA

View Full Version : how to emit signal in a static function ?



cxl2253
28th March 2007, 03:06
i defined a signal and want to emit it in a static function. as you know ,the refrenced signal should be static, but signal function cannot be static in qt, how should i do ? how to convert this signal function to static ? Anybody can tell me how to use static_cast to solve the problem?

aamer4yu
28th March 2007, 05:19
try implementing a function , say emitMySignal(), from where you emit the signal.
From the static function call this funtion, emitMySignal(), which emits the signal ...

Hope this works :)

cxl2253
28th March 2007, 05:51
My code just like that:
1 class mythread:public QThread
2 {
3 static void mycallbackfunc();
4 void myfunc()
5 private singlas:
6 void mysignal();
7 }
8 void mythread::myfunc()
9 {
10 somefuntion(mycallbackfunc)
11 }
12 void mythread::mycallbackfunc()
13 {
14 emit mysignal();
15 }

what should i do ? thanks

aamer4yu
28th March 2007, 06:45
just trying to understand wat u want to do...

why do u want to emit signal from a static function ?? what purpose do u want to achieve ??

cxl2253
28th March 2007, 07:02
because i use third party function, it used the callback .now I want to emit the signal in the callback funtion to inform the qt as indiating the progess. How to solve the problem?can you help me ?

aamer4yu
28th March 2007, 07:46
so why do u have to make the callback function as static ??

can u show some code ??

wysota
28th March 2007, 07:58
What sense would it make to emit a signal without having an object?

sunil.thaha
28th March 2007, 08:11
so why do u have to make the callback function as static ??
Callbacks functions has to be static member functions
Read this to know why http://www.newty.de/fpt/callback.html#intro


Now for the part of emitting a signal from the static function. I believe it makes no sense to have the signal emitted from a static function. Since a static function is not bound to an oobject how will you ever connect to that signal.

you just cannot write


connect( MyClass, SIGNAL( sinalEmittedFromStaticFunction() ), someObject, SLOT( whatEver() );



More over if you go through the Qt docs, you will find that the signals cannot be static.

But you can always post/send Custom Events from the static function.

high_flyer
28th March 2007, 09:56
I fail to see the need for a call back in a Qt application.
In Qt you can use a signal/slot connection or events.
I am sure that if you explain to us what it is you want to do we can show you how to do this with siganl and slots.

cxl2253
28th March 2007, 10:18
yes,you are all right. now I found a solution way. USED a static variable to record this address,then call non-static member function of the class.JUST LIKE THAT.
//mythread.h
1 static unsigned long classAddress;
2 class myclass: public QThread
3 {
Q_Object
4 private:
5 static void myfuntion(); // callback function
6 protected:
7 void run();
8 static void emitMsg( unsigned long user_value,char * filename)
9 {
10 myclass* pthis = (myclass*)user_value; // get this address
11 pthis->emit storescpProgressInfo(filename) ;
12 }
13 signals:
14 void storescpProgressInfo(char * filename);
15 }

//mythread.cpp
16 void myclass::myfuntion(char * filename)
17 {
18 classAddress =(unsigned long)this ;
19 emitMsg(classAddress,filename);
20 }

//main.cpp
21 frmmainWindow::frmmainWindow()
22 {
23 myclass my;
24 connect(&my,SIGNAL(storescpProgressInfo(char *)),this,SLOT(myslot(char *)));
25 }

the myclass can emit the signal,
but frmmainwindow cannot receive the SIGNAL and not load the myslot function, what's wrong ? can you help ?

sunil.thaha
28th March 2007, 10:22
Can you explain what exactly you are trying to achieve ? I just could not figure it out.
more over please use the code tags like shown below
[code]
(put your code here)
[/ code]

high_flyer
28th March 2007, 10:42
static void emitMsg( unsigned long user_value,char * filename)
{
myclass* pthis = (myclass*)user_value; // get this address
pthis->emit storescpProgressInfo(filename) ;
}

This makes NO SENSE in the context you made it!
Such call back is good, when you have the need to allow some external code to execute code it knows nothing about.
Then, such code will offer a call back signature that it knows, in which you can wrap your code for it to execute.
But in your case you only emit a signal, which means the other code is in the context of your class, which means it must have a pointer to your class, otherwise the signal will have no effect.
If you have pointer to your class, you don't need the call back!

what's wrong ?
What wrong is, that you are not listening to what we are saying to you, and you are not explainig what it is you are trying to do.
We can't help you if you don't supply us with details about your problem.

can you help ?
We try to help, but you need to help us help you.

cxl2253
28th March 2007, 14:25
I am sorry.My expression is poor.my problem is that i want to emit signal in the static function which will be used as a param in a callback function. why i must use the callback? because i use a third party libarary ,it used the callback, i have to do it. why i want to emit signal in the static function? I want to let the static function to inform its status and other can response alternatively.
Now the problem is that the emited signal cannot be recieved. tommorrow i will give the detail code, thanks all.

wysota
28th March 2007, 14:47
What do you mean by a "status of a static function"?

high_flyer
28th March 2007, 15:09
I am sorry.My expression is poor.my problem is that i want to emit signal in the static function which will be used as a param in a callback function. why i must use the callback? because i use a third party libarary ,it used the callback, i have to do it. why i want to emit signal in the static function? I want to let the static function to inform its status and other can response alternatively.
Now the problem is that the emited signal cannot be recieved. tommorrow i will give the detail code, thanks all.
Ok, lets see what we have here:
You have an external library which you are using.
You say the call back function should update a status, but you are not saying who is checking that status - is it the external lib that needs this status information?
At any rate, your problem is not "how to emit a signal in a tatic function" but how to update a status to some client.
If you will explain which code needs the status update, we might help you more.
If you need to use a callback function you wont be able to use signals, but there are other ways as well - depending on the task you have.

wysota
28th March 2007, 18:09
What high_flyer is saying is that we know a way to do what you want, but we don't want to tell you, because it's not a good thing to use such solutions and we think you may have a design flaw. So instead of continuing with a faulty design that will surely cause you more problems in future we suggest to modify the design to make your application foul proof.

If you really can't live without callbacks, I suggest to implement an additional layer (proxy) that will handle the callback-Qt transition in both ways. Then you'll have a nice loosely coupled design which should cause you no trouble.

BTW. In my personal opinion using callbacks is a Bad Thing (C). Qt signals-slots are soooooo much nicer.

hayati
28th March 2007, 18:48
OK let me explain what cxl2253 is trying to do?

Assume that you have a C library.
In the library's documentation you have a callback function about the progress of some event. So when this callback is called then cxl2253 want to emit a signal for passing info to related object.
Ok, let's make it clear.
Assume that you want to wrap a class to convert C library to C++ object. As used library's docs says you need to use a callback func, but callbacks are not encouraged in C++ so what else to do?
Then use a static class member. In this case static funcs cannot contain class wide variables.

But off course there are tricks to make them available.


But there is two things to take care of before using these tricks:
1. If you're using the callbacks within QThread, don't do any GUI thread operations. Do with


QApplication::postEvent()

whatever you do.
2. If you use emit within the QThread emit is syncronious, this means you're directly reaching the GUI thread so this is undefined behaviour also.

As a result you had better forget emit in static class functions if It's used in QThread.

wysota
28th March 2007, 19:05
OK let me explain what cxl2253 is trying to do?

Assume that you have a C library.
In the library's documentation you have a callback function about the progress of some event. So when this callback is called then cxl2253 want to emit a signal for passing info to related object.
We know that. But it's not mentioned anywhere that you should install callbacks on Qt objects. You should always think twice before mixing two technologies that use completely different approaches.



Assume that you want to wrap a class to convert C library to C++ object. As used library's docs says you need to use a callback func, but callbacks are not encouraged in C++ so what else to do?
<flamemode>Use another library?</flamemode>
Seriously - in such situations don't wrap the functions into classes. If you need callbacks - go ahead, create callback functions that will call regular methods from regular (maybe global?) objects. Then the objects can emit signals properly.

cxl2253
29th March 2007, 02:12
thanks all . I found that it's impossible to emit the signal in static function .Now I play the trick. I not emit the signal to inform the object which is out of the thread, I directly implement the code that shouble be in SLOT range. Because it is non-static member function of class ,i have to load it into static function.I used the trick mentioned before, used "this" address .
thanks all again.

Other more, if want to use QApplication.poseEvent(), what should i do ? in BCB,I can just write like that .


/////////////cfrmmain.h///////
enum { NM_STORESCP_CALLBACK = WM_USER + 100 };
void __stdcall MyStoreScpCallback(T_StoreProgress* progress, LPCSTR filename);
class TfrmMain : public TForm
{
BEGIN_MESSAGE_MAP
VCL_MESSAGE_HANDLER(NM_STORESCP_CALLBACK, TMessage, OnStoreSCPCallback);
END_MESSAGE_MAP(TForm);
}
//////////////cfrmmain.cpp////////
void __stdcall MyStoreScpCallback(T_StoreProgress* progress, LPCSTR filename)
{
///emit the message user defined :in QT ,how to postEvent and get the receive ????
SendMessage(Application->MainForm->Handle, NM_STORESCP_CALLBACK,
(WPARAM)progress, (LPARAM)filename);
}
void __fastcall TfrmMain::OnStoreSCPCallback(TMessage &Message)
{
///response to the message ,do something accoring to WPARAM LPARAM
}
void __fastcall TfrmMain::FormShow(TObject *Sender)
{
//now callback here
storescp_execute(m_iServerPort, MyStoreScpCallback);
}

wysota
29th March 2007, 06:22
You mean you use "this" from a static method?????????????????????????????????? And it actually works?

cxl2253
29th March 2007, 07:12
yes,:D .it works well.

wysota
29th March 2007, 07:19
yes,:D .it works well.

Can we see the code? Based on my knowledge you can't rely on "this" pointer in a static method as the static method is not part of any object...

cxl2253
30th March 2007, 04:41
of course,the following is code.but i still cannot decalre the static variable in class scope,when i do it ,the VC7 always report various error.either not define the variable or cannot be interped by metaobject.


///////////////////////storescpThread.h
typedef (*STORESCPCALLBACK)(void *callbackData, char* statusDetail);
static unsigned long classAddress;
class storescpThread:public QThread
{
Q_OBJECT
public:
storescpThread(QTextEdit *txtEdit,QObject *parent = 0)
~storescpThread();
protected:
void run();
static void emitMsg( unsigned long user_value,char * filename)
{
storescpThread* pthis = (storescpThread*)user_value; //
pthis->setText(state,filename);
}
void mycallback();
private :
QTextEdit * textEdit;
static void storeSCPCallback(void *callbackData, char* statusDetail);
void setText(char * state,char * name);
};

///////////////////////storeScpThread.cpp
storescpThread::storescpThread(QTextEdit *txtEdit,QObject *parent): QThread(parent)
{
textEdit=txtEdit;
classAddress =(unsigned long)this ;
}
void storescpThread:: storeSCPCallback(void *callbackData, char* statusDetail)
{
emitMsg(classAddress,statusDetail);
return ;
}
void storescpThread::mycallback()
{
myThirdCallFunction(storeSCPCallback); //the third party function, which used callback as param

}

wysota
30th March 2007, 11:33
Oh God.... This is some kind of madness... I won't even ask what happens if you have two instances of the thread class or what happens if you delete the object without unregistering the callback...

Why don't you move the callback method outside the class so that it's a standalone function instead? You can't call any of the nonstatic class member anyway, so what's the point of having this static method part of the thread class?

captainst
30th March 2011, 04:44
Implementing some Win32 Callback is quite necessary in some cases to make *good* use of Win32 API.

Found this old thread on google. What I did is to add a global pointer to the current class, like this:

in the header file

class MyClass {
public:
MyClass ();
~MyClass ();
private:
static void CALLBACK MyCallback (int nMsg);
void emitMySignal (int nMsg);
signals:
mySignal (int nMsg);
}

in the cpp file, at the beginning define a global pointer to the current class

MyClass* pThis;

MyClass:MyClass ()
{
pThis = this;
}

void MyClass::MyCallback (int nMsg)
{
pThis->emitMySignal(nMsg);
}

void MyClass::emitMySignal (int nMsg)
{
emit mySignal (nMsg);
}

Goddard
6th July 2016, 19:36
I had a very similar situation with the libusb library. If I wanted to have callbacks and use the async model they have laid out I couldn't figure out a better way.

Is this the best way still, at least when using existing c libraries?

jefftee
6th July 2016, 21:20
In my experience with callbacks from various libraries, there's usually a method for storing a pointer or user data that is presented to the callback. I've used that capability in the past to pass a pointer to the class instance, so that even though the static member callback function doesn't have a "this" pointer, the method would be able to execute any class functions or class data, etc.

Goddard
6th July 2016, 21:46
In my experience with callbacks from various libraries, there's usually a method for storing a pointer or user data that is presented to the callback. I've used that capability in the past to pass a pointer to the class instance, so that even though the static member callback function doesn't have a "this" pointer, the method would be able to execute any public class functions or public class data, etc.

So basically sharing the class instance pointer to the static function? Then just making sure it is only used within a class instance and dealing with removing the reference with what ever means the library offers.

jefftee
6th July 2016, 23:55
So basically sharing the class instance pointer to the static function? Then just making sure it is only used within a class instance and dealing with removing the reference with what ever means the library offers.
Easier to give you an example. Here's what I've used for libCurl when I've used its callback functions.

header file that declares the static member function:



private:
static size_t write_function( void *ptr, size_t size, size_t nmemb, void *stream);

cpp file that implements the static member functiion:



size_t libFlickr::write_function( void *ptr, size_t size, size_t nmemb, void *stream)
{
size_t total = size * nmemb;

libFlickr* pFlickr = reinterpret_cast<libFlickr*>(stream);

if (pFlickr)
{
pFlickr->some_public_method();
return total;
}
else
{
return 0;
}

}

and finally the cpp code that invokes libcurl, specifies the callback, and sets the user data pointer, etc:



m_code = curl_easy_setopt(m_pCurl, CURLOPT_WRITEFUNCTION, libFlickr::write_function);
m_code = curl_easy_setopt(m_pCurl, CURLOPT_WRITEDATA, (void*)this);
m_code = curl_easy_perform(m_pCurl);

In the case of libcurl, it passes the CURLOPT_WRITEDATA value to the callback function as the void* stream argument. Every other use I've had for callback functions has provided a way to pass data that is given back to the callback function, so passing the "this" pointer results in the callback receiving the instance pointer.

Hope that helps.

anda_skoa
7th July 2016, 10:06
the method would be able to execute any public class functions or public class data, etc.
Any method or data, even private.
The static method is in the same class context.

Cheers,
_

jefftee
7th July 2016, 16:24
Any method or data, even private.
The static method is in the same class context.
Thanks, I'll edit my post so that I don't mislead anyone that runs across this thread on the future.

Edit: For some reason, I don't see an option to edit my prior post...

anda_skoa
7th July 2016, 17:23
Strange, I edited it for you.

Cheers,
_

Goddard
7th July 2016, 21:36
Good stuff. I'm just learning working with this type of library. Appreciate that. I now noticed it does indeed offer a void* user_data parameter in the function to pass through. I just overlooked that completely.