关于利用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)这个函数内的代码比较可疑,但一时也没看出来,请问各位哪里出错了?
...全文
377 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)
代码转载自:https://pan.quark.cn/s/a4b39357ea24 基于VHDL语言的24进制多功能数字钟 FPGA多功能数字钟设计 安装要求 本项目采用QuartusII9.0版本设计,非9.0版本打开可能会存在兼容性问题。 本项目选用FPGA器件为CycloneIII_EP3C40Q240C8 设计任务 设计一个24进制多功能数字电子钟,要求具备以下功能: (1)时钟显示:能够以十进制在7段数码管上显示“时”、“分”、“秒”、“十分之一秒”。 (2)校表功能:能够对时钟进行校正。 (3)启动/暂停功能:能够控制时钟的启动和暂停。 (4)一键清零功能:能够将时钟清零。 (5)整点报时功能:能够在整点时发出报时信号。 (6)闹钟功能:能够在设置的时间到达时发出闹钟信号。 顶层设计原理图如下: image 设计方案/设计原理及总体框图 设计实现思路: (1)计时功能。 计时功能主要由四个计数器模块共同构成,其中十分之一秒计时器为十进制计数、分,秒计时器为六十进制计数、小时计时器为二十四进制计数。 计时器之间采用进位信号进行串联。 (2)十进制7端数码管显示功能。 显示功能由译码器模块实现。 译码器模块的两个输入端分别为刷新端和数据端。 七个译码器的刷新端连接十分之一秒的周期脉冲信号。 而数据端连接计数器的输出端,用以将4位输出BCD码译码为7端数码管的七位显示信号。 (3)校表功能。 校表功能由二选一模块和校时模式选择器模块构成。 其中二选一模块用于连接下一级计时器模块的进位信号和手动按钮脉冲信号。 当控制信号为“0”时,二选一模块输出计时器模块的进位信号。 而当控制信号为“1”时,二选一模块输出手动按钮信号。 控制信号由校时模式选择器模块输出,校时模式选择器输出端连...
内容概要:本文围绕基于交替方向乘子法(ADMM)的多主体综合能源系统分布式协同优化展开研究,提出一种可在保护各参与主体数据隐私的前提下实现全局协同优化的分布式算法框架。通过构建增广拉格朗日函数,将集中式优化问题分解为多个子问题,各主体并行迭代求解并仅交换边界变量信息,从而在保证隐私安全的同时实现系统整体能效与经济性的提升。研究详细阐述了ADMM算法的数学建模过程、收敛性条件及其实现在多主体电-热-气综合能源系统中的应用,并通过Matlab代码进行仿真验证,展示了其在园区、微电网群等场景下的有效性与实用性。; 适合人群:具备一定电力系统优化、分布式算法理论基础及Matlab编程能力的研究生、科研人员以及从事综合能源系统、能源互联网、智能电网等相关领域的工程师;特别适合关注分布式优化、隐私保护协同调度等前沿方向的专业技术人员。; 使用场景及目标:①应用于多主体异构能源系统的协同调度,如工业园区、城市能源网络、微电网集群等复杂场景;②实现各利益主体在不共享原始负荷、成本等敏感数据的情况下完成联合优化,提升系统整体运行效率;③为ADMM算法在实际能源系统中的工程化部署提供可复现的代码实例与完整技术路径参考。; 阅读建议:建议读者结合提供的Matlab代码逐模块理解算法实现细节,重点掌握增广拉格朗日函数构造、对偶变量更新机制与收敛判据的设计;同时可进一步拓展学习一致性ADMM(C-ADMM)、乘子惩罚方法等改进算法,深化对分布式优化理论体系的理解。

19,464

社区成员

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

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