gdi+ 绘图失败了吗?

baoyz 2008-10-30 03:04:54
我做了一个程序用GDI+绘图。目的是在一个对话框上画图片。
代码如下:

//绘图程序
void CMyDlg::OnDrawjpg(CString strPathname,int cx,int cy,float zoom)
{
//在矩形区域内显示jpg图像
CClientDC dc(this);
//创建Graphics对象
Graphics graphics(dc);
SafeDeleteImage();
m_pImage = Image::FromFile(strPathname.AllocSysString());
width = (int)(m_pImage->GetWidth()*zoom);
height = (int)(m_pImage->GetHeight()*zoom);
destPoints1[0] = Point(cx,cy);
destPoints1[1] = Point(cx+width,cy);
destPoints1[2] = Point(cx,cy+height);
if(graphics.DrawImage(m_pImage,destPoints1,3) != Ok)//如果绘图失败,就重新绘一次
{
OnDrawjpg(strPathname,cx,cy,zoom);
}
}

//调用
BOOL CMyDlg::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE) //按Esc时图片抖动
{
for (int i= 0;i<10 ;i++)
{
OnDrawjpg(strPicPathname[0],rand()*20.0/0x7fff,0-rand()*20.0/0x7fff,1);
Sleep(rand()*20.0/0x7fff);
OnDrawjpg(strPicPathname[0],0-rand()*20.0/0x7fff,0-rand()*20.0/0x7fff,1);
Sleep(rand()*20.0/0x7fff);
OnDrawjpg(strPicPathname[0],0-rand()*20.0/0x7fff,rand()*20.0/0x7fff,1);
Sleep(rand()*20.0/0x7fff);
OnDrawjpg(strPicPathname[0],rand()*20.0/0x7fff,rand()*20.0/0x7fff,1);
Sleep(rand()*20.0/0x7fff);
}
Sleep(10);
::SetForegroundWindow(m_hWnd);
//最后恢复原样。
OnDrawjpg(strPicPathname[0],0,0,1);

return TRUE;
}
}

问题是,通常情况下,震动完成后,会出现原始位置的图像。但是有不确定的时候——至少没发现任何规律——震动完成后,得到的是一个空的对话框。没有任何图像。加上那个“if()”也没有效果。

请问是哪里错了?
...全文
533 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
baoyz 2008-11-03
  • 打赏
  • 举报
回复
经过检查,内存确实没有泄露,进程内存从开始的5.6M,到震动时的8、9M,到停震后又回到5.6M,震动次数多了,会微量上涨。
使用Tinary3v0 的代码,到目前未见空窗口。

原错误原因我也不找了。现在结贴。
分给少了。有请Tinary3v0 到http://topic.csdn.net/u/20081103/11/8a360ea7-61fd-400e-a9ba-a011e6dfdfc1.html接分。
Tinary3v0 2008-10-31
  • 打赏
  • 举报
回复
.h文件中:
public:        
CString strPathname;//路径设成全局的,每次改动图片只需要重新赋值即可,
//去掉了Image *m_pImage;的声明,因为这个类实在是不好用,最好是用临时变量,我估计内存泄露就是出在这个东西上。


.cpp文件中:

BOOL CIrregularDlg::OnInitDialog()
{
//........
strPathname = "E-Mail.png"; //路径初始图片
return TRUE;
}


void CIrregularDlg::OnDrawjpg( CDC* pdc, int cx, int cy, float zoom)
{ // 函数这么改造,是为了引入内存DC句柄绘图。
Image m_pImage( strPathname.AllocSysString() ); //还是用临时变量吧,即便是你要改文件,改strPathname比较安全一点

Graphics graphics(pdc->m_hDC);
INT width = (int)(m_pImage.GetWidth()*zoom);
INT height = (int)(m_pImage.GetHeight()*zoom);
Point destPoints1[3];
destPoints1[0] = Point(cx,cy);
destPoints1[1] = Point(cx+width,cy);
destPoints1[2] = Point(cx,cy+height);
if(graphics.DrawImage(&m_pImage,destPoints1,3) != Ok)//如果绘图失败,就重新绘一次
{
OnDrawjpg( pdc,cx,cy,zoom);
}
}


