关于利用CPicture控件创建异形窗体的相关问题

Fireway2008 2008-12-08 09:50:50
各位高手,本人最近打算利用 CPicture 控件制作一个异形窗体,可是没有意料中的那样顺利。本人自写类 CMyStatic: public CStatic,关键代码如下:

1.添加了如下成员变量:
CBitmap m_bmpDraw;//选入的位图对象
UINT m_MaskBitmapID;// 位图资源ID


2.重载背景OnEraseBkgnd(CDC* pDC)
BOOL CMyStatic::OnEraseBkgnd(CDC* pDC)
{
CRect rectBk;// 客户区的大小
// 无标题栏-获取客户窗口区域
GetClientRect(&rectBk);


CDC memDC;// 内存设备描述表
CBitmap cBitmap;//位图对象
CBitmap* pOldMemBmp = NULL;
BITMAP stBitmap;

//1.构造内存设备环境,并将位图装入
memDC.CreateCompatibleDC(pDC);
//2.加载背景位图
cBitmap.LoadBitmap(m_MaskBitmapID);


pOldMemBmp = memDC.SelectObject(&cBitmap);
//read the cBitmap's size
cBitmap.GetBitmap(&stBitmap);
int stBMPwidth = stBitmap.bmWidth;
int stBMPHeigth = stBitmap.bmHeight;
// 将背景位图复制到窗口客户区
pDC->StretchBlt(0, 0, rectBk.Width(), rectBk.Height(), &memDC, 0, 0,
stBMPwidth, stBMPHeigth, SRCCOPY);//保证图片自适应picture控件大小

……
}

3.利用CreateRectRgn CombineRgn 进行异形窗体的创建
/*以下2个函数配合使用,适用于创建交替变化的异型窗体*/

void CMyStatic::SetMaskImage(UINT nBitmapID)
{
m_bmpDraw.DeleteObject();
// m_bmpDraw.LoadBitmap(m_MaskBitmapID);
m_bmpDraw.LoadBitmap(nBitmapID);//载入待显示的图片
CWindowDC dc(this);// 屏幕左上角(0,0)
// CClientDC dc(this);// 客户区(0,0)
SetupRegion(&dc);
}

void CMyStatic::SetupRegion(CDC *pDC)
{
CDC memDC;
CBitmap &cBitmap = m_bmpDraw;
CBitmap* pOldMemBmp = NULL;
COLORREF col, colMask;
CRect cRect;
int x, y;
CRgn wndRgn, rgnTemp;

GetWindowRect(&cRect);
CPoint ptOrg = cRect.TopLeft();


BITMAP bmInfo;
cBitmap.GetObject(sizeof(bmInfo),&bmInfo);
CRect rcNewWnd = CRect(ptOrg, CSize(bmInfo.bmWidth, bmInfo.bmHeight));

memDC.CreateCompatibleDC(pDC);
pOldMemBmp = memDC.SelectObject(&cBitmap);
colMask = memDC.GetPixel(0,0);//获取左上角的像素色彩
// 首先创建默认的完整区域为完整的 窗口区域

wndRgn.CreateRectRgn(0, 0, rcNewWnd.Width(), rcNewWnd.Height());
// 下面两层循环为检查背景位图像素颜色,
// 当像素颜色为指定的透明颜色时,将该点从区域中裁减掉


for(x=0; x<=rcNewWnd.Width(); x++)
{
for(y=0; y<=rcNewWnd.Height(); y++)
{
col = memDC.GetPixel(x, y);// 取得坐标处像素的颜色值 if(col == colMask)
{// 像素颜色为指定的透明颜色,创建透明的“微区域”
rgnTemp.CreateRectRgn(x, y, x+1, y+1);
// 从完整的区域中裁减掉透明的“微区域”
wndRgn.CombineRgn(&wndRgn, &rgnTemp, RGN_XOR);
// 删除刚创建的“微区域”,释放系统资源
rgnTemp.DeleteObject();
}
}
}
if (pOldMemBmp) memDC.SelectObject(pOldMemBmp);
// 设定窗口为指定的区域,并且擦除窗口重绘
SetWindowRgn((HRGN)wndRgn, TRUE);
MoveWindow(rcNewWnd);
}

1.本人在某对话框内放置一个picture控件,并将其绑定变量m_test.

2.对话框OnInitDialog() 内添加代码,m_test.SetMaskImage(m_MaskBitmapID);

3.picture控件内按默认设置的属性,未进行任何修改。

