WxWidgets custom events - c++

I'm trying to use a custom event in my WxWidgets C++ application, like described here.
In the constructor of my wxApp:
Connect(wxID_ANY, wxCommandEventHandler(APP::OnMyEvent));
Then the function that should catch the event:
void APP::OnMyEvent(wxCommandEvent& event)
{
exit(0); //testing
}
Finally, to test it:
wxCommandEvent MyEvent(wxEVT_COMMAND_BUTTON_CLICKED);
wxPostEvent(this, MyEvent);
I launch the thing...but it seems that the event is not posted or not caught.
Does someone understand this behaviour ?

You appear to be using the following overload of Connect:
void Connect(wxEventType eventType, wxObjectEventFunction function,
wxObject* userData = NULL, wxEvtHandler* eventSink = NULL)
If so, then should an event of type wxID_ANY happen (never?), then the connected function will be called.
Perhaps you need:
Connect(wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler(APP::OnMyEvent));

Related

Typecasting EventHandler in C++/CLI

I have a form (which I'll call MainForm) embedded with a TabControl. Every time the user creates a new tab it is filled with an instance of a pre-built Panel (which I'll call MyPanel) which contains many controls.
My MyPanel class has a private variable bool save_state which is set to false every time one of the (editable) controls is edited and set to true when the user "saves" the state of the panel.
I want a visual flag to keep track of tabs that have unsaved changes (e.g. the tab "Tab1" will instead display the text "Tab1 *" if it has unsaved changes). So I want to set up the event handler in my MainForm which can call a method in MyPanel to add the handler to each control.
Since not all my controls use the same EventHandler type (for example, I also need to track DataGridViewRowsAddedEvent, among others), I currently have several methods adding the appropriate handler to the corresponding controls (one for each type of Event Handler), each of which is running the same code (i.e. set the save_state bit to false and append " *" to the tab text.
For example, in MainForm.cpp I have:
#include "MyPanel.h"
void markUnsaved(void) {
// set panel bit to false
// append " *" to tab text if we haven't already
}
void MainForm::handler1(Object ^sender, EventArgs ^e) {
markUnsaved();
}
void MainForm::handler2(Object ^sender, DataGridViewRowsAddedEventArgs ^e) {
markUnsaved();
}
void Main::FormaddNewPanelToTab(int tab_index) {
// check index is valid ...
// make the new panel
MyPanel ^new_panel = gcnew MyPanel();
new_panel->addEventHandlerToControls(gcnew EventHandler(this, &MainForm::handler1));
new_panel->addDgvEventHandlerToControls(gcnew DataGridViewRowsAddedEventHandler(this, &MainForm::handler2));
// rest of code...
}
Though this currently works as intended, this (along with the several other Event Handler types I have to manage) makes my code look really silly.
I am hoping to be able to have have a single event handler in MainForm and a single method in MyPanel which type-casts the Event Handler passed and adds it to all the controls with the appropriate types.
I have tried doing simple casts such as:
void MyPanel::addHandlerToControls(EventHandler ^handler) {
control_NUD->ValueChanged += handler; // this works because ValueChanged is of type EventHandler
control_DGV->RowsAdded += (DataGridViewRowsAddedEventHandler ^)handler; // this compiles but throws an exception
// rest of the code...
}
to no avail.
Any help would be greatly appreciated!
I know this is maybe a bit late for answer but I'd want to show how would I solve this.
Firs of all I suggest to get rid from idea of casting event handlers. Kind of such approach may work in C# (with some adjustments) but as far as I know it's not possible in C++ /CLI.
I'd go for adding new event to a MyPanel class that will be invoked every time when the data on a panel is changed. But to avoid adding a lot of different handlers to a control events in a MyPanel class it's better to create one generic method that will handle all the neccessary control's events and fire new event. Maybe this sounds messy, let me show the code:
public ref class MyPanel
{
// Add a new event
public:
event EventHandler^ DataChanged;
// Add a method that will fire new event
// this methid will be invoked on every control's event that you'll subscribe
private:
generic <typename T>
void DataChangedHandler(System::Object^ sender, T e)
{
// Fire the event
DataChanged(this, EventArgs::Empty);
}
// Once the controls are initialized you may add the event handlers
// I put it in a constructor only for example
MyPanel()
{
control_NUD->ValueChanged += gcnew EventHandler(this, &MyPanel::DataChangedHandler<EventArgs^>);
control_DGV->RowsAdded += gcnew DataGridViewRowsAddedEventHandler(this, &MyPanel::DataChangedHandler<DataGridViewRowsAddedEventArgs^>);
// and so on...
}
}
/// And now in a main form we only need to subscribe to a DataChanged event
public ref class MainForm
{
//...
// the handler
void MyHandler(Object^ sender, EventArgs^ e)
{
markUnsaved();
}
void FormaddNewPanelToTab(int tab_index)
{
// make the new panel
MyPanel ^new_panel = gcnew MyPanel();
new_panel->DataChanged += gcnew EventHandler(this, &MainForm::MyHandler);
}
//...
}
Hope this helps.

How to connect signal and slot without using connect function?

Is there a way to connect signal and slot without using connect function?
If a way exists, please give some examples.
Nope, there is no other way, not in the public API at least. In Qt4 there is only the connect() function with the SIGNAL() and SLOT macro().
In Qt5 you have another, type-safe connection syntax, but it still uses the connect() function. And in QML you can use "attached handlers" - onSignal: doStuff() - but that's just for QML.
There is a way to use the meta-call interface to avoid using the connect() function. Depending on what you precisely need to do though this may not be the solution you are looking for, or it may be.
You essentially define a callback slot function in your QOBJECT class with a certain syntax and let the MOC sort the 'connection' out.
So say you wanted to use:
connect(ui->actionButton, SIGNAL(triggered()), this, SLOT(someCallbackSlot()));
but without having to use the callback function...
You can do it implicitly with a particular syntax of a member function in the QOBJECT who receives the signal:
class MyQtObj : public QWidget
{
QObject
private slots:
void on_actionButton_triggered();
}
Where on_actionButton_triggered is the functional equivalent of someCallbackSlot(), actionButton is the name of the button/action/signal emitter and triggered() is the signal emitted.
So any of these functions are valid providing the signal emitter is correct:
void on_minimizedButton_clicked();
void on_closeButton_released();
etc
When you run the Qt Meta-Object-Compiler and generate your moc_.cpp file of this class there will be a function called qt_static_metacall; this contains a switch statement that looks like :
void MyQtObj::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
if (_c == QMetaObject::InvokeMetaMethod) {
MyQtObj*_t = static_cast<MyQtObj*>(_o);
Q_UNUSED(_t)
switch (_id) {
case 0: _t->on_actionButton_triggered(); break;
default: ;
}
}
}
If you put a break point in this and trigger your action/button/signal you should see your function get executed.
I'm not too sure of the details of how this works though and I noticed it when I used this frame-less Qt window code and have now adopted it in my own Qt C++ projects.

