Container Windows

team bbl


Container windows are designed to hold further visual elements, either child windows or graphics drawn on the window.

wxPanel

wxPanel is essentially a wxWindow with some dialog-like properties. This is usually the class to use when you want to arrange controls on a window that's not a wxDialog, such as a wxFrame. It's often used for pages of a wxNotebook. wxPanel normally takes the system dialog color.

As with wxDialog, you can use InitDialog to send a wxInitDialogEvent to the panel, transferring data to the panel via validators or other means. wxPanel also handles navigation keys such as the Tab key to provide automatic traversal between controls, if the wxTAB_TRAVERSAL style is provided.

wxPanel has the following constructor in addition to the default constructor:

 wxPanel(wxWindow* parent, wxWindowID id,     const wxPoint& pos = wxDefaultPosition,     const wxSize& size = wxDefaultSize,     long style = wxTAB_TRAVERSAL|wxNO_BORDER,     const wxString& name = wxT("panel")); 

For example:

 wxPanel* panel = new wxPanel(frame, wxID_ANY,     wxDefaultPosition, (500, 300)); 

wxPanel Styles

There are no specific styles for wxPanel, but see the styles for wxWindow.

wxPanel Member Functions

There are no distinct wxPanel functions; please refer to the wxWindow member functions, inherited by wxPanel.

wxNotebook

This class represents a control with several pages, switched by clicking on tabs along an edge of the control. A page is normally a wxPanel or a class derived from it, although you may use other window classes.

Notebook tabs may have images as well as, or instead of, text labels. The images are supplied via a wxImageList (see Chapter 10), and specified by position in the list.

To use a notebook, create a wxNotebook object and call AddPage or InsertPage, passing a window to be used as the page. Do not explicitly destroy the window for a page that is currently managed by wxNotebook; use DeletePage instead, or let the notebook destroy the pages when it is itself destroyed.

Here's an example of creating a notebook with three panels, and a text label and icon for each tab:

 #include "wx/notebook.h" #include "copy.xpm" #include "cut.xpm" #include "paste.xpm" // Create the notebook wxNotebook* notebook = new wxNotebook(parent, wxID_ANY,   wxDefaultPosition, wxSize(300, 200)); // Create the image list wxImageList* imageList = new wxImageList(16, 16, true, 3); imageList->Add(wxIcon(copy_xpm)); imageList->Add(wxIcon(paste_xpm)); imageList->Add(wxIcon(cut_xpm)); // Create and add the pages wxPanel1* window1 = new wxPanel(notebook, wxID_ANY); wxPanel2* window2 = new wxPanel(notebook, wxID_ANY); wxPanel3* window3 = new wxPanel(notebook, wxID_ANY); notebook->AddPage(window1, wxT("Tab one"), true, 0); notebook->AddPage(window2, wxT("Tab two"), false, 1); notebook->AddPage(window3, wxT("Tab three"), false 2); 

Figure 4-9 shows the result on Windows.

Figure 4-9. A wxNotebook


On most platforms, there are scroll buttons to view tabs that cannot all be displayed on the window at once. However, on Mac OS, the tabs do not scroll, so the number you can display is limited by the window and tab label size.

If you use sizers to lay out controls on individual pages, and pass wxDefaultSize to the notebook constructor, wxNotebook will adjust its size to fit the sizes of its pages.

Notebook Theme Management

On Windows XP, the default theme paints a gradient on the notebook's pages. Although this is the expected native behavior, it can slow down performance, and you may prefer a solid background for aesthetic reasons, especially when the notebook is not being used in a dialog. If you want to suppress themed drawing, there are three ways of doing it. You can use the wxNB_NOPAGETHEME style to disable themed drawing for a particular notebook, you can call wxSystemOptions::SetOption to disable it for the whole application, or you can disable it for individual pages by using SetBackgroundColour. To disable themed pages globally, do this:

 wxSystemOptions::SetOption(wxT("msw.notebook.themed-background"), 0); 

Set the value to 1 to enable it again. To give a single page a solid background that matches the current theme, use

 wxColour col = notebook->GetThemeBackgroundColour(); if (col.Ok()) {     page->SetBackgroundColour(col); } 