经过测试,发现背景能顺利地载入,并且大小自适应于Picture 控件的大小。
根据异形窗体创建的原理,前景处应该有一个大小和背景一致的图片,以便裁剪后和背景图片叠加顺利生成异形窗体。但是出现的却是一个和原位图一样大小的图片覆盖在了picture控件之上!和picture控件大小不一致!
以上代码我曾经在创建异形对话框里用过,很成功,但移植到Picture控件就不行了。
本人认为CMyStatic::SetupRegion(CDC *pDC)这个函数内的代码比较可疑,但一时也没看出来,请问各位哪里出错了?
...全文
379 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
Tinary3v0 2008-12-16
  • 打赏
  • 举报
回复
Fireway2008 2008-12-16
  • 打赏
  • 举报
回复
太好了,问题解决,感谢各位高手的指点!
cnzdgs 2008-12-16
  • 打赏
  • 举报
回复
获取图象数据与GetPixel的差别在于GetPixel取每个点都要经过一系列中间过程,直接获取整个图象的数据只需要执行一次中间过程。
不要每个像素都CombineRgn的意思是不要每个像素都调用一次CombineRgn,把一系列像素合在一起,一次CombineRgn来完成,目的也是避免重复执行中间过程。
Tinary3v0 2008-12-16
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 Fireway2008 的回复:]
辛苦楼上的兄台了!
不知道能否采用GetBitmapBits 去处理图像,达到更优化的目的??
之前一楼的朋友提过:
使用GetPixel来扫描位图区效率是很低的,最好直接先获得整个图像区buffer,然后再扫描。
哪位高手可以指点一下??
[/Quote]
没有必要 就算是用了Buffer 也是一样的 你处理图像都要一个像素一个像素的来处理的

如果如18楼说的"不要每个像素都CombineRgn" 可能取到的边缘就没有那么精确了 可能会产生麻边。
cnzdgs 2008-12-16
  • 打赏
  • 举报
回复
就是取图象数据来分析,另外不要每个像素都CombineRgn。
Fireway2008 2008-12-16
  • 打赏
  • 举报
回复
辛苦楼上的兄台了!
不知道能否采用GetBitmapBits 去处理图像,达到更优化的目的??
之前一楼的朋友提过:
使用GetPixel来扫描位图区效率是很低的,最好直接先获得整个图像区buffer,然后再扫描。

哪位高手可以指点一下??
C_MFC 2008-12-16
  • 打赏
  • 举报
回复
真酷!佩服!
Tinary3v0 2008-12-15
  • 打赏
  • 举报
回复

自适应倒是可以做到,如上图,但是图片变得有点怪异,这个跟缩放图像的算法以及掩码颜色选择有关系,算法上的东西恐怕不容易解决。

代码也贴出来,大家检查一下看有没有别的地方需要修改的:
BOOL CMyStatic::OnEraseBkgnd(CDC* pDC) 
{
CRect rectBk;// 客户区的大小
// 无标题栏-获取客户窗口区域
GetWindowRect( &rectBk ); //这里我去取的窗口大小,当然去客户区也行 主要是为了跟SetupRegion中统一
CDC memDC;// 内存设备描述表
CBitmap cBitmap;//位图对象
CBitmap* pOldMemBmp = NULL;
BITMAP stBitmap;

//1.构造内存设备环境,并将位图装入
memDC.CreateCompatibleDC(pDC);
//2.加载背景位图
cBitmap.LoadBitmap(m_MaskBitmapID);

pOldMemBmp = memDC.SelectObject(&cBitmap);
//read the cBitmap's size
cBitmap.GetBitmap(&stBitmap);
int stBMPwidth = stBitmap.bmWidth;
int stBMPHeigth = stBitmap.bmHeight;
// 将背景位图复制到窗口客户区
pDC->StretchBlt( 0, 0, rectBk.Width(), rectBk.Height(), &memDC, 0, 0,stBMPwidth, stBMPHeigth, SRCCOPY); //这里直接把原图缩放到Static窗口贴图就行了。
//绘图完成后的清理
memDC.SelectObject(pOldMemBmp);
if(pOldMemBmp)
{
cBitmap.DeleteObject();
memDC.DeleteDC();
}
return TRUE;
}


