wxAuiToolBar的overflow cannot work on GTK 解决方法

wxAuiToolBar's overflow function cannot work as expected, when as pane in wxAuiManager, on GTK.
1
2

当增加一个AuiToolBar到一个auimanager之后,如果想用它的overflow feature,在gtk平台,无法工作。 WHY?

1) 首先查看wxAuiToolBar的OnSize函数做了些什么事情:

<!-- lang: cpp -->
void wxAuiToolBar:: OnSize(wxSizeEvent & WXUNUSED (evt))
{
     int x , y;
    GetClientSize(&x , &y);

    if (x > y)
         SetOrientation(wxHORIZONTAL );
    else
        SetOrientation(wxVERTICAL );

    if (((x >= y) && m_absolute_min_size .x > x) ||
        (( y > x ) && m_absolute_min_size.y > y))
    {
        // hide all flexible items
        size_t i , count;
        for (i = 0, count = m_items.GetCount (); i < count; ++i )
        {
            wxAuiToolBarItem& item = m_items. Item(i );
            if (item .sizer_item && item.proportion > 0 && item .sizer_item-> IsShown())
            {
                item.sizer_item ->Show( false);
                item.sizer_item ->SetProportion(0);
            }
        }
    }
    else
    {
        // show all flexible items
        size_t i , count;
        for (i = 0, count = m_items.GetCount (); i < count; ++i )
        {
            wxAuiToolBarItem& item = m_items. Item(i );
            if (item .sizer_item && item.proportion > 0 && !item .sizer_item-> IsShown())
            {
                item.sizer_item ->Show( true);
                item.sizer_item ->SetProportion( item.proportion );
             }
        }
     } 

     m_sizer->SetDimension (0, 0, x, y);

    Refresh(false );
    Update();
 }

可以看到函数对一些tool button做了show/hide设置。
然后设置断点,跟踪每次size时, x/y计算出来的值是多少。发现它始终就没变过,不管如何resize那个toolbar

2) 不从ClientSize里面获取x/y值,从evt参数中拿值。看下上层代码是如何给它值。发现下面函数触发OnSize函数调用:

void wxAuiToolBar:: DoSetSize(int x,
                         int y ,
                         int width ,
                         int height ,
                         int sizeFlags )
{
     wxSize parent_size = GetParent()-> GetClientSize();
     if (x + width > parent_size.x )
        width = wxMax (0, parent_size. x - x );
     if (y + height > parent_size.y )
        height = wxMax (0, parent_size. y - y );

     wxWindow::DoSetSize (x, y, width , height, sizeFlags);
 }

跟踪发现width/height确实是更改过的值,但是在wxWindow::DoSetSize函数中,但是gtk版本的DoSetSize函数(src/gtk/window.cpp: 2712行),对width/height进行了进一步的处理。在函数最后处理size事件

<!-- lang: cpp -->
2829     if (!m_nativeSizeEvent)
2830     {
2831         wxSizeEvent event( wxSize(m_width,m_height), GetId() );
2832         event.SetEventObject( this );
2833         GetEventHandler()->ProcessEvent( event );
2834     }

跟踪发现m_width/m_height,确实在函数内部以下代码段中更改了。

<!-- lang: cpp -->
2744     int minWidth  = GetMinWidth(),
2745         minHeight = GetMinHeight(),
2746         maxWidth  = GetMaxWidth(),
2747         maxHeight = GetMaxHeight();
2748
2749     if ((minWidth  != -1) && (m_width  < minWidth )) m_width  = minWidth;
2750     if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
2751     if ((maxWidth  != -1) && (m_width  > maxWidth )) m_width  = maxWidth;
2752     if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;

GetMinWidth函数调用GetMinSize函数获取widht。跟踪发现这个minsize失踪是toolbar最初显示出来的size。我们并没有设置它的minsize啊?是谁在其间调用了SetMinSize函数设置其值了?

3) GDB断点跟踪发现,在auimanager的Update函数中调用了Sizer的SetItemMinSize函数,进而调用了toolbar的SetMinSize函数:

<!-- lang: cpp -->
1658 void wxAuiManager::LayoutAddPane(wxSizer* cont,
1659                                  wxAuiDockInfo& dock,
1660                                  wxAuiPaneInfo& pane,
1661                                  wxAuiDockUIPartArray& uiparts,
1662                                  bool spacer_only)
...
1779     // determine if the pane should have a minimum size; if the pane is
1780     // non-resizable (fixed) then we must set a minimum size. Alternatively,
1781     // if the pane.min_size is set, we must use that value as well
1782
1783     wxSize min_size = pane.min_size;
1784     if (pane.IsFixed())
1785     {
1786         if (min_size == wxDefaultSize)
1787         {
1788             min_size = pane.best_size;
1789             pane_proportion = 0;
1790         }
1791     }
1792
1793     if (min_size != wxDefaultSize)
1794     {
1795         vert_pane_sizer->SetItemMinSize(
1796                         vert_pane_sizer->GetChildren().GetCount()-1,
1797                         min_size.x, min_size.y);
1798     }

我们的toolbar是一个fixed的pane,开始时并没有设置它的min size,所以1788行将会设置为best size,而best size将会是初始化时的size。这样1795行将会被调用到,而且是以best size的值来调用。

4) 找到根源之后,如何修改?
最简单的方式是在auimanager.AddPane调用增加toolbar时,设置它的minsize为一个tool button的size。这个size可以从toolbar提供的接口获取到。

你可能感兴趣的:(wxwidgets)