如何在WTL和MFC中使用duilib及如何静态使用duilib库

如何在WTL和MFC中使用duilib及如何静态使用duilib库,第1张

现在把我在实现过程中遇到的问题及解决方法列举一下 以便大家以后遇到问题的时候做一个参考。

1.我喜欢用静态库,不喜欢用动态库,用动态库就好像穿衣服还要随身携带衣架一样,多余还麻烦。

所以在用这个库的时候 第一件事就是把动态库变成静态库。还有改用成 unicode字符集

(1).找到uilib.h头文件 注释掉原有的定义:添加新的宏 #define UILIB_API

//#ifdef UILIB_EXPORTS

//#define UILIB_API __declspec(dllexport)

//#else

//#define UILIB_API __declspec(dllimport)

//#endif

(2)编译后不会报错,然后 在使用时就可以直接包含这个静态库了 同时要注意一点 还需要包含 几个静态库oledlg.lib dui.lib winmm.lib comctl32.lib

虽然也不简单,但是却可以让程序生成后 只有一个exe 也没有其他累赘。

2. 包含之后 编译工程 会报错createtextserver没有定义什么的。这个是因为新版本中加入了richedit支持,这个directui的 需要用到 texthost和textserver 这时候 需要引用richedit.dll和richedit.lib 为了方便,我把这部分的导入 放到了duilib库里面了。 至于是什么代码我就不贴了 导入库的代码 是个程序员就会了。

3.如果你的wtl ATL MFC文件已经包含了 atltypes之类的头文件,那你会发现会出N多的 crect cpoint csize等 说不知道用哪个。因为duilib自己实现了这三个函数 和ATL MFC WL里面的冲突了。那么这时候怎么办呢?.. 当然是用宏了,我们在duilib的 uibase.h下面可以找到他们定义 在定义前加#ifndef DUI_NOTYPES 定义后追加 #endif 这样我们在WTL中引入duilib库的时候 引用前加入 #define DUI_NOTYPES 就可以屏蔽掉那些错误了。

4. 接下来的问题 都快让我崩溃了,不过最后还是解决了。

在前面问题逐一解决之后 你会发现 项目里的很多地方都莫名其妙的报错了,甚至连最基本的 CDC CmemeryDC Cpen什么的都不认了 报一堆错误。

错误原因在于duilib里面的 windowsx.h头文件,这个是sdk编程人员不可能不知道的头文件了,里面是一些宏的定义,大大的方便了sdk编程。

而在这里却成了阻碍,那么怎么办呢? 我看了下报错的地方 又看了下windowsx里面宏,发现其实原因很简单,里面的一些宏定义和WTL的函数定义冲突了。那么这个时候 我们需要使用微软的 函数保护机制了。在我的项目中有冲突的是下面几个函数 SelectFont SelectPen 其实还有很多 selectbrush等。报什么错就加什么 没有必要一次加齐。

#ifdef _INC_WINDOWSX

#undef SelectFont

#undef SelectPen

#endif // _INC_WINDOWSX

5.那么到这个时候就可以正常的在WTL中使用duilib库了。

6.那么我们来说说 那棵树的实现。

树无疑 就是里面的list靠缩进实现了。节点我选择用以下模式做的。这样后面排序的时候 我只需要交换CHorizontalLayoutUI就可以了 而无须改变

CListContainerElementUI 索引号了。

CListContainerElementUI

CHorizontalLayoutUI

控件

控件

CHorizontalLayoutUI

CListContainerElementUI

7.自动计算下滚动条,

CListContainerElementUI 没有自动计算下滚动条的功能,可能是因为是容器 里面的东西多少位置之类的都无法确定吧。

我的项目为了针对我这个项目 我在CHorizontalLayoutUI 插入了Ctextui 在底层库里面加入自动计算Ctextui 的宽度并设置CListContainerElementUI 宽度的逻辑就可以了

在这个过程总需要注意CListContainerElementUI 的setfixwight 有刷新的 会导致死循环 所以要加一个默认参数。

8.排序 排序就不多说的 原理比较简单 一个快速排序,然后 颠倒CHorizontalLayoutUI和 tag就可以了、我的快排写的 比较麻烦好像 因为当时比较着急 写的时候比较乱 不过还可以 至少实现功能了,但是目前只是叶子节点排序,如果想实现非叶子节点排序也不是不可以,但是会比较麻烦 因为我也不用 就没写,有兴趣的自己写下吧。

demo真是非常之简单,只有一个treeviwe 其他的什么都没有.连标题栏什么都没写 那些我相信大家很简单的就能写出来。我把demo放到csdn上 想看的下载吧 。转载。

如果要使用Duilib美化,那么最好不要使用MFC中按钮或者控件,Duilib是在一个窗口上画出所有控件并模拟控件的 *** 作,而MFC中按钮或者控件都是窗口,Duilib不适用,如果想美化MFC中按钮或者控件,可以使用自绘控件,或针对美化MFC中按钮或者控件的皮肤库。

1. VK_TAB无效

2. 如果窗口中内嵌了WebBrowser,浏览器的CTRL+C、V无效,DEL无效

3. 如果窗口中内嵌了WebBrowser,则其他部分的滚动条将失效