Enable a button after closing a form

I want to Enable a button from the main form whenever a second form has been closed. I've read something about invokes, but didn't understood much.
How could I achieve this?
When you close the second form, its FormClosed event is automatically raised. Before an event is raised, you can register an event handler to events. This enables you to write code, which is automatically executed, when the event occurrs.
Registering an event handler in .NET is realised by adding a delegate instance to the event. A delegate is a type that describes a method signature. If you instantiate a delegate with gcnew you associate it with a function in your code. You can call the delegate by yourself (which is not needed here) or you can pass it to some other code, which then can invoke it. The latter one is used for events.
For your case that means:
Look at the FormClosed event's delegate type. It is the FormClosedEventHandler which is defined as delegate void FormClosedEventHandler(Object^ sender, FormClosedEventArgs^ e)
This means you must implement a method returning nothing (void) and accepting two arguments: a System::Object and a System::Windows::Forms::FormClosedEventArgs
Instantiate a FormClosedEventHandler delegate and associate it with your method
Register to the FormClosed event on the second form and enable the button in the event handler.
An example:
ref class MainForm
{
...
// event handler function (compatible to the FormClosedEventHandler delegate)
void OnSecondFormClosed(Object^ sender, FormClosedEventArgs^ e)
{
myButton->Enabled = true;
}
void DoSomethingWithSecondForm(Form^ secondForm)
{
// get a disabled Button
myButton->Enabled = false;
// create an event handler by instantiating a delegate
FormClosedEventHandler^ handler = gcnew FormClosedEventHandler(this, &MainForm::OnSecondFormClosed);
// register event handler
secondForm->FormClosed += handler;
}
...
}
(I did not compile the code, but this is how it works in general)
When both involved forms are created from within the same thread, there is no need to do some additional Invoke. Otherwise you must put changes to controls into the same thread that created the control. You can achieve this by passing a delegate to Control::Invoke or Control::BeginInvoke.
// event handler function (compatible to the FormClosedEventHandler delegate)
void OnSecondFormClosed(Object^ sender, FormClosedEventArgs^ e)
{
if (myButton->InvokeRequired)
{
// create a delegate to call the same event handler again
FormClosedEventHandler^ handler = gcnew FormClosedEventHandler(this, &MainForm::OnSecondFormClosed);
// BeginInvoke causes the delegate to be called asynchronously from the UI thread
myButton->BeginInvoke(handler, sender, e);
// nothing to be done here, the actual work happens when the delegate is actually called
return;
}
myButton->Enabled = true;
}

