Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何检测悬停在静态Win32控件上的情况?_C++_Winapi - Fatal编程技术网

C++ 如何检测悬停在静态Win32控件上的情况?

C++ 如何检测悬停在静态Win32控件上的情况?,c++,winapi,C++,Winapi,我在检测静态Win32控件上的悬停时遇到问题 这不是重复的问题,因为它查找多个静态控件,而不是在编译时查找静态控件的单个已知句柄 虽然这可以用另一种语言在几秒钟内完成,但在尝试了几个小时之后,我变得有点沮丧。我希望在这里得到答案 首先,我创建了一个名为Label的类。我在其中创建了一个静态控件窗口。现在我将静态作为标签 // Create the label's handle. m_handle = CreateWindowEx(NULL, "static", m_text.c_str(),

我在检测静态Win32控件上的悬停时遇到问题

这不是重复的问题,因为它查找多个静态控件,而不是在编译时查找静态控件的单个已知句柄

虽然这可以用另一种语言在几秒钟内完成,但在尝试了几个小时之后,我变得有点沮丧。我希望在这里得到答案

首先,我创建了一个名为Label的类。我在其中创建了一个静态控件窗口。现在我将静态作为标签

// Create the label's handle.
m_handle = CreateWindowEx(NULL, "static", m_text.c_str(),
    WS_CHILD | SS_LEFT | SS_NOTIFY, m_x, m_y, m_width, m_height,
    m_parentWindow, (HMENU)(UINT_PTR)m_id, m_hInstance, NULL);
if (m_handle == NULL)
    return false;
当鼠标悬停在此标签上时,应调用以下方法:

void Label::invokeOnMouseHover()
{
    if (m_onMouseOver)
        m_onMouseOver();
}
这将调用我的方法:

void lblName_onMouseOver()
{
    MessageBox::show("Hovering!", "My Console",
        MessageBoxButtons::Ok, MessageBoxIcon::Information);
}
以下是我从顶层创建它的方式:

Label lblName("This is a label.", 0, 0);
lblName.setVisible(true);
lblName.OnMouseOver(lblName_onMouseOver); 
frm.add(lblName);
承认吧,这一层很漂亮

虽然我的回调对我的按钮和复选框控件很好,但我注意到静态有点不同

那么,让我们往下看几个层次:

这在主窗口的过程中:

case WM_MOUSEMOVE:
{  
    int xPos = LOWORD(lParam);
    int yPos = HIWORD(lParam);

    frm.setMousePos(xPos, yPos);  

    // Get the static's id
    int id = // ?? Which static control id is it out of several?

                // Obtain the control associated with the id.
        X3D::Windows::Control *ctrl = frm.getControls().find(id)->second;
    if (ctrl == NULL)
        return 0;

    // Check if this is a X3D Label control.
    if (typeid(*ctrl) == typeid(X3D::Windows::Label))
    {
        Label *lbl = dynamic_cast<X3D::Windows::Label*>(ctrl);

        int xPos = GET_X_LPARAM(lParam);
        int yPos = GET_Y_LPARAM(lParam);

        if (xPos >= lbl->getX() &&
            yPos >= lbl->getY() &&
            (xPos < (lbl->getX() + lbl->getWidth())) &&
            (yPos < (lbl->getY() + lbl->getHeight())))
        {
            if (lbl != NULL)
                lbl->invokeOnMouseHover();
        }
    }
}
break; 
如果这是油漆问题,这就是我在WndProc的情况

    case WM_PAINT:
    {
        hDC = BeginPaint(hWnd, &ps);
        EndPaint(hWnd, &ps);

        return 0;
    }
    break;
更新#2:

替代方案解决了这个问题

如果将来有人在setWindowsSubClass()中遇到无法解析的外部符号的问题,请记住将以下内容添加到项目中,或者只对其进行杂注:

#pragma comment(lib, "comctl32.lib")

WM_MOUSEMOVE
为您提供的唯一识别信息是鼠标正在移动的
HWND
(或已移动的
HWND
)。报告的X/Y坐标相对于
HWND
。这是您正在寻找的
HWND
,因此您不需要搜索它,消息会将它提供给您