On platforms other than Windows, or if the application is not using Windows themes, GetThemeBackgroundColour will return an uninitialized color object, and this code will therefore work on all platforms. Please note that this syntax and behavior is subject to change, so refer to the wxNotebook documentation in your wxWidgets distribution for the latest information.

wxNotebook Styles

wxNotebook can have the window styles listed in Table 4-11, in addition to those described for wxWindow.

Table 4-11. wxNotebook Styles

wxNB_TOP

Place tabs on the top side.

wxNB_LEFT

Place tabs on the left side. Not supported under Windows XP for all themes.

wxNB_RIGHT

Place tabs on the right side. Not supported under Windows XP for all themes.

wxNB_BOTTOM

Place tabs under instead of above the notebook pages. Not supported under Windows XP for all themes.

wxNB_FIXEDWIDTH

All tabs will have same width. Windows only.

wxNB_MULTILINE

There can be several rows of tabs. Windows only.

wxNB_NOPAGETHEME

On Windows, suppresses the textured theme painting for the notebook's pages, drawing a solid color to match the current theme instead. This can improve performance in addition to giving an aesthetic choice.


wxNotebook Events

wxNotebook generates wxNotebookEvent propagating events (events that can be handled by the notebook or its ancestors) specified in Table 4-12.

Table 4-12. wxNotebook Events

EVT_NOTEBOOK_PAGE_CHANGED(id, func)

The page selection has changed.

EVT_NOTEBOOK_PAGE_CHANGING(id, func)

The page selection is about to change. You can veto the selection change with Veto.


wxNotebook Member Functions

These are the major wxNotebook functions.

AddPage adds a page, and InsertPage inserts a page at the given position. You can use a text label for the tab, or an image (specified by index into an image list), or both. For example:

 // Adds an unselected page with a label and an image // (index 2 in the associated image list). notebook->AddPage(page, wxT("My tab"), false, 2); 

DeletePage removes and destroys the specified page, while RemovePage just removes the page without deleting the page. Call DeleteAllPages to delete all the pages. When the wxNotebook is deleted, it will delete all its pages.

AdvanceSelection cycles through the pages, and SetSelection sets the specified page by zero-based index. Use GetSelection to get the index of the selected page, or wxNOT_FOUND if none was selected.

SetImageList sets a wxImageList to be used by the notebook but does not take ownership of it. Call AssignImageList if you want the notebook to delete the image list when it is destroyed. GetImageList returns the associated image list. An image list stores images to be shown on each page tab, if required. wxImageList is described in Chapter 10.

Use GetPage to return the page window for a given index, and use GetPageCount to return the number of pages in the notebook.

SetPageText and GetPageText are accessors for the label for a given page (by index).

SetPageImage and GetPageImage are accessors for the index of a page's image index in the notebook's image list.

Alternatives to wxNotebook

wxNotebook is derived from a base class wxBookCtrlBase, which abstracts the concept of a control that manages pages. There are two API-compatible variations of the wxNotebook concept, wxListbook and wxChoicebook, and you can implement your own, such as wxtreebook.

wxListbook uses a wxListCtrl to change pages; the list control displays icons with text labels underneath them, and can be on any of the four sides, defaulting to the left side. This is an attractive alternative to wxNotebook, and it has the advantage of being able to cope with an arbitrary number of pages even on Mac OS X because the list control can scroll.

wxChoicebook uses a choice control (a drop-down list) and is particularly handy for small devices with restricted screen space, such as smartphones. It does not display images, and by default, it will display the choice control at the top.

The include files for these classes are wx/listbook.h and wx/choicebk.h. Event handlers for these two classes take a wxListbookEvent or wxChoicebookEvent argument, respectively, and you can use the event macros EVT_XXX_PAGE_CHANGED(id, func) and EVT_XXX_PAGE_CHANGING(id, func) where XXX is LISTBOOK or CHOICEBOOK.

You can use the same window styles as wxNotebook, or you can use the equivalents, such as wxCHB_TOP or wxLB_TOP instead of wxNB_TOP.

wxScrolledWindow

