现在的位置: 首页 > 综合 > 正文

Visual C++打印机编程入门(一)

2014年09月02日 ⁄ 综合 ⁄ 共 2485字 ⁄ 字号 评论关闭

首先介绍两个术语。

dpi(dot per inch):每英寸的点数,用于表示打印机的分辨率。比如600dpi,则是横向、纵向都打600个点,一共可打360000个点。dpi的值越大,表示打印机的打印精度越高。我接触过的有203dpi、300dpi、600dpi。要想让打印效果好一些,最好用300dpi以上的打印机。

ppm(papers per minute):每分钟最多可以打印多少页,用于衡量打印机的打印速度。这个参数也很重要,比如我们有一个项目,需要边生产边给产品贴标,如果打印标签的速度过慢,就会跟不上生产。

Windows系统为打印功能提供了一些API,MFC又对这些API进行了封装。这些都为程序员开发打印机程序提供了便利。

MFC的SDI(单文档)和MDI(多文档)框架,都内置了功能很强的打印和预览功能。但我自己的项目很少使用它们,都是一些基于Dialog的MFC程序。所以打算从一些更底层的打印机制学起。

下面先写一段最简单的打印程序。

首先要创建一个打印机设备环境(DeviceContext),以下简称DC。就像在窗口上绘图或输出文本时,也要先为显示设备创建一个DC一样,还记得CDC、CWindowDC、CClientDC、CPaintDC这些吗?

然后调用DC类的StartDoc()函数开启一个打印作业。接着调用StretchBlt()函数向打印机DC绘制了一幅图片,图片是从本地bmp文件加载过来的。最后调用DC类的EndDoc()函数结束打印。

主要代码如下:

void CPrint01Dlg::Print()
{
	// Display the Windows Print dialog box with "All" radio button 
	// initially selected. All other radio buttons are disabled.
	CPrintDialog printDlg(FALSE);

	if (IDCANCEL == printDlg.DoModal())
		return;

	// 利用CPrintDialog生成打印机设备环境
	CDC dc;
	dc.Attach(printDlg.GetPrinterDC());
	dc.m_bPrinting = TRUE;

	DOCINFO di;
	::ZeroMemory(&di, sizeof(DOCINFO));
	di.cbSize = sizeof(DOCINFO);
	di.lpszDocName = _T("sample");

	// Start a print job.
	bool bPrintingOK = dc.StartDoc(&di);

	CPrintInfo info;
	// Set the number of the last page of the document.
	info.SetMaxPage(1);
	// Specifies the usable drawing area of the page in logical coordinates.
	info.m_rectDraw.SetRect(0, 0, dc.GetDeviceCaps(HORZRES), 
		dc.GetDeviceCaps(VERTRES));

	OnPrint(&dc, &info);

	if (bPrintingOK)
		dc.EndDoc(); // End a print job
	else
		dc.AbortDoc(); // Abort job. 

	dc.Detach(); // Detach the printer DC
}

void CPrint01Dlg::OnPrint(CDC *pdc, CPrintInfo *pInfo)
{
	// Load a bitmap.
	HANDLE file = ::LoadImage(NULL, _T("D:\\sample.bmp"), IMAGE_BITMAP, 0, 0, 
		LR_LOADFROMFILE);
	if (NULL == file)
		return;
 
	CBitmap bmp;
	// Attach a bitmap handle to a CBitmap object.
	if (!bmp.Attach(file))
		return;

	BITMAP bmpInfo;
	bmp.GetBitmap(&bmpInfo);

	CDC memDC;
	memDC.CreateCompatibleDC(pdc);
	HBITMAP hOldBmp = (HBITMAP)memDC.SelectObject(&bmp);

	CRect destRect = pInfo->m_rectDraw;
	pdc->StretchBlt(destRect.left, destRect.top, destRect.Width(), destRect.Height(),
		&memDC, 0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight, SRCCOPY);

	memDC.SelectObject(hOldBmp);
	memDC.DeleteDC();

	bmp.Detach(); 
}

下面来看看这段代码。除了上面提到的为打印机设备创建的DC对象和 它的几个成员函数:StartDoc()、StretchBlt()、EndDoc()、StretchBlt()之外,还创建了一个memDC。用过“双缓冲”绘图的朋友应该对这里的memDC很熟悉。我们经常用一张图片作为对话框的背景,主要是为了美化窗口。但在窗口大小发生变化,或者窗口频繁切换时,会发现背景图片有闪烁的现象,这个时候就需要采用“双缓冲”机制。创建一个与显示DC兼容的内存DC,然后将图片绘制到内存DC中,再从内存DC绘制到显示DC,这样就可以避免闪烁现象。

那这里为什么要用到memDC呢?Windows中的位图分两种:GDI位图和DIB位图。GDI位图是设备相关的,不能够直接将其选入到显示设备环境或者打印设备环境中。必须通过CDC::CreateCompatibleDC()函数为位图创建一个特殊的内存设备环境,然后再从内存设备环境绘制到目标设备环境。

最后贴一张这段程序的打印效果图片:

完整的源码地址:http://download.csdn.net/detail/zhuyf87/6782763

【上篇】
【下篇】

抱歉!评论已关闭.