BOOL CIrregularDlg::PreTranslateMessage(MSG* pMsg) 
{
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE) //按Esc时图片抖动
{
CDC *pdc=this->GetDC();
CDC MenDC;
CBitmap bm;
RECT rt;
GetClientRect(&rt); //得到窗口大小,这里根据自己需要更改

MenDC.CreateCompatibleDC(pdc); //创建内存DC
bm.CreateCompatibleBitmap(pdc,rt.right,rt.bottom);
MenDC.SelectObject(&bm);
//-------------------------------------------------------------------
for (int i= 0;i<10 ;i++)
{
MenDC.FillSolidRect(0,0,rt.right,rt.bottom,RGB(255,255,255)); //每次都先将窗口填充为白色,这里需要主要,如果是对话框 连
//上面的控件也会被覆盖了,如果不想覆盖只能想别的办法了。
OnDrawjpg(&MenDC,rand()*20.0/0x7fff,0-rand()*20.0/0x7fff,1);
Sleep(rand()*20.0/0x7fff);
pdc->BitBlt(0,0,rt.right,rt.bottom,&MenDC,0,0,SRCCOPY);
MenDC.FillSolidRect(0,0,rt.right,rt.bottom,RGB(255,255,255));
OnDrawjpg(&MenDC,0-rand()*20.0/0x7fff,0-rand()*20.0/0x7fff,1);
Sleep(rand()*20.0/0x7fff);
pdc->BitBlt(0,0,rt.right,rt.bottom,&MenDC,0,0,SRCCOPY);
MenDC.FillSolidRect(0,0,rt.right,rt.bottom,RGB(255,255,255));
OnDrawjpg(&MenDC,0-rand()*20.0/0x7fff,rand()*20.0/0x7fff,1);
Sleep(rand()*20.0/0x7fff);
pdc->BitBlt(0,0,rt.right,rt.bottom,&MenDC,0,0,SRCCOPY);
MenDC.FillSolidRect(0,0,rt.right,rt.bottom,RGB(255,255,255));
OnDrawjpg(&MenDC,rand()*20.0/0x7fff,rand()*20.0/0x7fff,1);
Sleep(rand()*20.0/0x7fff);
pdc->BitBlt(0,0,rt.right,rt.bottom,&MenDC,0,0,SRCCOPY);
}
Sleep(10);
//::SetForegroundWindow(m_hWnd); 这句有没有好像没有关系
MenDC.FillSolidRect(0,0,rt.right,rt.bottom,RGB(255,255,255));
OnDrawjpg(&MenDC,0,0,1);
//-------------------------------------------------------------------
pdc->BitBlt(0,0,rt.right,rt.bottom,&MenDC,0,0,SRCCOPY);
MenDC.DeleteDC();
bm.DeleteObject();
ReleaseDC(pdc);

return TRUE;
}
return CDialog::PreTranslateMessage(pMsg);
}


上面是我改的代码 在我这里运行没有问题,没有出现你说的内存泄漏问题。Image这个类是在是不好用啊,不能new,也没有自带的函数释放内存,
delete我认为又不安全。所以还是用临时变量的保险,它会调用析构函数释放内存。
palmax 2008-10-31
  • 打赏
  • 举报
回复
对于绘图程序,如果是gdi泄漏,那么你不停的拖一个其他窗口在你的程序上面来造成你自己窗口的重绘,在任务管理器里就会明显的看到gdi使用计数狂涨
对于内存泄漏,首先看看程序里哪些地方用了new,然后看怎么操作能调用到new,然后你就不停的那样操作,同样也会看到内存使用计数在不停的涨,对内存使用计数要注意不要最小化你的窗口,最小化的时候系统会回收一些程序使用的显存,让你误以为是内存回收,其实不是的。
baoyz 2008-10-31
  • 打赏
  • 举报
回复
谢谢palmax 指点。
我本来是做硬件设计的。临时自学了一阵子VC++ 6.0。我没系统的学过任何内容,都是用到什么功能就上网找。以至于很多的东西学不全,用不了。
我的工程是Ansi字符集编译的。我还真是分不清。不过您的方法可行。已经用上了。


To:Tinary3v0
m_pImage确实是一个全局变量。定义在CMyDlg.CPP开头了。这段程序是以前的程序留下来的习惯。
我以前经常判断一些指针变量,写c语言时,我搞不清形参实参什么的,所以我的程序里经常指针满天飞:)
因为有时指针赋值失败了,删除时就出错,所以才写成了这样。