All windows can have scrollbars, but extra code is required to make scrolling work. This gives the flexibility to define appropriate scrolling behaviors for different kinds of windows. wxScrolledWindow implements commonly required scrolling behavior by assuming that scrolling happens in consistent units, not different-sized jumps, and that page size (the amount scrolled when "paging" up, down, left, or right) is represented by the visible portion of the window. It is suited to drawing applications but is not so suitable for a sophisticated editor in which the amount scrolled may vary according to the size of text on a given line. For this, you would derive from wxWindow and implement scrolling yourself. wxGrid is an example of a class that implements its own scrolling, largely because columns and rows can vary in size.

To use a scrolled window, you need to define the number of pixels per logical scroll unit (how much the window is scrolled for a line up or down scroll event) and provide the virtual size in logical units. wxScrolledWindow will then take care of showing the scrollbars with appropriately sized "thumbs" (the parts you can drag) and will show or hide scrollbars as appropriate, according to the actual size of the window.

The following fragment shows how to create a scrolled window:

 #include "wx/scrolwin.h" wxScrolledWindow* scrolledWindow = new wxScrolledWindow(     this, wxID_ANY, wxPoint(0, 0), wxSize(400, 400),     wxVSCROLL|wxHSCROLL); // Set up virtual window dimensions. It will be 1000x1000 // and will scroll 10 pixels at a time int pixelsPerUnixX = 10; int pixelsPerUnixY = 10; int noUnitsX = 1000; int noUnitsY = 1000; scrolledWindow->SetScrollbars(pixelsPerUnitX, pixelsPerUnitY,     noUnitsX, noUnitsY); 

A second way to specify the virtual size is to use SetVirtualSize, which takes the virtual size in pixels, plus a call to SetScrollRate to set the horizontal and vertical scrolling increments. A third way is to set a sizer for the window, and the scrolled window will calculate the required scrollbar dimensions from the space taken up by the child windows. You will still need to call SetScrollRate to specify the scrolling increments.

You can provide a paint event handler as normal, but in order to draw the graphics at the appropriate position for the current positions of the scrollbars, call DoPrepareDC before drawing. This sets the device context's device origin. For example:

 void MyScrolledWindow::OnPaint(wxPaintEvent& event) {     wxPaintDC dc(this);     DoPrepareDC(dc);     dc.SetPen(*wxBLACK_PEN);     dc.DrawLine(0, 0, 100, 100); } 

Alternatively, you can override the OnDraw virtual function; wxScrolledWindow creates a paint device context and calls DoPrepareDC for you before calling your OnDraw function, so the code simplifies to the following:

 void MyScrolledWindow::OnDraw(wxDC& dc) {     dc.SetPen(*wxBLACK_PEN);     dc.DrawLine(0, 0, 100, 100); } 

Note that you will need to call DoPrepareDC if you draw on the window from outside the paint event, such as within a mouse event handler.

You can provide your own DoPrepareDC function. The default function simply shifts the device origin according to the current scroll positions so that subsequent drawing will appear at the right place:

 void wxScrolledWindow::DoPrepareDC(wxDC& dc) {     int ppuX, ppuY, startX, startY;     GetScrollPixelsPerUnit(& ppuX, & ppuY);     GetViewStart(& startX, & startY);     dc.SetDeviceOrigin( - startX * ppuX, - startY * ppuY ); } 

For more on painting on a wxScrolledWindow, including using buffered drawing, please see the section on wxPaintDC in Chapter 5, "Drawing and Printing."

wxScrolledWindow Styles

There are no special styles for wxScrolledWindow, but usually you will supply wxVSCROLL|wxHSCROLL (the default style for wxScrolledWindow). On some platforms, if these styles are not present, no scrollbars will be provided for efficiency reasons.

wxScrolledWindow Events

wxScrolledWindow generates wxScrollWinEvent events (see Table 4-13). These events do not propagate up the window parent-child hierarchy, so if you want to intercept these events, you must derive a new class or plug an event handler object into the window object. Normally you will not need to override the existing handlers for these events.

Table 4-13. wxScrolledWindow Events

EVT_SCROLLWIN(func)

Handles all scroll events.

EVT_SCROLLWIN_TOP(func)

Handles wxEVT_SCROLLWIN_TOP scroll-to-top events.

EVT_SCROLLWIN_BOTTOM(func)

Handles wxEVT_SCROLLWIN_TOP scroll-to-bottom events.