Qt dialog how can I trigger accept() and reject() from function

I have situation that I open QDialog window from the main.cpp file and then I wait for the exec() method to return based on success or fail of the QDialog. Like this :
int main( ... ) {
LoginDialog *loginDlg = new LoginDlg;
if( loginDlg->exec() != Qt:;Accepted ) {
return 0;
}
//check the login Info
delete loginDlg;
MainWindow w;
w.show()
return app.exec();
}
From the Qt Examples (Address book) I saw I just can use the accept() and reject() slots.
The thing is that I like the window to close based on some function flow, and not ok/close buttons.
How can I trigger those slots from function? .
As liaK pointed out you can just call the following functions from your code:
loginDlg->accept();
loginDlg->reject();
You can also call the following equivalent function using the result as a parameter:
loginDlg->done(QDialog::Accepted);
loginDlg->done(QDialog::Rejected);
PS: Note also there is no Qt::Accepted value as specified in your question.
The correct constant is QDialog::Accepted
Just call them.. They are normal functions..
E.g:
loginDlg->accept();
Also see this..

Creating a custom message/event with Qt

I have an RPC thread that is calling back to me from that thread. I need to somehow inform Qt that it needs to make a function call from the main thread. In straight Windows I could do this by using a custom message and then posting that message to the message queue, e.g., I could create a WM_CALLFUNCTION message and pass the function pointer through wParam and the parameter (class pointer) through lParam.
Has anyone an idea how I could do this with Qt? I've come across QCustomEvent but I have no idea how to use it or how to process it. Any help would be hugely appreciated!
Edit:
In the end I went with QMetaObject::invokeMethod which works perfectly.
Using custom events generally involves creating your own QEvent subclass, overriding customEvent() in the QObject class that will receive the event (often the main window class) and some code that "posts" the event from your thread to the receiver.
I like to implement the event posting code as a method of the receiver class. That way, the caller only has to know about the recevier object and not any of the "Qt" specifics. The caller will invoke this method which will then essentially post a message to itself. Hopefully the code below will make it clearer.
// MainWindow.h
...
// Define your custom event identifier
const QEvent::Type MY_CUSTOM_EVENT = static_cast<QEvent::Type>(QEvent::User + 1);
// Define your custom event subclass
class MyCustomEvent : public QEvent
{
public:
MyCustomEvent(const int customData1, const int customData2):
QEvent(MY_CUSTOM_EVENT),
m_customData1(customData1),
m_customData2(customData2)
{
}
int getCustomData1() const
{
return m_customData1;
}
int getCustomData2() const
{
return m_customData2;
}
private:
int m_customData1;
int m_customData2;
};
public:
void postMyCustomEvent(const int customData1, const int customData2);
....
protected:
void customEvent(QEvent *event); // This overrides QObject::customEvent()
...
private:
void handleMyCustomEvent(const MyCustomEvent *event);
The customData1 and customData2 are there to demonstrate how you might pass some data along in your event. They don't have to be ints.
// MainWindow.cpp
...
void MainWindow::postMyCustomEvent(const int customData1, const int customData2)
{
// This method (postMyCustomEvent) can be called from any thread
QApplication::postEvent(this, new MyCustomEvent(customData1, customData2));
}
void MainWindow::customEvent(QEvent * event)
{
// When we get here, we've crossed the thread boundary and are now
// executing in the Qt object's thread
if(event->type() == MY_CUSTOM_EVENT)
{
handleMyCustomEvent(static_cast<MyCustomEvent *>(event));
}
// use more else ifs to handle other custom events
}
void MainWindow::handleMyCustomEvent(const MyCustomEvent *event)
{
// Now you can safely do something with your Qt objects.
// Access your custom data using event->getCustomData1() etc.
}
I hope I didn't leave anything out. With this in place, code in some other thread just needs to get a pointer to a MainWindow object (let's call it mainWindow) and call
mainWindow->postMyCustomEvent(1,2);
where, just for our example, 1 and 2 can be any integer data.
In Qt 3, the usual way to communicate
with the GUI thread from a non-GUI
thread was by posting a custom event
to a QObject in the GUI thread. In Qt
4, this still works and can be
generalized to the case where one
thread needs to communicate with any
other thread that has an event loop.
To ease programming, Qt 4 also allows
you to establish signal--slot
connections across threads. Behind the
scenes, these connections are
implemented using an event. If the
signal has any parameters, these are
also stored in the event. Like
previously, if the sender and receiver
live in the same thread, Qt makes a
direct function call.
--
http://doc.qt.nokia.com/qq/qq14-threading.html#signalslotconnectionsacrossthreads