我把程序全都改好了。还是在有的时候会贴图失败(不是经常的)。无奈呀。好像失败的时候总是在最后一次恢复原样的贴图后“出错”。而且今天我把图片改小了(以前是全屏图片,程序的目的是一个可以晃动的桌面)。果然如您所说,贴的图都叠在一起了,从边沿处可以看见原先贴片的边角。
但是一旦贴图“失败”了,不是最后一次贴图没有,而是所有的贴片都消失了。直接回到对话框的“底板”上。会不会是对话框由于某种原因“刷新”了?

最后问一句,如果内存泄露了。在哪里可以看出来呀?在任务管理器里程序的内存始终5、6M的样子。

再次谢谢各位关注。
Tinary3v0 2008-10-30
  • 打赏
  • 举报
回复
void CMyDlg::SafeDeleteImage()
{
if(m_pImage != NULL)
{
delete m_pImage;
m_pImage = NULL;
}
}
???????????????????????????????????????

你这样清除图像指针???
m_pImage应该是一个全局变量吧,或者说你CMyDlg类里面的公有成员变量吧。
你把一个这样的变量delete, 然后再=NULL????尽量不要这么做。
毕竟它是个全局性质的变量,不到析构函数里面不要做你上面的操作。
你这个SafeDeleteImage函数还不如不加。

我那个代码是能够执行过去而没有内存增加的,你那么用或者去掉SafeDeleteImage函数,把一部分临时变脸声明成成员变量
还不行么? 还有什么问题么

palmax 2008-10-30
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 baoyz 的回复:]
strPathname.AllocSysString();这句是我抄的。:)一般用什么函数比较好?
[/Quote]

你的工程是Ansi字符集编译的吧?

可以用ATL转换宏 A2W
使用方法:
#include <atlconv.h>

在函数的第一句,必须是第一句,加上
void CMyDlg::OnDrawjpg(CString strPathname,int cx,int cy,float zoom)
{
USES_CONVERSION;

后面就可以使用 m_pImage = Image::FromFile(A2W(strPathname));
baoyz 2008-10-30
  • 打赏
  • 举报
回复
TO:palmax
我开始没写全。
我在CMyApp.cpp里#include “xxx”下面有

#define UNICODE
#ifndef ULONG_PTR
#define ULONG_PTR unsigned long*
#endif
#include "gdiplus.h" //请修改为你的头文件路径
using namespace Gdiplus;


BOOL CMyApp::InitInstance()
{
……
……
//////////////////////////////////////////////////////////////////////////
//初始化gdiplus的环境
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
// Initialize GDI+.
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); //是这个初始化吗?
//////////////////////////////////////////////////////////////////////////

CMyDlg dlg;
m_pMainWnd = &dlg;
……
……
//////////////////////////////////////////////////////////////////////////
//关闭gdiplus的环境
GdiplusShutdown(gdiplusToken);
//////////////////////////////////////////////////////////////////////////

// Since the dialog has been closed, return FALSE so that we exit the
// application, rather than start the application's message pump.
return FALSE;
}

在CMyDlg.cpp头文件下有

//////////////////////////////////////////////////////////////////////////
#define UNICODE
#ifndef ULONG_PTR
#define ULONG_PTR unsigned long*
#endif
#include "gdiplus.h"
using namespace Gdiplus;
#pragma comment(lib, "gdiplus.lib")
//////////////////////////////////////////////////////////////////////////


strPathname.AllocSysString();这句是我抄的。:)一般用什么函数比较好?

TO:Tinary3v0
每次m_pImage = Image::FromFile(strPathname.AllocSysString()); 之前的SafeDeleteImage();

void CMyDlg::SafeDeleteImage()
{
if(m_pImage != NULL)
{
delete m_pImage;
m_pImage = NULL;
}
}

这个应该在绘图后清除对吧?
Image *m_pImage;//定义在

最后那句是有的。就是原程序太长了。没贴出来。
Tinary3v0 2008-10-30
  • 打赏
  • 举报
