滚动文本在静态控件中被否定 (C++ WinAPI)
Scrolling text gets negated in static control (C++ WinAPI)
我有一些奇怪的控制,
CreateWindowEx(!tset&USE?WS_EX_OVERLAPPEDWINDOW:0,
tset&USE?"static":"edit",0,WS_CHILD|WS_VISIBLE|
(!tset&USE?ES_MULTILINE|ES_WANTRETURN|ES_AUTOVSCROLL|WS_VSCROLL //when it's edit
:SS_NOTIFY|SS_EDITCONTROL),5,60,390,474,hwnd,HMENU(10),0,0); //when it's static
SetWindowSubclass(GetDlgItem(hwnd,10),tset&USE?BOR:NoMenu,0,0);
一切都取决于主题是否活跃。这里 tset
是位标志的 enum
类型的实例。 一切都很好,除了当控件处于静态模式时滚动。它没有收到 WM_MOUSEWHEEL
消息,我让它通过以下方式接收它们:
LRESULT CALLBACK BOR(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp,UINT_PTR,DWORD_PTR)
{
if(msg==WM_MOUSEMOVE&&GetDlgCtrlID(hwnd)==10)
{
POINT x{LOWORD(lp),HIWORD(lp)}; ClientToScreen(hwnd,&x);
RECT rc; GetWindowRect(hwnd,&rc); if(PtInRect(&rc,x)&&GetCapture()!=hwnd){SetCapture(hwnd); hwnd3=SetFocus(hwnd);}
if(!PtInRect(&rc,x)&&GetCapture()==hwnd){ReleaseCapture(); SetFocus(hwnd3);} //hwnd3 is an instance of HWND defined in global scope, for giving focus back
}
if(msg==WM_MOUSEWHEEL)
{
RECT rc; GetWindowRect(GetParent(hwnd),&rc);
HRGN x; GetWindowRgn(GetParent(hwnd),x);
ScrollWindowEx(hwnd,0,short(HIWORD(wp)),0,0,x,&rc,SW_INVALIDATE|SW_ERASE);
ShowWindow(GetParent(hwnd),SW_HIDE); ShowWindow(GetParent(hwnd),SW_SHOW);
SetFocus(hwnd);
return 1;
}
return DefSubclassProc(hwnd,msg,wp,lp);
}
现在当鼠标进入我控件的客户区时,如果它处于静态模式,它会捕获鼠标并获得焦点。所以它在其子类回调函数中拦截 WM_MOUSEWHEEL
消息,我可以在静态模式下滚动我的控件。这是确切的问题:几毫秒后,文本滚动后, window 以某种方式将自身更新到其初始未滚动状态。我的努力被否定了。是否清楚为什么会这样,以及如何解决?
@Edit:为什么我不直接将 WS_VSCROLL
添加到它的静态版本中呢?因为它具有 SS_NOTIFY
风格,我需要它以其他方式响应 WM_COMMAND
消息。这就是我尝试手动滚动它的原因。
@更新:
这两个屏幕截图中的文本长度相同。当控件处于编辑状态时,它的垂直滚动条是正确的。但是当它处于静态时,垂直滚动条与实际文本长度不匹配。此外,滚动条始终处于相同的大小和相同的位置,与文本长度无关,并且它也是不可滚动的。为什么会这样?
@Update:感谢问题很容易通过其他方式解决。
为了从未回答列表中删除问题,我将重复并扩展其中一条评论。
查看这些图片,我们可以立即看出它们呈现方式的明显差异。左图的每一行都以不同的字符开头,而右图总是以相同的字符开头。它们在滚动条中的拇指大小也非常不同。
由于问题似乎源于尝试使用两个不同的控件来完成基本相同的任务,我建议始终使用编辑控件。 (这是一个表现得很好,并且不换行的那个)
与其使用两种不同类型的控件,我建议只切换只读标志。幸运的是(!)现在唯一的区别是处理鼠标和键盘消息的方式——希望你能通过这种方法获得类似的行为和外观。
我想到的消息是 EM_SETREADONLY
.
虽然问题已经成功回答,但我在微软文档中找不到支持我理论的参考资料,因此使用了类似'hopefully'的语言。
我有一些奇怪的控制,
CreateWindowEx(!tset&USE?WS_EX_OVERLAPPEDWINDOW:0,
tset&USE?"static":"edit",0,WS_CHILD|WS_VISIBLE|
(!tset&USE?ES_MULTILINE|ES_WANTRETURN|ES_AUTOVSCROLL|WS_VSCROLL //when it's edit
:SS_NOTIFY|SS_EDITCONTROL),5,60,390,474,hwnd,HMENU(10),0,0); //when it's static
SetWindowSubclass(GetDlgItem(hwnd,10),tset&USE?BOR:NoMenu,0,0);
一切都取决于主题是否活跃。这里 tset
是位标志的 enum
类型的实例。 一切都很好,除了当控件处于静态模式时滚动。它没有收到 WM_MOUSEWHEEL
消息,我让它通过以下方式接收它们:
LRESULT CALLBACK BOR(HWND hwnd,UINT msg,WPARAM wp,LPARAM lp,UINT_PTR,DWORD_PTR)
{
if(msg==WM_MOUSEMOVE&&GetDlgCtrlID(hwnd)==10)
{
POINT x{LOWORD(lp),HIWORD(lp)}; ClientToScreen(hwnd,&x);
RECT rc; GetWindowRect(hwnd,&rc); if(PtInRect(&rc,x)&&GetCapture()!=hwnd){SetCapture(hwnd); hwnd3=SetFocus(hwnd);}
if(!PtInRect(&rc,x)&&GetCapture()==hwnd){ReleaseCapture(); SetFocus(hwnd3);} //hwnd3 is an instance of HWND defined in global scope, for giving focus back
}
if(msg==WM_MOUSEWHEEL)
{
RECT rc; GetWindowRect(GetParent(hwnd),&rc);
HRGN x; GetWindowRgn(GetParent(hwnd),x);
ScrollWindowEx(hwnd,0,short(HIWORD(wp)),0,0,x,&rc,SW_INVALIDATE|SW_ERASE);
ShowWindow(GetParent(hwnd),SW_HIDE); ShowWindow(GetParent(hwnd),SW_SHOW);
SetFocus(hwnd);
return 1;
}
return DefSubclassProc(hwnd,msg,wp,lp);
}
现在当鼠标进入我控件的客户区时,如果它处于静态模式,它会捕获鼠标并获得焦点。所以它在其子类回调函数中拦截 WM_MOUSEWHEEL
消息,我可以在静态模式下滚动我的控件。这是确切的问题:几毫秒后,文本滚动后, window 以某种方式将自身更新到其初始未滚动状态。我的努力被否定了。是否清楚为什么会这样,以及如何解决?
@Edit:为什么我不直接将 WS_VSCROLL
添加到它的静态版本中呢?因为它具有 SS_NOTIFY
风格,我需要它以其他方式响应 WM_COMMAND
消息。这就是我尝试手动滚动它的原因。
@更新:
这两个屏幕截图中的文本长度相同。当控件处于编辑状态时,它的垂直滚动条是正确的。但是当它处于静态时,垂直滚动条与实际文本长度不匹配。此外,滚动条始终处于相同的大小和相同的位置,与文本长度无关,并且它也是不可滚动的。为什么会这样?
@Update:感谢
为了从未回答列表中删除问题,我将重复并扩展其中一条评论。
查看这些图片,我们可以立即看出它们呈现方式的明显差异。左图的每一行都以不同的字符开头,而右图总是以相同的字符开头。它们在滚动条中的拇指大小也非常不同。
由于问题似乎源于尝试使用两个不同的控件来完成基本相同的任务,我建议始终使用编辑控件。 (这是一个表现得很好,并且不换行的那个)
与其使用两种不同类型的控件,我建议只切换只读标志。幸运的是(!)现在唯一的区别是处理鼠标和键盘消息的方式——希望你能通过这种方法获得类似的行为和外观。
我想到的消息是 EM_SETREADONLY
.
虽然问题已经成功回答,但我在微软文档中找不到支持我理论的参考资料,因此使用了类似'hopefully'的语言。