Guidance
指路人
g.yi.org
Guidance Forums / wxWidgets (wxWindows) in C++ / problems (wxWindows 2.4.2) with putting controls in different classes and in different files

Register 
注册
Search 搜索
首页 
Home Home
Software
Upload

  
Forum List • Thread List • Refresh • New Topic • Search • Previous • Next First 1 Last
Message1. problems (wxWindows 2.4.2) with putting controls in different classes and in different files
#2868
Posted by: jmoliere 2003-11-08 02:32:30
Hello,
I have been playing with wxWindows and the calendar sample that comes with wxWindows.  I broke up the calendar into seperate classes and moved all the event handling to MyFrame.  I did all this just to see wxWindows perform event handling from different classes.

You can find the source at
http://www.molamini.com/wx/calendar.zip

I have only developed this on a Windows environment (VC++ .Net) -- I don't know how to make Makefiles for Unix so I hope this problem is only specific to Windows

The problem is that I get a runtime exception when the code executes
this->m_date->SetLabel(*date);//
in the method
void MyPanel2::SetSelectedDateLabel(const wxString* date)

I tried using the wxTextCtrl and the wxStaticText to no avail.

After showing this problem to a colleague, he said that it's a bug with wxWindows.  I'd like to verify this also.

Can someone explain why this code fails?

Thanks!



Post Edited (11-09-03 23:39)
James Moliere
wxWindows@molamini.com
Message2. Re: problems (wxWindows 2.4.2) with putting controls in different classes and in different files
#2869
Posted by: jmoliere 2003-11-08 10:14:49
It is interesting that all examples of wxWindows have the classes and code ALL in 1 file.  It appears that there's a bug that keeps samples from being able to be broken up into seperate files.

For those that are interested, there seems to be a SERIOUS problem with Activation Records (Stack Frames) with WxWindows.

Here's the problem
The program in the previous message basically has 2 classes, 1) MyFrame and 2) MyPanel2.  I set all event handling of MyFrame and MyPanel2 in MyFrame -- I do this because this is my style of programming. 

I run the program and everything starts fine.  When I click a date, my program tries to change the variable m_date (from MyPanel2) to the date selected (causing the runtime error).  The path of execution is MyFrame->OnCalendarChange gets called.  Inside OnCalendarChange, the method this->m_panel->SetSelectedDateLabel(&s); gets called.  Inside the SetSelectedDateLabel is 1 method (when executed causes a runtime error when executed).  The method is

this->m_date->SetLabel(*date);


The problem is that the 'this' in MyPanel when executing 'SetSelectedDatelabel' is not pointing to the right location.  On VC++ .Net, it should point to address '0x00a11bc0' but it points to address '0x00520b3c' (const wxWindowListNode:: 'vftable').

This seems to be a very serious bug.
James Moliere



Post Edited (11-08-03 13:16)
James Moliere
wxWindows@molamini.com
Message3. Re: problems (wxWindows 2.4.2) with putting controls in different classes and in different files
#2875
Posted by: upCASE 2003-11-11 04:13:58
Hi James!
I had a look at your source and after playing with it I actually got it to work.
The problem isn't really wxWindows, but your style of coding :)
No, sorry, I don't want to start a flame war or something. It's just that your understanding of how the event tables work isn't quite correct.
In your example, all event handling stuff is managed by your MyFrame class. But when you set up the event tables, you defined one for MyPanel2, too.

To solve your problem:
1. Define your event table like this

BEGIN_EVENT_TABLE(MyFrame, wxFrame)

    EVT_MENU(Calendar_File_Quit,  MyFrame::OnQuit)
    EVT_MENU(Calendar_File_About, MyFrame::OnAbout)
 ...
 ...
 ...
    EVT_UPDATE_UI(Calendar_Cal_Year, MyFrame::OnAllowYearUpdate)
    
    EVT_CALENDAR            (Calendar_CalCtrl,   MyFrame::OnCalendar)
    EVT_CALENDAR_MONTH      (Calendar_CalCtrl,   MyFrame::OnCalMonthChange)
    EVT_CALENDAR_YEAR       (Calendar_CalCtrl,   MyFrame::OnCalYearChange)
    EVT_CALENDAR_SEL_CHANGED(Calendar_CalCtrl,   MyFrame::OnCalendarChange)
    EVT_CALENDAR_WEEKDAY_CLICKED(Calendar_CalCtrl, MyFrame::OnCalendarWeekDayClick)
    
END_EVENT_TABLE()

2. Comment out the event table for MyPanel2
3. Don't declare an event table for MyPanel2 (meaning no DECLARE_EVENT_TABLE() in MyPanel2.h

That's all I did to make it run (except I had to add some headers you missed, because gcc doesn't use precompiled headers). And trust me, it really works.

