wxNotebook on MS-Windows 7 : Won't change panel

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
Virchanza
Experienced Solver
Experienced Solver
Posts: 78
Joined: Sun Jul 19, 2009 6:12 am

wxNotebook on MS-Windows 7 : Won't change panel

Post by Virchanza » Mon Jun 07, 2010 11:36 am

My main dialog window contains a wxNotebook.

The wxNotebook contains 3 panels, which of course can be navigated through by using the 3 tabs at the top of the notebook.

My program works absolutely fine on Linux (wxGTK).

However, I complied it on MS-Windows 7 Ultimate, ran it, but the wxNotebook doesn't work properly. When you click on a tab, the notebook actually changes tab (and it sends the events CHANGING and CHANGED), but it still displays the previous panel... it won't display the new panel corresponding to the tab you clicked???

Has anyone else seen behaviour like this?

I thought it might be something in my code that was causing this, so I decided to create a new empty project in Codeblocks, and I copied my wxFormbuilder project file into the new project. I compiled the program, and again, the same problem with the wxNotebook.

I'm using Ubuntu right now to type this post so I can't post a minimal program that exhibits the problem, but I'll boot into MS-Windows later on and post a small code snippet that shows the problem.

I tried using the wxAuiNotebook in MS-Windows and it works fine, but I wanna use the plain old wxNotebook for simplicity.

User avatar
doublemax
Moderator
Moderator
Posts: 15921
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post by doublemax » Mon Jun 07, 2010 12:39 pm

Sounds like a wrong parenting issue. The pages you add to the wxNotebook must have the notebook as parent.

If that's not it, check if the wxWidgets "notebook" sample shows the same error.
Use the source, Luke!

Virchanza
Experienced Solver
Experienced Solver
Posts: 78
Joined: Sun Jul 19, 2009 6:12 am

Post by Virchanza » Mon Jun 07, 2010 2:10 pm

I checked the code that was auto-generated by wxFormBuilder:

Code: Select all

m_notebook1 = new wxNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxNB_BOTTOM );

m_panel_socket = new wxPanel( m_notebook1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );

m_notebook1->AddPage( m_panel_socket, wxT("Step 1: Open Network Interface"), true );

m_panel_arp = new wxPanel( m_notebook1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );

m_notebook1->AddPage( m_panel_arp, wxT("Step 2: Send ARP Requests"), false );

m_panel_probe = new wxPanel( m_notebook1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );

m_notebook1->AddPage( m_panel_probe, wxT("Step 3: Send Internet Probes"), false );

m_notebook1->Connect( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, wxNotebookEventHandler( Dialog_Main__Auto_Base_Class::On_Tab_Already_Changed ), NULL, this );
m_notebook1->Connect( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, wxNotebookEventHandler( Dialog_Main__Auto_Base_Class::On_Try_Change_Tab ), NULL, this );
Everything looks alright (...unless you notice something?)

I'll try the wxNotebook sample on Win7 later.

Virchanza
Experienced Solver
Experienced Solver
Posts: 78
Joined: Sun Jul 19, 2009 6:12 am

Post by Virchanza » Tue Jun 08, 2010 10:06 am

I figured out the problem.

In my code, I processed two events from the notebook:
OnNotebookPageChanged
OnNotebookPageChanging

Here's my code for "OnNotebookPageChanged":

Code: Select all

void Dialog_Main::OnNotebook1_Page_Changed( wxNotebookEvent& event )
{
    /* All this function does is set the
       default button whenever a new tab
       is selected.
    */

    switch ( event.GetSelection() )
    {
    case 0: /* Step 1: Open Network Interface */

        m_button_Toggle_Open_Interface->SetDefault();
        m_combo_NetworkInterface->SetFocus();
        break;

    case 1: /* Step 2: Send ARP Requests */

        m_arptab_button_Toggle_Send_ARPs->SetDefault();
        m_arptab_txt_networks->SetFocus();
        break;

    case 2: /* Step 3: Send Internet Probes */

        m_probetab_button_Toggle_Send_Probes->SetDefault();
        m_probetab_txt_mac_src->SetFocus();
        break;

    default:

        assert("What the $%^&'s going on?!" == 0);
    }
}
This code works absolutely fine on GTK, but it's problematic on MS-Windows 7 Ultimate because it doesn't display the newly selected panel (the tab changes but it still displays the old panel).

The remedy is to add the following line to the end of that function:

Code: Select all

event.Skip();
This makes it work properly on MS-Windows 7 Ultimate.

Is this behaviour "acceptable" on the MS-Windows port of wxWidgets?

