第十三篇:在SOUI中使用有窗口句柄的子窗口


前言:

無論一個DirectUI系統提供的DUI控件多么豐富,總會有些情況下用戶需要在DUI窗口上放置有窗口句柄的子窗口。

為了和無窗口句柄的子窗口相區別,這里將有窗口句柄的子窗口稱之為真窗口

每一個使用SOUI創建的界面都是從SHostWnd派生出來的。SHostWnd本身就是一個有窗口句柄的真窗口。

因此和一般的win32編程一樣,用戶可以簡單的自己以SHostWnd.m_hWnd為父窗口創建各種真子窗口。然后和win32一樣,響應resize等消息自己管理子窗口的位置及顯示。

很顯然,這樣處理將不能有效的利用SOUI提供的強大的布局及子窗口管理功能。

為了能夠更有效的管理真窗口,在SOUI系統中提供了一個控件:SRealWnd。

SRealWnd派生自SWindow,因此它能夠實現和SWindow一樣的布局功能,並被SOUI系統管理窗口的各種狀態:如size,visible等。

要使用SReaWnd來管理子窗口,我們首先需要實現一個接口:IRealWndHandler

IRealWndHandler的定義:

    /** 
    * @struct     IRealWndHandler
    * @brief     
    *
    * Describe   
    */
    struct IRealWndHandler : public IObjRef
    {
        /**
        * SRealWnd::OnRealWndCreate
        * @brief    窗口創建
        * @param    SRealWnd *pRealWnd -- 窗口指針
        *
        * Describe  窗口創建
        */    
        virtual HWND OnRealWndCreate(SRealWnd *pRealWnd)=NULL;

        /**
        * SRealWnd::OnRealWndDestroy
        * @brief    銷毀窗口
        * @param    SRealWnd *pRealWnd -- 窗口指針
        *
        * Describe  銷毀窗口
        */
        virtual void OnRealWndDestroy(SRealWnd *pRealWnd)=NULL;

        /**
        * SRealWnd::OnRealWndInit
        * @brief    初始化窗口
        * @param    SRealWnd *pRealWnd -- 窗口指針
        * @return   BOOL -- FALSE:交由系統處理,TRUE:用戶處理
        *
        * Describe  初始化窗口
        */
        virtual BOOL OnRealWndInit(SRealWnd *pRealWnd)=NULL;

        /**
        * SRealWnd::OnRealWndSize
        * @brief    調整窗口大小
        * @param    SRealWnd *pRealWnd -- 窗口指針
        * @return   BOOL -- FALSE:交由SOUI處理; TRUE:用戶管理窗口的移動
        *
        * Describe  調整窗口大小
        */
        virtual BOOL OnRealWndSize(SRealWnd *pRealWnd)=NULL;
    };

可以看到這里一共有4個接口,其中OnRealWndInit是OnRealWndSize為真窗口初始化及位置調整的回調,一般可以不處理,其它2個接口則是管理真窗口的創建及銷毀,因此必須有實現。

接口實現示例:

真窗口的具體使用方法可以參考SOUI代碼中samples目錄下的mfc.demo。

這里把代碼實現帖出來:

SouiRealWndHandler.h

#pragma once

#include <unknown/obj-ref-impl.hpp>

namespace SOUI
{
    class CSouiRealWndHandler :public TObjRefImpl2<IRealWndHandler,CSouiRealWndHandler>
    {
    public:
        CSouiRealWndHandler(void);
        ~CSouiRealWndHandler(void);

        /**
         * SRealWnd::OnRealWndCreate
         * @brief    創建真窗口
         * @param    SRealWnd * pRealWnd --  窗口指針
         * @return   HWND -- 創建出來的真窗口句柄
         * Describe  
         */    
        virtual HWND OnRealWndCreate(SRealWnd *pRealWnd);

        /**
        * SRealWnd::OnRealWndDestroy
        * @brief    銷毀窗口
        * @param    SRealWnd *pRealWnd -- 窗口指針
        *
        * Describe  銷毀窗口
        */
        virtual void OnRealWndDestroy(SRealWnd *pRealWnd);

        /**
        * SRealWnd::OnRealWndInit
        * @brief    初始化窗口
        * @param    SRealWnd *pRealWnd -- 窗口指針
        *
        * Describe  初始化窗口
        */
        virtual BOOL OnRealWndInit(SRealWnd *pRealWnd);

        /**
        * SRealWnd::OnRealWndSize
        * @brief    調整窗口大小
        * @param    SRealWnd *pRealWnd -- 窗口指針
        * @return   BOOL -- TRUE:用戶管理窗口的移動;FALSE:交由SOUI自己管理。
        * Describe  調整窗口大小, 從pRealWnd中獲得窗口位置。
        */
        virtual BOOL OnRealWndSize(SRealWnd *pRealWnd);
    };

}

