Winapi 如何使用Win32在滚动条触底时启用按钮?
我正在用Win32编写一个许可协议对话框,我被难住了。像往常一样,当richedit控件的滚动条的滑块触底时,我希望“接受/不接受”按钮变为启用状态,但我找不到一种方法来获得该事件的通知。我能了解的最早情况是当用户释放鼠标左键时 有办法做到这一点吗 以下是我迄今为止所做的尝试: richedit wndproc中的WM_VSCROLL和WM_LBUTTONUP dlgproc中的EN_MSGFILTER通知是正在设置筛选器掩码 dlgproc中的WM_VSCROLL和WM_LBUTTONUP。 dlgproc中的EN_VSCROLL通知 我太绝望了,我尝试了投票,但也没有成功,因为很明显,当鼠标按钮落在滑块上时,计时器消息停止到达。我尝试了两种方法: 在dlgproc中轮询的计时器回调 在richedit的wndproc中轮询的计时器回调Winapi 如何使用Win32在滚动条触底时启用按钮?,winapi,scrollbar,Winapi,Scrollbar,我正在用Win32编写一个许可协议对话框,我被难住了。像往常一样,当richedit控件的滚动条的滑块触底时,我希望“接受/不接受”按钮变为启用状态,但我找不到一种方法来获得该事件的通知。我能了解的最早情况是当用户释放鼠标左键时 有办法做到这一点吗 以下是我迄今为止所做的尝试: richedit wndproc中的WM_VSCROLL和WM_LBUTTONUP dlgproc中的EN_MSGFILTER通知是正在设置筛选器掩码 dlgproc中的WM_VSCROLL和WM_LBUTTONUP。
您需要对编辑框进行子分类,并截获发送到编辑框本身的消息 编辑:一些代码演示启用按钮的滚动条:
#include <windows.h>
#include <richedit.h>
LRESULT __stdcall RichEditSubclass
(
HWND window,
UINT message,
WPARAM w_param,
LPARAM l_param
)
{
HWND
parent = reinterpret_cast <HWND> (GetWindowLong (window, GWL_HWNDPARENT));
WNDPROC
proc = reinterpret_cast <WNDPROC> (GetWindowLong (parent, GWL_USERDATA));
switch (message)
{
case WM_VSCROLL:
{
SCROLLINFO
scroll_info =
{
sizeof scroll_info,
SIF_ALL
};
GetScrollInfo (window, SB_VERT, &scroll_info);
if (scroll_info.nPos + static_cast <int> (scroll_info.nPage) >= scroll_info.nMax ||
scroll_info.nTrackPos + static_cast <int> (scroll_info.nPage) >= scroll_info.nMax)
{
HWND
button = reinterpret_cast <HWND> (GetWindowLong (parent, 0));
EnableWindow (button, TRUE);
}
}
break;
}
return CallWindowProc (proc, window, message, w_param, l_param);
}
LRESULT __stdcall ApplicationWindowProc
(
HWND window,
UINT message,
WPARAM w_param,
LPARAM l_param
)
{
bool
use_default_proc = false;
LRESULT
result = 0;
switch (message)
{
case WM_CREATE:
{
CREATESTRUCT
*creation_data = reinterpret_cast <CREATESTRUCT *> (l_param);
RECT
client;
GetClientRect (window, &client);
HWND
child = CreateWindow (RICHEDIT_CLASS,
TEXT ("The\nQuick\nBrown\nFox\nJumped\nOver\nThe\nLazy\nDog\nThe\nQuick\nBrown\nFox\nJumped\nOver\nThe\nLazy\nDog"),
WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL | ES_DISABLENOSCROLL,
0, 0, client.right, client.bottom - 30,
window,
0,
creation_data->hInstance,
0);
SetWindowLong (window, GWL_USERDATA, GetWindowLong (child, GWL_WNDPROC));
SetWindowLong (child, GWL_WNDPROC, reinterpret_cast <LONG> (RichEditSubclass));
SetWindowLong (child, GWL_ID, 0);
child = CreateWindow (TEXT ("BUTTON"), TEXT ("Go Ahead!"), WS_CHILD | WS_VISIBLE | WS_DISABLED, 0, client.bottom - 30, client.right, 30, window, 0, creation_data->hInstance, 0);
SetWindowLong (window, 0, reinterpret_cast <LONG> (child));
SetWindowLong (child, GWL_ID, 1);
}
break;
case WM_COMMAND:
if (HIWORD (w_param) == BN_CLICKED && LOWORD (w_param) == 1)
{
DestroyWindow (window);
}
break;
default:
use_default_proc = true;
break;
}
return use_default_proc ? DefWindowProc (window, message, w_param, l_param) : result;
}
int __stdcall WinMain
(
HINSTANCE instance,
HINSTANCE unused,
LPSTR command_line,
int show
)
{
LoadLibrary (TEXT ("riched20.dll"));
WNDCLASS
window_class =
{
0,
ApplicationWindowProc,
0,
4,
instance,
0,
LoadCursor (0, IDC_ARROW),
reinterpret_cast <HBRUSH> (COLOR_BACKGROUND + 1),
0,
TEXT ("ApplicationWindowClass")
};
RegisterClass (&window_class);
HWND
window = CreateWindow (TEXT ("ApplicationWindowClass"),
TEXT ("Application"),
WS_VISIBLE | WS_OVERLAPPED | WS_SYSMENU,
CW_USEDEFAULT,
CW_USEDEFAULT,
400, 300, 0, 0,
instance,
0);
MSG
message;
int
success;
while (success = GetMessage (&message, window, 0, 0))
{
if (success == -1)
{
break;
}
else
{
TranslateMessage (&message);
DispatchMessage (&message);
}
}
return 0;
}
上述操作无法处理用户在编辑框中移动光标的问题。您需要对编辑框进行子分类,并截取发送到编辑框本身的消息 编辑:一些代码演示启用按钮的滚动条:
#include <windows.h>
#include <richedit.h>
LRESULT __stdcall RichEditSubclass
(
HWND window,
UINT message,
WPARAM w_param,
LPARAM l_param
)
{
HWND
parent = reinterpret_cast <HWND> (GetWindowLong (window, GWL_HWNDPARENT));
WNDPROC
proc = reinterpret_cast <WNDPROC> (GetWindowLong (parent, GWL_USERDATA));
switch (message)
{
case WM_VSCROLL:
{
SCROLLINFO
scroll_info =
{
sizeof scroll_info,
SIF_ALL
};
GetScrollInfo (window, SB_VERT, &scroll_info);
if (scroll_info.nPos + static_cast <int> (scroll_info.nPage) >= scroll_info.nMax ||
scroll_info.nTrackPos + static_cast <int> (scroll_info.nPage) >= scroll_info.nMax)
{
HWND
button = reinterpret_cast <HWND> (GetWindowLong (parent, 0));
EnableWindow (button, TRUE);
}
}
break;
}
return CallWindowProc (proc, window, message, w_param, l_param);
}
LRESULT __stdcall ApplicationWindowProc
(
HWND window,
UINT message,
WPARAM w_param,
LPARAM l_param
)
{
bool
use_default_proc = false;
LRESULT
result = 0;
switch (message)
{
case WM_CREATE:
{
CREATESTRUCT
*creation_data = reinterpret_cast <CREATESTRUCT *> (l_param);
RECT
client;
GetClientRect (window, &client);
HWND
child = CreateWindow (RICHEDIT_CLASS,
TEXT ("The\nQuick\nBrown\nFox\nJumped\nOver\nThe\nLazy\nDog\nThe\nQuick\nBrown\nFox\nJumped\nOver\nThe\nLazy\nDog"),
WS_CHILD | WS_VISIBLE | ES_MULTILINE | ES_AUTOVSCROLL | WS_VSCROLL | ES_DISABLENOSCROLL,
0, 0, client.right, client.bottom - 30,
window,
0,
creation_data->hInstance,
0);
SetWindowLong (window, GWL_USERDATA, GetWindowLong (child, GWL_WNDPROC));
SetWindowLong (child, GWL_WNDPROC, reinterpret_cast <LONG> (RichEditSubclass));
SetWindowLong (child, GWL_ID, 0);
child = CreateWindow (TEXT ("BUTTON"), TEXT ("Go Ahead!"), WS_CHILD | WS_VISIBLE | WS_DISABLED, 0, client.bottom - 30, client.right, 30, window, 0, creation_data->hInstance, 0);
SetWindowLong (window, 0, reinterpret_cast <LONG> (child));
SetWindowLong (child, GWL_ID, 1);
}
break;
case WM_COMMAND:
if (HIWORD (w_param) == BN_CLICKED && LOWORD (w_param) == 1)
{
DestroyWindow (window);
}
break;
default:
use_default_proc = true;
break;
}
return use_default_proc ? DefWindowProc (window, message, w_param, l_param) : result;
}
int __stdcall WinMain
(
HINSTANCE instance,
HINSTANCE unused,
LPSTR command_line,
int show
)
{
LoadLibrary (TEXT ("riched20.dll"));
WNDCLASS
window_class =
{
0,
ApplicationWindowProc,
0,
4,
instance,
0,
LoadCursor (0, IDC_ARROW),
reinterpret_cast <HBRUSH> (COLOR_BACKGROUND + 1),
0,
TEXT ("ApplicationWindowClass")
};
RegisterClass (&window_class);
HWND
window = CreateWindow (TEXT ("ApplicationWindowClass"),
TEXT ("Application"),
WS_VISIBLE | WS_OVERLAPPED | WS_SYSMENU,
CW_USEDEFAULT,
CW_USEDEFAULT,
400, 300, 0, 0,
instance,
0);
MSG
message;
int
success;
while (success = GetMessage (&message, window, 0, 0))
{
if (success == -1)
{
break;
}
else
{
TranslateMessage (&message);
DispatchMessage (&message);
}
}
return 0;
}
上述操作无法处理用户在编辑框中移动光标的问题。即使有可能,我认为您也不应该这样做-用户将不知道为什么按钮被禁用。这可能会让人非常困惑,应该不惜一切代价避免让用户困惑-
这就是为什么大多数许可证对话框都有默认启用拒绝的接受/拒绝单选按钮,所以您必须主动启用接受 即使这是可能的,我认为你不应该这样做-用户将不知道为什么按钮被禁用。这可能会让人非常困惑,应该不惜一切代价避免让用户困惑-
这就是为什么大多数许可证对话框都有默认启用拒绝的接受/拒绝单选按钮,所以您必须主动启用接受 我建议启动Spy++并查看哪些windows消息被发送到哪里
我建议启动Spy++并查看哪些windows消息被发送到何处
为什么不使用EM_gethumb消息呢。假设Rich Edit 2.0或更高版本
如果幸运的话,此底部位置将与EM_GETLINECOUNT匹配。为什么不使用EM_gethumb消息呢。假设Rich Edit 2.0或更高版本
如果幸运的话,此底部位置将与EM_GETLINECOUNT匹配。我看到的所有许可协议都有此功能。我对此表示怀疑。无论如何,我的答案是:不要这样做。我不会说每个许可协议都有,事实上我见过的大多数协议都没有。但我已经看到了一些,所以这当然是可能的。是的,我已经看到了上面的答案。这是可以做到的,我会相应地编辑我的答案。我看到的所有许可协议都有这个功能。我对此表示怀疑。无论如何,我的答案是:不要这样做。我不会说每个许可协议都有,事实上我见过的大多数协议都没有。但我已经看到了一些,所以这当然是可能的。是的,我已经看到了上面的答案。这是可以做到的,我会相应地编辑我的答案。可能在桥旁边,但我认为这不是一个好的UI设计。这感觉像是随意造成的不便。人们不读那些东西。让他们在继续之前向下滚动并不会改变这一点。像这样的一个功能给设计带来了营销/美感的味道。可能在桥旁边,但我认为这不是一个好的UI设计。这感觉像是随意造成的不便。人们不读那些东西。让他们在继续之前向下滚动并不会改变这一点。像这样的功能给设计带来了营销/美化的味道。Skizz,我对richedit控件进行了子类化,并截获了Windows发送给该控件的消息。我在我最初的帖子中给出了这方面的例子。例如,当我说我在richedit的wndproc中查找了WM_VSCROLL时,这意味着我用自己的wndproc替换了richedit的默认wndproc,并截取了它的WM_VSCROLL消息。崔布,我试着用传统的方式来做。我将看到更多的许可协议屏幕,但我认为大多数屏幕只有在滚动到底部时才启用Accept。关于两个按钮都启动offSkizz,我可能错了。在回复您的代码示例时,我的原始帖子说我已经尝试过了。我举的第一个例子是:richedit的wndproc中的WM_VSCROLL和WM_LBUTTONUP,这就是你在例子中所做的——响应控件wndproc中的WM_VSCROLL。再一次-我重复我自己-我已经尝试过了,但它没有达到这个目的,因为操作系统不会将WM_VSCROLL发送到控件的wndproc,而
ser按住鼠标按钮,将鼠标光标放在拇指上。这就是问题所在。我上面发布的代码在使用VS2k5时按照要求工作。唯一真正的问题是滚动条的位置!=拇指位于滚动条底部时滚动条最大值。正确的测试是滚动条位置+页面大小>=滚动条最大值。我认为您不理解这个问题。它确实有效!该代码还跟踪ScrollInfo.nTrackPos,即使用户没有松开鼠标按钮,它也会被更新!Skizz,我对richedit控件进行了子类化,并截获了Windows发送给该控件的消息。我在我最初的帖子中给出了这方面的例子。例如,当我说我在richedit的wndproc中查找了WM_VSCROLL时,这意味着我用自己的wndproc替换了richedit的默认wndproc,并截取了它的WM_VSCROLL消息。崔布,我试着用传统的方式来做。我将看到更多的许可协议屏幕,但我认为大多数屏幕只有在滚动到底部时才启用Accept。关于两个按钮都启动offSkizz,我可能错了。在回复您的代码示例时,我的原始帖子说我已经尝试过了。我举的第一个例子是:richedit的wndproc中的WM_VSCROLL和WM_LBUTTONUP,这就是你在例子中所做的——响应控件wndproc中的WM_VSCROLL。再一次-我重复我自己-我已经尝试过了,但它没有达到这个目的,因为当用户在拇指上按住鼠标按钮时,操作系统不会将WM_VSCROLL发送到控件的wndproc。这就是问题所在。我上面发布的代码在使用VS2k5时按照要求工作。唯一真正的问题是滚动条的位置!=拇指位于滚动条底部时滚动条最大值。正确的测试是滚动条位置+页面大小>=滚动条最大值。我认为您不理解这个问题。它确实有效!该代码还跟踪ScrollInfo.nTrackPos,即使用户没有松开鼠标按钮,它也会被更新!EM_gethumb不计入行数。EM_gethumb不计入行数。