void CMyStatic::SetupRegion(CDC *pDC)
{
//---------------------------------------------------------

CRect wndRet;
GetWindowRect( &wndRet );

//---------------------------------------------------------

CBitmap &orgImg = m_bmpDraw;
BITMAP orgInf; orgImg.GetBitmap( &orgInf );
int orgWid = orgInf.bmWidth;
int orgHit = orgInf.bmHeight; //取得原图宽度和高度

//---------------------------------------------------------

CDC istMDC;
CBitmap* preImg = NULL;
istMDC.CreateCompatibleDC( pDC );
preImg = istMDC.SelectObject( &orgImg ); //创建第一层内存DC,并选中原图

//---------------------------------------------------------

CBitmap sndImg;
CDC sndMDC;
sndMDC.CreateCompatibleDC( &istMDC );
sndImg.CreateCompatibleBitmap( &istMDC, wndRet.Width( ),wndRet.Height( ) );
sndMDC.SelectObject( &sndImg ); //创建第二层内存DC,创建一个与当前窗口大小相同的内存图片并选入第二层内存DC。

sndMDC.StretchBlt( 0, 0, wndRet.Width( ), wndRet.Height( ) , &istMDC, 0, 0,orgWid, orgHit, SRCCOPY);

//将原图缩小或放大到当前窗口大小,从第一层内存DC贴到第二层内存DC
//经过上面一步后,实际上就是将位图收缩到了Static窗体当中,此后再去除掩码颜色得到的窗口区域将和Static窗口匹配
//这里直接使用默认的图像缩放(插值),如果对图像不满意,这里只能再用图像处理的方法来解决了,不过速度上可能就比较慢了。

//---------------------------------------------------------

COLORREF mrkCol = sndMDC.GetPixel( 0, 0 );
CRgn wndRgn; wndRgn.CreateRectRgn( 0, 0, wndRet.Width( ), wndRet.Height( ) );

for( int x = 0; x <= wndRet.Width( ); x ++ )
{
for( int y = 0; y <= wndRet.Height( ); y ++ )
{
COLORREF nowCol = sndMDC.GetPixel( x, y );
if( nowCol == mrkCol )
{
CRgn tmpRgn;
tmpRgn.CreateRectRgn( x, y, x + 1, y + 1 );
wndRgn.CombineRgn( &wndRgn, &tmpRgn, RGN_XOR );
tmpRgn.DeleteObject( );
}
}
}

if ( preImg ) istMDC.SelectObject( preImg );

SetWindowRgn( ( HRGN )wndRgn, TRUE );

//----清理内存,防止内存泄露---------------------------------

preImg->DeleteObject();
preImg = NULL;
sndMDC.DeleteDC();
istMDC.DeleteDC();
sndImg.DeleteObject();
orgImg.DeleteObject();

//-----------------------------------------------------------
}
Fireway2008 2008-12-14
  • 打赏
  • 举报
回复
区域裁剪成功了
可是,位图并不能压缩至 picture对话框的大小
我希望这个位图自适应picture控件的大小,如何做到呢?


会不会还与下边的代码有关系呢?
请各位高手指点!
GetWindowRect(&cRect);
CPoint ptOrg = cRect.TopLeft();

BITMAP bmInfo;
cBitmap.GetObject(sizeof(bmInfo),&bmInfo);
CRect rcNewWnd = CRect(ptOrg, CSize(bmInfo.bmWidth, bmInfo.bmHeight)); //这里载入的是位图的大小信息
filec75 2008-12-13
  • 打赏
  • 举报
回复
不懂,up
Fireway2008 2008-12-13
  • 打赏
  • 举报
回复
我按如下方式进行设定,可是发现问题依旧。void CMyStatic::PreSubclassWindow()
{
DWORD style = GetClassLong(m_hWnd, GCL_STYLE);
SetClassLong(m_hWnd, GCL_STYLE, style & ~CS_PARENTDC);
// CStatic::PreSubclassWindow();
}
是不是还有哪些地方没弄对的?
zskof 2008-12-09
  • 打赏
  • 举报
回复
回答10楼的问题,用GetBitmapBits
Fireway2008 2008-12-09
  • 打赏
  • 举报
回复
一楼的朋友提过:
使用GetPixel来扫描位图区效率是很低的,最好直接先获得整个图像区buffer,然后再扫描。

那么我应该如何实现呢?
先获取整个图像区之后稍描 和 直接稍描整个图像区有什么区别呢?
scq2099yt 2008-12-09
  • 打赏
  • 举报
回复
试试8楼的方法
cnzdgs 2008-12-08
  • 打赏
  • 举报
回复
知道问题了,控件一般是CS_PARENTDC类风格,与父窗口共用DC,所以可以绘制到外面的区域,改一下类风格就可以了:
DWORD style = GetClassLong(m_hWnd, GCL_STYLE);
SetClassLong(m_hWnd, GCL_STYLE, style & ~CS_PARENTDC);
Fireway2008 2008-12-08
  • 打赏
  • 举报
回复
楼上的朋友,我的目的是 在picture控件内载入一个位图,然后让位图自适应picture控件框的 大小,你的理解正好相反了。

另外,你的作品在哪里,我走了趟你的空间没看到对应下载地址
有没有源代码供我参考?
zskof 2008-12-08
  • 打赏
  • 举报
