本周任务:"具体在下面一排" <后续为:基本控件.可拓展性,界面配置>
模块分类 + 渲染- 已解决;
结构和框架<目录下面有图>;
消息机制 - 已解决;
类关系图.
待办:补充控件列表列举.
******************************************************************
能做什么:
多语言,动画,模块支持多分<脚本创建UI>.LUA脚本模块.
可拓展性:
<skin> xml标签可以拓展 </skin> 圆形头像.
模块分类:<除utilities模块外,其它模块都为soui模块服务。>
utilities模块提供一些工具类,主要包含pugixml,及一个String类。
soui-sys-resource模块是一个纯资源DLL,提供一些内置控件必须的资源。
demo模块是SOUI界面库的功能演示程序。
translator实现一个从XML文件加载多语言翻译资料的类似QT的语言翻译模块。
render-gdi和render-skia分别实现两个基于GDI及SKIA的渲染模块,它们可以相互替换。GDI的优点是体积小,但是对于apha通道支持能力有限;而skia的优点是速度快,全面支持alpha通道,但是程序体积会有所增加, DLL编译后有1M,压缩后有600K。
resprovider-zip实现了一个从ZIP文件加载程序资源的模块。加上soui中内置的两个资源加载模块,SOUI可以选择从文件中,从EXE资源中及从ZIP文件包中加载程序资源。
script-lua是一个脚本支持模块,目前只实现了几个基本类的导出,要使用更多SOUI类型,还需要增加导出代码。加载LUA脚本模块,注意,脚本模块只有在SOUI内核是以DLL方式编译时才能使用。
并且订阅,也是脚本中相应的唯一方式。
♣消息中心概念[记得区分消息订阅"事件和函数绑定"和消息中心的概念]:<应用场景:线程来数据,通知UI刷新>
SNotifyCenter单例:
1、通过使用全局单例,SNotifyCenter可以在代码任意位置获取它的指针(前提当然是要在它的生命周期内);
2、使用SNotifyCenter产生的通知采用SOUI的事件系统来派发,通过结合SOUI的事件订阅系统,用户可以在任意位置处理发出的事件。
FireEventSync, FireEventAsync.
用来触发事件。
RegisterEventMap,UnregisterEventMap.
提供事件处理订阅。
流程实际上有四步:
TplEventArgs<EventLoginModule2UI_GetToken> 派生事件对象.内嵌套数据对象.
窗口从:public TAutoEventMapReg<CMainWnd>派生 //通知中心自动注册 派生.<这步和this相关>
事件消息宏绑定.<对象类中> EVENT_HANDLER(EVT_LOGINMODULE2UI_ACCLOGIN, OnEventLoginModule2UIAccLogin) EVENT_MAP_BEGIN() EVENT_MAP_END() 中
向事件中心添加事件 addEvent
线程中触发:
"触发的时候,New 对应的消息."EventLoginModule2UI_GetToken* pEvt = new EventLoginModule2UI_GetToken(this); <窗口对象的this,给谁处理>
pEvt->m_pKfTokenInfo = pInfo; 消息
SNotifyCenter::getSingleton().FireEventAsync(pEvt); 处理完返回
pEvt->Release();
http://www.cnblogs.com/setoutsoft/p/5642056.html http://blog.csdn.net/ceffans/article/details/78403910 demo:中的page_misc.xml.
notifyCenter.addEvent(EVENTID(EventSendMsg));
notifyCenter.subscribeEvent(&CMainWnd::OnCenterEventSendMsg, this);
也可以通过这种方式绑定:
最终fire<要触发的时候>.
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
窗口和控件关系[总结话语]:
1.每一个使用SOUI创建的界面都是从SHostWnd派生出来的。SHostWnd本身就是一个有窗口句柄的真窗口,因此和一般的win32编程一样,用户可以简单的自己以SHostWnd.m_hWnd为父窗口创建各种真子窗口利用SOUI提供的强大的布局及子窗口管理功能,提供了一个控件:SRealWnd。SRealWnd派生自SWindow,因此它能够实现和SWindow一样的布局功能,要使用SReaWnd来管理子窗口,我们首先需要实现一个接口:IRealWndHandler.<博客:http://www.cnblogs.com/setoutsoft/p/4001039.html>
2.暂时接触到的类:SHostWnd<派生自CSimpleWnd>,SWindow<假窗口,控件>.
3.RegisterSkinClass<SSkinMask>()注册属性;RegisterSkinClass<SSkinNewScrollbar>()注册窗口.
控件两种处理事件方式及其控件属性:
1.SHostWnd窗口的派生类中重载:
UI控件的事件及响应函数映射表: virtual BOOL SHostWnd::_HandleEvent(SOUI::EventArgs *pEvt){return FALSE;}<EVENT_MAP_BEGIN + EVENT_MAP_END>
EVENT_MAP_BEGIN()
EVENT_MAP_DECLEAR()
EVENT_NAME_COMMAND(L"btn_close", OnClose)
EVENT_ID_COMMAND(3, OnRestore)
2.♣消息订阅:<第八篇> 命名空间:SOUI_EVENTS
pHeader->GetEventSet()->subscribeEvent(EVT_HEADER_CLICK,Subscriber(&CMainDlg::OnListHeaderClick,this));<这种最友好 id 加 函数>
bool CMainDlg::OnListHeaderClick(EventArgs *pEvtBase)
要想活用:Events.h中的预定义各种消息订阅的值.EVT_CTXMENU <这里 - 函数参数类型中 定义了事件ID>
m_pChatInput->GetEventSet()->subscribeEvent(&CMainWnd::OnInputRichMenu, this);//涉及到函数类型参数宏.函数参数类型EventCtxMenu 从 public TplEventArgs<EventCtxMenu> 派生.
template<typename T, typename A>
bool subscribeEvent(bool (T::* pFn)(A *), T* pObject) {
return subscribeEvent(A::EventID, Subscriber(pFn, pObject));
}
EventCtxMenu -+ 有好多本身就是预定义的.!<例如鼠标右键.>
3.tab多页面设计分发处理:
EVENT_MAP_BEGIN() //相当于两个tab.因为在不同的页中.
EVENT_NAME_COMMAND(L"btn_close", OnClose)
CHAIN_EVENT_MAP_MEMBER(m_imgMergerHandler) //使用CHAIN_EVENT_MAP_MEMBER宏将来自不同页面的控件事件传递到不同的事件处理对象中。
EVENT_MAP_END()
class CImageMergerHandler : public IFileDropHandler
EVENT_MAP_BEGIN()
EVENT_CHECK_SENDER_ROOT(m_pPageRoot)
//在事件映射表的开始,我们采用EVENT_CHECK_SENDER_ROOT(m_pPageRoot)这个宏来识别那些来自本页面的事件。如果事件是来自其它页面则不处理。
EVENT_NAME_COMMAND(L"btn_save", OnSave) //这里SWindow *m_pPageRoot;存在一个设计技巧.maindlg中处理WM_INITDIALOG时被调用,在oninit中保存了一个页面根节点的指针:以便于过滤.
EVENT_MAP_BREAK()
//注意,这里是以break结尾的.
控件属性:宏展开构成一个空的SetAttribute函数。<宏来处理SObject的属性 >
SOUI_ATTRS_BEGIN
ATTR_STRINGW(L"name",m_strName,FALSE)
ATTR_CUSTOM(L"skin", OnAttrSkin) //直接获得皮肤对象
OUI_ATTRS_END
先查目标对象的属性映射表,再找基类的属性映射表,最后查对象的DefAttributeProc。
自定义控件开发过程:
所有SOUI控件都是在namespace SOUI中,因此自定义控件也最好是放在SOUI这个namespace里。
步骤流程:
1.xml标签.
2.SOUI_CLASS_NAME(SRadioBox2,L"radio2")
3.处理消息和消息列表.
void OnPaint(IRenderTarget *pRT);
SOUI_MSG_MAP_BEGIN()
MSG_WM_PAINT_EX(OnPaint)
消息映射宏模仿的MFC,但又不全一样.转到定义.
SOUI_MSG_MAP_END()
4.自定义属性列表.
SOUI_ATTRS_BEGIN()
ATTR_CUSTOM(L"skin", OnAttrSkin) //为控件提供一个skin属性,用来接收SSkinObj对象的name
SOUI_ATTRS_END()
其它:控件通讯
在SOUI中也可以使用SWindow::SSendMessage来向目标窗口发送一个消息来通讯,但不支持PostMessage
SOUI_MSG_MAP_BEGIN()
MSG_WM_PAINT_EX(OnPaint)
MSG_WM_DESTROY(OnDestroy)
MSG_WM_LBUTTONDOWN(OnLButtonDown)
MSG_WM_MOUSEMOVE(OnMouseMove)
MSG_WM_MOUSELEAVE(OnMouseLeave)
MSG_WM_KEYDOWN(OnKeyDown)
SOUI_MSG_MAP_END()
窗口消息:[重要]由于SWindow的消息来自SHostWnd的消息分发,如果在SHostWnd或者SHostDialog的派生类中处理了一个消息,如果没有将该消息交给SHostWnd继续处理,可能导致SOUI不能正常工作。
*
[基类:SWindow - 假窗口 -]窗口消息:在SWindow及其派生类中处理消息使用WTL基本一致的消息映射宏:
一
SOUI_MSG_MAP_BEGIN()
般
MSG_WM_PAINT_EX(OnPaint)
假
MSG_WM_DESTROY(OnDestroy)
窗
MSG_WM_LBUTTONDOWN(OnLButtonDown)
口,
MSG_WM_MOUSEMOVE(OnMouseMove)
控
MSG_WM_MOUSELEAVE(OnMouseLeave)
件
MSG_WM_KEYDOWN(OnKeyDown)
画
SOUI_MSG_MAP_END()
上
[基类:CSimpleWnd -真窗口-]窗口消息:在CSimpleWnd的派生类(包括SHostWnd, SHostDialog)中直接使用WTL的消息映射宏处理真窗口消息:
去
BEGIN_MSG_MAP_EX(CXXXDlg)
.
MESSAGE_HANDLER(WM_MYMSG,OnMyMsg) //自定义消息
会
MESSAGE_HANDLER(WM_MSG, OnMsg)
截
MSG_WM_CLOSE(OnClose)
获
CHAIN_MSG_MAP(SHostWnd)
,
REFLECT_NOTIFICATIONS_EX()
所
END_MSG_MAP()
假
LRESULT OnMyMsg(UINT uMsg,WPARAM wp,LPARAM lp,BOOL & bHandled);
.
没有WTL使用经历的朋友可能想知道如何将一个消息交给SHostWnd继续处理。当用户在自己的消息映射表中增加一个消息处理函数,而且是插入在映射表的CHAIN_MSG_MAP(SHostWnd)前
(也应该在此之前,否则很可能就收不到消息),默认情况下会自动标志该消息已经被处理了,如此一来就不会继续交给SHostWnd处理,解决办法很简单,在你的消息处理函数中增加一行:
SetMsgHandled(FALSE);<这里在onsize 调用.不然的话也会导致截获处理,因为比如有一些不是自己处理的size 和 timer 基类处理的.被截获了>
有了这一行,你就不用担心你的消息处理影响到SHostWnd的处理了。
/*定时器篇章*/
很多朋友在使用SOUI时处理自己的Timer,结果导致SOUI中的动画不动了,就是因为这个原因:SOUI内部需要处理自己的定时器消息,但它被最外层的消息映射表截断了。
但是需要注意的是,这个映射宏会截获所有分发给宿主窗口的定时器,如果不是自己创建的定时器,则需要继续交给基类处理。
可以调用:SetMsgHandled(FALSE); 或者:SHostWnd::OnTimer(UINT_PTR idEvent);
/*就像 我本来想在真窗口上面处理 绘画WM_LBUTTONDOWN,然后若不在这个处理函数SetMsgHandled(FALSE),就不会触发相应button触发消息*/ 这里要进行设置的,会截获全部的.!<根据具体需求>
实现截获:第十八篇.
类似:PreTranslateMessage.除了需要实现IMessageFilter外,还需要向当前的MessageLoop注册该IMessageFilter。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
资源解析:DEF默认之意. == 可以用ID 和 R 标识的.<比字符创要快.变动大\?>
[资源]uires.idx[资源-命名-路径 绑定]:定义资源."resource"根节点。UIDEF[init.xml-全局ui定义,被main函数中被SApplication对象使用],ICON,CURSOR[光标],LAYOUT[xml布局,全部],IMGX,GIF,rtf[字体],script[Lua脚本],translator[翻译]。
init.xml: 在UIDEF下,可以定义font[字体],string[字符创],skin[图片表],style[class 样式],objattr五个子节点。其它xml,为其它布局xml.
skin->SSkinImgList(imglist)[图片列表], SSkinImgFrame(imgframe)[九宫格], SSkinButton(button), SSkinGradation(gradation), SSkinScrollbar(scrollbar), SSkinMenuBorder(border)这几种绘图类型。
->gif 还有这种操作
[理解完美]这样理解:控件中窑相应的属性,比如skin = 值. 这个值就在init.xml<skin>中单个的name定义</skia>
uires.idx中的name 供给 init.xml 中的资源src 引用.init.xml中的name 供给 布局.xml 中的控件
布局.xml:能定义局部的skia对象和其他对象. 并且其中的控件引用的值是init.xml 当前类型嵌套标签[<skins> </skins>]中的name.
include只有一个属性:src,src定义如何去引用在另一个XML文件中定义的布局XML,如“layout:page_layout” page_layout”中有以"include"的根节点.代表include代表该文件只能是被其它的有include元素的布局文件引用.
总结:布局.xml 找 init.xml,init.xml找uires.idx.
/*
举例: !!!.重要:标签都有对应的类和属性.!!!
imglist包含4个属性:
SOUI_ATTRS_BEGIN()
ATTR_CUSTOM(L"src", OnAttrImage) //skinObj引用的图片文件定义在uires.idx中的name属性。
ATTR_INT(L"tile", m_bTile, TRUE) //绘制是否平铺,0--位伸(默认),其它--平铺
ATTR_INT(L"vertical", m_bVertical, TRUE)//子图是否垂直排列,0--水平排列(默认), 其它--垂直排列
ATTR_INT(L"states",m_nStates,TRUE) //子图数量,默认为1
SOUI_ATTRS_END()
假定上图的图片在uires.idx中的定义为:
uires.idx
<imgx>
<file name='btn_next' file='image\btn.next.png'/>
</imgx>
init.xml
<skins>
<imglist name=“skin_btn_next" src="imgx:btn_next" states="4" tile="0" vertical="0"/>
</skins>
布局.xml
<imgbtn name="btn_close" skin="_skin.btn.close" pos="-35,0" tip="close" animate="1"/>
*/
资源管理:IResProvider
SApplication::AddResProvider(IResProvider *)接口将创建的资源加载器交给SOUI系统管理。
SApplication::RemoveResProvider(IResProvider *)来删除
SApplication::HasResource来查询一个资源是否存在
布局概念:[SOUI中只提供锚点布局] 考虑到锚点布局更直观,而且功能上完全可以解决布局需求,为了简化设计,
锚点布局:对于父窗口不同锚点的位置,当父窗口大小改变时,子窗口也会根据锚点的位置变化自动调整.pos,offset(pos2type), size="width,height", width,height.
width,height[full[代表高度或者宽度和父窗口的客户区大小相等],-1,非负整数.]
pos:指定4个值时,分别代表控件的left,top,right,bottom,指定两个值时代表控件的x,y
指定4个值时,pos目前支持7种标志:|,%,[,],{,},@ <demo中,两个值也支持>
“|”代表参考父窗口的中心;如|-10代表在父窗口的中心向左/上偏移10象素。
“%”代表在父窗口的百分比,可以是小数,负数。如:%40代表在父窗口的40%位置,%-40则等价于(1-40%)。
口诀,相对于兄弟:前rb[]后lt;前lt{}后rb.
“[”相对于前一兄弟窗口。用于X时,参考前一兄弟窗口的right,用于Y时参考前一兄弟窗口的bottom
“]”相对于后一兄弟窗口。用于X时,参考后一兄弟的left,用于Y时参考后一兄弟的top
“{”相对于前一兄弟窗口。用于X时,参考前一兄弟窗口的left,用于Y时参考前一兄弟窗口的top
“}”相对于后一兄弟窗口。用于X时,参考后一兄弟的right,用于Y时参考后一兄弟的bottom
“@”标志用来指定窗口的大小,只能出现在pos属性的第3,4个值中,用来标识窗口的宽度。当后面的值为负时,代表自动计算窗口的宽度或者高度(2015.3.3新增加解释)。
注:“|“, "[" ,"]", "{", "}" 中指定的值都可以为正或者负,
正时向右或者下偏移,负则向左或者上偏移。
当没有上述标志时,负号代表参考父窗口的右边或者下边缩进绝对值位置。如:pos="0,0,-0,-0"代表占满父窗口。而pos="10,10,-10,-10"则代表在父窗口的基础上向内全部缩进10点。
@:指定窗口的size。只能用于x2,y2,用于x2时,指定窗口的width,用于y2时指定窗口的height。注:只能为正值,负号会自动忽略。
其中“{”和“}”是SOUI在DUIENGINE的基础上新增加的布局标志(SOUI是在DUIENGINE的基础上全面重构而来)。
注意!!!由于系统运行向前及向后引用,理论上有可能出来循环引用,导致界面布局失败,因此在使用"[","{",“}” 和"]"这几个标志时需要特别注意。
当pos只指定了x1,y1时,通常需要和offset(或者pos2type),size(或者width,height)配合使用。
pos2type,offset属性包含两个值,用来代表窗口在通过其它布局属性完成后的偏移量:如offset="-1,-1",该offset表明窗口向左方及上方各平衡一个窗口大小的单位。<备注:本来以自己左上定点定位,offset指定为(x,y),左或者右移窗口的0.5,也就是一半.>
九宫格:margin-x="150" margin-y="150"
支持任意窗口相对布局.
指定id窗口值:http://www.cnblogs.com/setoutsoft/p/5164402.html
支持窗口容器布局:
<window layout="vbox"> 会导致pos属性没有意义. 还可以指定排序方式:gravity - left(默认), center, right, hbox有: top(默认), center, bottom.
子空间可以使用layout_gravity: 属性,自定义自己排序方式.
[容器间距]使用extend="left,top,right,bottom", extend_left, extend_top, extend_right, extend_bottom来指定间距. (相当于android的margin)
自适应大小:
Create 未指定大小.<caption size="-2,-1" colorBkgnd="#ffff00"> 拿个地方指定负值,就哪里进行自适应.
网格布局:
GridLayout
文本翻译:
自定义控件:第十篇.
控件的扩展和绘图对象的扩展套路类似,也是先从系统提供的基础类派生,再注册到系统,最后再XML或者代码中使用。
关于控件属性表:从控件xml被加载到内存中.被那个表的值接收.
在SOUI中使用有窗口句柄的子窗口:<第十三篇>
自定义控件-窗口-类:<xml标签 - 关联类>
SWkeLoader wkeLoader;
if(wkeLoader.Init(_T("wke.dll")))
{
theApp->RegisterWndFactory(TplSWindowFactory<SWkeWebkit>());//注册WKE浏览器
}
theApp->RegisterWndFactory(TplSWindowFactory<SGifPlayer>());//注册GIFPlayer
theApp->RegisterSkinFactory(TplSkinFactory<SSkinGif>());//注册SkinGif
theApp->RegisterSkinClass<SSkinMask>();
//这是注册头像控件.<圆形头像.>
功能型查看汇总:
分层窗口的使用:
layeredWindow="1"
richedit可见区域内ole刷新: + 一种快速刷新richedit中内嵌动画的方法的实现
http://www.cnblogs.com/setoutsoft/p/4227529.html
http://www.cnblogs.com/setoutsoft/p/4242907.html
在SOUI中使用代码向窗口中插入子窗口:这个功能必然用得到.<不是窗口,仅仅是动态穿件子控件>
http://www.cnblogs.com/setoutsoft/p/4301928.html
SOUI一个重要特点就是能够自动布局,这个过程的秘密就在于SWindow::OnRelayout方法。
LUA脚本 + 导出SOUI对象到LUA脚本
http://www.cnblogs.com/setoutsoft/p/4340851.html
http://www.cnblogs.com/setoutsoft/p/4361310.html
SListView和SComboView:MVC 以及屏幕适配器配件使用.
SMcListView:博客举例接口.
http://www.cnblogs.com/setoutsoft/p/4863555.html
非半透明窗口实现圆角:http://www.cnblogs.com/setoutsoft/p/5088169.html <属性直接修改(有无子窗口) 或者, 直接有demo>
RichEdit old支持复制粘贴:http://www.cnblogs.com/setoutsoft/p/5240324.html
磁力吸附效果:
多语言动态切换效果:
切换UI语言后,使用SDispatchMessage方法向所有SWindow发送UM_SETLANGUAGE消息.收到消息,重新处理显示.
CAutoRefPtr<ITranslatorMgr> trans; //多语言翻译模块,由translator.dll提供
bLoaded = pComMgr->CreateTranslator((IObjRef**)&trans);
SASSERT_FMT(bLoaded, _T("load interface [%s] failed!"), _T("translator"));
if (trans) {//加载中文语言翻译包}
DPI适配功能:
SOUI需要支持DPI变化时的字体重建,布局坐标重排,图片资源重新获取3部分工作。<已经弄好了,引用流程>
<img skin="scale_pic" pos="|0,|0" offset="-0.5,-0.5"/> 同名skin.然后窗体为:<window pos="20,20,@100dp,@30dp" colorBkgnd="rgba(255,0,0,128)">100dp*30dp</window>
字体和布局的DPIAware很简单,只需要在那些需要dpi自动缩放的位置或者字体大小数字后加上dp即可,可参考上面的XML, pos,size,width, height等属性都可以通过加dp来实现dpiaware。
这里后面的@为指代宽高,这样.在后面加dp.其实是都可以加dp的.
实用demo功能:
demo源码:
托盘显示和菜单:
<shellnotifyicon> 标签.自定义控件,从wwnd派生.
分隔xm设计功能:
<include src="layout:page_ctrls"/>
基本类使用:
FindChildByName/FindChildByID方法.SListCtrl *pList = FindChildByName2<SListCtrl>(L"lc_test");
/*没什么难度,经验总结*/
1.EVENT_NAME_HANDLER(L"lc_test", EVT_CTXMENU, OnMclvCtxMenu)
2.sbTop="30" 基类. butto 渐隐效果-animte=1
3.通过资源设置属性换皮肤:
GetRoot()->SetAttribute(_T("skin"),_T("myskinhellp"),FALSE); <查找到对应窗口,都能设置>
4.画png 图片:
IBitmap * pBmp = SResLoadFromFile::LoadImage(_T("C:\\Users\\Administrator\\Desktop\\123.jpg"));CRect rcClient = GetClientRect(); CSize szBmp(pBmp->Size());pRT->DrawBitmap(rcClient, pBmp, 0, 0);
5.getwindowrect()只有宽度和高度.只能通过其他控价 - 包括getparent() 在进行 FindChildByName. 进行查找控件,获得相对位置.
6.看是注册 控件-还是属性.RegisterWindowClass<SWindow <假窗口> RegisterSkinClass<SSkinObjBase>
7.自定义控件:绘画画笔之类的-从SWindow派生.为啥从ima控件派生有问题\? <这边处理截获soui的消息,应该是没问题的.但是\?demo测测,为什么img有问题>
8.控件可以隐藏.!!<真窗口不响应WM_PAINT直接getdc release绘画,都是画上去的,并且还是透明窗口.>
9.最小化窗口恢复:
解决了, 是因为最小化按钮使用的是SendMessage(WM_SYSCOMMAND, SC_MINIMIZE), 那就必须使用SC_RESTORE来恢复窗口.
10布局可能混乱.
字体没设定.
formattedText.Format(_T("<text font-size=\"%d\" font-face=\"微软雅黑\"><![CDATA["), fontSize);
richedit的使用:这边,会有bug,实际上拷贝下qqlogin中的 dll 即可解决.
11.从外部加载png图片,当成教材显示.
pRT->ReleaseDC(tem);
IBitmap *p = SResLoadFromFile::LoadImageW(_T("C:\\Users\\Administrator\\Desktop\\2.png"));
CRect winrect = GetWindowRect();
pRT->DrawBitmap(&winrect, p, 0, 0);
12.截图操作:
用hbitmap 来 来构建bitmap对象.然后就能用gdi+ 进行 Bitmap<对象构建.>
常见类派生和使用:
SObject:RichEditObj<基础件>-RichEditContent<文本件>-RichEditPara<缩进效果>
SWindow:所有控件,假窗口的派生.
你面上了一家可以的公司的话,进公司学习的东西比你现在自学的不知道强多少倍
人要学会反省,你缺的就是这一点。知道自己哪里不足也不对症下药
IRenderTarget *pRT = GetRenderTarget(&use, OLEDC_OFFSCREEN, FALSE);
这边get后,记得释放掉.
截图所使用到的代码:
CovertToGrayBitmap(HBITMAP hSourceBmp ,HDC sourceDc) --自定义函数,实现位图颜色反转.
HBITMAP retBmp = hSourceBmp;
BITMAPINFO bmpInfo;
ZeroMemory(&bmpInfo ,sizeof(BITMAPINFO));
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
GetDIBits(sourceDc ,retBmp ,0 ,0 ,NULL ,&bmpInfo ,DIB_RGB_COLORS);
BYTE* bits = new BYTE[bmpInfo.bmiHeader.biSizeImage];
GetBitmapBits(retBmp ,bmpInfo.bmiHeader.biSizeImage ,bits);
int bytePerPixel = 4;//默认32位
if( bmpInfo.bmiHeader.biBitCount == 24 )
{
bytePerPixel = 3;
}
for( DWORD i = 0;i<bmpInfo.bmiHeader.biSizeImage;i += bytePerPixel )
{
*(bits + i) = *(bits + i) * 2 / 5;
*(bits + i + 1) = *(bits + i + 1) * 2 / 5;
*(bits + i + 2) = *(bits + i + 2) * 2 / 5;
//BYTE r=*(bits+i);
//BYTE g=*(bits+i+1);
//BYTE b=*(bits+i+2);
//*(bits+i)=*(bits+i+1)=*(bits+i+2)=(r+b+g)/3;
}
SetBitmapBits(retBmp ,bmpInfo.bmiHeader.biSizeImage ,bits);
delete[] bits;