由于我对duilib还不熟悉,当碰到这几个问题时,一下子没了主意,只好请教于群内的各路大神,可更多的得到的答复是:为什么要与MFC混用?

我想大家可能更多的是考虑一个项目新建立,能直接使用duilib框架,还用什么MFC,而且MFC似乎本来就不怎么受人待见;但这里我想说的是,对于若干MFC的老项目,想切换UI到duilib上,难道说完全重写过么? 而且我已经做过迁移测试,将MFC项目的UI切换到duilib,可以比较简单的在duilib的UI与旧的MFC窗口的逻辑中间加一层代理转发,这样的工作量还是可以控制的。

扯远了,最终经过多次询问,还是在群里碰到了有相关处理经验的朋友,经过他们的指点,总算对这种兼容处理有了一些思路,下面就将我目前的处理方案贴出来:

1. VK_TAB无效

这个需要在MFC的窗口类中处理 PreTranslateMessage ,将对于VK_TAB的处理强制交给duilib的 CPaintManagerUI::TranslateMessage 来处理

2. 如果窗口中内嵌了WebBrowser,浏览器的CTRL+C、V无效,DEL无效

这个与第一点类似,将给duilib来处理即可

第1与2点代码如下:

BOOL CMFCTestDlg::PreTranslateMessage( MSG* pMsg )

{

if( pMsg->message == WM_KEYDOWN)

{

{

if (pMsg->wParam == VK_ESCAPE || pMsg->wParam == VK_RETURN || pMsg->wParam == VK_TAB || pMsg->wParam == VK_DELETE)

{

if(m_dlgWnd.TranslateMessage(pMsg))

return TRUE

}

else if (pMsg->wParam == 'C' || pMsg->wParam == 'V')

{

if( (GetKeyState(VK_CONTROL) &0x8000))

{

m_dlgWnd.TranslateMessage(pMsg)

}

}

}

}

return CDialog::PreTranslateMessage(pMsg)

//TranslateMessage方法仅是转而调用CPaintManagerUI::TranslateMessage

bool MainFrame::TranslateMessage( MSG* pMsg )

{

return m_PaintManager.TranslateMessage(pMsg)

}

这里其实根本原因,原理我还没搞清楚,请知道的补充一下。

3. 如果窗口中内嵌了WebBrowser,则其他部分的滚动条将失效

这个问题以前就发现了,但在昨天才发现,如果将内嵌的浏览器拿掉的话,滚动条又正常了,进行了跟踪,发现是由于当窗口中未选中任何的Edit或其他可 *** 作的控件时,默认的焦点是在这个 WebBrowser 上[原因不详],这样鼠标中键滚轮滚动时,WM_MOUSEWHEEL消息会被路由到 LRESULT CActiveXWnd::HandleMessage,而此处对于消息 WM_MOUSEWHEEL是直接丢弃,导致了滚动条消息丢失了,按如下处理可以解决这个问题:

将WM_MOUSEWHEEL消息发给主窗口进行处理:

LRESULT CActiveXWnd::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)

{

LRESULT lRes=0

BOOL bHandled = TRUE

switch( uMsg ) {

case WM_PAINT: lRes = OnPaint(uMsg, wParam, lParam, bHandled)break

case WM_SETFOCUS: lRes = OnSetFocus(uMsg, wParam, lParam, bHandled)break

case WM_KILLFOCUS: lRes = OnKillFocus(uMsg, wParam, lParam, bHandled)break

case WM_ERASEBKGND:lRes = OnEraseBkgnd(uMsg, wParam, lParam, bHandled)break

case WM_MOUSEACTIVATE: lRes = OnMouseActivate(uMsg, wParam, lParam, bHandled)break

case WM_MOUSEWHEEL:

{

::PostMessage(::GetParent(GetHWND()), uMsg, wParam, lParam)

return 0

}

break

default:

bHandled = FALSE

}

if( !bHandled ) return CWindowWnd::HandleMessage(uMsg, wParam, lParam)

return lRes

}

按上述处理,目前这几个问题基本得到了处理,我也敢在项目中应用了,但其实这里还是有细节问题的,比如:

1. 按TAB键后,如果没有WebBrowser,则按到最后,TAB就没办法切换有焦点的控件了,一直出现叮叮的系统声音[不可 *** 作]

2. 按TAB键,如果有WebBrowser,则最终焦点进入WebBrowser后,不能切换出来了,只能通过鼠标来调整焦点;另外如果当前窗口没选中任何控件,默认焦点在 WebBrowser 中,按TAB键则直接进入了WebBrowser 中。

3. 另外还有一个问题duilib的问题,我这边暂时简单处理了一下

所有的button类[button,check,option等]均会响应TABSTOP,这个可以在XML文件中通过keyboard属性来设置,但库中的CTreeViewUI中创建节点中会自动添加按钮,这种需要手动将其设置为不响应TABSTOP:

pFolderButton->SetKeyboardEnabled(false)

pDottedLine->SetKeyboardEnabled(false)

pCheckBox->SetKeyboardEnabled(false)

pItemButton->SetKeyboardEnabled(false)

我目前直接将所有按钮的默认接受属性设置成了false,需要的时候针对需要的按钮设置 keyboard属性。


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/bake/11178728.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-14
下一篇2023-05-14

发表评论

登录后才能评论

评论列表(0条)

    保存