EVT_SCROLLWIN_LINEUP(func)

Handles wxEVT_SCROLLWIN_LINEUP line up events.

EVT_SCROLLWIN_LINEDOWN(func)

Handles wxEVT_SCROLLWIN_LINEDOWN line down events.

EVT_SCROLLWIN_PAGEUP(func)

Handles wxEVT_SCROLLWIN_PAGEUP page up events.

EVT_SCROLLWIN_PAGEDOWN(func)

Handles wxEVT_SCROLLWIN_PAGEDOWN page down events.


wxScrolledWindow Member Functions

These are the major wxScrolledWindow functions.

CalcScrolledPosition and CalcUnscrolledPosition both take four arguments: two integers for the position input in pixels, and two pointers to integers for the transformed position output, also in pixels. CalcScrolledPosition calculates the device position from the logical position. For example, if the window is scrolled 10 pixels down from the top, the logical first visible position is 0, but the device position is -10. CalcUnscrolledPosition does the inverse, calculating the logical position from the device position.

EnableScrolling enables or disables physical scrolling in horizontal and vertical directions independently. Physical scrolling is the physical transfer of bits up or down the screen when a scroll event occurs. If the application scrolls by a variable amount (for example, if there are different font sizes), then physical scrolling will not work, and you should switch it off. If physical scrolling is disabled, you will have to reposition child windows yourself. Physical scrolling may not be available on all platforms, but it is enabled by default where it is available.

GetScrollPixelsPerUnit returns the horizontal and vertical scroll unit sizes in two pointers to integers. A value of zero indicates that there is no scrolling in that direction.

GetViewStart returns the position of the first visible position on the window, in logical units. Pass two pointers to integers to receive the values. You will need to multiply by the values returned by GetScrollPixelsPerUnit to get pixel values.

GetVirtualSize returns the size in device units (pixels) of the scrollable window area. Pass two pointers to integers to receive the virtual width and height.

DoPrepareDC prepares the device context by setting the device origin according to the current scrollbar positions.

Scroll scrolls a window so that the view is at the given point in scroll units (not pixels), passed as two integers. If either parameter is -1, that position will be unchanged.

SetScrollbars sets the pixels per unit in each direction, the number of units for the virtual window in each direction, the horizontal and vertical position to scroll to (optional), and a boolean to indicate whether the window should be refreshed (false by default).

SetScrollRate sets the horizontal and increment scroll rate (the same as the pixels per unit parameters in SetScrollbars).

SetTargetWindow can be used to scroll a window other than the wxScrolledWindow.

Scrolling Without Using wxScrolledWindow

If you want to implement your own scrolling behavior, you can derive a class from wxWindow and use wxWindow::SetScrollbar to set scrollbar properties.

SetScrollbar takes the arguments listed in Table 4-14.

Table 4-14. SetScrollbar Arguments

int orientation

The scrollbar to set: wxVERTICAL or wxHORIZONTAL.

int position

The position of the scrollbar "thumb" in scroll units.

int visible

The size of the visible portion of the scrollbar, in scroll units. Normally, a scrollbar is capable of indicating the visible portion visually by showing a different length of thumb.

int range

The maximum value of the scrollbar, where zero is the start position. You choose the units that suit you, so if you wanted to display text that has 100 lines, you would set this to 100. Note that this doesn't have to correspond to the number of pixels scrolledit is up to you how you actually show the contents of the window.

bool refresh

true if the scrollbar should be repainted immediately.


Let's say you want to display 50 lines of text, using the same font. The window is sized so that you can only see 16 lines at a time.

You would use

 SetScrollbar(wxVERTICAL, 0, 16, 50) 

Note that with the window at this size, the thumb position can never go above 50 minus 16, or 34.

You can determine how many lines are currently visible by dividing the current view size by the character height in pixels.

When defining your own scrollbar behavior, you will always need to recalculate the scrollbar settings when the window size changes. You could therefore introduce a new function AdjustScrollbars into which you place your scrollbar calculations and SetScrollbar call. AdjustScrollbars can be called initially, and also from your wxSizeEvent handler function.

It's instructive to look at the implementations of wxScrolledWindow and wxGrid if you're thinking of implementing your own scrolling behavior.

