改进duilib的richedit控件的部分功能
转载请说明原出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/41208207
如果要使用透明异形窗体功能,首先要改进duilib库让他本身支持(可以下载duilib扩展群群主改进的库,或者下载我的库),然后要开启窗体的bktrans属性。这时只要使用透明的背景素材就能做出透明异形窗体。但是透明窗体并不好驾驭,会带来很多麻烦。其中之一就是原Edit控件无法使用,这时改用Richedit控件是不错的选择。
RichEdit有很多优势,一是支持透明窗体、二十属性更丰富功能更多,他本身就可以是透明背景,同时还是容器,可以容纳其他控件。不过我在使用他的过程中发现几点不足,所以做了简单的改进,记录到博客里。
改进如下:
1.richedit 控件的容器布局基类从Container改为HorizontalLayout。可以支持相对布局,让richedit可以内嵌更复杂灵活的布局
2.richedit 增加textpadding属性,方便控制布局,控制文字和光标的输出范围,而不需要用原来的inset属性来控制光标的位置
3.richedit增加四种状态的图片,normal、hot、focus、disable,来完成一些细节效果的显示
改进1:
richedit本身是个容器,这点很不错,但是他继承自CContainer容器,本身没有布局功能,这点很不好。我这里做改进时没有让他继承CHorizontalLayout类,因为richedit已经重写了SetPos函数,直接用CHorizontalLayout的SetPos函数的逻辑代码替换掉richedit的SetPos函数的部分代码就行了。记住不要全部替换,因为richedit的SetPos函数的前段的代码是处理richedit光标的代码。修改后的完整代码如下:
void CRichEditUI::SetPos(RECT rc)
{
CControlUI::SetPos(rc);
rc = m_rcItem; rc.left += m_rcInset.left;
rc.top += m_rcInset.top;
rc.right -= m_rcInset.right;
rc.bottom -= m_rcInset.bottom;
bool bVScrollBarVisiable = false;
if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) {
bVScrollBarVisiable = true;
rc.right -= m_pVerticalScrollBar->GetFixedWidth();
}
if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible() ) {
rc.bottom -= m_pHorizontalScrollBar->GetFixedHeight();
} if( m_pTwh ) {
RECT rcRich = rc;
rcRich.left += m_rcTextPadding.left;
rcRich.right -= m_rcTextPadding.right;
rcRich.top += m_rcTextPadding.top;
rcRich.bottom -= m_rcTextPadding.bottom;
m_pTwh->SetClientRect(&rcRich);
if( bVScrollBarVisiable && (!m_pVerticalScrollBar->IsVisible() || m_bVScrollBarFixing) ) {
LONG lWidth = rcRich.right - rcRich.left + m_pVerticalScrollBar->GetFixedWidth();
LONG lHeight = 0;
SIZEL szExtent = { -1, -1 };
m_pTwh->GetTextServices()->TxGetNaturalSize(
DVASPECT_CONTENT,
GetManager()->GetPaintDC(),
NULL,
NULL,
TXTNS_FITTOCONTENT,
&szExtent,
&lWidth,
&lHeight);
if( lHeight > rcRich.bottom - rcRich.top ) {
m_pVerticalScrollBar->SetVisible(true);
m_pVerticalScrollBar->SetScrollPos(0);
m_bVScrollBarFixing = true;
}
else {
if( m_bVScrollBarFixing ) {
m_pVerticalScrollBar->SetVisible(false);
m_bVScrollBarFixing = false;
}
}
}
} if( m_pVerticalScrollBar != NULL && m_pVerticalScrollBar->IsVisible() ) {
RECT rcScrollBarPos = { rc.right, rc.top, rc.right + m_pVerticalScrollBar->GetFixedWidth(), rc.bottom};
m_pVerticalScrollBar->SetPos(rcScrollBarPos);
}
if( m_pHorizontalScrollBar != NULL && m_pHorizontalScrollBar->IsVisible() ) {
RECT rcScrollBarPos = { rc.left, rc.bottom, rc.right, rc.bottom + m_pHorizontalScrollBar->GetFixedHeight()};
m_pHorizontalScrollBar->SetPos(rcScrollBarPos);
}
// 注释掉原来的布局代码
// for( int it = 0; it < m_items.GetSize(); it++ ) {
// CControlUI* pControl = static_cast<CControlUI*>(m_items[it]);
// if( !pControl->IsVisible() ) continue;
// if( pControl->IsFloat() ) {
// SetFloatPos(it);
// }
// else {
// pControl->SetPos(rc); // 所有非float子控件放大到整个客户区
// }
// }
// 替换为新的布局控制代码
SIZE szAvailable = { rc.right - rc.left, rc.bottom - rc.top };
if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible() )
szAvailable.cx += m_pHorizontalScrollBar->GetScrollRange(); int nAdjustables = 0;
int cxFixed = 0;
int nEstimateNum = 0;
for( int it1 = 0; it1 < m_items.GetSize(); it1++ ) {
CControlUI* pControl = static_cast<CControlUI*>(m_items[it1]);
if( !pControl->IsVisible() ) continue;
if( pControl->IsFloat() ) continue;
SIZE sz = pControl->EstimateSize(szAvailable);
if( sz.cx == 0 ) {
nAdjustables++;
}
else {
if( sz.cx < pControl->GetMinWidth() ) sz.cx = pControl->GetMinWidth();
if( sz.cx > pControl->GetMaxWidth() ) sz.cx = pControl->GetMaxWidth();
}
cxFixed += sz.cx + pControl->GetPadding().left + pControl->GetPadding().right;
nEstimateNum++;
}
cxFixed += (nEstimateNum - 1) * m_iChildPadding; int cxExpand = 0;
int cxNeeded = 0;
if( nAdjustables > 0 ) cxExpand = MAX(0, (szAvailable.cx - cxFixed) / nAdjustables);
// Position the elements
SIZE szRemaining = szAvailable;
int iPosX = rc.left;
if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible() ) {
iPosX -= m_pHorizontalScrollBar->GetScrollPos();
}
int iAdjustable = 0;
int cxFixedRemaining = cxFixed;
for( int it2 = 0; it2 < m_items.GetSize(); it2++ ) {
CControlUI* pControl = static_cast<CControlUI*>(m_items[it2]);
if( !pControl->IsVisible() ) continue;
if( pControl->IsFloat() ) {
SetFloatPos(it2);
continue;
}
RECT rcPadding = pControl->GetPadding();
szRemaining.cx -= rcPadding.left;
SIZE sz = pControl->EstimateSize(szRemaining);
if( sz.cx == 0 ) {
iAdjustable++;
sz.cx = cxExpand;
// Distribute remaining to last element (usually round-off left-overs)
if( iAdjustable == nAdjustables ) {
sz.cx = MAX(0, szRemaining.cx - rcPadding.right - cxFixedRemaining);
}
if( sz.cx < pControl->GetMinWidth() ) sz.cx = pControl->GetMinWidth();
if( sz.cx > pControl->GetMaxWidth() ) sz.cx = pControl->GetMaxWidth();
}
else {
if( sz.cx < pControl->GetMinWidth() ) sz.cx = pControl->GetMinWidth();
if( sz.cx > pControl->GetMaxWidth() ) sz.cx = pControl->GetMaxWidth(); cxFixedRemaining -= sz.cx;
} sz.cy = pControl->GetFixedHeight();
if( sz.cy == 0 ) sz.cy = rc.bottom - rc.top - rcPadding.top - rcPadding.bottom;
if( sz.cy < 0 ) sz.cy = 0;
if( sz.cy < pControl->GetMinHeight() ) sz.cy = pControl->GetMinHeight();
if( sz.cy > pControl->GetMaxHeight() ) sz.cy = pControl->GetMaxHeight(); RECT rcCtrl = { iPosX + rcPadding.left, rc.top + rcPadding.top, iPosX + sz.cx + rcPadding.left + rcPadding.right, rc.top + rcPadding.top + sz.cy};
pControl->SetPos(rcCtrl);
iPosX += sz.cx + m_iChildPadding + rcPadding.left + rcPadding.right;
cxNeeded += sz.cx + rcPadding.left + rcPadding.right;
szRemaining.cx -= sz.cx + m_iChildPadding + rcPadding.right;
}
cxNeeded += (nEstimateNum - 1) * m_iChildPadding;
//reddrain
if( m_pHorizontalScrollBar != NULL ) {
if( cxNeeded > rc.right - rc.left ) {
if( m_pHorizontalScrollBar->IsVisible() ) {
m_pHorizontalScrollBar->SetScrollRange(cxNeeded - (rc.right - rc.left));
}
else {
m_pHorizontalScrollBar->SetVisible(true);
m_pHorizontalScrollBar->SetScrollRange(cxNeeded - (rc.right - rc.left));
m_pHorizontalScrollBar->SetScrollPos(0);
rc.bottom -= m_pHorizontalScrollBar->GetFixedHeight();
}
}
else {
if( m_pHorizontalScrollBar->IsVisible() ) {
m_pHorizontalScrollBar->SetVisible(false);
m_pHorizontalScrollBar->SetScrollRange(0);
m_pHorizontalScrollBar->SetScrollPos(0);
rc.bottom += m_pHorizontalScrollBar->GetFixedHeight();
}
}
}
//redrain
}
这样子改进后,就可以很简单的做出仿酷狗的搜索栏的效果,也就是richedit内嵌一个按钮。而不需要用到绝对布局来控制按钮,也不需要为按钮的位置自适应文字担心。
对应的布局代码如下:
<RichEdit name="Edt_Title_Search" rich="false" multiline="false" font="0" text="张学友 童真年代" height="27" textpadding="9,3,35,5" textcolor="#646464" bkcolor="#00FFFFFF" bkimage="UI\title\edit.png" >
<Control height="1"/>
<Button name="Btn_Title_Search" width="33" height="27" normalimage="UI\title\search_normal.png" hotimage="UI\title\search_hover.png" pushedimage="UI\title\search_down.png" />
</RichEdit>
这个改进我已经用到仿酷狗里面了,大家可以下载我的源码去看。布局中设置了一个高度为1的Control,起到了占位作用,让按钮可以自适应位置。
改进2:
在duilib的CRichEditUI控件中,richedit的功能,实际上是调用了系统的richedit的接口来完成的,在CRichEditUI中把这个richedit当作了容器中的一个控件,所以这个richedit的位置,是在SetPos函数中去指定的。在原本CRichEditUI中,要想控制文本的输入区域和光标的位置,需要用到inset属性来控制,这显然和Label以及Edit控件的使用方法不一样。Label和Edit都是用textpadding属性来控制的,所以修改了CRichEdit的代码,让他改用textpadding属性来控制。
首先要在UIRichEdit.h文件中增加两个成员函数和一个成员变量,并且在构造函数里初始化,详细的相信也不需要多说:
RECT GetTextPadding() const;
void SetTextPadding(RECT rc);
RECT m_rcTextPadding;
然后修改SetAttribute函数,增加如下代码:
else if( _tcscmp(pstrName, _T("textpadding")) == 0 ) {
RECT rcTextPadding = { 0 };
LPTSTR pstr = NULL;
rcTextPadding.left = _tcstol(pstrValue, &pstr, 10); ASSERT(pstr);
rcTextPadding.top = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
rcTextPadding.right = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
rcTextPadding.bottom = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
SetTextPadding(rcTextPadding);
}
最后修改SetPos函数,在函数里根据m_rcTextPadding的值去布局richedit组件的位置就可以了,SetPos函数已经在前面给出了。
改进3:
在Edit控件中,支持四种状态的图片:normal、hot、focus、disable。这样可以做到一些细微的效果,比如鼠标移动到edit上面后让控件边框变亮,这点可以看QQ登录器的帐号和密码输入框。但是richedit控件却没有,所以我给他增加了这几个状态图。
1、 首先还是成员函数和成员变量:
LPCTSTR GetNormalImage();
void SetNormalImage(LPCTSTR pStrImage);
LPCTSTR GetHotImage();
void SetHotImage(LPCTSTR pStrImage);
LPCTSTR GetFocusedImage();
void SetFocusedImage(LPCTSTR pStrImage);
LPCTSTR GetDisabledImage();
void SetDisabledImage(LPCTSTR pStrImage);
void PaintStatusImage(HDC hDC);
CDuiString m_sNormalImage;
CDuiString m_sHotImage;
CDuiString m_sFocusedImage;
CDuiString m_sDisabledImage;
然后对应的函数定义为:
LPCTSTR CRichEditUI::GetNormalImage()
{
return m_sNormalImage;
} void CRichEditUI::SetNormalImage(LPCTSTR pStrImage)
{
m_sNormalImage = pStrImage;
Invalidate();
} LPCTSTR CRichEditUI::GetHotImage()
{
return m_sHotImage;
} void CRichEditUI::SetHotImage(LPCTSTR pStrImage)
{
m_sHotImage = pStrImage;
Invalidate();
} LPCTSTR CRichEditUI::GetFocusedImage()
{
return m_sFocusedImage;
} void CRichEditUI::SetFocusedImage(LPCTSTR pStrImage)
{
m_sFocusedImage = pStrImage;
Invalidate();
} LPCTSTR CRichEditUI::GetDisabledImage()
{
return m_sDisabledImage;
} void CRichEditUI::SetDisabledImage(LPCTSTR pStrImage)
{
m_sDisabledImage = pStrImage;
Invalidate();
} RECT CRichEditUI::GetTextPadding() const
{
return m_rcTextPadding;
} void CRichEditUI::SetTextPadding(RECT rc)
{
m_rcTextPadding = rc;
Invalidate();
} void CRichEditUI::PaintStatusImage(HDC hDC)
{
if( IsFocused() ) m_uButtonState |= UISTATE_FOCUSED;
else m_uButtonState &= ~ UISTATE_FOCUSED;
if( !IsEnabled() ) m_uButtonState |= UISTATE_DISABLED;
else m_uButtonState &= ~ UISTATE_DISABLED; if( (m_uButtonState & UISTATE_DISABLED) != 0 ) {
if( !m_sDisabledImage.IsEmpty() ) {
if( !DrawImage(hDC, (LPCTSTR)m_sDisabledImage) ) m_sDisabledImage.Empty();
else return;
}
}
else if( (m_uButtonState & UISTATE_FOCUSED) != 0 ) {
if( !m_sFocusedImage.IsEmpty() ) {
if( !DrawImage(hDC, (LPCTSTR)m_sFocusedImage) ) m_sFocusedImage.Empty();
else return;
}
}
else if( (m_uButtonState & UISTATE_HOT ) != 0 ) {
if( !m_sHotImage.IsEmpty() ) {
if( !DrawImage(hDC, (LPCTSTR)m_sHotImage) ) m_sHotImage.Empty();
else return;
}
} if( !m_sNormalImage.IsEmpty() ) {
if( !DrawImage(hDC, (LPCTSTR)m_sNormalImage) ) m_sNormalImage.Empty();
else return;
}
}
2、同样也需要在SetAttribute中增加如下代码:
else if( _tcscmp(pstrName, _T("normalimage")) == 0 ) SetNormalImage(pstrValue);
else if( _tcscmp(pstrName, _T("hotimage")) == 0 ) SetHotImage(pstrValue);
else if( _tcscmp(pstrName, _T("focusedimage")) == 0 ) SetFocusedImage(pstrValue);
else if( _tcscmp(pstrName, _T("disabledimage")) == 0 ) SetDisabledImage(pstrValue);
3、另外还需要增加一个成员变量来记录控件是否处在hot状态下
UINT m_uButtonState;
然后在DoEvent函数中加入如下代码来改变成员变量
else if( event.Type == UIEVENT_MOUSEMOVE )
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>if( IsEnabled() ) {
<span style="white-space:pre"> </span>m_uButtonState |= UISTATE_HOT;
<span style="white-space:pre"> </span>Invalidate();
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>else if( event.Type == UIEVENT_BUTTONUP )
<span style="white-space:pre"> </span>{ <span style="white-space:pre"> </span>return;
}
<span style="white-space:pre"> </span>else if( event.Type == UIEVENT_MOUSEENTER )
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>if( IsEnabled() ) {
<span style="white-space:pre"> </span>m_uButtonState |= UISTATE_HOT;
<span style="white-space:pre"> </span>Invalidate();
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>else if( event.Type == UIEVENT_MOUSELEAVE )
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>if( IsEnabled() ) {
<span style="white-space:pre"> </span>m_uButtonState &= ~UISTATE_HOT;
<span style="white-space:pre"> </span>Invalidate();
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>return;
<span style="white-space:pre"> </span>}
总结:
上面的所有代码的改进,我都已经在我自己的库里面改好了,我自己的库下载地址为:点击打开链接。
如果有错误或者不妥,请联系我。
Redrain 2014.11.17
QQ:491646717
改进duilib的richedit控件的部分功能的更多相关文章
- 增加duilib edit控件的提示功能和多种文字颜色
转载请说明原出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/41786407 duilib的CEditUI控件内部使用了win32的原生 ...
- duilib修复ActiveXUI控件bug,以支持flash透明动态背景
转载请说明原出处,谢谢~~ 昨天在QQ控件里和同学说起QQ2013登陆窗体的开发,从界面角度考虑,单单一个登陆界面是很容易做出来的.腾讯公司为了 防止各种盗号行为可谓煞费苦心,QQ2013采用了动态背 ...
- 将webkit内核封装为duilib的浏览器控件
转载请说明出处,谢谢~~ 原本的duilib是自带浏览器控件的,但是使用了IE内核,我在做仿酷狗音乐播放器时,在右侧乐库要用到浏览器控件,而我使用自带的IE控件却发现了不少缺点,这也是duilib一直 ...
- RichEdit控件 SDK 参考手册
RichEdit控件 SDK 参考手册 摘要: 本文对Rich Edit控件底层消息机制进行了讲解,以期读者对Windows平台下的Rich Edit控件有一个更深入的认识,同时对于使用Win32 S ...
- 让DELPHI自带的richedit控件显示图片
让DELPHI自带的richedit控件显示图片 unit RichEx; { 2005-03-04 LiChengbin Added: Insert bitmap or gif into RichE ...
- 添加RichEdit控件后导致MFC对话框程序无法运行的解决方法
新建一个基于对话框的MFC程序,对话框上添加了RichEdit控件,编译成功后无法运行起来,Debug版本与Release版本均不行! Windbg分析结果: WARNING: Stack unwin ...
- 给Webkit内核的浏览器控件增加互交功能
转载请说明出处,谢谢~~ 昨天封装了基于webkit的wke浏览器内核,做成了duilib的浏览器控件,实现了浏览功能,但是单单的浏览功能还不满足需求,在我的仿酷狗项目中乐库的功能需要与浏览器互交. ...
- Victor 串口 VCL 控件 - 简单实用, 功能强大的 C++ Builder 串口控件!
源:Victor 串口 VCL 控件 - 简单实用, 功能强大的 C++ Builder 串口控件! 2014年02月06日发布控件的重要更新版本: Victor 串口控件 1.5.0.2 版本 (包 ...
- JS实现为控件添加倒计时功能
一.概述 在有些报表需求中,需要为控件添加倒计时功能,限制到某一个时间点后能进行一项操作或不能进行某项操作,比如查询,导出功能等等,又需要人性化地显示还有多少时间,即倒计时功能,比如下图中我们限制这个 ...
随机推荐
- mac 下tomcat启动报错 unknown host
解决方法:sudo scutil --set HostName localhost
- thrift 安装介绍
一.About thrift thrift是一种可伸缩的跨语言服务的发展软件框架.它结合了功能强大的软件堆栈的代码生成引擎,以建设服务,工作效率和无缝地与C + +,C#,Ja ...
- c# 将字符串转换为逻辑表达式(字符串转换布尔)
比如:string str="6>5"; 要的效果是:bool result=6>5 方案一: 命名空间:System.Data: DataTable dt = new ...
- Eclipse项目内存溢出解决方案
方法一: 打开eclipse,选择Window--Preferences...在对话框左边的树上双击Java,再双击Installed JREs,在右边选择前面有对勾的JRE,再单击右边的“Edit” ...
- Eclipse 插件 —— RunJettyRun 的下载、安装与使用
关于 Jetty 与 Eclipse 的集成,网上很多都是使用 Eclipse 的一个自动安装功能 —— Software Update.个人不太喜欢这种方式.这种安装方式有点问题:第一,需要网络流畅 ...
- 《c程序设计语言》读书笔记--每行一个单词打印输入的字符,除去空符
#include <stdio.h> int main() { int c; while((c = getchar()) != EOF) { if(c != '\n' && ...
- 一个国内的 android 在线帮助网站
只支持到 api 19 http://cs.szpt.edu.cn/android/develop/index.html
- Xcode使用版本
Xcode6中创建分类.协议等文件的方法 Xcode 5.1.1 与 Xcode 6.0.1 的共存之路 http://jingyan.baidu.com/article/1612d500457df1 ...
- 如何配置LCD背光和LED,调试方法
LCD背光和LED配置文件 alps/custom/<proj name>lk/cust_leds.c alps/custom/<proj name>/kernel/leds/ ...
- leetcode:Remove Linked List Elements
Remove all elements from a linked list of integers that have value val. ExampleGiven: 1 --> 2 --& ...