Page 1 of 1

Problem with GUI tutorial snippets

Posted: Mon Apr 25, 2011 10:00 am
by brianempson
Hello, I am new to the engine and just started fiddling with some different things. I was messing around with the GUI functions, specifically using an EventReceiver to capture GUI commands, it worked before, but I changed something (don't remember what) and now I get "Runtime Error, pure virtual function!" upon execution.

Here is the conditional path that leads to the error, pressing ` causes a runtime error.

Code: Select all

				if (keyboard.getKey() == '`')
				{
					if (show_console == 0)
					{
						show_console = 1;
						IGUIScrollBar* con_scroll = guienv->addScrollBar(true,rect<s32>(400, 50, 410, 350), 0, GUI_ID_CONSOLE_SCROLL);
						con_scroll->setMax(500);
						con_scroll->setPos(0);
						IGUIListBox* con_win = guienv->addListBox(rect<s32>(50, 50, 400, 350));
						IGUIEditBox* con_edit = guienv->addEditBox(L"Commands go here.", rect<s32>(50, 350, 400, 360));
						guienv->hasFocus(con_edit);
						SAppContext context;
				        context.device = device;
						context.counter = 0;
						context.listbox = con_win;
						// Then create the event receiver, giving it that context structure.
						GuiEvent guirecv(context);
						// And tell the device to use our custom event receiver.
						device->setEventReceiver(&guirecv);
					}
					else
					{
						show_console = 0;
						camera->setInputReceiverEnabled(true);
						device->getCursorControl()->setVisible(false);
						//device->setEventReceiver(&keyboard);
					}
				}
Removing this line "fixes" it, but I don't get the functionality I want (a working receiver):

Code: Select all

device->setEventReceiver(&guirecv);
Here is the actual receiver code:

Code: Select all


#ifndef GUI_H
#define GUI_H

#include "polybius.h"


class GuiEvent : public IEventReceiver
{
public:
        GuiEvent(SAppContext & context) : Context(context) { }

        virtual bool OnEvent(const SEvent& event)
        {
                if (event.EventType == EET_GUI_EVENT)
                {
                        s32 id = event.GUIEvent.Caller->getID();
                        IGUIEnvironment* env = Context.device->getGUIEnvironment();
                        switch(event.GUIEvent.EventType)
                        {
							case EGET_SCROLL_BAR_CHANGED:
                                if (id == GUI_ID_CONSOLE_SCROLL)
                                {
                                        s32 pos = ((IGUIScrollBar*)event.GUIEvent.Caller)->getPos();
                                        
                                        for (u32 i=0; i<EGDC_COUNT ; ++i)
                                        {
                                                SColor col = env->getSkin()->getColor((EGUI_DEFAULT_COLOR)i);
                                                col.setAlpha(pos);
                                                env->getSkin()->setColor((EGUI_DEFAULT_COLOR)i, col);
                                        }
                                        
                                }
                                break;
							case EGET_EDITBOX_ENTER:
								if (id == GUI_ID_CONSOLE_EDIT)
								{
								//	Context.console_command = ((IGUIEditBox*)event.GUIEvent.Caller)->getText();
								//	Context.device->getLogger()->log(Context.console_command.c_str());
								}
								break;
                        default:
                                break;
                        }
                }

                return false;
        }

private:
        SAppContext & Context;
};

#endif
Here is the header, polybius.h:

Code: Select all

#ifndef POLYBIUS_H
#define POLYBIUS_H

//Header for all engine functions
#include <irrlicht.h>
#include <vector>
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

#define VERSION .1a

class KeyboardEvent; //Forward declarations
class ConsoleEvent;

// Declare a structure to hold some context for the event receiver so that it
// has it available inside its OnEvent() method.
struct SAppContext
{
        IrrlichtDevice *device;
        s32             counter;
        IGUIListBox*    listbox;
//		stringw console_command;
};

// Define some values that we'll use to identify individual GUI controls.
enum
{
        //GUI_ID_QUIT_BUTTON = 101,
        //GUI_ID_NEW_WINDOW_BUTTON,
        //GUI_ID_FILE_OPEN_BUTTON,
        GUI_ID_CONSOLE_SCROLL,
		GUI_ID_CONSOLE_EDIT
};

#endif
I put breakpoints at every line on the receiver code, the program jumps to it, hits the constructor and then dies after it hits the problem line. My programming is pretty sloppy and I'm not versed in virtual functions, could anyone help me out?
[/code]

Posted: Tue Apr 26, 2011 8:34 am
by CuteAlien
You set your event-receiver to a local variable. Local variables are created on the stack and destroyed as soon as the scope ends (the scope ends on the } bracket). So when you pass a pointer to that variable to Irrlicht then Irrlicht will use an event-receiver which is already destroyed in memory the next line.

So either use a scope which exist longer (for example global, or in your main() function) or create your event-receiver on the heap instead (using new/delete for your objects).