【问题标题】:How to create custom window to be child?如何创建自定义窗口作为孩子?
【发布时间】:2021-12-13 21:40:15
【问题描述】:

我尝试创建从 CWnd 派生自 CFrameWnd 父级的自定义子窗口。子窗口只是带有边框样式的矩形。子创建在父创建之后。它处理OnCreate 事件。但子窗口不出现。这里有什么问题?

#include <afxwin.h>

class Index: public CWnd
{
  public:
    Index()
    {
      CWnd* parentWnd = AfxGetApp()->m_pMainWnd;

      Create(
        NULL, 
        NULL,
        WS_CHILD | WS_BORDER, 
        CRect(CPoint(0, 0), CSize(100, 100)),
        parentWnd, NULL, NULL);
    };
};

class MainFrame: public CFrameWnd
{
  public:
    MainFrame()
    {
      Create(
        NULL,
        "Parent and Child",
        WS_OVERLAPPEDWINDOW,
        CRect(CPoint(0, 0), CSize(640, 360))
      );
    };

  protected:
    afx_msg int OnCreate(LPCREATESTRUCT);
    DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(MainFrame, CFrameWnd)
  ON_WM_CREATE()
END_MESSAGE_MAP()

int MainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
  Index* index = new Index;
  index->ShowWindow(SW_NORMAL);
  
  return 0;
};

class Application: public CWinApp
{
  BOOL InitInstance()
  {
    m_pMainWnd = new MainFrame;
    m_pMainWnd->ShowWindow(SW_NORMAL);
    m_pMainWnd->UpdateWindow();

    return true;
  };    
};

Application app;

【问题讨论】:

    标签: c++ windows mfc


    【解决方案1】:

    当覆盖CWnd::OnCreateCWinApp::InitInstance等方法时,一定要调用基类。

    避免在构造函数中创建新窗口,这会使调试变得非常困难。在父窗口的OnCreate方法中创建子窗口,通过this表示父窗口:

    class Index : public CWnd
    {
    public:
        Index() {}
    };
    
    class MainFrame : public CFrameWnd
    {
    public:
        MainFrame(){};
        afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct)
        {
            CFrameWnd::OnCreate(lpCreateStruct);
            Index* index = new Index;
            index->Create(NULL, NULL, WS_CHILD | WS_VISIBLE | WS_BORDER,
                CRect(0, 0, 400, 300), this, NULL, NULL);
            index->ShowWindow(SW_NORMAL);
            return 0;
        };
        DECLARE_MESSAGE_MAP()
    };
    BEGIN_MESSAGE_MAP(MainFrame, CFrameWnd)
        ON_WM_CREATE()
    END_MESSAGE_MAP()
    
    class Application : public CWinApp
    {
        BOOL InitInstance()
        {
            CWinApp::InitInstance();
            m_pMainWnd = new MainFrame;
            m_pMainWnd->CreateEx(0, AfxRegisterWndClass(0), NULL,
                WS_VISIBLE | WS_OVERLAPPEDWINDOW, 20, 20, 600, 400, NULL, 0);
            return true;
        };
    }; Application app;
    

    【讨论】:

    • 也许在 Create 调用中设置 WS_VISIBLE 样式或使用 SW_SHOW 调用 ShowWindow?
    • @JohnCz 我确实设置了WS_VISIBLE
    【解决方案2】:

    你的帖子只显示 WS_CHILD | WS_BORDER 用于索引类。

    我回来了。 我非常忙,但现在我有时间深入研究您的代码。

    我在很多地方都看到过类似的代码,老实说,这应该永远不会出现。 几件事: 我从不在类的构造函数中进行任何分配。既不记忆也不处理。如果分配失败,则无法正常退出应用程序但会崩溃。有更合适的地方要求创建窗口。

    您发布的代码将会崩溃,因为您调用了 CWnd 类的 Create 成员,而不是 CFrameWnd 类。它以不同的方式实现 Create,调用 CreateEx。 CWnd 会断言。这就是我改变它的原因。

    发布的代码不是您正在构建的代码,这会使任何帮助您的尝试变得更加困难。 继续: 您正在堆上分配 MainFrame 和 Index 对象。这将造成内存泄漏,因为您没有在退出时清理分配。 这不适用于 MainFrame。这个类在 PostNcDestroy 上调用 delete。这是设计使然。所有 Document、View 和 Frame 类都设计为动态分配并释放对象分配。您可以将 Index 类对象声明为 MainFrame 的成员变量。这样,它将在框架(堆栈)上分配,并在 MainFrame 对象超出范围时自动释放。

    当您调用 Create 将 Index 类附加到窗口句柄时,将 AFX_IDW_PANE_FIRST 值作为 ID 传递。框架窗口将自动调整具有此 ID 的窗口大小。 另一条建议:将定义和声明保存在单独的文件中——.cpp 和 .h。此外,将类保存在不同的文件中。它使代码维护变得更加容易。在您的情况下,您需要一个 .cpp 文件来构建 exe。

    我知道这是一个练习,但如果你要学习,最好从一开始就正确地做。我没有将这个 sn-p 分成不同的单元,以便您更轻松地比较代码并查看更改。

    #include <afxwin.h>
    
    class Index : public CWnd
    {
    public:
        Index()
        {
        };
    
        void OnPaint()
        {
            CPaintDC dc(this); // device context for painting  added to indicate that this exists
            CRect recWnd;
            GetClientRect(recWnd);
            dc.DrawText(CString(_T("This is a child window")), CRect(0, 10, recWnd.Width(), 50), DT_CENTER);
        }
    
        DECLARE_MESSAGE_MAP()
    
    };
    
    BEGIN_MESSAGE_MAP(Index, CWnd)
        ON_WM_PAINT()
    END_MESSAGE_MAP()
    
    
    class MainFrame : public CFrameWnd
    {
    public:
        MainFrame()
        {
        };
    
        int OnCreate(LPCREATESTRUCT lpCreateStruct)
        {
            // below, keep only one line uncommented
    
            // if this line is uncommented Index windows will automatically resize. 
            //m_Index.Create(NULL, NULL, WS_CHILD, CRect(0, 0, 0, 0), this, AFX_IDW_PANE_FIRST, NULL);
    
            //This version will not 
            m_Index.Create(NULL, NULL, WS_CHILD | WS_BORDER, CRect(0, 0, 300, 100), this, NULL, NULL);
            
            m_Index.ModifyStyleEx(0, WS_EX_CLIENTEDGE); //to better see the client
            m_Index.ShowWindow(SW_NORMAL);
    
            return 0;
        };
    
    protected:
        Index m_Index;
    protected:
        DECLARE_MESSAGE_MAP()
    };
    BEGIN_MESSAGE_MAP(MainFrame, CFrameWnd)
            ON_WM_CREATE()
    END_MESSAGE_MAP()
    
    
    class Application : public CWinApp
    {
        virtual BOOL InitInstance()
        {
            MainFrame* pMainFrame = new MainFrame;
    
            pMainFrame->Create(NULL, _T("Parent and Child"), WS_OVERLAPPEDWINDOW, CRect(0, 0, 640, 360));
            m_pMainWnd = pMainFrame;
    
            m_pMainWnd->ShowWindow(SW_NORMAL);
            m_pMainWnd->UpdateWindow();
    
            return true;
        };
    };
    
    Application app; 
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-15
      • 2011-06-16
      • 1970-01-01
      • 1970-01-01
      • 2017-05-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多