Pattern for wxNoteBook pages

54 views
Skip to first unread message

Carsten A. Arnholm

unread,
Mar 25, 2011, 3:02:01 PM3/25/11
to wx-u...@lists.wxwidgets.org
wxNoteBook works well for many things I do, but I wonder if there is
something I am missing wrt. the pages it contains and how to use it.

Typically, when the user changes the selected page, something like
OnNotebookPageChanged(wxNotebookEvent& event) is generated.

There, what I normally want is to call something on the selected page to
get that page to do something andt update itself. But how is this best done?

I can get the page as
wxWindow* page = m_notebook->GetPage(event.GetSelection());

But this is a very generic class, and not a "wxPage*" or something like
that.

My question is: Which is the proper way in this case to tell the page to
update itself?

Carsten Arnholm

Vadim Zeitlin

unread,
Mar 25, 2011, 7:20:20 PM3/25/11
to wx-u...@googlegroups.com
On Fri, 25 Mar 2011 20:02:01 +0100 "Carsten A. Arnholm" <arn...@online.no> wrote:

CAA> I can get the page as
CAA> wxWindow* page = m_notebook->GetPage(event.GetSelection());
CAA>
CAA> But this is a very generic class, and not a "wxPage*" or something like
CAA> that.

You can either cast in your own code (as many people do) or spend some
more effort initially and define a custom wxNotebook-derived class that
provides a type-safe accessor to its page corresponding to their real type
in your application to save you the need to have the casts elsewhere.
However you do need a cast somewhere unless you're prepared to store the
pointers to your pages yourself duplicating wxWindow* pointers already
stored by wxNotebook.

CAA> My question is: Which is the proper way in this case to tell the page to
CAA> update itself?

This depends on what do you mean by "update itself". wxWindow does have
methods such as Refresh() and Update() but it's probably not a good idea to
override them and by default they don't do what you want to do, I think.

Regards,
VZ

--
TT-Solutions: wxWidgets consultancy and technical support
http://www.tt-solutions.com/

Carsten A. Arnholm

unread,
Mar 26, 2011, 8:28:01 AM3/26/11
to wx-u...@lists.wxwidgets.org
On 03/26/2011 12:20 AM, Vadim Zeitlin wrote:
> CAA> My question is: Which is the proper way in this case to tell the page to
> CAA> update itself?
>
> This depends on what do you mean by "update itself". wxWindow does have
> methods such as Refresh() and Update() but it's probably not a good idea to
> override them and by default they don't do what you want to do, I think.
>
> Regards,
> VZ
>

Ok, thanks, so it confirms that there wasn't really anything basic I had
missed.

Let me try to explain a little more. I have several times found myself
creating applications that use a database and where the main frame
contains a wxNotebook. In these situations, I tend to use the first tab
to make selections of data from the database (i.e. which info is the
user looking at), and the other tabs are various views on the selected
information.

So when the user switches to any of the "view" tabs, the page must be
told to do whatever it needs to do, which often means to look up the
current selection settings, make some computation + redraw the result. I
found this could easily end up as non-safe if-then-else sections that
would have to be kept in sync with any change in the pages and their order.

So instead, I was thinking:

// abstract interface used for pages in a wxNoteBook or wxChoiceBook
#include <wx/panel.h>

class wxBookCtrlPage : public wxPanel {
public:
wxBookCtrlPage();
virtual ~wxBookCtrlPage();

/// Init is called when page should be (re-)initialised
virtual void Init() = 0;

/// PageSelected is called whenever the current page is selected
virtual void PageSelected() = 0;
};

By doing this, all we need to do in the
wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED handler is cast the selected page
window to wxBookCtrlPage* and call PageSelected(), without having to
manage each page variant separately. Of course, one could even make a
class derived from wxNoteBook that only allowed wxBookCtrlPage pages,
and implemented a wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED handler, that did
the cast and called PageSelected() on behalf of the application.

My original question was whether something like this already existed in
wxWidgets, but it seems not. I am thinking that perhaps what I outlined
above could be a useful, general pattern that could make it easier/safer
to use wxNoteBook/wxChoiceBook as described?

Of course, there might be other approaches that might work too, i.e.
sending custom events to the windows for example. But I tend to prefer
language features over events.

Any comments on these thoughts are most welcome.

Regards
Carsten Arnholm

Vadim Zeitlin

unread,
Mar 27, 2011, 12:17:24 PM3/27/11
to wx-u...@googlegroups.com
On Sat, 26 Mar 2011 13:28:01 +0100 "Carsten A. Arnholm" <arn...@online.no> wrote:

CAA> Let me try to explain a little more. I have several times found myself
CAA> creating applications that use a database and where the main frame
CAA> contains a wxNotebook. In these situations, I tend to use the first tab
CAA> to make selections of data from the database (i.e. which info is the
CAA> user looking at), and the other tabs are various views on the selected
CAA> information.

This is OT but I find this UI pretty strange as according to your
description the first tab is completely different from the other ones while
wxNotebook pages are supposed to be "equal" in some sense.