How should I know when to call Skip and when not to call Skip when I handle an event?

I decided to write "event.Skip()" at the end of my other event handler too (the event handler of PageChanging), but ironically this broke my program! If I call Skip at the end of the Page_Changing event handler, it ignores the previous call I made to event.Veto() and the tab control navigates to a tab which is supposed to be off-limits!

User avatar
doublemax
Moderator
Moderator
Posts: 15921
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post by doublemax » Tue Jun 08, 2010 1:02 pm

There must be something else going on, you shouldn't need event.Skip() here.

I checked one of my projects with a wxNoteBook and the wxWidgets notebook sample, and they both work fine on Windows 7 (without event.Skip() )

Try comparing your code to the sample, maybe you can spot a difference.
Use the source, Luke!

Virchanza
Experienced Solver
Experienced Solver
Posts: 78
Joined: Sun Jul 19, 2009 6:12 am

Post by Virchanza » Wed Jun 09, 2010 8:09 am

OK I've tried to put together minimalistic code that demonstrates this problem.

First of all let me tell you what I did on MS-Windows 7 Ultimate. I downloaded the code for wxMSW, and I compiled it as follows:

Code: Select all

mingw32-make -f makefile.gcc BUILD=debug UNICODE=1 SHARED=0 RUNTIME_LIBS=static
mingw32-make -f makefile.gcc BUILD=release UNICODE=1 SHARED=0 RUNTIME_LIBS=static
I used wxFormBuilder to design a simple dialog box containing a wxNotebook, and I took the code from it and used it to make a little sample program which exhibits the problem I've described.

Here's the code for my sample program (I've condensed it into one source file):

Code: Select all

#ifdef WX_PRECOMP
#include "wx_pch.h"
#endif

#include <wx/app.h>

#include "wx/wxprec.h"

#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif

#include <wx/string.h>
#include <wx/button.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/sizer.h>
#include <wx/panel.h>
#include <wx/bitmap.h>
#include <wx/image.h>
#include <wx/icon.h>
#include <wx/combobox.h>
#include <wx/checkbox.h>
#include <wx/notebook.h>
#include <wx/dialog.h>

class Dialog_Main : public wxDialog {
protected:

    wxNotebook* m_notebook1;
    wxPanel* m_panel1;
    wxButton* m_button3;
    wxPanel* m_panel2;
    wxComboBox* m_comboBox1;
    wxPanel* m_panel3;
    wxCheckBox* m_checkBox1;

    virtual void OnClose( wxCloseEvent& event )
    {
        Destroy();
    }

    void OnNotebook_Page_Changed( wxNotebookEvent& event )
    {
        /* event.Skip(); */

        /* We don't Skip the event */
    }

public:
    Dialog_Main( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT("wxWidgets Application Template"), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 366,308 ), long style = wxDEFAULT_DIALOG_STYLE );

    ~Dialog_Main()
    {
        m_notebook1->Disconnect( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, wxNotebookEventHandler( Dialog_Main::OnNotebook_Page_Changed ), NULL, this );
        this->Disconnect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( Dialog_Main::OnClose ) );
    }
};

