class MenuBarWindow : public TopWindow { protected: MenuBar m_menuBar; public: typedef MenuBarWindow CLASSNAME; MenuBarWindow(int _sizeX, int _sizeY); protected: virtual void MenuBarMain(Bar& _bar) = 0; }; MenuBarWindow::MenuBarWindow(int _sizeX, int _sizeY) { SetRect(0, 0, Zx(_sizeX), Zy(_sizeY + m_menuBar.GetStdHeight(m_menuBar.GetFont()))); AddFrame(m_menuBar); m_menuBar.Set(THISBACK(MenuBarMain)); } class FnWindow : public MenuBarWIndow { protected: Button b_fn1; // ... Button b_fn8; public: typedef FnWindow CLASSNAME; FnWindow(int _sizeX, int _sizeY); private: virtual void OnClickFn1() = 0; // ... virtual void OnClickFn8() = 0; }; FnWindow::FnWindow(int _sizeX, int _sizeY) : MenuBarWindow(_sizeX, _sizeY) { // Adding buttons here... b_fn1 <<= THISBACK(OnClickFn1); // ... b_fn8 <<= THISBACK(OnClickFn8); } // MyWindow header... MyWindow::MyWindow(int _sizeX, int _sizeY) : FnWindow(_sizeX, _sizeY) { // do sth... }
virtual void MenuBarMain(Bar& _bar) = 0;
m_menuBar.Set(THISBACK(MenuBarMain));
I had an interesting issue with a MenuBar and a THISBACK.
I made three classes: MenuBarWindow, FnWindow and MyWindow.
- MenuBarWindow only has the MenuBar attribute and the method I want as its callback.
- FnWindow inherits from MenuBarWindow and has some buttons for the F1-F8 keys and the corresponding callback methods.
- MyWindow inherits from FnWindow and is the main window in my application.
Here is an example code:
class MenuBarWindow : public TopWindow { protected: MenuBar m_menuBar; public: typedef MenuBarWindow CLASSNAME; MenuBarWindow(int _sizeX, int _sizeY); protected: virtual void MenuBarMain(Bar& _bar) = 0; }; MenuBarWindow::MenuBarWindow(int _sizeX, int _sizeY) { SetRect(0, 0, Zx(_sizeX), Zy(_sizeY + m_menuBar.GetStdHeight(m_menuBar.GetFont()))); AddFrame(m_menuBar); m_menuBar.Set(THISBACK(MenuBarMain)); } class FnWindow : public MenuBarWIndow { protected: Button b_fn1; // ... Button b_fn8; public: typedef FnWindow CLASSNAME; FnWindow(int _sizeX, int _sizeY); private: virtual void OnClickFn1() = 0; // ... virtual void OnClickFn8() = 0; }; FnWindow::FnWindow(int _sizeX, int _sizeY) : MenuBarWindow(_sizeX, _sizeY) { // Adding buttons here... b_fn1 <<= THISBACK(OnClickFn1); // ... b_fn8 <<= THISBACK(OnClickFn8); } // MyWindow header... MyWindow::MyWindow(int _sizeX, int _sizeY) : FnWindow(_sizeX, _sizeY) { // do sth... }
In the MyWindow files are declarations and definitions for the virtual methods.
If I run this the program stops and shows me this and exits the application when you continue:
If I removeand movevirtual void MenuBarMain(Bar& _bar) = 0;from MenuBarWindow to MyWindow everything works fine.m_menuBar.Set(THISBACK(MenuBarMain));
At first I thought this is because the method is pure virtual and needs an implementation in the class from where I call it or use THISBACK but then I should get this strange behaviour after my changes as well because I do the same with the button callbacks but they work perfectly.
So does anyone has an idea why this is happening? Is this a generell C++ thing or is it a U++ thing?
MenuBarWindow::MenuBarWindow(int _sizeX, int _sizeY) { SetRect(0, 0, Zx(_sizeX), Zy(_sizeY + m_menuBar.GetStdHeight(m_menuBar.GetFont()))); AddFrame(m_menuBar); m_menuBar.Set(THISBACK(MenuBarMain)); // <-- Undefined behaviour. }
MyWindow::MyWindow(int _sizeX, int _sizeY) : FnWindow(_sizeX, _sizeY) { AddFrame(m_menuBar); // This should m_menuBar.Set(THISBACK(MenuBarMain)); // work. }
As far as I can see, you are calling a pure virtual method (or storing its address -which is undefined at that moment) from base constructor.
Calling a pure virtual method from base constructor is undefined behaviour. (Since at that point the vtable entry for the said method is not yet assigned. It is basically "0" (undefined)). That's why you dont't even get an explicit error message.
Also I see that you use some obscure internal macro(s) explicitly. You dont need them at all.
But why is it working for the OnClickButton callbacks in the FnWindow?
What macros do you mean and how can I avoid them?
#define _FN_LABEL(button, label) button.SetLabel(label).Enable(true) #define FN_LABEL(number, label) _FN_LABEL(b_fn##number, label) #define _FN_UNLABEL(button) button.SetLabel("").Enable(false) #define FN_UNLABEL(number) _FN_UNLABEL(b_fn##number)
Hello Daniel,
It is because those button events aren't called immediately. They are called when there is some user action (They are called WHEN there is action (click/push, etc.).
Had they been called immediately you would have the same undefined behaviour.
On the other hand, MenuBar::Set() method calls the provided callback, and sets the menubar immediately, which leads to crash.
Hello Daniel,
Ah, that's my fault. Nevermind. (For some reason, the below macros reminded me of U++ internal macros used in the TheIDE layout editor.)