回复
你的代买这么改了以后内存不会再增加了:
void CIrregularDlg::OnDrawjpg(CString strPathname, int cx, int cy, float zoom)
{
//在矩形区域内显示jpg图像
CClientDC dc(this);
//创建Graphics对象
Graphics graphics(dc);
// SafeDeleteImage(); //我声明的临时变量,不知道你这句是做什么用的。
Image *m_pImage;
m_pImage = Image::FromFile(strPathname.AllocSysString());
INT width = (int)(m_pImage->GetWidth()*zoom);
INT height = (int)(m_pImage->GetHeight()*zoom);
Point destPoints1[3];
destPoints1[0] = Point(cx,cy);
destPoints1[1] = Point(cx+width,cy);
destPoints1[2] = Point(cx,cy+height);
if(graphics.DrawImage(m_pImage,destPoints1,3) != Ok)//如果绘图失败,就重新绘一次
{
OnDrawjpg(strPathname,cx,cy,zoom);
}
delete m_pImage; //把临时变量指针删除
}

BOOL CIrregularDlg::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE) //按Esc时图片抖动
{
for (int i= 0;i<10 ;i++)
{
OnDrawjpg("E-Mail.png",rand()*20.0/0x7fff,0-rand()*20.0/0x7fff,1);
Sleep(rand()*20.0/0x7fff);
OnDrawjpg("E-Mail.png",0-rand()*20.0/0x7fff,0-rand()*20.0/0x7fff,1);
Sleep(rand()*20.0/0x7fff);
OnDrawjpg("E-Mail.png",0-rand()*20.0/0x7fff,rand()*20.0/0x7fff,1);
Sleep(rand()*20.0/0x7fff);
OnDrawjpg("E-Mail.png",rand()*20.0/0x7fff,rand()*20.0/0x7fff,1);
Sleep(rand()*20.0/0x7fff);
}
Sleep(10);
::SetForegroundWindow(m_hWnd);
//最后恢复原样。
OnDrawjpg("E-Mail.png",0,0,1);

return TRUE;
}


return CDialog::PreTranslateMessage(pMsg); //这句不能少,少了程序没法用
}


你说的空对话框以及最后位置不对的情况我没有发现。由于没有使用内存绘图,我这里都是叠加的影像,你应该在
PreTranslateMessage函数里面添加了内存贴图的部分了吧。
dirdirdir3 2008-10-30
  • 打赏
  • 举报
回复
//绘图程序
void CMyDlg::OnDrawjpg(CString strPathname,int cx,int cy,float zoom)
{
//在矩形区域内显示jpg图像
CClientDC dc(this);
//创建Graphics对象
Graphics graphics(dc);
SafeDeleteImage();
m_pImage = Image::FromFile(strPathname.AllocSysString());
width = (int)(m_pImage->GetWidth()*zoom);
height = (int)(m_pImage->GetHeight()*zoom);
destPoints1[0] = Point(cx,cy);
destPoints1[1] = Point(cx+width,cy);
destPoints1[2] = Point(cx,cy+height);
if(graphics.DrawImage(m_pImage,destPoints1,3) != Ok)//如果绘图失败,就重新绘一次
{
OnDrawjpg(strPathname,cx,cy,zoom);<---------------你这里不就循环了???????????
}
}

应该是
void CMyDlg::OnDrawjpg(CString strPathname,int cx,int cy,float zoom)
{
//在矩形区域内显示jpg图像
CClientDC dc(this);
//创建Graphics对象
Graphics graphics(dc);
SafeDeleteImage();
m_pImage = Image::FromFile(strPathname.AllocSysString());
width = (int)(m_pImage->GetWidth()*zoom);
height = (int)(m_pImage->GetHeight()*zoom);
destPoints1[0] = Point(cx,cy);
destPoints1[1] = Point(cx+width,cy);
destPoints1[2] = Point(cx,cy+height);
while(graphics.DrawImage(m_pImage,destPoints1,3) != Ok)//如果绘图失败,就重新绘一次
{
//超时退出.............
}
}

palmax 2008-10-30
  • 打赏
  • 举报
回复
strPathname.AllocSysString() 这句有内存泄漏
palmax 2008-10-30
  • 打赏
  • 举报
回复
你有调试吗? Image::FromFile 是否已经有问题了?

还有你有调用GdiplusStartup初始化GDI+了吗?
dch4890164 2008-10-30
  • 打赏
  • 举报
回复
呵呵典型的资源耗尽现象
zhoujianhei 2008-10-30
  • 打赏
  • 举报
回复
GDI+资源耗尽,检查代码避免冗余。

19,464

社区成员

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

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