upcase
upCASE
-----------------------------------
If it was hard to write, it should be hard to read!- Do. Or do not. There is no try!
Message4. Re: problems (wxWindows 2.4.2) with putting controls in different classes and in different files
#2877
Posted by: jmoliere 2003-11-11 06:13:04
upCASE (Ren¨?),
No flames from me!  Just warmth and high fives. 

I'm new to WxWindows and I'd like to use it on my next project.  My lack of understanding of this library I'm sure is obvious.  What's funny is, if I move all the code in MyPanel2 back to calendar.  The code runs fine.  By simply seperating the classes to their respective class file, this library had problems.

I don't remember ever losing a pointer to 'this' on a method call so I had to point this problem out -- it was also driving me nuts.

Thanks!

Take care!

James Moliere
wxWindows@molamini.com
Message5. Re: problems (wxWindows 2.4.2) with putting controls in different classes and in
#2878
Posted by: upCASE 2003-11-11 18:21:42
Hi James!
Well, you're quite right. I was puzzled too that I lost the tis pointer on that specific method call, while other calls worked perfectly and the string you passed was there...
To me this seems like a problem with the event table macros and maybe seperate compilation, although I normally use seperate compilation and it works fine. The way you implemented the event tables does not seem to be the API want's you to do it :)
Maybe you could solve this problem in another way. There are fucntions for plugging event handlers dynamically, like the "Java"-way, and not setting up event tables. But I have to confess, I never used them, because until now the macros worked fine for me. I'll have a look into that matter later this day when I'm back home.

Meanwhile, have you considered posting your thoughts and findings to the wxWindows mailing list? This forum is normally more a base for newbies and advanced users using wxWindows together with Dev-C++ and not frequented by the wxWindows developers (I think). Since this is really a weird "bug" (carefull with that term :) I don't want my head chopped off) it may be of interest for the developers to know about it. You could also send a private mail to Julian or Robert, I guess they'll be the ones to know more about the event handling routines.

Till then: Good luck and happy coding!
upCASE (the name is René :))

btw: Appart from your problem wxWindows is really a nice lib. I used MFC and Qt before, but somehow I allways wished I had used wxWindows...
upCASE
-----------------------------------
If it was hard to write, it should be hard to read!- Do. Or do not. There is no try!
Message6. Re: problems (wxWindows 2.4.2) with putting controls in different classes and in
#2887
Posted by: jmoliere 2003-11-14 13:58:37
upCASE,

You said in your previous message,

"Maybe you could solve this problem in another way. There are fucntions for plugging event handlers dynamically, like the "Java"-way, and not setting up event tables."

Can you elaborate on what you mean by the Java way?  I'm looking at the manual at the link below and am interested in programming wxWindows the java way.

http://www.wxwindows.org/manuals/2.4.2/wx449.htm#overviews

I don't see anything in the form of listeners.  I'm interested because I'd like to get away from passing some ID for every control I want to receive an event from.

BTW, I didn't get very far in my evaluation of wxWindows because of the calendar issue.

Thanks!

James Moliere
wxWindows@molamini.com
Message7. Re: problems (wxWindows 2.4.2) with putting controls in different classes and in different files
#2894
Posted by: upCASE 2003-11-16 19:41:14
Hi!
Ok, maybe my expression "java way" was a bit too much. I should have said "java-like way".
Problem is that you can't get totaly rid of the IDs, because of the underlying API (meaning win32 API on windows and GTK on linux). I'm no expert on GTK, but have some experience with win32 API.
On Windows every window or control has it's own ID, meaning a positive number that should be unique to this window. Windows manages events with callback functions and event loops. For example when you program a dialog, this dialog will have a callback function that handles all events. You normally have a switch() case construct in it to determine what kind of event has just occured, like  WM_LBUTTONDOWN for "left mouse button down" or BM_CLICKED for "a button was clicked" (meaning inside the client area of that button WM_LBUTTONDOWN and WM_LBUTTONUP happend). These platform specific events are wrapped up in wxWindows with the wxEvent classes containing information about the events and command IDs like wxEVT_COMMAND_BUTTON_CLICKED to handle them inside the underlying loops.

Now, you could go and assign -1 or NULL as the controls ID. This is totaly ok, but might be confusing when working with event table macros. Normally you give a button an ID and set up an event table, so that if an event occurs where the ID of the emiting control is that of the button, you know what function gets called.
You could use wxID_ANY as an ID for more then one button and then have one event table entry calling one function for all buttons. Sure, then the function would have to look up what button was pressed and take the correct actions.

What I meant now by "java-like way" is, that you don't have to setup event tables and use the DECLARE_EVENT_TABLE() macro. Instead you can use wxEvtHandler::Connect() and wxEvtHandler::Disconnect() to assign the event functions dynamically. There is no such thing as a Java listener however...
Using a listener you would normally just add the button listener to the button and override the actionPerformed() method (it has been some time since I last did Java :)). So, when the button is pressed, actionPerformed() is called and everything is fine.
Using wxWindows there is no "standard" method like actionPerformed() that is called. Instead you'll have to specify the exact function yourself. I did a little example for using Connect(). I think it is the most "java-like" it can get under wxWindows. But if you like I'm pretty sure you could program something like listeners for wxWindows, but currently there is no such thing.

