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" 的末尾,多了一行。
关于这个问题的一些说明:
- 一直是默认的白色(自定义bg的时候勾选)
其他行变黑)
- 只有在使用
SetPopupMaxHeight
时才会发生
- 它只发生在 Mac(即 Windows 没有问题)
- 点击那个额外的行将关闭弹出窗口(所以我猜它是弹出窗口的一部分 window)
这是代码(针对 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);
我尝试了一些方法:
- 使用了默认的
OnDrawItem
方法(同样的问题)
- 检查了对
OnDrawItem
的额外调用(没有额外调用)
- 在
OnMeasureHeight
中调整了返回的项目高度(同一问题)
检查了 samples/combo/combo.cpp 示例的行为(相同问题)
关于我的 wxWidgets 构建的一些信息:
- 直接从他们的 github 仓库中克隆了它
- 除了在 setup.h 中定义
wxUSE_XTEST 1
外,未对 wxWidgets 源代码进行任何更改
- 我检查过
wxUSE_ODCOMBOBOX
和 wxUSE_COMBOCTRL
#define
'd
- 为 ../configure 使用了以下选项
--with-osx_cocoa
--with-macosx-version-min=10.7
--with-macosx-sdk=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk
--enable-debug
--disable-shared
--enable-unicode
--prefix="$(pwd)"
关于我的环境的一些信息:
- macOS 10.12.5 (Sierra)
- Xcode 8.3.3 (8E3004b)
- minimal_cocoa 显示 wxWidgets 3.1.1
以前有人遇到过这个问题吗?
我现在正在解决这个问题,不再使用 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 循环。
我已经实现了自定义 wxOwnerDrawnComboBox based on the API docs. I then placed it on a wxPanel
then used SetPopupMaxHeight 来限制组合弹出窗口一次只显示 3 个项目。但是弹出 在弹出 window.
截图如下(我在minimal_cocoa示例项目上实现):
如图所示,只有 6 项,但在 "item 5" 的末尾,多了一行。
关于这个问题的一些说明:
- 一直是默认的白色(自定义bg的时候勾选) 其他行变黑)
- 只有在使用
SetPopupMaxHeight
时才会发生
- 它只发生在 Mac(即 Windows 没有问题)
- 点击那个额外的行将关闭弹出窗口(所以我猜它是弹出窗口的一部分 window)
这是代码(针对 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);
我尝试了一些方法:
- 使用了默认的
OnDrawItem
方法(同样的问题) - 检查了对
OnDrawItem
的额外调用(没有额外调用) - 在
OnMeasureHeight
中调整了返回的项目高度(同一问题) 检查了 samples/combo/combo.cpp 示例的行为(相同问题)
关于我的 wxWidgets 构建的一些信息:
- 直接从他们的 github 仓库中克隆了它
- 除了在 setup.h 中定义
wxUSE_XTEST 1
外,未对 wxWidgets 源代码进行任何更改- 我检查过
wxUSE_ODCOMBOBOX
和wxUSE_COMBOCTRL
#define
'd
- 我检查过
- 为 ../configure 使用了以下选项
--with-osx_cocoa
--with-macosx-version-min=10.7
--with-macosx-sdk=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk
--enable-debug
--disable-shared
--enable-unicode
--prefix="$(pwd)"
关于我的环境的一些信息:
- macOS 10.12.5 (Sierra)
- Xcode 8.3.3 (8E3004b)
- minimal_cocoa 显示 wxWidgets 3.1.1
以前有人遇到过这个问题吗?
我现在正在解决这个问题,不再使用 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 循环。