SouiRealWndHandler.cpp:

#include "StdAfx.h"
#include "SouiRealWndHandler.h"

namespace SOUI
{
    CSouiRealWndHandler::CSouiRealWndHandler(void)
    {
    }

    CSouiRealWndHandler::~CSouiRealWndHandler(void)
    {
    }

    HWND CSouiRealWndHandler::OnRealWndCreate( SRealWnd *pRealWnd )
    {
        const SRealWndParam &param=pRealWnd->GetRealWndParam();
        if(param.m_strClassName==_T("button"))
        {//只實現了button的創建
            //分配一個MFC CButton對象
            CButton *pbtn=new CButton;
            //創建CButton窗口,注意使用pRealWnd->GetContainer()->GetHostHwnd()作為CButton的父窗口
            //把pRealWnd->GetID()作為真窗口的ID
            pbtn->Create(param.m_strWindowName,WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,::CRect(0,0,0,0),CWnd::FromHandle(pRealWnd->GetContainer()->GetHostHwnd()),pRealWnd->GetID());
            //把pbtn的指針放到SRealWnd的Data中保存,以便在窗口destroy時釋放pbtn對象。
            pRealWnd->SetData(pbtn);
            //返回成功創建后的窗口句柄
            return pbtn->m_hWnd;
        }else
        {
            return 0;
        }
    }

    void CSouiRealWndHandler::OnRealWndDestroy( SRealWnd *pRealWnd )
    {
        const SRealWndParam &param=pRealWnd->GetRealWndParam();
        if(param.m_strClassName==_T("button"))
        {//銷毀真窗口,釋放窗口占用的內存
            CButton *pbtn=(CButton*) pRealWnd->GetData();
            if(pbtn)
            {
                pbtn->DestroyWindow();
                delete pbtn;
            }
        }
    }
    
    //不處理,返回FALSE
    BOOL CSouiRealWndHandler::OnRealWndSize( SRealWnd *pRealWnd )
    {
        return FALSE;
    }

    //不處理,返回FALSE
    BOOL CSouiRealWndHandler::OnRealWndInit( SRealWnd *pRealWnd )
    {
        return FALSE;
    }
}

整體上代碼很簡單,配上注釋,應該一看就懂。

XML配置:

<SOUI title="DUI-DEMO" width="600" height="400" appwin="0" ncRect="5,5,5,5"  resize="1" translucent="0">
  <root skin="skin.bkframe" cache="1">
    <caption pos="0,0,-0,29">
      <text pos="11,9" >%title% ver:%ver%</text>
      <imgbtn id="1" name="btn_close" skin="skin.btnclose" pos="-45,0" tip="close" animate="0"/>
    </caption>
    <window pos="0,29,-0,-0">
      <realwnd pos="10,10,-10,-10" name="mfcbtn" wndclass="button" id="100" wndname="MFC Button"/>
    </window>
  </root>
</SOUI>

在XML中,我們使用了一個realwnd的標簽,該標簽有一個重要的屬性:wndclass,IRealWndHandler通過該屬性來判斷應該創建一個什么樣的真窗口。

運行效果:

上面紅框中的按鈕即為使用realwnd標簽創建的MFC Button。

真窗口的消息響應:

由於真窗口是SOUI主窗口的子窗口,因此真窗口的消息可以在SOUI主窗口的消息映射表中處理(注意:這里不是SOUI控件的事件映射表)。

如:

#pragma once

class CRealWndDlg : public SOUI::SHostDialog
{
public:
    CRealWndDlg(void);
    ~CRealWndDlg(void);

    //響應MFC.button的按下消息, nID==100為在XML中指定的realwnd的id屬性。
    void OnBtnClick( UINT uNotifyCode, int nID, HWND wndCtl )
    {
        if(uNotifyCode == BN_CLICKED && nID == 100)
        {
            SOUI::SMessageBox(m_hWnd,_T("the real mfc button is clicked!"),_T("mfc.demo"),MB_OK|MB_ICONEXCLAMATION);
        }
    }

    //消息映射表
    BEGIN_MSG_MAP_EX(CMainDlg)
        MSG_WM_COMMAND(OnBtnClick)
        CHAIN_MSG_MAP(SOUI::SHostDialog)
        REFLECT_NOTIFICATIONS_EX()
    END_MSG_MAP()
};

結束語:

很顯然,通過這種方式,也可以非常方便的創建出各種類型的其它窗口。

窗口創建出來后,系統就會自動管理窗口狀態。

最后,要記住一條:有真窗口時,SOUI主窗口不能設置translucent="1"這一屬性。因為任何子窗口在半透明窗口上都不能正常顯示。這一條也適用於包含IE控件的窗口。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM