【问题标题】:Why my custom CStatic derived control does not receive WM_SIZE message?为什么我的自定义 CStatic 派生控件没有收到 WM_SIZE 消息?
【发布时间】:2011-01-28 02:25:06
【问题描述】:

我目前正在开发一个从 CStatic MFC 类(智能设备 C++ 项目)派生的自定义控件。 我使用 VC++ MFC 类向导创建了控件类,选择 CStatic 类作为其基类。我已使用类视图为我的控件类添加 OnSize 事件处理程序(我已从消息列表中选择 WM_SIZE 消息),并且 Visual Studio 已创建新的 OnSize 方法以及 BEGIN_MESSAGE_MAP(...) 和 END_MESSAGE_MAP 之间的 ON_WM_SIZE() 语句()。 问题是我的控件没有收到 WM_SIZE,因此永远不会调用 OnSize 方法 - 我使用 MoveWindow 更改控件的大小 - 正如我在对话框窗口中看到的那样,它的大小发生了变化,但从未发送过 WM_SIZE 消息。当我通过 SendMessage 或 PostMessage 函数发送 WM_SIZE 时 - 控制 OnSize 方法被正常调用。我错了什么?我已阅读有关 CStatic 控制的 MSDN 文档,但没有任何信息表明 WM_SIZE 消息永远不会发送到静态控制窗口。

对不起,我的英语不好。