如果需要访问
HWND
的控件ID,可以使用。但是请注意,每个
HWND
都有自己的窗口过程,因此控件ID通常只对通知消息有用,例如
WM_COMMAND
WM_NOTIFY
,它们被发送到控件的父窗口(即使这样,此类通知也会携带子控件的
HWND

当鼠标移动到特定的
HWND
上时,
WM_MOUSEMOVE
仅发布到该
HWND
的消息过程(或发布到捕获鼠标的
HWND
)。听起来您希望它被发布到控件的父窗口,但事实并非如此。这就是为什么没有调用
WM\u MOUSEMOVE
处理程序的原因。您在错误的级别处理消息。您需要准备在每个控件的基础上处理消息,而不是使用控件自己的消息过程

通过
SetWindowLongPtr(GWLP\u USERDATA)
SetWindowSubClass()
SetProp()
,将
控件的
指针存储在其关联的
HWND
本身中会更有效,然后,您的消息处理程序可以在需要时访问消息报告的
HWND
控件*
指针,例如:

// Create the label's handle.
m_handle = CreateWindowEx(NULL, TEXT("static"), m_text.c_str(),
    WS_CHILD | SS_LEFT | SS_NOTIFY, m_x, m_y, m_width, m_height,
    m_parentWindow, (HMENU)(UINT_PTR)m_id, m_hInstance, NULL);
if (!m_handle)
    return false;
SetWindowLongPtr(m_handle, GWLP_USERDATA, (LONG_PTR)(X3D::Windows::Control*)this);
m_oldproc = (WNDPROC) SetWindowLongPtr(m_handle, GWL_WNDPROC, (LONG_PTR)&MyWndProc);

...

LRESULT CALLBACK MyWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_MOUSEMOVE:
        {
            ...

            X3D::Windows::Control *ctrl = (X3D::Windows::Control*) GetWindowLongPtr(hWnd, GWLP_USERDATA);
            if (ctrl)
            {
                // Check if this is a X3D Label control.
                Label *lbl = dynamic_cast<X3D::Windows::Label*>(ctrl);
                if (lbl)
                    lbl->invokeOnMouseHover();
            }

            break;
        }

        ...
    }

    return CallWindowProc(m_oldproc, hWnd, uMsg, wParam, lParam);
}
//创建标签的句柄。
m_handle=CreateWindowEx(空,文本(“静态”),m_TEXT.c_str(),
WS|u CHILD | SS|u LEFT | SS|u NOTIFY,m|x,m|y,m|u width,m|u height,
m_parentWindow,(humenu)(UINT_PTR)m_id,m_hInstance,NULL);
if(!m_handle)
返回false;
SetWindowLongPtr(m_句柄,GWLP_用户数据,(LONG_PTR)(X3D::Windows::Control*)this);
m_oldproc=(WNDPROC)SetWindowLongPtr(m_handle,GWL_WNDPROC,(LONG_PTR)和MyWndProc);
...
LRESULT回调MyWndProc(HWND HWND、UINT uMsg、WPARAM WPARAM、LPARAM LPARAM)
{
开关(uMsg)
{
案例WM_MOUSEMOVE:
{
...
X3D::Windows::Control*ctrl=(X3D::Windows::Control*)GetWindowLongPtr(hWnd,GWLP_USERDATA);
如果(ctrl)
{
//检查这是否是X3D标签控件。
标签*lbl=动态投影(ctrl);
如果(lbl)
lbl->invokeOnMouseHover();
}
打破
}
...
}
返回CallWindowProc(m_oldproc、hWnd、uMsg、wParam、lParam);
}
或者:

// Create the label's handle.
m_handle = CreateWindowEx(NULL, TEXT("static"), m_text.c_str(),
    WS_CHILD | SS_LEFT | SS_NOTIFY, m_x, m_y, m_width, m_height,
    m_parentWindow, (HMENU)(UINT_PTR)m_id, m_hInstance, NULL);
if (!m_handle)
    return false;
SetWindowSubclass(m_handle, &MySubclassProc, 1, (DWORD_PTR)(X3D::Windows::Control*)this);

...

LRESULT CALLBACK MySubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
    switch (uMsg)
    {
        case WM_NCDESTROY:
            RemoveWindowSubclass(hWnd, &MySubclassProc, uIdSubclass);
            break;

        case WM_MOUSEMOVE:
        {
            X3D::Windows::Control *ctrl = (X3D::Windows::Control*) dwRefData;

            // Check if this is a X3D Label control.
            Label *lbl = dynamic_cast<X3D::Windows::Label*>(ctrl);
            if (lbl)
                lbl->invokeOnMouseHover();

            break;
        }

        ...
    }

    return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
