一.问题的提出
微软资源管理器一般来说应该算是一个非常优秀的软件,但是其微软资源的图像浏览功能应该来说是有些问题的(可能是我的windows版本比较老(windows2000),且不说JPEG的BUG,就他采用的单线程读图应该就算是不合理之处,为什么这么说,我们可以做个试验,首先构造一个BMP图像,图像应尽可能大一点,我选择了6146*2048的24位色的图片,大约36M多,当点击此图片后,系统将非常缓慢的显示此图片的预览图,而且无法快速切换至其他文件(可能是我的机器太慢了),很明显微软在这里没有采用多线程处理,系统将把图像的所有数据读入内存后才进行处理显示,这就容易造成读取大图像文件的死机.因为在读取文件的过程中用户是无法中断的. 如何能快速切换文件呢? 一般对于一个需要较长时间处理数据的程序,用户可能希望在处理过程中提前中断当前的数据操作,我们有几种方式处理:
1.采用单线程处理方法:
这种方法一般采用的方法是在数据处理的过程中加入
MSG message;
if (::PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) {
::TranslateMessage(&message);
::DispatchMessage(&message);
}
等语句,如果发生用户中断或其他消息,则系统执行用户中断或其他消息相应的消息处理程序,消息处理完成后,程序再返回原来数据处理过程继续执行相关的代码. 这种方式的优点就是编程简单,只要在程序中设置一个全局变量,在用户中断消息中改变这个变量,数据处理时判断如果变量改变则退出处理即可.在一般情况下这种办法还是比较有效的,但是这种方法也有些问题,比如在这种情况下,你的鼠标按住窗口不停的拖动,系统就不会运行数据处理直到你松开鼠标按钮.由于数据处理很容易被系统的消息所干扰,采用这种方法在实际程序的运行过程中会使人感觉程序不是很流畅.
2.采用多线程处理方法 这里我们可以将文件分为界面线程和工作线程,工作线程负责读取文件并发送读取进度和读取内容到界面线程,而界面线程负责界面的显示和用户切换文件后,结束工作线程.需要指出的是在目前的单CPU+WINDOWS的环境下采用多线程进行数据,并不能提高数据的处理速度(超线程CPU除外),他所能提高的是界面的反应速度,即界面的友好程度.当然这种友好程度也会被一些其他程序过多的占用CPU所干扰.
二.如何使用多线程
1.demo界面设置:
为了能很好的模拟测试多线程绘图显示程序,我们建立了一个简单的demo程序,
先使用mfc向导,建立一个对话框程序,并增加全局变量CDib m_dib,对话框上建立三
个按钮和一个进度条,按钮1的功能为将c:/test1.bmp读入m_dib,按钮2的功能为将
c:/test2.bmp读入m_dib,按钮3的功能为终止m_dib的读入(关于CDib将在以后详细
说明),进度条用于显示当前读入数据的进度,于是按钮中的代码如下:
void CDemoDlg::OnButton1()
{
m_dib.LoadBmp ("c://test1.bmp");
}
void CDemoDlg::OnButton2()
{
m_dib.LoadBmp ("c://test2.bmp");
}
void CDemoDlg::OnButton3()
{
m_dib.DoStop(); //停止CDib的读入操作
}
但是,m_dib读入功能为多线程读取函数那有可能在读取test1.bmp时,程序要求读取test2.bmp,
所以按钮中的代码修改如下:
void CDemoDlg::OnButton1()
{
m_dib.DoStop(); //这也可以直接加入LoadBmp中
m_dib.LoadBmp ("c://test1.bmp");
}
void CDemoDlg::OnButton2()
{
m_dib.DoStop();
m_dib.LoadBmp("c://test2.bmp");
}
当然我们还要显示m_Dib,为了显示m_Dib我们对OnPaint作如下修改:
void CDemoDlg::OnPaint()
{
CPaintDC dc(this);
CRect clientRc;
GetClientRect(&clientRc); //取得窗体大小
CDC memDC1; //我们将读入的图像置于memDC1中
CDC memDC2; //memDC2设置背景图像
CBitmap m_bitmap;
CBitmap * m_pOldBitmap;
CBitmap * m_pOldBitmapA;
memDC1.CreateCompatibleDC(&dc);
memDC2.CreateCompatibleDC(&dc);
m_bitmap.CreateCompatibleBitmap(&dc,clientRc.Width() , clientRc.Height());
m_pOldBitmapA = memDC2.SelectObject(&m_bitmap);
m_pOldBitmap = memDC1.SelectObject(&m_Dib); //m_Dib为全局变量
memDC2.BitBlt(0,0, clientRc.Width(), clientRc.Height(),
&memDC1,0,0, SRCCOPY); //将读入的图像复制到背景图中
dc.BitBlt(0,0, clientRc.Width(), clientRc.Height(),
&memDC2,0,0, SRCCOPY); //显示当前图像
memDC2.SelectObject(m_pOldBitmapA );
memDC1.SelectObject(m_pOldBitmap );
}
我们建立两个消息函数负责子线程向界面线程报告完成情况和状态,
ON_MESSAGE(WM_SETPOS, ON_WM_SETPOS) //负责子线程向主线程报告完成进度
ON_MESSAGE(WM_INTERRUPT, ON_WM_INTERRUPT) //负责子线程向主线程报告是否中断
在CDib中我们每次读入图像的一行,然后发送WM_SETPOS消息给界面线
程,界面则刷新当前图像和进度条,在ON_WM_SETPOS中,wParam为bmp总行
数,lParam为目前处理的行数,为了简化程序我们只处理自底向上(即bmp图
像高度>0)的图像.
void CDemoDlg::ON_WM_SETPOS(WPARAM wParam, LPARAM lParam)
{
CRect clientRc;
GetClientRect(&clientRc); //取得当前窗体大小
CProgressCtrl *cw;
cw=(class CProgressCtrl *)GetDlgItem(IDC_PROGRESS1);
cw->SetRange (0,100); //设置进度条
float l;
if (wParam!=0)
l=(float) lParam/(float)wParam*100;
else
l=0;
cw->SetPos ((int)l); //更新进度条
CRect rc;
rc.SetRect (0,wParam-lParam,clientRc.Width(),wParam-lParam+1);
InvalidateRect(&rc,false); //刷新当前行
}
至此我们的界面程序基本完成.
2.CDib设置:
下面我们进行CDib的构建,为了方便图像的显示处理我们继承CBitmap构建CDib,
为了解说方便,我们只处理24位色图,这里我们给出CDib基本结构,其他部分读者可以
自由扩充.
class CDib : public CBitmap
{
public:
CDib(); //构造函数
virtual ~CDib(); //析构函数
BYTE * m_lpBits; //数据指针,指向cbitmap的数据区
LPBITMAPINFOHEADER m_lpBmih;//图像头指针
HANDLE hMutex; //互斥变量
HANDLE hStopEvent; //线程读到此信号,立即退出现有的操作
CWnd * m_Wnd; //用于子线程发送消息界面指针
CWinThread *m_cAniThread; //多线程中,子线程对象
virtualvoid DoStop(); //用于界面线程中停止当前线程
BOOL LoadBmp(LPCTSTR lpszPathName, CDC* pDC = NULL);
//由bmp读入图像
static UINT ThreadProcRead(LPVOID parm);
//多线程函数读入图像
.
.
.
protected:
BOOL AttachDib(HGDIOBJ hObject);
//Attach Object
BOOL DeleteDib(); //delete object
void Initialize(); //设置图像头等操作
.
.
.
}
分享到:
相关推荐
当涉及到多线程(Multithreading)时,MFC GDI多线程绘图是一种技术,允许程序在不同的线程中同时进行图形绘制,提高应用性能和响应速度。 在MFC中,多线程的实现主要是通过`CWinThread`类来完成的。每个线程都由一...
综上所述,"GDI多线程绘图"是结合了MFC框架和Windows图形绘制技术的一个复杂话题,涉及到线程创建、GDI对象的管理和同步、以及性能优化等多个方面。通过深入理解和熟练应用这些概念,开发者可以构建出更高效、更响应...
《VC下Matcom多线程绘图技术详解》 在计算机编程领域,高效的数据处理和图形渲染是关键问题之一。特别是在复杂的科学计算和可视化应用中,多线程技术的运用可以显著提升性能,减少等待时间。本文将深入探讨如何在VC...
Java多线程绘图的24点游戏-part2 比较大,有三个压缩包哦。
CSS3 overfl处理用法 h5多线程绘图 JQ JSCSS3 overfl处理用法 h5多线程绘图 JQ JS
首先,我们要了解“多线程绘图”。在Windows编程中,通常使用GDI(Graphics Device Interface)或GDI+进行图形绘制。而`CClientDC`是MFC(Microsoft Foundation Classes)框架中用于窗口客户区绘图的类,它提供了一...
侯俊杰的《深入浅出MFC》第十四章多线程程序。 按照书上的要求添加了菜单和命令处理,并在线程函数ThreadFunc中加上了计算与绘图功能,实现了与第一章相似的功能。 不足之处是由于不知道该如何获取View窗口的句柄,...
Java多线程绘图的24点游戏-part3 比较大,有三个压缩包哦。
5. **优化**:在多线程绘图中,要注意避免过度创建线程,因为线程的创建和销毁都有一定的开销。同时,应合理调度线程,防止资源过度消耗,保证系统稳定运行。 6. **异常处理**:在多线程环境下,异常处理显得尤为...
在编程领域,尤其是在GUI(图形用户界面)应用开发中,多线程技术是解决性能问题的一个重要手段。本文将深入探讨如何使用Qt框架中的多线程功能,特别是结合QChart和QThread,来实现动态波形图表的高效展示。这对于...
在Qt框架中,多线程技术是用于提升应用程序性能、优化资源使用的关键工具。当我们需要进行耗时操作,如长时间的计算或者频繁的数据更新(如实时显示系统时间),使用多线程可以避免阻塞主线程,保持用户界面的流畅...
在C#编程中,多线程技术是一种提升应用程序性能的有效方式,特别是在处理耗时操作如在图像上绘制图形和文字时。本项目"使用多线程动态在多张图上画图和写字"旨在实现一个功能,即在用户点击开始按钮后,三张图片将...
大一学生作品。系同学所作。比较大,有三个压缩包哦。
3. **QObject和线程关联**:Qt的对象模型支持多线程,但并不是所有Qt对象都可以在任何线程中使用。QObject的`moveToThread()`函数可以将对象及其子对象移动到指定的线程。 4. **线程安全通信**:为了在主线程和绘图...
`temp.dcu`、`p2.dcu`、`p.dcu`、`main.dcu`等可能是编译后的单元文件,包含着实现多线程绘图逻辑的代码;`main.ddp`是项目文件,记录了项目的设置和依赖关系;`main.dfm`和`temp.dfm`可能是窗体设计文件,定义了...
在本文中,我们将深入探讨如何使用Delphi进行多线程缓冲区绘图,这是一个非常实用的技术,特别是在处理大型图像或需要高效更新用户界面的应用中。Delphi作为一个强大的面向对象的编程环境,提供了丰富的多线程支持,...
【标题】"VC 绘图实例-多线程.rar"是一个关于使用Microsoft Visual C++ (VC++)进行图形绘制和多线程编程的源代码集合。这个压缩包包含了一系列的示例,展示了如何在C++环境下利用图形库进行复杂的绘图操作,并通过多...
通过这个基础示例,你可以开始探索QCustomPlot的更多功能,如添加多个图、设置轴的刻度间隔、添加图例、调整线条样式等,以满足你的特定需求。 总之,QCustomPlot是Qt环境中进行复杂图形绘制的理想选择,它的强大...
而"drown_c_thread"可能是源代码文件或可执行文件,包含实际的双缓冲和多线程绘图实现。 总的来说,理解和掌握双缓冲绘图和多线程技术对于C#游戏开发者至关重要。通过实践这样的项目,我们可以深化对这两种技术的...