【问题讨论】:

    标签: visual-c++ windows-mobile mfc custom-controls


    【解决方案1】:

    对于基于 Windows 对话框的项目,我已经测试了您所描述的内容。调用 MoveWindow 后,我在自定义控件中收到 WM_SIZE 消息。您能否发布一些源代码,特别是对于您使用自定义静态控件进行测试的对话框类?

    发布代码后更新

    你是在调试器中运行的吗?我想知道为什么在打开对话框时您没有立即收到异常,因为 CThreatSelection::OnSize 作为第一个事件之一被触发,甚至在您的控件的窗口句柄 threatGrid.m_hWnd 完全存在之前。因此,在 OnSize 对话框事件中调用 threatGrid.MoveWindow 应该会在对话框打开时引发异常。

    我不确定您要达到什么目的,但看起来您希望在对话框打开后立即根据对话框大小调整自定义静态的大小:

    为此,一个可能的替代方案可能是:删除 CThreatSelection::OnSize 并替换为 CThreatSelection::OnInitDialog

    CThreatSelection::OnInitDialog()
    {
        CDialog::OnInitDialog();
    
        // ... perhaps other Init-Stuff...
    
        CRect rect;
        GetClientRect(&rect);
    
        threatGrid.MoveWindow(0,0, rect.Width(), rect.Height(), FALSE);
    
        return TRUE;
    }
    

    在这里您可以调用threatGrid.MoveWindow,因为窗口句柄threatGrid.m_hWnd 已经在OnInitDialog 中创建。

    【讨论】:

    • 确实是我要找的:) 非常感谢,是的,这是我在这里的第一个问题,所以我为我的不合适的代码 sn-p 道歉。我是本地智能设备编程的新手 - 从 C# 回来 - 我想根据屏幕方向的变化来改变我的控件大小 - 在 C# 中最好是覆盖 OnResize 事件处理程序 - 所以我认为它在 MFC 框架中是相似的。 .. 但正如你在上面发布的那样,它不是。
    • 好的,我将控制大小初始化移到了 OnInitDialog 方法中,但仍然控制 OnSize 永远不会被系统调用...
    • Michael,您是否将代码 (threatGrid.MoveWindow) 放在 CDialog::OnInitDialog() 之后? (我已经在我的答案中编辑了代码片段以明确这一点。)这很重要,否则您会遇到与以前相同的问题:threatGrid.m_HWnd 尚未初始化。你能调试你的代码(或者在你的智能设备上调试困难时输出一条消息)并看看threatGrid.m_HWnd的值吗?调用 MoveWindow 时不能为 NULL。
    • 是的,我做到了。问题不在于 MoveWindow - 我的控件位置正确 - 您的提示使我能够更正初始化阶段,但是......问题是当 windows mobile 上的屏幕方向发生变化时。 WM_SETTINGSCHANGE 消息被发布到主窗口 - 我收到它,并在此消息处理程序内的自定义控件上调用 MoveWindow - 然后正确定位控件,但不知何故 WM_SIZE 消息永远不会被控件 OnSize 消息处理程序“捕获”...
    • 为了清楚起见,我将描述我的工作:1) 生成 CStatic 派生类 2) 添加 OnPaint、OnSize 消息处理程序 3) 编辑资源(可视化编辑器) - 向对话框添加静态控件资源,然后将变量添加到该控件,选择我的自定义类作为控件类 4)在 CDialog::OnInitDialog 语句之后对我的控件进行大小初始化 5)在我的自定义控件类的 OnSize 处理程序中设置断点 6)调试
    【解决方案2】:

    下面是 MFC 向导生成的基于 CDialog 的窗口的标题

    #pragma once
    #include "threatgrid.h"
    #define COLUMN_COUNT 4
    // CThreatSelection dialog
    
    class CThreatSelection : public CDialog
    {
        DECLARE_DYNAMIC(CThreatSelection)
    
    public:
        CThreatSelection(CWnd* pParent = NULL);   // standard constructor
        virtual ~CThreatSelection();
    
    // Dialog Data
        enum { IDD = IDD_THSELECT };
    
    protected:
        virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    
        DECLARE_MESSAGE_MAP()
    public:
        virtual BOOL OnInitDialog();
    private:
    
    public:
    
        // My custom cotrol field
        CThreatGrid threatGrid;
        afx_msg void OnSize(UINT nType, int cx, int cy);
    };

    这是正文:

    // ThreatSelection.cpp : implementation file
    //
    
    #include "stdafx.h"
    #include "SpeedNotifyNative.h"
    #include "ThreatSelection.h"
    
    
    // CThreatSelection dialog
    
    IMPLEMENT_DYNAMIC(CThreatSelection, CDialog)
    
    CThreatSelection::CThreatSelection(CWnd* pParent /*=NULL*/)
        : CDialog(CThreatSelection::IDD, pParent)
        , threatGrid(theApp.imaging, 3)
    {
    
    }
    
    CThreatSelection::~CThreatSelection()
    {
    }
    
    void CThreatSelection::DoDataExchange(CDataExchange* pDX)
    {
        CDialog::DoDataExchange(pDX);
        DDX_Control(pDX, IDC_THGRID, threatGrid);
    }
    
    
    BEGIN_MESSAGE_MAP(CThreatSelection, CDialog) 
        ON_WM_SIZE()
    END_MESSAGE_MAP()
    
    
    // CThreatSelection message handlers
    
    BOOL CThreatSelection::OnInitDialog()
    {
        CDialog::OnInitDialog();
    
        // TODO:  Add extra initialization here
        return TRUE;  // return TRUE unless you set the focus to a control
        // EXCEPTION: OCX Property Pages should return FALSE
    }
    
    
    void CThreatSelection::OnSize(UINT nType, int cx, int cy)
    {
        threatGrid.MoveWindow(0,0, cx, cy, FALSE);
        //threatGrid.SizeChanged(cx,cy); I use it normally because no WM_SIZE is sent to threatGrid
        CDialog::OnSize(nType, cx, cy);
        // TODO: Add your message handler code here
    }

    ...还有我的自定义控件标题:

    
    #pragma once
    #include "atltypes.h"
    #include "GridIcon.h"
    
    // CThreatGrid
    class ImagingSystem;
    class CThreatGrid : public CStatic
    {
        DECLARE_DYNAMIC(CThreatGrid)
    
    public:
        CThreatGrid(ImagingSystem* imaging, int cols);
        virtual ~CThreatGrid();
    
    protected:
        DECLARE_MESSAGE_MAP()
    
    private:
        // Obiekt podsystemu obrazowania
        ImagingSystem* imaging;
        // Ilość kolumn w siatce
        int columns;
        // Spacing elementów
        int spacing;
    public:
        // Informuje kontrolkę o zmianie rozmiaru - dotychczas nie udało mi się znaleźć rozwiązania dlaczego WM_SIZE nie ejst wysyłane
        void SizeChanged(int cx, int cy);
    private:
        // Aktualny rozmiar - śledzony niezależnie aby uniknąć niepotrzebnych przeładowań obrazków
        CSize currSize;
        // Lista ikon
        std::vector icons;
    public:
        afx_msg void OnSize(UINT nType, int cx, int cy);
    };

    ...和我的自定义控件体:

    
    // ThreatGrid.cpp : implementation file
    //
    
    #include "stdafx.h"
    #include "SpeedNotifyNative.h"
    #include "ThreatGrid.h"
    
    
    // CThreatGrid
    
    IMPLEMENT_DYNAMIC(CThreatGrid, CStatic)
    
    CThreatGrid::CThreatGrid(ImagingSystem* imaging, int cols)
    : imaging(imaging)
    , columns(cols)
    {
    
    }
    
    CThreatGrid::~CThreatGrid()
    {
    
    }
    
    
    BEGIN_MESSAGE_MAP(CThreatGrid, CStatic)
    
        ON_WM_SIZE()
    END_MESSAGE_MAP()
    
    
    // Informuje kontrolkę o zmianie rozmiaru - dotychczas nie udało mi się znaleźć rozwiązania dlaczego WM_SIZE nie ejst wysyłane
    void CThreatGrid::SizeChanged(int cx, int cy)
    {
       CSize nSize(cx,cy);
       if(nSize != currSize)
       {
           currSize = nSize;
           int wspc = (int)(0.015 * cx);
           int hspc = (int)(0.015 * cy);
           spacing = (wspc  0 )
            {
                int rows = (icons.size() + columns - 1) / columns;
                int width = (currSize.cx - spacing * (2 + columns - 1)) / columns;
                int height = (currSize.cy - spacing * (2 + rows - 1)) / rows;
                CSize size;
                if ( width Calculate(i / columns, i % columns, abspoint, size, spacing);
                }
            }
       }
    }
    
    void CThreatGrid::OnSize(UINT nType, int cx, int cy)
    {
        CStatic::OnSize(nType, cx, cy);
    
        // NEVER CALLED BY SYSTEM 
    }
    

    【讨论】:

    • 啊,顺便说一句:您应该在原始问题帖子中(通过编辑)对您的问题进行澄清(例如此代码 sn-p)。 Stackoverflow 没有论坛的结构。一个问题和(也许)许多答案应始终保持清晰分开。但我认为,对于您在这里的第一个问题,这是可以原谅的 ;)
    猜你喜欢
    • 2010-11-15
    • 1970-01-01
    • 2011-08-07
    • 1970-01-01
    • 2021-12-20
    • 2012-06-13
    • 2021-11-15
    • 1970-01-01
    • 2017-07-08
    相关资源
    最近更新 更多