Dialog_Main::Dialog_Main( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : wxDialog( parent, id, title, pos, size, style )
{
	this->SetSizeHints( wxDefaultSize, wxDefaultSize );

	wxBoxSizer* bSizer1;
	bSizer1 = new wxBoxSizer( wxHORIZONTAL );

	m_notebook1 = new wxNotebook( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, 0 );
	m_panel1 = new wxPanel( m_notebook1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
	wxBoxSizer* bSizer3;
	bSizer3 = new wxBoxSizer( wxVERTICAL );

	m_button3 = new wxButton( m_panel1, wxID_ANY, wxT("MyButton"), wxDefaultPosition, wxDefaultSize, 0 );
	bSizer3->Add( m_button3, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5 );

	m_panel1->SetSizer( bSizer3 );
	m_panel1->Layout();
	bSizer3->Fit( m_panel1 );
	m_notebook1->AddPage( m_panel1, wxT("Panel has button"), true );
	m_panel2 = new wxPanel( m_notebook1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
	wxBoxSizer* bSizer4;
	bSizer4 = new wxBoxSizer( wxVERTICAL );

	m_comboBox1 = new wxComboBox( m_panel2, wxID_ANY, wxT("Combo!"), wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
	bSizer4->Add( m_comboBox1, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );

	m_panel2->SetSizer( bSizer4 );
	m_panel2->Layout();
	bSizer4->Fit( m_panel2 );
	m_notebook1->AddPage( m_panel2, wxT("Panel has combo box"), false );
	m_panel3 = new wxPanel( m_notebook1, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL );
	wxBoxSizer* bSizer5;
	bSizer5 = new wxBoxSizer( wxVERTICAL );

	m_checkBox1 = new wxCheckBox( m_panel3, wxID_ANY, wxT("Check Me!"), wxDefaultPosition, wxDefaultSize, 0 );

	bSizer5->Add( m_checkBox1, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 5 );

	m_panel3->SetSizer( bSizer5 );
	m_panel3->Layout();
	bSizer5->Fit( m_panel3 );
	m_notebook1->AddPage( m_panel3, wxT("Panel has check box"), false );

	bSizer1->Add( m_notebook1, 1, wxEXPAND | wxALL, 5 );

	this->SetSizer( bSizer1 );
	this->Layout();

	// Connect Events
	this->Connect( wxEVT_CLOSE_WINDOW, wxCloseEventHandler( Dialog_Main::OnClose ) );
	m_notebook1->Connect( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, wxNotebookEventHandler( Dialog_Main::OnNotebook_Page_Changed ), NULL, this );
}

class Notebook_ProblemApp : public wxApp
{
public:

    virtual bool OnInit()
    {
        Dialog_Main *dlg = new Dialog_Main(0L);

        if (!dlg)
            return false;

        dlg->Show();

        return true;
    }
};

IMPLEMENT_APP(Notebook_ProblemApp);
I compiled it in Release Mode on my own computer running MS-Windows 7, here's the executable:

http://virjacode.com/stuff/Notebook_Problem.exe

If I edit the code so that the PAGE_CHANGED event gets Skip'ed at the end, the problem goes away.

User avatar
doublemax
Moderator
Moderator
Posts: 15921
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Post by doublemax » Wed Jun 09, 2010 9:50 am

Your sample showed the problem even on XP.

I don't know why it makes a difference, but it started working when i changed this:

Code: Select all

m_notebook1->Connect( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, wxNotebookEventHandler( Dialog_Main::OnNotebook_Page_Changed ), NULL, this );
To:

Code: Select all

this->Connect( wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, wxNotebookEventHandler( Dialog_Main::OnNotebook_Page_Changed ));
Maybe wxDialog has some additional default event processing or so, i really have no idea.

BTW: The Disconnect() calls in the dtor are unnecessary because the objects get destroyed anyway.
Use the source, Luke!

Virchanza
Experienced Solver
Experienced Solver
Posts: 78
Joined: Sun Jul 19, 2009 6:12 am

Post by Virchanza » Wed Jun 09, 2010 10:39 am

Just so you know, that code was generated by wxFormBuilder.

When you use wxFormBuilder to handle events, it automatically writes the code, and for the PAGE_CHANGED event it came out with:

Code: Select all

m_notebook1->Connect(...
Instead of:

Code: Select all

this->Connect(...
I'm pretty new to wxWidgets and I don't know much at all about how it works under-the-hood, so really I haven't a clue what's going on.

Thanks for the tip about not having to Disconnect (wxFormBuilder wrote that code for me, but it gives an option where you can tell it not to Disconnect).

Virchanza
Experienced Solver
Experienced Solver
Posts: 78
Joined: Sun Jul 19, 2009 6:12 am

Post by Virchanza » Mon Jun 14, 2010 10:10 am

Any news on this?

Should I report a bug?

Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria » Mon Jun 14, 2010 11:49 pm

This is very subtle behavior; if no one else here knows, I may recommend asking on the mailing list, where you can reach wxWidgets authors.

Another possibility, if you can, is to try the code under another platform; if there is a different behavior between platform then it is almost always right to open a bug report
"Keyboard not detected. Press F1 to continue"
-- Windows

Virchanza
Experienced Solver
Experienced Solver
Posts: 78
Joined: Sun Jul 19, 2009 6:12 am

Post by Virchanza » Tue Jun 15, 2010 9:50 am

Auria wrote:This is very subtle behavior; if no one else here knows, I may recommend asking on the mailing list, where you can reach wxWidgets authors.

Another possibility, if you can, is to try the code under another platform; if there is a different behavior between platform then it is almost always right to open a bug report
I've tried it on Ubuntu Lucid Lynx using wxGTK, and this weird behaviour doesn't happen at all.

So far I've only seen it on wxMSW.

Auria
Site Admin
Site Admin
Posts: 6695
Joined: Thu Sep 28, 2006 12:23 am
Contact:

Post by Auria » Tue Jun 15, 2010 4:55 pm

This is probably a good candidate for bug report, then
"Keyboard not detected. Press F1 to continue"
-- Windows

Post Reply