views:

284

answers:

2

Hello everyone!

I'm currently developing a custom control that derives from CStatic MFC class (Smart Device C++ project). I have created the control class using VC++ MFC class wizard, selecting CStatic class as its base class. I have used Class View to add OnSize event handler for my control class (I have selected WM_SIZE message from messages list), and new OnSize method has been created by Visual Studio along with ON_WM_SIZE() statement between BEGIN_MESSAGE_MAP(...) and END_MESSAGE_MAP(). The problem is that my control does not receive WM_SIZE thus OnSize method is never called - I used MoveWindow to change size of my control - its size changes as I have seen on dialog window but WM_SIZE message is never being sent. When I send WM_SIZE through SendMessage or PostMessage function - the control OnSize method is called normally. What do I wrong? I've read MSDN docs about CStatic control and there is no information that WM_SIZE message is never sent to a static control window.

Sorry for my bad English.

A: 

For a Windows dialog based project I've tested what you describe. I receive WM_SIZE messages in the custom control after a call of MoveWindow. Can you post a few pieces of your source code, especially for the dialog class where you use your custom Static control for your test?

Update after you posted your code

Did you run this in a debugger? I'm wondering why you don't get immediately an exception when the dialog is opened because CThreatSelection::OnSize is fired as one of the first events, even before the window handle threatGrid.m_hWnd of your control exists at all. So calling threatGrid.MoveWindow in your OnSize dialog event should cause an exception when the dialog opens.

I'm not sure what you are trying to achieve but it looks that you want to resize your custom Static according to the dialog size as soon as the dialog opens:

For this a possible alternative could be: Remove CThreatSelection::OnSize and place in CThreatSelection::OnInitDialog instead:

CThreatSelection::OnInitDialog()
{
    CDialog::OnInitDialog();

    // ... perhaps other Init-Stuff...

    CRect rect;
    GetClientRect(&rect);

    threatGrid.MoveWindow(0,0, rect.Width(), rect.Height(), FALSE);

    return TRUE;
}

Here you can call threatGrid.MoveWindow because the Window Handle threatGrid.m_hWnd is already created in OnInitDialog.

Slauma
Indeed it is what I was looking for:) Thank you very much, and yes it is my very first question here so I apologize for my out of place code snippet. I'm a newbie in native smart device programming - back from C# - I wanted to change my control size accordingly to screen orientation change - in C# the best would be to override OnResize event handler - so I thought it is similar in MFC framework... But as You posted above it is not.
Michael P
OK, I moved cotrol size initialization into OnInitDialog method, but still control OnSize is never called by the system...
Michael P
Michael, did you place the code (threatGrid.MoveWindow) AFTER CDialog::OnInitDialog()? (I've edited the code fragment in my answer to make this clear.) That's important, otherwise you have the same problem as before: threatGrid.m_HWnd is not yet initialized. Can you debug your code (or output a message if debugging on your smart device is difficult) and take a look at the value of `threatGrid.m_HWnd`? It must not be NULL when you call MoveWindow.
Slauma
Yes I did. The problem is not with MoveWindow - my control is positioned properly - Your hint made me able to correct initialization stage, but... The problem is when screen orientation changes on windows mobile. The WM_SETTINGSCHANGE message is posted to main window - I receive it, and call MoveWindow on my custom control inside this message handler - the control is then properly positioned but somehow WM_SIZE message is never "caught" by the control OnSize message handler...
Michael P
To make the whole thing clear I'll describe what I do:1) Generate CStatic derived class2) Add OnPaint, OnSize message handlers3) Edit resources (visual editor) - add static control to dialog resource, then add variable to that control, selecting my custom class as control class4) Put size initialization of my control after CDialog::OnInitDialog statement5) Set a breakpoint inside OnSize handler of my custom control class6) Debug
Michael P
Results:Control is positioned properly after EVERY MoveWindow call on my custom control object.Debugger never stops at the one and only breakpoint inside control OnSize - even if I put DebugOutputString with some text it never gets called...
Michael P
Now I really don't have an idea anymore. What you describe is exactly what I did (Old Visual C++ 6 compiler on Windows XP) and I receive the WM_SIZE messages always after MoveWindow. I was guessing it could be related to Windows Mobile but this MSDN doc for Windows Mobile ( http://msdn.microsoft.com/en-us/library/aa932458.aspx ) explicitly says: `"MoveWindow sends WM_WINDOWPOSCHANGED, WM_MOVE, and WM_SIZE messages to the window."` I don't know what's going wrong in your example.
Slauma
Someone had the same problem. Unfortunately they want money to view the answer: http://www.experts-exchange.com/Programming/System/Windows__Programming/MFC/Q_21679424.html
Slauma
I'm using MS Visual Studio 2008 and I'm developing for smart device - Windows Mobile - there can be a difference in MFC implementation. Never mind - now I decided to use Frame - View design - View is not a control, but its a window without title bar, etc. and it RECEIVES WM_SIZE finally...
Michael P
A: 

Below is a header of my CDialog based window generated by MFC wizard

#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);
};

Here is te body:

// 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
}

...And my custom control header:


#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);
};

...and my custom control body:


// 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 
}
Michael P
Hello Michael, I've updated my answer. Take a look.
Slauma
Ah, and by the way: You should place clarifications of your question (like this code snippet) in your original question post (by editing it). Stackoverflow does not have the structure of a discussion forum. One question and (perhaps) many answers shall always stay clearly separated. But it's excusable, I think, for your very first question here ;)
Slauma