buttonevent.h:

#include <wx/event.h>

class ButtonEvent
{
public:
    ButtonEvent(){wxMessageBox("Hi");}
    void OnButton(wxEvent& e){
        wxButton* b = (wxButton*)e.GetEventObject();
        wxMessageBox( "Label is:n"+ b->GetLabel());
        }
};

MyFrame.cpp

#include "MyFrame.h"
#include "buttonevent.h"

MyFrame::MyFrame(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style):
    wxFrame(parent, id, title, pos, size, wxDEFAULT_FRAME_STYLE)
{
    // begin wxGlade: MyFrame::MyFrame
    button_1 = new wxButton(this, -1, wxT("Please press me, I'm dynamically connected..."));
    button_2 = new wxButton(this, -1, wxT("Hi, I'm the second button using the ButtonEvent class"));

    set_properties();
    do_layout();
    // end wxGlade
    
    button_1->Connect(-1,wxEVT_COMMAND_BUTTON_CLICKED,
                        (wxObjectEventFunction)
                        &MyFrame::OnButton);
                        
    button_2->Connect(-1,wxEVT_COMMAND_BUTTON_CLICKED,
                        (wxObjectEventFunction)
                         &ButtonEvent::OnButton);
}

void MyFrame::OnButton(wxEvent& e)
{
    wxMessageBox("Hello");
    
}
void MyFrame::set_properties()
{
    // begin wxGlade: MyFrame::set_properties
    SetTitle(wxT("frame_1"));
    // end wxGlade
}


void MyFrame::do_layout()
{
    // begin wxGlade: MyFrame::do_layout
    wxBoxSizer* sizer_1 = new wxBoxSizer(wxVERTICAL);
    wxBoxSizer* sizer_3 = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer* sizer_2 = new wxBoxSizer(wxHORIZONTAL);
    sizer_2->Add(button_1, 0, wxALIGN_CENTER_VERTICAL, 0);
    sizer_1->Add(sizer_2, 1, wxALIGN_CENTER_HORIZONTAL, 0);
    sizer_3->Add(button_2, 0, wxALIGN_CENTER_VERTICAL, 0);
    sizer_1->Add(sizer_3, 1, wxALIGN_CENTER_HORIZONTAL, 0);
    SetAutoLayout(true);
    SetSizer(sizer_1);
    sizer_1->Fit(this);
    sizer_1->SetSizeHints(this);
    Layout();
    // end wxGlade
}

MyFrame.h

#include <wx/wx.h>
#include <wx/image.h>

#ifndef MYFRAME_H
#define MYFRAME_H

// begin wxGlade: dependencies
// end wxGlade


class MyFrame: public wxFrame {
public:
    MyFrame(wxWindow* parent, int id, const wxString& title, const wxPoint& pos=wxDefaultPosition, const wxSize& size=wxDefaultSize, long style=wxDEFAULT_FRAME_STYLE);

private:
    // begin wxGlade: MyFrame::methods
    void set_properties();
    void do_layout();
    // end wxGlade
    void OnButton(wxEvent& e);
protected:
    // begin wxGlade: MyFrame::attributes
    wxButton* button_1;
    wxButton* button_2;
    // end wxGlade
};

#endif // MYFRAME_H

main.cpp

#include <wx/wx.h>
#include <wx/image.h>
#include "MyFrame.h"



class MyApp: public wxApp {
public:
    bool OnInit();
};

IMPLEMENT_APP(MyApp)

bool MyApp::OnInit()
{
    wxInitAllImageHandlers();
    MyFrame* frame_1 = new MyFrame(0, -1, "");
    SetTopWindow(frame_1);
    frame_1->Show();
    return true;
}

Here, ButtonEvent is something like a listener, but you'll still have to specify that ButtonEvent::OnButton() is to be called if the event happens when using Connect().

I hope I made myself clear, because I feel a bit tired and I think I talked a bit gibberish...

You should really start using wxWindows and learn/adapt the way wxWindows handles events. I know it is quite unusual coming from Java, but you won't find a toolkit for C++ GUI programming that uses exactly the "Java way" of event handling. You can take a look at Qt from Trolltech for example. It's another good and complete framework, but actually the event handling they use made me skip to wxWindows, because it's just so weird...

If you have questions, feel free to post them ;)

upcase

upCASE
-----------------------------------
If it was hard to write, it should be hard to read!- Do. Or do not. There is no try!
Forum List • Thread List • Refresh • New Topic • Search • Previous • Next First 1 Last
掌柜推荐
 
 
 
 
 
 
 
 
 
 
 
 
© Mon 2024-10-7  Guidance Laboratory Inc.
Email:webmaster1g.yi.org Hits:0