//创建标签的句柄。
m_handle=CreateWindowEx(空,文本(“静态”),m_TEXT.c_str(),
WS|u CHILD | SS|u LEFT | SS|u NOTIFY,m|x,m|y,m|u width,m|u height,
m_parentWindow,(humenu)(UINT_PTR)m_id,m_hInstance,NULL);
if(!m_handle)
返回false;
setWindowsSubclass(m_handle和MySubclassProc,1,(DWORD_PTR)(X3D::Windows::Control*)this);
...
LRESULT回调MySubclassProc(HWND HWND、UINT uMsg、WPARAM WPARAM、LPARAM LPARAM、UINT_PTR uIdSubclass、DWORD_PTR dwRefData)
{
开关(uMsg)
{
案例WM\NCU:
移除Windows子类(hWnd和MySubclassProc、uIdSubclass);
打破
案例WM_MOUSEMOVE:
{
X3D::Windows::Control*ctrl=(X3D::Windows::Control*)DWREF数据;
//检查这是否是X3D标签控件。
标签*lbl=动态投影(ctrl);
如果(lbl)
lbl->invokeOnMouseHover();
打破
}
...
}
返回def子类proc(hWnd、uMsg、wParam、lParam);
}

这篇文章没有回答您提出的问题,但您应该阅读它。这是很重要的,在我上面相当尖刻的评论之后,它是以一种乐于助人的精神发布的。我希望你觉得是这样

这个类库要出问题了。这样的代码(使用动态\u cast):

然后:

class Label : public Control   // Derived class
{
    ...
    virtual void onMouseHover (...) override { ...  }
    ...
};
现在谈谈我的第二点:您将发现,特别是对于对话框,您的应用程序将需要处理大量基类不理解(或不关心)的消息

你打算怎么做?对于应用程序(或类库中实现的特定类型的控件)感兴趣的每一条新消息,是否要向基类添加代码?这不是一个很有吸引力的前景

没有
// Create the label's handle.
m_handle = CreateWindowEx(NULL, TEXT("static"), m_text.c_str(),
    WS_CHILD | SS_LEFT | SS_NOTIFY, m_x, m_y, m_width, m_height,
    m_parentWindow, (HMENU)(UINT_PTR)m_id, m_hInstance, NULL);
if (!m_handle)
    return false;
SetWindowSubclass(m_handle, &MySubclassProc, 1, (DWORD_PTR)(X3D::Windows::Control*)this);

...

LRESULT CALLBACK MySubclassProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
    switch (uMsg)
    {
        case WM_NCDESTROY:
            RemoveWindowSubclass(hWnd, &MySubclassProc, uIdSubclass);
            break;

        case WM_MOUSEMOVE:
        {
            X3D::Windows::Control *ctrl = (X3D::Windows::Control*) dwRefData;

            // Check if this is a X3D Label control.
            Label *lbl = dynamic_cast<X3D::Windows::Label*>(ctrl);
            if (lbl)
                lbl->invokeOnMouseHover();

            break;
        }

        ...
    }

    return DefSubclassProc(hWnd, uMsg, wParam, lParam);
}
case WM_MOUSEMOVE:
{
    X3D::Windows::Control *ctrl = (X3D::Windows::Control*) dwRefData;

    // Check if this is a X3D Label control.
    Label *lbl = dynamic_cast<X3D::Windows::Label*>(ctrl);
    if (lbl)
        lbl->invokeOnMouseHover();

    break;
}
class Control                  // Base class
{
    ...
    virtual void onMouseHover (...) { }
    ...
};
class Label : public Control   // Derived class
{
    ...
    virtual void onMouseHover (...) override { ...  }
    ...
};
typedef INT_PTR (Window::*MESSAGE_HANDLER)
    (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

// Register a message handler
void Window::RegisterMessageHandler (UINT uMsg, MESSAGE_HANDLER handler);
class Control                  // Base class
{
    ...
    std::unordered_map <UINT, MESSAGE_HANDLER> m_message_map;
    ...
};
void Window::RegisterMessageHandler (UINT uMsg, MESSAGE_HANDLER handler)
{
    m_message_map.emplace (uMsg, handler);
}
LRESULT CALLBACK MySubclassProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData)
{
    X3D::Windows::Control *ctrl = (X3D::Windows::Control*) dwRefData;
    auto handler ctrl->m_message_map.find (uMsg);
    if (handler != ctrl->m_message_map.end ())
        return handler.second (hWnd, uMsg, wParam, lParam);
    ...
}