回复
这个程序我有点疑问,你是按原图大小来做rgn切割的吧,并将控件置为原图那么大,那么刷背景的时候不存在缩放的问题吧。

如果你是在做项目中需要用异形窗体,可以去我的空间下载,试试我的UI引擎。先创建一个Image,加载图片后直接调用图片的方法CreateRgn即可根据图片创建一个异形rgn。使用GetPixel来扫描位图区效率是很低的,最好直接先获得整个图像区buffer,然后再扫描。
Fireway2008 2008-12-08
  • 打赏
  • 举报
回复
4 楼的朋友,我已经把所有的代码罗列出来了。
剩下的工作就是调用而已。
SetWindowRgn也能执行得到。

我仔细想了想,发现
GetWindowRect(&cRect);
CPoint ptOrg = cRect.TopLeft();

BITMAP bmInfo;
cBitmap.GetObject(sizeof(bmInfo),&bmInfo);
CRect rcNewWnd = CRect(ptOrg, CSize(bmInfo.bmWidth, bmInfo.bmHeight)); //这里载入的是位图的大小信息

但 我的picture控件是比位图要小的,如何把位图压缩并进行区域裁剪呢?
walkbywind 2008-12-08
  • 打赏
  • 举报
回复
mark...
zskof 2008-12-08
  • 打赏
  • 举报
回复
http://download.csdn.net/source/848502

不好意思,之前csdn的服务器出了问题把我上传的删了,可以再试试
加载更多回复(2)
内容概要:本文系统研究了基于豪猪优化算法(CPO)的多无人机协同集群在三维空间中的避障路径规划问题,聚焦于实现以最低成本为目标的航迹优化,综合考虑路径长度、飞行高度、威胁规避及转弯角度等多个关键因素。通过构建精细化的三维环境模型与多无人机协同机制,采用Matlab平台实现CPO算法的仿真与验证,充分展示了该算法在复杂动态障碍环境下的高效搜索能力与全局优化性能。研究不仅涵盖了路径规划的数学建模与目标函数设计,还深入探讨了算法的收敛特性与鲁棒性,为智能群体系统在实际场景中的应用提供了理论依据与技术支撑。; 适合人群:具备一定编程基础和优化算法背景,从事无人机系统控制、智能路径规划、群体协同、人工智能与自动化等相关领域的科研人员、高校研究生及工程技术人员。; 使用场景及目标:①应用于多无人机协同执行侦察、灾害监测、应急救援、区域巡检等复杂任务中的自主路径规划;②为智能优化算法在三维动态环境下的路径决策问题提供可复现的技术范例;③支持研究人员对CPO算法与其他主流群智能算法(如PSO、GWO、WOA等)进行性能对比与改进研究,推动路径规划技术的发展。; 阅读建议:建议结合提供的Matlab代码进行实践操作,重点理解目标函数的多维度建模方式与CPO算法的迭代优化流程,可通过调整环境参数与约束条件进行仿真实验,对比不同算法在相同场景下的路径质量与收敛速度,从而深入掌握其优势与适用边界。
内容概要:本文围绕电动汽车参与电力系统运行备用的能力评估展开深入研究,利用Matlab代码实现对电动汽车集群提供运行备用服务的建模与仿真分析。研究重点在于量化电动汽车作为分布式灵活资源参与电网辅助服务的潜力,通过构建精细化的数学模型,分析其可调功率容量、响应速度、时空分布特性及聚合能力,并采用多面体聚合、内近似模型与闵可夫斯基和等先进方法精确刻画其可调度能力边界。研究进一步结合大规模电动汽车接入场景,探讨其在多时间尺度调度框架下参与调峰、调频等辅助服务的优化策略,评估其对提升高比例可再生能源电网灵活性与稳定性的贡献,最终通过仿真验证所提模型与方法的有效性与实用性。; 适合人群:具备电力系统分析、智能电网、新能源汽车或优化调度等相关专业背景,熟悉Matlab/Simulink仿真工具,从事科研、工程应用的高校研究生、科研人员及电力行业工程师。; 使用场景及目标:①精确评估大规模电动汽车集群在不同约束条件下可提供的运行备用容量;②研究电动汽车在日前、日内及实时调度中的动态响应能力与优化调度策略;③为高渗透率新能源电力系统提供基于移动储能的灵活性资源解决方案,支撑电网安全经济运行。; 阅读建议:建议结合Matlab代码与技术文档同步学习,重点关注多面体聚合建模、能力边界计算及优化调度算法的设计与实现,可进一步拓展至V2G(车辆到电网)、需求响应等互动场景进行二次开发与应用验证。

19,464

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