You may want to look at wxVScrolledWindow in the wxWidgets reference manual; this can be used to build a scrolled window class that can scroll by lines of unequal height in the vertical direction.

wxSplitterWindow

This class manages up to two subwindows (use nested splitter windows if you need more splits). The current view can be split into two by the application, for example, from a menu command. It can be unsplit either by the application or via the splitter window user interface by double-clicking on the sash or dragging the sash until one of the panes has zero size (override the latter behavior with SetMinimumPaneSize).

On most platforms, when the sash is dragged, a reverse-video line will be drawn to show where the sash will end up. You can pass wxSP_LIVE_UPDATE to let the sash move in "real time" instead, resizing the child windows. This is the default (and only) mode on Mac OS X.

The following fragment shows how to create a splitter window, creating two subwindows and hiding one of them.

 #include "wx/splitter.h" wxSplitterWindow* splitter = new wxSplitterWindow(this, wxID_ANY,     wxPoint(0, 0), wxSize(400, 400), wxSP_3D); leftWindow = new MyWindow(splitter); leftWindow->SetScrollbars(20, 20, 50, 50); rightWindow = new MyWindow(splitter);   rightWindow->SetScrollbars(20, 20, 50, 50);   rightWindow->Show(false); splitter->Initialize(leftWindow); // Unncomment this to prevent unsplitting //    splitter->SetMinimumPaneSize(20); 

This fragment shows how the splitter window can be manipulated after creation:

 void MyFrame::OnSplitVertical(wxCommandEvent& event) {     if ( splitter->IsSplit() )         splitter->Unsplit();     leftWindow->Show(true);     rightWindow->Show(true);     splitter->SplitVertically( leftWindow, rightWindow ); } void MyFrame::OnSplitHorizontal(wxCommandEvent& event) {     if ( splitter->IsSplit() )         splitter->Unsplit();     leftWindow->Show(true);     rightWindow->Show(true);     splitter->SplitHorizontally( leftWindow, rightWindow ); } void MyFrame::OnUnsplit(wxCommandEvent& event) {     if ( splitter->IsSplit() )         splitter->Unsplit(); } 

Figure 4-10 shows how the wxWidgets splitter sample looks on Windows without the wxSP_NO_XP_THEME style. If you use this style, the splitter will take on a more traditional look with a sunken border and 3D sash.

Figure 4-10. A wxSplitterWindow


wxSplitterWindow Styles

wxSplitterWindow can have the window styles shown in Table 4-15 in addition to those described for wxWindow.

Table 4-15. wxSplitterWindow Styles

wxSP_3D

Draws a 3D-effect border and sash.

wxSP_3DSASH

Draws a 3D-effect sash.

wxSP_3DBORDER

Synonym for wxSP_BORDER.

wxSP_BORDER

Draws a standard border.

wxSP_NOBORDER

No border (the default).

wxSP_NO_XP_THEME

Add a sunken border and 3D sash on Windows, if you don't like the minimal (but more native) look.

wxSP_PERMIT_UNSPLIT

Always enable the window to unsplit, even with the minimum pane size other than zero.

wxSP_LIVE_UPDATE

Resize the child windows immediately as the splitter is being moved.


wxSplitterWindow Events

wxSplitterWindow generates wxSplitterEvent propagating events, as listed in Table 4-16.

Table 4-16. wxSplitterWindow Events

EVT_SPLITTER_SASH_POS_CHANGING(id, func)

Processes a wxEVT_COMMAND_SPLITTER_SASH_ POS_CHANGING event, generated when the sash position is in the process of being changed. Call Veto to stop the sash position changing, or call the event's SetSashPosition function to change the sash position.

EVT_SPLITTER_SASH(id, func)

Processes a wxEVT_COMMAND_SPLITTER_ SASH_POS_CHANGED event, generated when the sash position is changed. May be used to modify the sash position before it is set, or to prevent the change from taking place, by calling the event's SetSashPosition function.

EVT_SPLITTER_UNSPLIT(id, func)

Processes a wxEVT_COMMAND_SPLITTER_UNSPLIT event, generated when the splitter is unsplit.

EVT_SPLITTER_DCLICK(id, func)

