第十三篇:在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控件的窗口。

时间: 2024-10-13 08:06:02

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

Egret入门学习日记 --- 第二十三篇(书中 9.9~9.11 节 内容)

第二十三篇(书中 9.9~9.11 节 内容) 今天,来9.9节. 重点: 1.VSlider的声明和使用. 操作: 1.VSlider的声明和使用. 其实和HSlider的使用方式差不多. 至此,9.9节 内容结束. 开始 9.10节. 重点: 1.配合TextureMerger,生成艺术字图集资源. 2.导入艺术字资源,并使用. 3.调整艺术字间距. 操作: 1.配合TextureMerger,生成艺术字图集资源. 打开TextureMerger,选择Bitmap Font . 点击添加字符

第二十一篇:SOUI中的控件注册机制

Win32编程中,用户需要一个新控件时,需要向系统注册一个新的控件类型.注册以后,调用::CreateWindow时才能根据标识控件类型的字符串创建出一个新的控件窗口对象. 为了能够从XML描述的字符串中创建出需要的控件对象,和Win32类似,在SOUI中要创建一个新的控件也同样需要向SOUI系统注册新的控件类. 从demo.cpp的main中我们可以看到类似如下的控件注册控件的代码: //向SApplication系统中注册由外部扩展的控件及SkinObj类 SWkeLoader wkeLoa

第二十八篇:SOUI中自定义控件开发过程

在SOUI中已经提供了大部分常用的控件,但是内置控件不可能满足用户的所有要求,因此一个真实的应用少不得还要做一些自定义控件. 学习一个新东西,最简单的办法就是依葫芦画瓢.事实上在SOUI系统中内置控件和自定义控件的开发流程是完全一样的,因此只需要打开SOUI的源代码,随便找一个控件看一下就大体差不多了. 下面我以controls.extend目录下的的SRadioBox2控件为例对控件开发过程需要注意的地方做一点说明. 要开发一个控件,首先要确定的是应该从哪个控件来继承.选择一个合适的基类是正确

第二十三篇:在SOUI中使用LUA脚本开发界面

像写网页一样做客户端界面可能是很多客户端开发的理想. 做好一个可以实现和用户交互的动态网页应该包含两个部分:使用html做网页的布局,使用脚本如vbscript,javascript做用户交互的逻辑.当需求变化时,只需要在服务端把相关代码调整一下,用户即可看到新的内容(界面). 传统的客户端程序开发流程和网页开发可能完全不同. 首先是界面的布局,在老式的界面布局过程中,程序员先在界面上放好各种控件,然后需要自己通过相应的代码来维护界面在不同状态下控件的显示状态及位置.当界面中元素很多时,单纯布局

第二十五篇:在SOUI中做事件分发处理

不同的SOUI控件可以产生不同的事件.SOUI系统中提供了两种事件处理方式:事件订阅 + 事件处理映射表(参见第八篇:SOUI中控件事件的响应) 事件订阅由于直接将事件及事件处理函数连接,不存在事件分发的问题,这里主要介绍使用事件映射表时的事件分发. 在回答这个问题前,首先了解一下什么是事件分发. 在大型项目中,程序逻辑可能非常复杂,如果将所有UI中控件的事件处理集中在一个消息/事件映射表里,代码的可维护性会变得非常差.解决这个问题常见的方法就是将事件进行分类(如根据来源分类),不同类别的事件采

第二十篇:在SOUI中使用分层窗口

从Windows 2K开始,MS为UI开发引入了分层窗口这一窗口风格.使用分层窗口,应用程序的主窗口可以是半透明,也可以是逐点半透明(即每一个像素点的透明度可以不同). 可以说,正是因为有了分层窗口,在Windows上开发的应用程序的UI才真正炫起来. 在UI的主窗口上加一个分层窗口的风格对于一个稍有点UI开发经验的程序员来说是非常简单的,本篇要说的是在SOUI的窗口系统中实现SOUI的分层窗口. 正如使用系统的窗口已经可以实现很漂亮的UI,我们还是会需要DirectUI这样的UI开发技术:有了

第五篇:在SOUI中使用XML布局窗口

窗口布局的概念 每一个UI都是由大量的界面元素构成的,在Windows编程,这些界面元素的最小单位通常称之为控件. 布局就是这些控件在主界面上的大小及相对位置. 传统的布局一般使用一个4个绝对坐标来定义一个控件在主窗口的位置.对于窗口是固定大小的界面来说,这种方式是最简单有效的. 然而问题在于在Windows系统上编程,基本上很少有程序的窗口是固定大小的,用户希望它的窗口能够随时调整大小.调整大小后界面里的控件还能够按照一定的规则进行重排. 我自己最讨厌的就是在WM_SIZE里重排控件位置. 随

第二十三篇:Windows中的ACPI

一直不太清楚ACPI驱动在WINDOWS中的作用. 甚至不了解ACPI协议的作用. 于是, 随便翻了下"格蠹汇编"中的第24章, 如何跟踪ACPI代码, 算是对ACPI有了一个初步性的了解. ACPI向OS报告硬件信息, 而OS通过ACPI控制硬件. ACPI就是OS与硬件/固件之间的一个标准接口协议. ACPI通过ASL(ACPI SOURCE LANGUAGE)来描述系统硬件的属性与方法, ASL最终会被编译为AML(ACPI MACHINE LANGUAGE)的字节码(BYTEC

第十五篇:在SOUI中消息通讯

SOUI是一套基于Win32 SDK的窗口开发的一套DirectUI框架.在SOUI中除了有真窗口使用窗口消息通讯机制外,还有SOUI控件之间的通讯,及控件的事件处理等. 1.真窗口消息通讯 因此可以使用::SendMessage这个API来与宿主窗口通讯.在任意一个地方只要获取到了SOUI的宿主窗口句柄就可以向该窗口发消息. 发消息以后可以在主界面的真窗口的消息映射表中响应各种自定义消息(如下): #define WM_MYMSG (WM_USER+100) LRESULT OnMyMsg(U