CAA> class wxBookCtrlPage : public wxPanel {
CAA> public:
CAA> wxBookCtrlPage();
CAA> virtual ~wxBookCtrlPage();
CAA>
CAA> /// Init is called when page should be (re-)initialised
CAA> virtual void Init() = 0;
CAA>
CAA> /// PageSelected is called whenever the current page is selected
CAA> virtual void PageSelected() = 0;
CAA> };
CAA>
CAA> By doing this, all we need to do in the
CAA> wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED handler is cast the selected page
CAA> window to wxBookCtrlPage* and call PageSelected(), without having to
CAA> manage each page variant separately. Of course, one could even make a
CAA> class derived from wxNoteBook that only allowed wxBookCtrlPage pages,
CAA> and implemented a wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED handler, that did
CAA> the cast and called PageSelected() on behalf of the application.

The latter is more or less what I meant.

CAA> My original question was whether something like this already existed in
CAA> wxWidgets, but it seems not. I am thinking that perhaps what I outlined
CAA> above could be a useful, general pattern that could make it easier/safer
CAA> to use wxNoteBook/wxChoiceBook as described?

PageSelected() is not always enough, you can have other methods too. I
also think you could avoid the casts by avoiding the calls to
PageSelected() in the first place and updating the page when it becomes
visible. I'm not sure if handling wxShowEvent works but overriding virtual
Show() method almost certainly should (event is nicer however as then you
can avoid subclassing the pages too and just Connect() it to the notebook
itself).

Carsten A. Arnholm

unread,
Mar 27, 2011, 4:42:05 PM3/27/11
to wx-u...@lists.wxwidgets.org
On 03/27/2011 06:17 PM, Vadim Zeitlin wrote:
> On Sat, 26 Mar 2011 13:28:01 +0100 "Carsten A. Arnholm"<arn...@online.no> wrote:
>
> This is OT but I find this UI pretty strange as according to your
> description the first tab is completely different from the other ones while
> wxNotebook pages are supposed to be "equal" in some sense.

I understand. Sometimes it makes sense though. But as you say it is
really OT wrt. to the issue as the selection stuff could have been done
in a different way, but the question would be the same wrt. wxNotebook.

> Of course, one could even make a
> CAA> class derived from wxNoteBook that only allowed wxBookCtrlPage pages,
> CAA> and implemented a wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED handler, that did
> CAA> the cast and called PageSelected() on behalf of the application.
>
> The latter is more or less what I meant.

I have experimented now with a "wxNotebookAuto" that inherits from
wxNotebook and implements a wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED event
handler using Connect() in the constructor. The handler calls Show(true)
on the selected page. It seems to work.

[ A note on the Connect() call: I may have missed something in the docs,
but I find it difficult to find information on which event handler macro
to use in each case when using Connect(), and similarly which exact
event object type should be used. Eventually I found out by searching
header files that "wxNotebookEventHandler()" was the most likely guess
for the macro in this case. But even with that guess, a search in the
(trunk) docs. gave no hits at all. The documentation for Connect()
mentions a wxObjectEventFunction, but provides no further clues. I am
using 2.8.11 btw. ]

> I'm not sure if handling wxShowEvent works but overriding virtual
> Show() method almost certainly should (event is nicer however as then you
> can avoid subclassing the pages too and just Connect() it to the notebook
> itself).

I use Code::Blocks with wxSmith to create the notebook and pages, and
then you get wxPanel-derived pages. So with the above scheme one must
only implement the virtual bool Show(bool) method for each concrete page.

I will play around with this scheme a little more to see if it answers
my question. So far I think the answer is yes.

Regards
Carsten Arnholm

iko...@earthlink.net

unread,
Mar 27, 2011, 6:22:48 PM3/27/11
to wx-u...@googlegroups.com, wx-u...@lists.wxwidgets.org
Hi, guys,

Using EVT_SHOW for the wxPanel on wxNotebook does not work on wxGTK.
There is a bug open about that. Ticket #12687 with the code example.

Thank you.
>
>Regards
>Carsten Arnholm
>
>--
>Please read http://www.wxwidgets.org/support/mlhowto.htm before posting.
>
>To unsubscribe, send email to wx-users+u...@googlegroups.com
>or visit http://groups.google.com/group/wx-users

Carsten A. Arnholm

unread,
Mar 28, 2011, 6:11:02 PM3/28/11
to wx-u...@lists.wxwidgets.org
On 03/28/2011 12:22 AM, iko...@earthlink.net wrote:
>> I will play around with this scheme a little more to see if it answers
>> my question. So far I think the answer is yes.
>
> Using EVT_SHOW for the wxPanel on wxNotebook does not work on wxGTK.
> There is a bug open about that. Ticket #12687 with the code example.

Ok, thanks for the information. I am not using that event (calling
instead the virtual Show(bool) from the wxNotebook derivative. I have
not had time to test on Linux yet, but that will come soon.

After some testing, I found that I had to explicitly Hide() the pages
that were not selected, or else they would show through the selected one
when I resized the main frame window (wxMSW, wx2.8.11 MSVC 2008
compiler). Slightly surprising, but not a big problem to handle it.

Regards
Carsten Arnholm

Reply all
Reply to author
Forward
0 new messages