Processes a wxEVT_COMMAND_SPLITTER_ DOUBLECLICKED event, generated when the sash is double-clicked.


wxSplitterWindow Member Functions

These are the major wxSplitterWindow functions.

GetMinimumPaneSize and SetMinimumPaneSize are accessors for the minimum pane size. The default minimum pane size is zero, which means that either pane can be reduced to zero by dragging the sash, thus removing one of the panes. To prevent this behavior (and veto out-of-range sash dragging), set a minimum size, for example 20 pixels. However, if the wxSP_PERMIT_UNSPLIT style is used when a splitter window is created, the window may be unsplit even if the minimum size is non-zero.

GetSashPosition and SetSashPosition are accessors for the sash position. Passing true to SetSashPosition resizes the pane and redraws the sash and border.

GetSplitMode and SetSplitMode are accessors for the split orientation, which can be wxSPLIT_VERTICAL or wxSPLIT_HORIZONTAL.

GetWindow1 and GetWindow2 get the pointers to the two panes.

Initialize can be called with a pointer to a window if you only want to have one pane initially.

IsSplit tests whether the window is split.

ReplaceWindow replaces one of the windows managed by the wxSplitter Window with another one. Generally, it's better to use this function instead of calling Unsplit and then resplitting the window.

SetSashGravity takes a floating-point argument, which determines the position of the sash as the window is resized. A value of 0.0 (the default) means that only the bottom or right child window will be resized, and a value of 1.0 means that only the top or left child window will be resized. Values inbetween indicate that the change in size should be distributed between both child windows (a value of 0.5 distributes the size evenly). Use GetSashGravity to return the current setting.

SplitHorizontally and SplitVertically initialize the splitter window with two panes and optionally an initial sash size.

Unsplit removes the specified pane.

UpdateSize causes the splitter to update its sash position immediately (normally, this is done in idle time).

Sizing Issues with wxSplitterWindow

There are subtleties to be aware of when using a splitter window as part of a sizer hierarchy. If you don't need the sash to be moveable, you can create both child windows with absolute sizes. This will fix the minimum size of both child windows, and the sash will therefore not be free to move. If you need the sash to be moveable, as is normally the case, pass default values to the child windows and specify an initial minimum size in the splitter window constructor. Then add the splitter window to its sizer, passing the wxFIXED_MINSIZE flag to Add, which tells wxWidgets to treat the specified size as the minimum size.

Another issue is that a splitter does not set its sash position (and therefore the sizes of its child windows) until idle time, when it can be sure that sizing has been finalized and the sash position won't be set prematurely. This can result in a sash that visibly repositions itself just after the window has been shown. To fix this, call wxSplitterWindow::UpdateSize as soon as you have done your layout, for example after a wxSizer::Fit call. The splitter will update its sash and child window sizes immediately.

By default, when the user or application resizes the splitter, only the bottom (or right) window is adjusted to take into account the new size. If you need different behavior, use SetSashGravity as documented in the previous section.

Alternatives to wxSplitterWindow

If you have a lot of "split" windows in your application, consider using wxSashWindow. This is a window that allows any of its edges to have a sash (as specified by the application) that can be dragged to resize the window. The actual content window is normally created by the application as a child of wxSashWindow.

When a sash is dragged, it notifies the application with a wxSashEvent so the handler can change the window size accordingly before laying out the windows. Layout is achieved via a class called wxLayoutAlgorithm, which provides LayoutWindow, LayoutFrame, and LayoutMDIFrame methods for arranging the sash windows on different kinds of parent windows.

You can also use the class wxSashLayoutWindow, which responds to events of type wxQueryLayoutInfoEvent to provide orientation and size information to wxLayoutAlgorithm.

Please see the reference manual for further details. wxSashWindow doesn't permit moving or undocking windows, and it's likely that these classes will be superceded by a general docking and layout framework in the near future.

Figure 4-11 shows a view of the wxSashWindow sample provided in samples/sashtest.

Figure 4-11. The wxSashWindow demo


    team bbl



    Cross-Platform GUI Programming with wxWidgets
    Cross-Platform GUI Programming with wxWidgets
    ISBN: 0131473816
    EAN: 2147483647
    Year: 2005
    Pages: 262

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net