OSX 上的 wxOwnerDrawnComboBox 在滚动底部有一个额外的行

wxOwnerDrawnComboBox on OSX has an extra row at the bottom of the scroll

我已经实现了自定义 wxOwnerDrawnComboBox based on the API docs. I then placed it on a wxPanel then used SetPopupMaxHeight 来限制组合弹出窗口一次只显示 3 个项目。但是弹出 在弹出 window.

底部显示了一个额外的白行

截图如下(我在minimal_cocoa示例项目上实现):

如图所示,只有 6 项,但在 "item 5" 的末尾,多了一行。

关于这个问题的一些说明:

这是代码(针对 minimal_cocoa 项目进行了简化):


// CUSTOM CLASS DECLARATION

class MyOwnerDrawnComboBox : public wxOwnerDrawnComboBox
{
public:
    static int getItemHeight()
    {
        return 25;
    }

public:
    // ctor

    MyOwnerDrawnComboBox(wxWindow* parent,
                         const wxPoint& pos = wxDefaultPosition,
                         const wxSize& size = wxDefaultSize,
                         int n = 0,
                         const wxString choices[] = NULL,
                         long style = wxODCB_STD_CONTROL_PAINT)
    : wxOwnerDrawnComboBox(parent,
                           wxID_ANY,
                           wxEmptyString,
                           pos,
                           size,
                           n,
                           choices,
                           style,
                           wxDefaultValidator,
                           "MyOwnerDrawnComboBox")
    {
    }

    // overrides

    virtual void OnDrawItem (wxDC& dc, const wxRect& rect, int item, int flags) const
    {
        dc.SetTextForeground(*wxRED);

        // for debugging purposes, display the item index instead
        wxString label = wxString::Format("item %d", item);
        dc.DrawLabel(label, rect, wxALIGN_LEFT | wxALIGN_CENTER_VERTICAL);
    }

    virtual wxCoord OnMeasureItem (size_t item) const
    {
        return 25;
    }

    virtual wxCoord OnMeasureItemWidth (size_t item) const
    {
        return -1; // use default
    }
};

// CUSTOM CLASS USAGE

wxPanel* panel = new wxPanel(this, wxID_ANY);
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
wxString items[] = {"1", "2", "3", "4", "5", "6"}; // unused
MyOwnerDrawnComboBox* odcb = new MyOwnerDrawnComboBox(panel,
                                                      wxDefaultPosition,
                                                      wxSize(150, 30),
                                                      6,
                                                      items);
odcb->SetPopupMaxHeight(3 * MyOwnerDrawnComboBox::getItemHeight());
sizer->Add(odcb, 0, wxALL, 10);
sizer->Layout();
panel->SetSizer(sizer);

我尝试了一些方法:

  1. 使用了默认的 OnDrawItem 方法(同样的问题)
  2. 检查了对 OnDrawItem 的额外调用(没有额外调用)
  3. OnMeasureHeight 中调整了返回的项目高度(同一问题)
  4. 检查了 samples/combo/combo.cpp 示例的行为(相同问题)


关于我的 wxWidgets 构建的一些信息:

关于我的环境的一些信息:


以前有人遇到过这个问题吗?
我现在正在解决这个问题,不再使用 SetPopupMaxHeight

如果有人有解决方案,请分享。

我通过对 wx 源代码进行一些更改来修复它。

src/generic/vscroll.cpp

wxVarScrollHelperBase::DoScrollToUnit:

// determine the real first unit to scroll to: we shouldn't scroll beyond
// the end
size_t unitFirstLast = FindFirstVisibleFromLast(m_unitMax - 1, true);
if ( unit > unitFirstLast )
    unit = unitFirstLast;

false 传递给 FindFirstVisibleFromLast

这将允许该方法将一个项目视为第一个项目,即使最后一个项目仅部分可见("partially" 这里,根据我的测试,真的很像 "almost fully visible",只有大约 ~2pts 是隐藏的)。使用 true,滚动向下移动到下一个项目,从而添加额外的行。

src/generic/odcombo.cpp

wxVListBoxComboPopup::OnMouseMove:

        // Only change selection if item is fully visible
        if ( (y + fromBottom) >= 0 )
        {
            wxVListBox::SetSelection((int)line);
            return;
        }

为了匹配 wxVListBoxComboPopup::GetAdjustedSize 中考虑的 2pt 边框,我将 IF 条件更改为 (y + fromBottom + 2) 以允许将鼠标移到滚动 window 中的最后一项上,即使它不是完全可见的。

src/generic/vlbox.cpp

    else // line is at least partly visible
    {
        // it is, indeed, only partly visible, so scroll it into view to
        // make it entirely visible
        // BUT scrolling down when m_current is first visible makes it
        // completely hidden, so that is even worse
        while ( (size_t)m_current + 1 == GetVisibleRowsEnd() &&
                (size_t)m_current != GetVisibleRowsBegin() &&
                ScrollToRow(GetVisibleBegin() + 1) ) ;

注释掉当鼠标指针悬停在部分可见项目上时禁用自动滚动的 while 循环。