How to manually call button.onClick function
How to manually call button.onClick function
Heyall,
I am going through introduction tutorials (http://wiki.codeblocks.org/index.php/WxSmith_tutorials), so I am fairly new to this.
So as you know, my question is, how to call onButton1Click(wxCommandEvent& event) manually. I made new .cpp file which gets Frame object from [nameOfProject]app class. So I can access the function from this .cpp file, but I don't know how/what to pass as its parameter (event).
Hope you guys can help me out.
I am going through introduction tutorials (http://wiki.codeblocks.org/index.php/WxSmith_tutorials), so I am fairly new to this.
So as you know, my question is, how to call onButton1Click(wxCommandEvent& event) manually. I made new .cpp file which gets Frame object from [nameOfProject]app class. So I can access the function from this .cpp file, but I don't know how/what to pass as its parameter (event).
Hope you guys can help me out.
Re: How to manually call button.onClick function
Why would you want to do that? This would be very unusual.
Usually it is the other way around, the event handler calls the user defined function which executes the code triggered by user actions. The user defined function can be called from multiple places, e.g. Save and SaveAs handlers...
Usually it is the other way around, the event handler calls the user defined function which executes the code triggered by user actions. The user defined function can be called from multiple places, e.g. Save and SaveAs handlers...
Re: How to manually call button.onClick function
I understand, makes more sense.PB wrote:Why would you want to do that? This would be very unusual.
Usually it is the other way around, the event handler calls the user defined function which executes the code triggered by user actions. The user defined function can be called from multiple places, e.g. Save and SaveAs handlers...
But I dont know how it solves my problem. Basically I am making a GUI application for using a dongle to communicate with microcontroller with messages. I have a handler function for receiving messages (the dongle driver API calls this function when it receives new message).
In my handler function I have 'printg("new message received\n")' (printg is from tutorial http://wiki.codeblocks.org/index.php/Wx ... ng_Results and i have it set globally). The problem is, this text is never displayed.
I know the function is working ok, because it works in my console application (where i have infinite while loop).
Can you maybe help me with this?
Re: How to manually call button.onClick function
I do not know about printg, the function seems rather arcane and not very useful, considering there is wxLog* family of functions.
Sorry, I do not understand the handler issue. So this is not actually a button click handler?
I assume you want to call the microcontroller function with some parameters when a button is clicked? Or is the issue that you do not receive message from the microcontroller? If it is the latter I suppose it depends on how the communication is established - is it a callback function, a windows message....
Sorry, I do not understand the handler issue. So this is not actually a button click handler?
I assume you want to call the microcontroller function with some parameters when a button is clicked? Or is the issue that you do not receive message from the microcontroller? If it is the latter I suppose it depends on how the communication is established - is it a callback function, a windows message....
Re: How to manually call button.onClick function
Sorry about not being understandable, I will try to clarify.PB wrote:I do not know about printg, the function seems rather arcane and not very useful, considering there is wxLog* family of functions.
Sorry, I do not understand the handler issue. So this is not actually a button click handler?
I assume you want to call the microcontroller function with some parameters when a button is clicked? Or is the issue that you do not receive message from the microcontroller? If it is the latter I suppose it depends on how the communication is established - is it a callback function, a windows message....
printg() function prints string into wxTextCtrl object. I understand wxLog is not the same. (?)
>Sorry I do not understand the handler issue. So this is not actually a button click handler?
No it's not. Dongle's driver API calls my handler function (basically a callback function) when new message is received by this dongle. My handler function then reads this new message and prints it. This handler exists so I don't have to read new messages in while loop to check if there are new messages. The dongle's driver does it for me and tells me, when new message arrives.
This program is all working in my console application, so not wxWidgets used here.
Now I want to add GUI to this program, so I draw GUI with wxWidgets. Now I want to connect functionality of my console application, and this GUI.
So what I did is make MainFrame from GUI global (so my console module can see it). Now, when message handler is called by dongle's driver API, I want to read new message and print it into wxTextCtrl object's field. In order to do that, I took printg() function from tutorial I mentioned in first post.
Problem is new messages arent being printed.
So...
>I assume you want to call the microcontroller function with some parameters when a button is clicked? Or is the issue that you do not receive message from the microcontroller? If it is the latter I suppose it depends on how the communication is established - is it a callback function, a windows message....
It's the latter. My callback function (handler) is not being called by microcontroller when new messages arrives.
I don't know how to solve this yet.
Re: How to manually call button.onClick function
I am not sure if this will be any help, but here is an example of "translating" the callback function call into a custom wxEvent.
viewtopic.php?f=1&t=44428&start=15#p183078
However, this may be an overkill for your case and you could do it simpler.
I would also make sure the callback is called in the context of the GUI thread. Depending on the 3rd party library, this may not be always the case.
But it still does not explain why the callback function is not called. My guess would be that it is called but the printg call gets lost. Did you try placing a breakpoint there to see if this is the case? Or perhaps calling it using CallAfter()? Or maybe just for debugging, use wxYield() to give the UI chance to update...
It is difficult to say without saying any relevant code...
viewtopic.php?f=1&t=44428&start=15#p183078
However, this may be an overkill for your case and you could do it simpler.
I would also make sure the callback is called in the context of the GUI thread. Depending on the 3rd party library, this may not be always the case.
But it still does not explain why the callback function is not called. My guess would be that it is called but the printg call gets lost. Did you try placing a breakpoint there to see if this is the case? Or perhaps calling it using CallAfter()? Or maybe just for debugging, use wxYield() to give the UI chance to update...
It is difficult to say without saying any relevant code...
Re: How to manually call button.onClick function
In pseudo code:
It can be improved if that callback above is a member of a class that has access to the wxTextCtrl to be updated, e.g. by storing a weak pointer to it, instead of using a global pointer. Global pointers can be dangling.
Code: Select all
void MyDongleReceiverCallback(SomeDongleMsgType doMsg) //you do have this, right?
{
wxString msg = TransformTowxString(doMsg);
globalTextCtrlPtr->SetValue(msg); //this is a global pointer
]
Re: How to manually call button.onClick function
Thank you, @PB and @Manolo, for your suggestions and help.
I found out why my callback function didn't work. It's very simple and : microcontroller was OFF. So dongle couldn't communicate with it. Please dont crucify me, I am not a jedi yet.
Nevertheless, I would like to follow Manolo's suggestion and not use global functions (printg()), it's bad programming.
@PB
>I would also make sure the callback is called in the context of the GUI thread.
I don't understand this. How do you make sure it's called in context of GUI thread?
@Manolo
>callback function
Yes I do have exactly such callback function. MainFrame of GUI is global, but I can't seem to access wxTextCtrl component. I was thinking, in this callback function, to put a simple (Results is wxTextCtrl component's name):
But Results is private, so I can't access it. I can use:
somewhere in GUI main.cpp file though. Why can I access it here, but not from dongle callback function?
I found out why my callback function didn't work. It's very simple and : microcontroller was OFF. So dongle couldn't communicate with it. Please dont crucify me, I am not a jedi yet.
Nevertheless, I would like to follow Manolo's suggestion and not use global functions (printg()), it's bad programming.
@PB
>I would also make sure the callback is called in the context of the GUI thread.
I don't understand this. How do you make sure it's called in context of GUI thread?
@Manolo
>callback function
Yes I do have exactly such callback function. MainFrame of GUI is global, but I can't seem to access wxTextCtrl component. I was thinking, in this callback function, to put a simple (Results is wxTextCtrl component's name):
Code: Select all
MainFrame->Results->AppendText("lala");
Code: Select all
Results->appendText("lala");
Re: How to manually call button.onClick function
If the function is not called in the GUI thread, you should not call any GUI-related methods or bad things may happen. You can check whether it is the GUI thread (= thread in which wxWidgets were initialized) by #including <wx/thread> and in the callback function check the return value of wxThread::IsMain(). If the method returns false you should take this into account.ValeV wrote:@PB
>I would also make sure the callback is called in the context of the GUI thread.
I don't understand this. How do you make sure it's called in context of GUI thread?
Re: How to manually call button.onClick function
It returns false, so I am not in GUI thread. Does this mean I shouldn't write some text in wxTextCtrl? What are my options?PB wrote:If the function is not called in the GUI thread, you should not call any GUI-related methods or bad things may happen. You can check whether it is the GUI thread (= thread in which wxWidgets were initialized) by #including <wx/thread> and in the callback function check the return value of wxThread::IsMain(). If the method returns false you should take this into account.ValeV wrote:@PB
>I would also make sure the callback is called in the context of the GUI thread.
I don't understand this. How do you make sure it's called in context of GUI thread?
Re: How to manually call button.onClick function
If it is just for debugging, you can redirect all wxLog* output e.g. with wxLogTextCtrl or use wxLogWindow.ValeV wrote:It returns false, so I am not in GUI thread. Does this mean I shouldn't write some text in wxTextCtrl? What are my options?
If you need it for real, there are several options. You can use e.g. wxQueueEvent() or CallAfter() which will be executed in the main thread.
The code below demonstrates using both an event and CallAfter(), as well as redirecting a log. Please notice that in your application the callback function is probably not a member of a wxDialog/wxFrame/etc and therefore you must somehow pass it a pointer to the frame or dialog where you want the data. How you do this depends on callback function, some allow a custom data which makes this easy, some do not and you must use another way (usually a global/static variable, see e.g. wxMIDICallBackWrapper in the first and second code blocks here).
Code: Select all
#include <wx/wx.h>
class MyDialog : public wxDialog
{
public:
MyDialog() :
wxDialog(NULL, wxID_ANY, "Test", wxDefaultPosition, wxSize(800, 500)),
m_dataPacketCount(0)
{
wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
// this button will communicate the data to m_dataDisplay using an event
wxButton* buttonUseEvent = new wxButton(this, wxID_ANY, "This button uses wxQueueEvent()");
mainSizer->Add(buttonUseEvent, wxSizerFlags().Expand().Border());
buttonUseEvent->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MyDialog::OnButtonSendDataEvent, this);
// this handles the data event
Bind(wxEVT_THREAD, &MyDialog::OnHandleDataEvent, this);
// this button will use CallAfter() to communicate the data to m_dataDisplay
wxButton* buttonCallAfter = new wxButton(this, wxID_ANY, "This button uses CallAfter()");
mainSizer->Add(buttonCallAfter, wxSizerFlags().Expand().Border());
buttonCallAfter->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MyDialog::OnButtonUseCallAfter, this);
// this is where the data will be displayed
m_dataDisplay = new wxTextCtrl(this, wxID_ANY, "<No data packet arrived yet>", wxDefaultPosition, wxDefaultSize, wxTE_READONLY);
m_dataDisplay->SetBackgroundColour(*wxYELLOW);
mainSizer->Add(m_dataDisplay, wxSizerFlags().Expand().Border());
// this is where all wxLog*() calls will be redirected to
wxTextCtrl* logCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize,
wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2);
wxLog::SetActiveTarget(new wxLogTextCtrl(logCtrl));
mainSizer->Add(logCtrl, wxSizerFlags().Expand().Border().Proportion(1));
SetSizer(mainSizer);
}
private:
size_t m_dataPacketCount;
wxTextCtrl* m_dataDisplay;
void UpdateDataDisplay(const wxString& data)
{
wxLogMessage("Updating data display to '%s'", data);
m_dataDisplay->SetValue(data);
}
// handler for buttonUseEvent
void OnButtonSendDataEvent(wxCommandEvent&)
{
const wxString data = wxString::Format("Data packet no. %zu", ++m_dataPacketCount);
wxThreadEvent threadEvent;
wxLogMessage("Sending custom event with data '%s'", data);
threadEvent.SetString(data);
wxQueueEvent(this, threadEvent.Clone());
}
// handler for buttonCallAfter
void OnButtonUseCallAfter(wxCommandEvent&)
{
const wxString data = wxString::Format("Data packet no. %zu", ++m_dataPacketCount);
wxLogMessage("Calling CallAfter() to set data to '%s'", data);
CallAfter(&MyDialog::SetDataWithCallAfter, data);
}
// handles event sent from OnButtonSendDataEvent()
void OnHandleDataEvent(wxThreadEvent& evt)
{
const wxString data = evt.GetString();
wxLogMessage("Setting data from OnHandleDataEvent(): '%s'", data);
UpdateDataDisplay(data);
}
// called with CallAfter() from OnButtonUseCallAfter
void SetDataWithCallAfter(const wxString& data)
{
wxLogMessage("Setting data from SetDataWithCallAfter(): '%s'", data);
UpdateDataDisplay(data);
}
};
class MyApp : public wxApp
{
public:
bool OnInit()
{
MyDialog().ShowModal();
return false;
}
}; wxIMPLEMENT_APP(MyApp);
-
- Filthy Rich wx Solver
- Posts: 235
- Joined: Fri Sep 14, 2012 8:26 am
- Location: Kontich, Belgium
- Contact:
Re: How to manually call button.onClick function
Hi ValeV,
Maybe this reply is a little late, maybe you already have an answer, anyway. The way I understand your question is that when binding your GUI button with a method like onButton1Click(wxCommandEvent& event) this is Ok when the user clicks the button. If, however, you want to call that function you don't have a wxCommandEvent, so how can you call that method. Well the way I solved this is :
Where MyButtonMethod contains all code to handle the button. Doing it that way, you can now call MyButtonMethod from your code with a wxCommandEvent event.
Hope this sets you on your way, good luck.
Regards,
Nunki
Maybe this reply is a little late, maybe you already have an answer, anyway. The way I understand your question is that when binding your GUI button with a method like onButton1Click(wxCommandEvent& event) this is Ok when the user clicks the button. If, however, you want to call that function you don't have a wxCommandEvent, so how can you call that method. Well the way I solved this is :
Code: Select all
void MyClass::TestButton( wxCommandEvent& event )
{
MyButtonMehod(....);
event.Skip();
}
Hope this sets you on your way, good luck.
Regards,
Nunki