您现在的位置是:网站首页> C/C++
Qt、VC打印功能技术收集
- C/C++
 - 2025-09-07
 - 1905人已阅读
 
Qt、VC打印功能技术收集
    
    
    
VC WinUSB VC++ HIDAPI实现USB数据读写
    
    
C++调用USB小票打印机 第一种办法 无驱动
bSuccess = WriteFile(m_hCom, pbuff, len, &written, &m_ov);
if (!bSuccess )
{
if (ERROR_IO_PENDING == GetLastError())
{
WaitForSingleObject(m_ov.hEvent, 10); // 无纸或其他情况阻塞只等待10毫秒
// return -1;
}
}
    
//链接打印机
int InitPort(PrintDevice &device)
{
hPort = CreateFile(device.Port.c_str(), GENERIC_READ | GENERIC_WRITE,
0, NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL);
    
if (hPort == INVALID_HANDLE_VALUE)
{ // 打开端口失败
return false;
}
else
{
    
printf("InitPort Hello\r\n");
    
//设置端口缓冲
SetupComm(hPort, 1024, 1024);
    
// 设定通讯端口超时参数
COMMTIMEOUTS tmouts;
tmouts.ReadIntervalTimeout = 100;
tmouts.ReadTotalTimeoutMultiplier = 100;
tmouts.ReadTotalTimeoutConstant = 100;
tmouts.WriteTotalTimeoutConstant = 100;
tmouts.WriteTotalTimeoutMultiplier = 100;
SetCommTimeouts(hPort, &tmouts);
    
//设定通讯端口通讯参数
DCB dcb;
BOOL bol = TRUE;
    
//dcb.DCBlength = sizeof(dcb);
bol = GetCommState(hPort, &dcb);
dcb.BaudRate = device.BawdRate;
dcb.ByteSize = device.DataBits;
dcb.StopBits = device.StopBits;
dcb.Parity = device.Parity;
    
bol = SetCommState(hPort, &dcb); //配置串口
// 清除通讯端口缓存
PurgeComm(hPort, PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_RXABORT);
    
// 初始化重叠IO对象
OVERLAPPED m_OverlappedRead;
OVERLAPPED m_OverlappedWrite;
HANDLE m_hStopCommEvent;
HANDLE m_hDataReady;
memset(&m_OverlappedRead, 0, sizeof(OVERLAPPED));
m_OverlappedRead.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
memset(&m_OverlappedWrite, 0, sizeof(OVERLAPPED));
m_OverlappedWrite.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    
// 初始化事件对象
m_hStopCommEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
m_hDataReady = CreateEvent(NULL, FALSE, FALSE, NULL);
    
//初始化打印ESC @
DWORD iBytesLength;
char chInitCode[] = "\x0D\x1B\x40";
if (!WriteFile(hPort, chInitCode, (DWORD)3L, &iBytesLength, NULL))
return false;
}
    
return true;
}
    
int WriteData(string meg)
{
DWORD dwWrite;
return WriteFile(hPort, meg.c_str(), (DWORD)meg.length(), &dwWrite, NULL);
}
    
//打印数据,meg打印字符串,bBold=true粗体,nZoom=2大一号字体, nHAil=2居中对齐,nHAil=3右对齐。部分打印机可能中文字体设置无效,请加上FS !命令设置中文字体。
bool OnWriteData(string meg, bool bBold, bool bDTall, bool bDWide, int nHAil)
{
char s[120] = "";
memset(s, 0, 120);
    
long nMode = 0;
DWORD iBytesLength;
    
if (bBold)
nMode += 8;
    
if (bDTall)
nMode += 16;
    
if (bDWide)
nMode += 32;
    
if (nMode > 0)
{
//sprintf(s, "\x1B\x21%c", nMode);
sprintf_s(s, sizeof(s), "\x1B\x21%c", nMode);
if (strlen(s) < 3)
{
iBytesLength = 0;
WriteFile(hPort, s, (DWORD)3L, &iBytesLength, NULL);
}
else
WriteData(s);
}
    
switch (nHAil)
{
case 1:
break;
case 2:
strcat_s(s, strlen("\x1B\x61\x01") + 1, "\x1B\x61\x01");
WriteData(s);
break;
case 3:
strcat_s(s, strlen("\x1B\x61\x02") + 1, "\x1B\x61\x02");
WriteData(s);
break;
default:
break;
}
    
WriteData(meg);
    
iBytesLength = 0;
strcpy_s(s, strlen("\x1B\x21\x00") + 1, "\x1B\x21\x00");
WriteFile(hPort, s, (DWORD)3L, &iBytesLength, NULL);
    
return true;
};
    
    
//获取CreateFile的USB端口号
    
    
// 根据GUID获得设备路径
// lpGuid: GUID指针
// pszDevicePath: 设备路径指针的指针,用于返回找到的路径
// 返回: 成功得到的设备路径个数,可能不止1个
int GetDevicePath(LPGUID lpGuid, LPTSTR* pszDevicePath)
{
HDEVINFO hDevInfoSet;
SP_DEVINFO_DATA spDevInfoData;
SP_DEVICE_INTERFACE_DATA ifData;
PSP_DEVICE_INTERFACE_DETAIL_DATA pDetail;
int nCount;
int nTotle;
BOOL bResult;
    
char* strUSBPrint = "USB 打印支持";
    
// 取得一个该GUID相关的设备信息集句柄
hDevInfoSet = ::SetupDiGetClassDevs(lpGuid, // class GUID
NULL, // 无关键字
NULL, // 不指定父窗口句柄
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); // 目前存在的设备
    
// 失败...
if (hDevInfoSet == INVALID_HANDLE_VALUE)
{
return 0;
}
    
// 申请设备接口数据空间
pDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)::GlobalAlloc(LMEM_ZEROINIT, INTERFACE_DETAIL_SIZE);
    
pDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
    
nTotle = -1;
nCount = 0;
bResult = TRUE;
    
// 设备序号=0,1,2... 逐一测试设备接口,到失败为止
while (bResult)
{
nTotle++;
spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
    
// 枚举符合该GUID的设备接口
bResult = ::SetupDiEnumDeviceInfo(
hDevInfoSet, // 设备信息集句柄
(ULONG)nTotle, // 设备信息集里的设备序号
&spDevInfoData); // 设备接口信息
    
if (bResult)
{
DWORD DataT;
TCHAR buf[MAX_PATH];
DWORD nSize = 0;
    
// get Friendly Name or Device Description
if (SetupDiGetDeviceRegistryProperty(hDevInfoSet, &spDevInfoData,
SPDRP_FRIENDLYNAME, &DataT, (PBYTE)buf, sizeof(buf), &nSize)) {
}
else if (SetupDiGetDeviceRegistryProperty(hDevInfoSet, &spDevInfoData,
SPDRP_DEVICEDESC, &DataT, (PBYTE)buf, sizeof(buf), &nSize)) {
}
else {
lstrcpy(buf, _T("Unknown"));
}
    
//是否是要找的设备类型
if (strcmp(buf, strUSBPrint) != 0)
continue;
    
ifData.cbSize = sizeof(ifData);
    
// 枚舉符合該GUID的設備接口
bResult = ::SetupDiEnumDeviceInterfaces(
hDevInfoSet, // 設備信息集句柄
NULL, // 不需額外的設備描述
lpGuid, // GUID
(ULONG)nTotle, // 設備信息集里的設備序號
&ifData); // 設備接口信息
    
if (bResult)
{
// 取得该设备接口的细节(设备路径)
bResult = SetupDiGetInterfaceDeviceDetail(
hDevInfoSet, // 设备信息集句柄
&ifData, // 设备接口信息
pDetail, // 设备接口细节(设备路径)
INTERFACE_DETAIL_SIZE, // 输出缓冲区大小
NULL, // 不需计算输出缓冲区大小(直接用设定值)
NULL); // 不需额外的设备描述
    
if (bResult)
{
// 复制设备路径到输出缓冲区
::strcpy_s(pszDevicePath[nCount], 256, pDetail->DevicePath);
// 调整计数值
nCount++;
}
}
}
}
    
// 释放设备接口数据空间
::GlobalFree(pDetail);
    
// 关闭设备信息集句柄
::SetupDiDestroyDeviceInfoList(hDevInfoSet);
    
return nCount;
}
    
C++ win32 USB打印机开发
基于打印驱动
1 : 获得本地打印驱动
struct PrintInfo
{
BOOL m_bisPrintPage;
string sDeviceName;
string sPortName;
string sShareName;
string sLoction;
string sPaperType;
int nWidthMin;
bool bisPrint;
PrintInfo()
{
m_bisPrintPage = FALSE;
sDeviceName = "";
sPortName = "";
sShareName = "";
sLoction = "";
sPaperType = "";
nWidthMin = 0;
bisPrint = FALSE;
}
    
};
typedef vector<PrintInfo> PrintInfo_Ary;
int GetLocalPrinterDrivers(PrintInfo_Ary &Drivers)
{
DWORD Flags = PRINTER_ENUM_FAVORITE | PRINTER_ENUM_LOCAL; //local printers
DWORD cbBuf;
DWORD pcReturned;
DWORD index;
DWORD Level = 2;
CHAR Name[500];
LPPRINTER_INFO_2A pPrinterEnum = NULL;
    
memset(Name, 0, sizeof(CHAR)* 500);
::EnumPrintersA(Flags, Name, Level, NULL, 0, &cbBuf, &pcReturned);
pPrinterEnum = (LPPRINTER_INFO_2A)LocalAlloc(LPTR, cbBuf + 4);
if (!pPrinterEnum)
{
goto clean_up;
}
    
if (!EnumPrintersA(
Flags, // DWORD Flags, printer object types
Name, // LPTSTR Name, name of printer object
Level, // DWORD Level, information level
(LPBYTE)pPrinterEnum, // LPBYTE pPrinterEnum, printer information buffer
cbBuf, // DWORD cbBuf, size of printer information buffer
&cbBuf, // LPDWORD pcbNeeded, bytes received or required
&pcReturned) // LPDWORD pcReturned number of printers enumerated
)
{
goto clean_up;
}
if (pcReturned > 0)
{
for (index = 0; index < pcReturned; index++)
{
PrintInfo DeviceDate;
if ((pPrinterEnum + index)->pPrinterName != NULL)
DeviceDate.sDeviceName = (pPrinterEnum + index)->pPrinterName;
else
DeviceDate.sDeviceName ="";
if ((pPrinterEnum + index)->pPortName != NULL)
DeviceDate.sPortName = (pPrinterEnum + index)->pPortName;
else
DeviceDate.sPortName = "";
if ((pPrinterEnum + index)->pShareName != NULL)
DeviceDate.sShareName = (pPrinterEnum + index)->pShareName;
else
DeviceDate.sShareName = "";
if ((pPrinterEnum + index)->pLocation != NULL)
DeviceDate.sLoction = (pPrinterEnum + index)->pLocation;
else
DeviceDate.sLoction = "";
if ((pPrinterEnum + index)->pDevMode)
{
DeviceDate.nWidthMin = (pPrinterEnum + index)->pDevMode->dmPaperWidth;
DeviceDate.sPaperType = (char*)((pPrinterEnum + index)->pDevMode->dmFormName);
}
//DeviceDate.nWidthMin = (pPrinterEnum + index)->pDevMode->dmPaperWidth;
//DeviceDate.sPaperType = (char*)((pPrinterEnum + index)->pDevMode->dmFormName);
DWORD nstuse = (pPrinterEnum + index)->Status;
DWORD Attributes = (pPrinterEnum + index)->Attributes;
DeviceDate.m_bisPrintPage = BisConnectedA(nstuse, Attributes);
Drivers.push_back(DeviceDate);
    
}
}
clean_up:
LocalFree(LocalHandle(pPrinterEnum));
return (int)Drivers.size();
}
2: 打开设备进行打印打开一个打印机驱动DriverName 是驱动名称
{
HDC hdcPrint = CreateDC(NULL, DriverName, NULL, NULL);
HFONT Font = CreateFont(32, 0, 0, 0, fontWeight, 0, 0, 0,
DEFAULT_CHARSET, OUT_TT_PRECIS,
CLIP_TT_ALWAYS, PROOF_QUALITY,VARIABLE_PITCH | FF_MODERN | 0x04,L"宋体");
//设置打印梯子
SelectObject(hdcPaint,Font);
LPCWSTR Lp = L"task";
DOCINFO div={sizeof (DOCINFO),Lp};
//编辑一个文档
StartDoc(hdcPrint, &m_di);
//编辑一个文档的一页
StartPage(hdcPrint);
RECT rect;
rect.top = 0;
rect.bottom = 200;
rect.left = 0;
rect.right = 380;
DrawTextA(hdcPrint, "helleo world",13, &rect, DT_LEFT | DT_TOP | DT_EXPANDTABS | DT_NOPREFIX | DT_EDITCONTROL | DT_WORDBREAK | DT_EXTERNALLEADI NG | DT_CALCRECT);
DrawTextA(hdcPrint,"helleo world",13,&rect, DT_LEFT | DT_TOP | DT_EXPANDTABS | DT_NOPREFIX | DT_EDITCONTROL | DT_WORDBREAK | DT_EXTERNALLEADING );
//....
//结束编辑页
EndPage(hdcPrint);
//结束整个文本编辑
EndDoc(hdcPrint);
CloseHandle(hdcPrint);
}
    
基于硬件驱动开发
1: 获得打印设备信息
#pragma once
    
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <windows.h>
#include <devguid.h>
#include <setupapi.h>
#include <vector>
#pragma comment (lib, "setupapi.lib")
const char DRIVER_NAME_USBPRINT[] = "USB 打印支持";
const char DRIVER_NAME_USBPRINT_EN[] = "USB Printing Support";
    
struct deviceinfo {
std::string sdeviceid;
std::string sdesc;
std::string sdevicepath;
std::string sdeviceshow;
deviceinfo() {
sdeviceid = "";
sdesc = "";
sdevicepath = "";
sdeviceshow = "";
}
};
    
std::vector<deviceinfo > g_printerdevices;
const GUID GUID_DEVINTERFACE_USB_HUB = { 0xf18a0e88L, 0xc30c, 0x11d0, { 0x88, 0x15, 0x00, 0xa0, 0xc9, 0x06, 0xbe, 0xd8 } };
const GUID GUID_DEVINTERFACE_USB_DEVICE = { 0xA5DCBF10L, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } };
const GUID GUID_DEVINTERFACE_USB_HOST_CONTROLLER = { 0x3abf6f2dL, 0x71c4, 0x462a, { 0x8a, 0x92, 0x1e, 0x68, 0x61, 0xe6, 0xaf, 0x27 } };
const GUID GUID_USB_WMI_STD_DATA = { 0x4E623B20L, 0xCB14, 0x11D1, { 0xB3, 0x31, 0x00, 0xA0, 0xC9, 0x59, 0xBB, 0xD2 } };
const GUID GUID_USB_WMI_STD_NOTIFICATION = { 0x4E623B20L, 0xCB14, 0x11D1, { 0xB3, 0x31, 0x00, 0xA0, 0xC9, 0x59, 0xBB, 0xD2 } };
const GUID USBPrinterGUID = { 0x4d36e979L, 0xe325, 0x11ce, { 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 } };
//GUID__DEVINTERFACE_USB_DEVICE
int GetUSBPrintDevices(const GUID guid)
{
const GUID GUID_DEVINTERFACE_USB_DEVICE = guid;
const GUID* InterfaceGuid = &GUID_DEVINTERFACE_USB_DEVICE;
    
// that contains all devices of a specified class
HDEVINFO hDevInfo = SetupDiGetClassDevsA(InterfaceGuid,
NULL, // Enumerator
NULL,
DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
    
if (hDevInfo == INVALID_HANDLE_VALUE)
{
return 1;
}
    
SP_DEVINFO_DATA DeviceInfoData;
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
PSP_DEVINFO_DATA pDeviceInfoData = &DeviceInfoData;
    
DWORD MemberIndex;
    
bool found_usb_printer_flag = false;
    
for (MemberIndex = 0;
SetupDiEnumDeviceInfo(hDevInfo,
MemberIndex,
pDeviceInfoData) == TRUE;
MemberIndex++)
{
SP_DEVICE_INTERFACE_DATA DeviceInterfaceData;
DeviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
PSP_DEVICE_INTERFACE_DATA pDeviceInterfaceData = &DeviceInterfaceData;
    
DWORD RequiredSize;
PDWORD pRequiredSize = &RequiredSize;
    
DWORD InnerMemberIndex;
for (InnerMemberIndex = 0; SetupDiEnumDeviceInterfaces(hDevInfo,
pDeviceInfoData,
InterfaceGuid,
InnerMemberIndex,
pDeviceInterfaceData) == TRUE;
InnerMemberIndex++)
{
DWORD DeviceInterfaceDetailDataSize = 0;
BOOL first_call_result = SetupDiGetDeviceInterfaceDetailA(hDevInfo,
pDeviceInterfaceData,
NULL, // NULL DeviceInterfaceDetailData pointer
0, // DeviceInterfaceDetailDataSize of zero
pRequiredSize,
pDeviceInfoData);
    
if (first_call_result == TRUE)
{
continue;
}
else
{
DWORD first_call_error = GetLastError();
if (first_call_error != ERROR_INSUFFICIENT_BUFFER)
{
continue;
}
else
{
    
CHAR* buffer = new CHAR[RequiredSize];
PSP_DEVICE_INTERFACE_DETAIL_DATA_A pDeviceInterfaceDetailData =
(PSP_DEVICE_INTERFACE_DETAIL_DATA_A)buffer;
pDeviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
    
DWORD DeviceInterfaceDetailDataSize = RequiredSize;
PDWORD pDeviceInterfaceDetailDataSize = &DeviceInterfaceDetailDataSize;
    
BOOL second_call_result = SetupDiGetDeviceInterfaceDetailA(hDevInfo,
pDeviceInterfaceData,
pDeviceInterfaceDetailData,
DeviceInterfaceDetailDataSize,
&RequiredSize,
pDeviceInfoData);
    
if (second_call_result == FALSE)
{
DWORD last_error_number_second_call = GetLastError();
CHAR last_error_message_second_call[512];
FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, 0,
last_error_number_second_call, 0,
last_error_message_second_call,
1024, NULL);
}
else
{
DWORD dwNumberOfBytesWritten = 0;
    
CHAR szDescription[MAX_PATH];
memset(szDescription, 0, MAX_PATH);
    
const GUID* ClassGuid = &(pDeviceInfoData->ClassGuid);
SetupDiGetClassDescriptionA(ClassGuid, szDescription, MAX_PATH, &RequiredSize);
    
memset(szDescription, 0, MAX_PATH);
SetupDiGetDeviceInstanceIdA(hDevInfo, pDeviceInfoData, szDescription, MAX_PATH, 0);
    
char szName[64] = {0};
if (SetupDiGetDeviceRegistryProperty(hDevInfo,
pDeviceInfoData,
SPDRP_FRIENDLYNAME,
0L,
(PBYTE)szName,
63,
0))
{
}
else if (SetupDiGetDeviceRegistryProperty(hDevInfo,
pDeviceInfoData,
SPDRP_DEVICEDESC,
0L,
(PBYTE)szName,
63,
0))
{
};
    
std::string sdrivername = szName;
if(sdrivername.find(DRIVER_NAME_USBPRINT) != std::string::npos || sdrivername.find(DRIVER_NAME_USBPRINT_EN) != std::string::npos)
{
deviceinfo device;
device.sdeviceid = szDescription;
device.sdesc = szName;
device.sdevicepath = pDeviceInterfaceDetailData->DevicePath;
GetShowNames(device.sdeviceid ,device.sdeviceshow);
g_printerdevices.push_back(device);
}
} // end if second call returned true
    
// now free the buffer
delete[] buffer;
} // end if first call was successful
} // end if on second call
} // end iterate through device interfacess
} // end iterate through device info
    
SetupDiDestroyDeviceInfoList(hDevInfo);
return 0;
}
2. 选取一个设备打印
const char initialize_printer_command[] = {ESCAPE_CODE, AT_CODE, NULL_CODE};
const char ESC_WIDTHANDHEGHIT2[] = {0x1c,0x21,12};
int WiterFileInfo(HANDLE handle,const char* sdata)
{
    
DWORD dwInitializePrinterNumberOfBytesToWrite = 0;
DWORD dwInitializePrinterNumberOfBytesWritten = 0;
    
dwInitializePrinterNumberOfBytesToWrite = (DWORD)strlen(sdata);
    
BOOL ret = WriteFile( handle,
sdata,
dwInitializePrinterNumberOfBytesToWrite,
&(dwInitializePrinterNumberOfBytesWritten),
NULL);
    
return dwInitializePrinterNumberOfBytesWritten;
    
}
    
    
int USBPrintData(deviceinfo &driver)
{
HANDLE handle = CreateFileA(driver.sdevicepath.c_str(),
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
OPEN_EXISTING,
0,
NULL);
if (handle == INVALID_HANDLE_VALUE)
{
CloseHandle(handle);
return 0;
}
else
{
int i = 0;
}
    
DWORD dwInitializePrinterNumberOfBytesToWrite = 0;
DWORD dwInitializePrinterNumberOfBytesWritten = 0;
//ESC 指令打印
WiterFileInfo(handle,initialize_printer_command);
sprintf(write,"%s两倍大小字体\n",ESC_WIDTHANDHEGHIT2);
WiterFileInfo(handle,write);
//空白纸走3行
WiterFileInfo(handle," \n \n \n");
CloseHandle(handle);
return 0;
}
一点ESC指令测试
    
const char ESC_INIT_RWX[] = {0x1B,0x40}; //初始化;
const char ESC_LINE_TAB[] = {0x0A}; //换行
const char ESC_LINE_ADD[] = {0x1B,0x21,0x28}; //加粗
//const char ESC_LINE_H2[] = {0x1D,0x21,0x04}; //倍高 垂直( 三位符(倍高度) 1 2 4 8 1-7 倍)
//const char ESC_LINE_W2[] = {0x1D,0x21,0x20}; //倍高 垂直( 三位符(倍高度) 10 20 30 40 宽度 )
const char ESC_LINE_H1[] = {0x1D,0x21,0x01}; //倍高 垂直( 三位符(倍高度) 1 2 4 8 1-7 倍)
const char ESC_LINE_H2[] = {0x1D,0x21,0x02}; //倍高 垂直( 三位符(倍高度) 1 2 4 8 1-7 倍)
const char ESC_LINE_H3[] = {0x1D,0x21,0x04}; //倍高 垂直( 三位符(倍高度) 1 2 4 8 1-7 倍)
    
const char ESC_LINE_W1[] = {0x1D,0x21,0x10}; //倍高 垂直( 三位符(倍高度) 10 20 30 40 宽度 )
const char ESC_LINE_W2[] = {0x1D,0x21,0x20}; //倍高 垂直( 三位符(倍高度) 10 20 30 40 宽度 )
const char ESC_LINE_W3[] = {0x1D,0x21,0x30}; //倍高 垂直( 三位符(倍高度) 10 20 30 40 宽度 )
    
const char ESC_LINE_T1[] = {0x1B,0x21,0x02}; //原始高度
const char ESC_LINE_T2[] = {0x1D,0x21,0x11}; //倍高 垂直( 三位符(倍高度) 10 20 30 40 宽度 )
const char ESC_LINE_T3[] = {0x1D,0x21,0x22}; //倍高 垂直( 三位符(倍高度) 10 20 30 40 宽度 )
const char ESC_LINE_T4[] = {0x1D,0x21,0x34}; //倍高 垂直( 三位符(倍高度) 10 20 30 40 宽度 )
const char ESC_LINE_T5[] = {0x1D,0x21,0x48}; //倍高 垂直( 三位符(倍高度) 10 20 30 40 宽度 )
    
无驱打印
使用Win32 API打印原始数据(强烈建议)
#include "stdafx.h"
#include <windows.h>
#include <string>
#include <IOSTREAM>
#include <winioctl.h>
#include <setupapi.h>
    
#pragma comment(lib, "setupapi.lib")
    
using namespace std;
    
typedef struct DataInfo
{
string Port; //串口端口号
int BawdRate;//波特率
int DataBits; //数据位
char Parity; //校验位
int ReceiveBuffer; //缓冲区
int StopBits;//停止位
}PrintDevice;
    
// SetupDiGetInterfaceDeviceDetail所需要的输出长度,定义足够大
#define INTERFACE_DETAIL_SIZE (1024)
    
//设备数量上限,假设16台上限
#define MAX_DEVICE 16
    
    
    
//USB类的GUID
const GUID USB_GUID = {0xa5dcbf10, 0x6530, 0x11d2, {0x90, 0x1f, 0x00, 0xc0, 0x4f, 0xb9, 0x51, 0xed}};
    
HANDLE hPort=NULL; //句柄
    
//封装的打印函数
int WriteData(string meg);
//打印内容
bool OnWriteData(string meg, bool bBold = false, bool bDTall = false, bool bDWide = false, int nHAil = 1);
//链接设备
int InitPort(PrintDevice &device);
//参数初始化
void InitializeDevicePar(PrintDevice &device);
//找设备
int GetDevicePath(LPGUID lpGuid, LPTSTR* pszDevicePath);
    
int _tmain(int argc, _TCHAR* argv[])
{
//////////////////////////////////////////////////////////////////////////////////////////////////
//遍历USB设备,找到POS打印机路径
int i, nDevice;
char* szDevicePath[MAX_DEVICE]; // 设备路径
    
// 分配需要的空间
for (i = 0; i < MAX_DEVICE; i++)
{
szDevicePath[i] = new char[256];
}
    
// 取设备路径
nDevice = GetDevicePath((LPGUID)&USB_GUID, szDevicePath);
// GUID_CLASS_USB_DEVICE;
//////////////////////////////////////////////////////////////////////////////////////////////////
i = 0;
while (i < nDevice)
{
PrintDevice device;
InitializeDevicePar(device); //初始化打印机参数
    
device.Port = szDevicePath[i++];
    
printf("device.Port = %s\n",device.Port.c_str());
    
InitPort(device); //初始化打印机端口
    
string s;
    
////////////////////////////打印头信息开始//////////////////////////////////
OnWriteData("*****Now You See Me*****\n\n",true, true, true);
    
OnWriteData("- - - - - - - - - - - - - - - -\n");
    
OnWriteData("So You Want?\n",false, true);
    
OnWriteData("- - - - - - - - - - - - - - - -\n");
    
OnWriteData("这是一个基于ESC_POS打印机的USB无驱动打印Demo\n",true, true, true);
    
OnWriteData("我找到了你的电脑上所有的USB打印机\n",true, true, true, 2);
    
OnWriteData("然后给所有找到的打印机发送打印命令\n", true, true, true, 3);
    
OnWriteData("* * * * * * * * * * * * * * * *\n");
    
OnWriteData("OK打印完成\n\n",false, false, true, 2);
    
s = "\x1D\x56\x41\x00";
WriteData(s);
    
CloseHandle(hPort);//关闭端口
}
// 释放空间
for (i = 0; i< MAX_DEVICE; i++)
{
delete szDevicePath[i];
}
    
return 0;
}
    
//初始化参数
void InitializeDevicePar(PrintDevice &device)
{
device.Port="COM4";
device.BawdRate=9600;
device.DataBits=8;
device.StopBits=ONESTOPBIT;
device.Parity=NOPARITY; //NONE
device.ReceiveBuffer=256;
}
    
//链接打印机
int InitPort(PrintDevice &device)
{
hPort = CreateFile(device.Port.c_str(), GENERIC_READ | GENERIC_WRITE,
0, NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL );
    
if (hPort == INVALID_HANDLE_VALUE)
{ // 打开端口失败
return false;
}
else
{
    
printf("InitPort Hello\r\n");
    
//设置端口缓冲
SetupComm(hPort, 1024, 1024);
    
// 设定通讯端口超时参数
COMMTIMEOUTS tmouts;
tmouts.ReadIntervalTimeout = 100;
tmouts.ReadTotalTimeoutMultiplier = 100;
tmouts.ReadTotalTimeoutConstant = 100;
tmouts.WriteTotalTimeoutConstant = 100;
tmouts.WriteTotalTimeoutMultiplier = 100;
SetCommTimeouts(hPort, &tmouts);
    
//设定通讯端口通讯参数
DCB dcb;
BOOL bol = TRUE;
    
//dcb.DCBlength = sizeof(dcb);
bol=GetCommState(hPort, &dcb);
dcb.BaudRate = device.BawdRate;
dcb.ByteSize =device.DataBits;
dcb.StopBits = device.StopBits;
dcb.Parity = device.Parity;
    
bol = SetCommState(hPort, &dcb); //配置串口
// 清除通讯端口缓存
PurgeComm(hPort, PURGE_TXCLEAR | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_RXABORT);
    
// 初始化重叠IO对象
OVERLAPPED m_OverlappedRead;
OVERLAPPED m_OverlappedWrite;
HANDLE m_hStopCommEvent;
HANDLE m_hDataReady;
memset(&m_OverlappedRead, 0, sizeof(OVERLAPPED));
m_OverlappedRead.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
memset(&m_OverlappedWrite, 0, sizeof(OVERLAPPED));
m_OverlappedWrite.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    
// 初始化事件对象
m_hStopCommEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
m_hDataReady = CreateEvent(NULL, FALSE, FALSE, NULL);
    
//初始化打印ESC @
DWORD iBytesLength;
char chInitCode[] = "\x0D\x1B\x40";
if (!WriteFile(hPort, chInitCode, (DWORD)3L, &iBytesLength, NULL))
return false;
}
    
return true;
}
    
int WriteData(string meg)
{
DWORD dwWrite;
return WriteFile(hPort, meg.c_str(), (DWORD)meg.length(), &dwWrite, NULL);
}
    
//打印数据,meg打印字符串,bBold=true粗体,nZoom=2大一号字体, nHAil=2居中对齐,nHAil=3右对齐。部分打印机可能中文字体设置无效,请加上FS !命令设置中文字体。
bool OnWriteData(string meg, bool bBold, bool bDTall, bool bDWide, int nHAil)
{
char s[120] = "";
memset(s, 0, 120);
    
long nMode = 0;
DWORD iBytesLength;
    
if (bBold)
nMode += 8;
    
if (bDTall)
nMode += 16;
    
if (bDWide)
nMode += 32;
    
if (nMode > 0)
{
sprintf(s, "\x1B\x21%c", nMode);
    
if (strlen(s) < 3)
{
iBytesLength = 0;
WriteFile(hPort, s, (DWORD)3L, &iBytesLength, NULL);
}
else
WriteData(s);
}
    
switch (nHAil)
{
case 1:
break;
case 2:
strcat(s, "\x1B\x61\x01");
WriteData(s);
break;
case 3:
strcat(s, "\x1B\x61\x02");
WriteData(s);
break;
default:
break;
}
    
WriteData(meg);
    
iBytesLength = 0;
strcpy(s, "\x1B\x21\x00");
WriteFile(hPort, s, (DWORD)3L, &iBytesLength, NULL);
    
return true;
};
    
////////////////////////////////////////////////////////////////////////////////////////////////////////
//获取CreateFile的USB端口号
////////////////////////////////////////////////////////////////////////////////////////////////////////
    
// 根据GUID获得设备路径
// lpGuid: GUID指针
// pszDevicePath: 设备路径指针的指针,用于返回找到的路径
// 返回: 成功得到的设备路径个数,可能不止1个
int GetDevicePath(LPGUID lpGuid, LPTSTR* pszDevicePath)
{
HDEVINFO hDevInfoSet;
SP_DEVINFO_DATA spDevInfoData;
SP_DEVICE_INTERFACE_DATA ifData;
PSP_DEVICE_INTERFACE_DETAIL_DATA pDetail;
int nCount;
int nTotle;
BOOL bResult;
    
char* strUSBPrint = "USB 打印支持";
    
// 取得一个该GUID相关的设备信息集句柄
hDevInfoSet = ::SetupDiGetClassDevs(lpGuid, // class GUID
NULL, // 无关键字
NULL, // 不指定父窗口句柄
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); // 目前存在的设备
    
// 失败...
if (hDevInfoSet == INVALID_HANDLE_VALUE)
{
return 0;
}
    
// 申请设备接口数据空间
pDetail = (PSP_DEVICE_INTERFACE_DETAIL_DATA)::GlobalAlloc(LMEM_ZEROINIT, INTERFACE_DETAIL_SIZE);
    
pDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
    
nTotle = -1;
nCount = 0;
bResult = TRUE;
    
// 设备序号=0,1,2... 逐一测试设备接口,到失败为止
while (bResult)
{
nTotle++;
spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
    
// 枚举符合该GUID的设备接口
bResult = ::SetupDiEnumDeviceInfo(
hDevInfoSet, // 设备信息集句柄
(ULONG)nTotle, // 设备信息集里的设备序号
&spDevInfoData); // 设备接口信息
    
if (bResult)
{
DWORD DataT ;
TCHAR buf[MAX_PATH];
DWORD nSize = 0;
    
// get Friendly Name or Device Description
if ( SetupDiGetDeviceRegistryProperty(hDevInfoSet, &spDevInfoData,
SPDRP_FRIENDLYNAME, &DataT, (PBYTE)buf, sizeof(buf), &nSize) ) {
} else if ( SetupDiGetDeviceRegistryProperty(hDevInfoSet, &spDevInfoData,
SPDRP_DEVICEDESC, &DataT, (PBYTE)buf, sizeof(buf), &nSize) ) {
} else {
lstrcpy(buf, _T("Unknown"));
}
    
//是否是要找的设备类型
if (strcmp(buf, strUSBPrint) != 0)
continue;
    
ifData.cbSize = sizeof(ifData);
    
// 枚舉符合該GUID的設備接口
bResult = ::SetupDiEnumDeviceInterfaces(
hDevInfoSet, // 設備信息集句柄
NULL, // 不需額外的設備描述
lpGuid, // GUID
(ULONG)nTotle, // 設備信息集里的設備序號
&ifData); // 設備接口信息
    
if (bResult)
{
// 取得该设备接口的细节(设备路径)
bResult = SetupDiGetInterfaceDeviceDetail(
hDevInfoSet, // 设备信息集句柄
&ifData, // 设备接口信息
pDetail, // 设备接口细节(设备路径)
INTERFACE_DETAIL_SIZE, // 输出缓冲区大小
NULL, // 不需计算输出缓冲区大小(直接用设定值)
NULL); // 不需额外的设备描述
    
if (bResult)
{
// 复制设备路径到输出缓冲区
::strcpy_s(pszDevicePath[nCount], 256,pDetail->DevicePath);
// 调整计数值
nCount++;
}
}
}
}
    
// 释放设备接口数据空间
::GlobalFree(pDetail);
    
// 关闭设备信息集句柄
::SetupDiDestroyDeviceInfoList(hDevInfoSet);
    
return nCount;
}
用VC++实现USB接口读写数据的程序
使用一个GUIDguidHID_1查找并打开一个USB设备
extern "C" int PASCAL SearchUSBDevice()
{
HANDLE hUsb;
    
int nCount, i, j;//标记同一设备个数
HDEVINFO hDevInfoSet;
BOOL bResult;
    
PSP_DEVICE_INTERFACE_DETAIL_DATA pDetail =NULL;
    
memset(m_sysversion, 0, 20);
GetSysVersion(m_sysversion);
    
// 检索相关GUID的USB设备总设备个数
if (!GetUSBList())
{
return 0;
}
// 取得一个该GUID相关的设备信息集句柄
hDevInfoSet = ::SetupDiGetClassDevs((LPGUID)&guidHID_1,//GUID_CLASS_USB_DEVICE, // class GUID
NULL, // 无关键字
NULL, // 不指定父窗口句柄
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); // 目前存在的设备
    
// 失败...
if (hDevInfoSet == INVALID_HANDLE_VALUE)
{
return NULL;
}
    
// 申请设备接口数据空间
    
nCount = 0;
bResult = TRUE;
for (i=0; i< 34; i++)
{
bDeviceOpen[i] = FALSE;
memset(m_DeviceDesc[i], 0, 256);
}
    
SP_DEVICE_INTERFACE_DATA ifdata;
// 设备序号=0,1,2... 逐一测试设备接口,到失败为止
while (bResult)
{
    
ifdata.cbSize = sizeof(ifdata);
// 枚举符合该GUID的设备接口
bResult = ::SetupDiEnumDeviceInterfaces(
hDevInfoSet, // 设备信息集句柄
NULL, // 不需额外的设备描述
(LPGUID)&guidHID_1,//GUID_CLASS_USB_DEVICE, // GUID
(ULONG)nCount, // 设备信息集里的设备序号
&ifdata); // 设备接口信息
    
if (bResult)
{
ULONG predictedLength = 0;
ULONG requiredLength = 0;
// 取得该设备接口的细节(设备路径)
bResult = SetupDiGetInterfaceDeviceDetail(
hDevInfoSet, // 设备信息集句柄
&ifdata, // 设备接口信息
NULL, // 设备接口细节(设备路径)
0, // 输出缓冲区大小
&requiredLength, // 不需计算输出缓冲区大小(直接用设定值)
NULL); // 不需额外的设备描述
// 取得该设备接口的细节(设备路径)
predictedLength=requiredLength;
    
// if(pDetail)
// {
// pDetail =NULL;
// }
pDetail = (PSP_INTERFACE_DEVICE_DETAIL_DATA)::GlobalAlloc(LMEM_ZEROINIT, predictedLength);
pDetail->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
bResult = SetupDiGetInterfaceDeviceDetail(
hDevInfoSet, // 设备信息集句柄
&ifdata, // 设备接口信息
pDetail, // 设备接口细节(设备路径)
predictedLength, // 输出缓冲区大小
&requiredLength, // 不需计算输出缓冲区大小(直接用设定值)
NULL); // 不需额外的设备描述
    
if (bResult)
{
// 复制设备路径到输出缓冲区
//::strcpy(pszDevicePath[nCount], pDetail->DevicePath);
if (strcmp(m_sysversion, "winnt")==0)
{
char ch[18];
for(i=0;i<17;i++){
ch[i]=*(pDetail->DevicePath+8+i);
}
ch[17]='\0';
if (strcmp(ch,"vid_0471&pid_0666")==0)//比较版本号,防止意外出错
{
    
memset( &READ_OS, 0, sizeof( OVERLAPPED ) ) ;
memset( &WRITE_OS, 0, sizeof( OVERLAPPED ) ) ;
    
READ_OS.hEvent = CreateEvent( NULL, // no security
TRUE, // explicit reset req
FALSE, // initial event reset
NULL ) ; // no name
if (READ_OS.hEvent == NULL)
{
break;
}
    
WRITE_OS.hEvent = CreateEvent( NULL, // no security
TRUE, // explicit reset req
FALSE, // initial event reset
NULL ) ; // no name
if (NULL == WRITE_OS.hEvent)
{
CloseHandle( READ_OS.hEvent );
break;
}
    
hUsb=CreateFile(pDetail->DevicePath,//&guidHID_1,//
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL/*|
FILE_FLAG_OVERLAPPED*/,
NULL);
if (hUsb != NULL)
{
// 比较定位找到的USB在哪个USB PORT上
char id[30];
memset(id, 0, 30);
i=0;
do
{
id[i]=*(pDetail->DevicePath+26+i);
i++;
}
while(id[i-1]!='#');
id[i-1] = '\0';
for (j=0; j<34; j++)
{
if(strcmp(id, m_USBList[j])==0)
{
sprintf(m_DeviceDesc[j+1], "%s", pDetail->DevicePath);
m_USBPositionMap[nCount] = j+1;
break;
}
}
    
CloseHandle(hUsb);
nCount++;
// break;
}
}// 比较驱动版本
}// 比较操作系统版本
else
{
memset( &READ_OS, 0, sizeof( OVERLAPPED ) ) ;
memset( &WRITE_OS, 0, sizeof( OVERLAPPED ) ) ;
    
READ_OS.hEvent = CreateEvent( NULL, // no security
TRUE, // explicit reset req
FALSE, // initial event reset
NULL ) ; // no name
if (READ_OS.hEvent == NULL)
{
break;
}
    
WRITE_OS.hEvent = CreateEvent( NULL, // no security
TRUE, // explicit reset req
FALSE, // initial event reset
NULL ) ; // no name
if (NULL == WRITE_OS.hEvent)
{
CloseHandle( READ_OS.hEvent );
break;
}
    
hUsb=CreateFile(pDetail->DevicePath,//&guidHID_1,//
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL/*|
FILE_FLAG_OVERLAPPED*/,
NULL);
if (hUsb != NULL)
{
if(strcmp(pDetail->DevicePath, m_USBList[j])==0)
{
sprintf(m_DeviceDesc[j+1], "%s", pDetail->DevicePath);
m_USBPositionMap[nCount] = j+1;
break;
}
CloseHandle(hUsb);
nCount++;
// break;
}
}
}
}
}
// 释放设备接口数据空间
::GlobalFree(pDetail);
    
// 关闭设备信息集句柄
::SetupDiDestroyDeviceInfoList(hDevInfoSet);
    
iDeviceCount = nCount;
    
return nCount;
}
    
// 写
BOOL Writestr(char *buf,int buflen, int index)
{
BOOL fWriteStat;
DWORD dwErrorFlags;
DWORD dwError;
COMSTAT ComStat;
char szError[ 10 ] ;
DWORD ret;
int len, i, j, packet;
div_t div_result;
BYTE sendpacket[65];
BYTE xorcode="0x00";
    
if (m_gphdCom[index] == NULL) // no usb device(jk100c)
{
return -1;
}
    
div_result = div(buflen, 58);
if (div_result.rem == 0)
{
packet = div_result.quot;
}
else
{
packet = div_result.quot+1;
}
for (i=0; i<packet; i++)
{
memset(sendpacket, 0, 65);
if(i==packet-1)
{
// end packet
if (div_result.rem == 0)
{
len = 58;
}
else
{
len = div_result.rem;
}
}
else
{
len = 58;
}
sendpacket[0] = 0x13;
sendpacket[1] = 3+len;
sendpacket[2] = 0x01;
sendpacket[3] = packet*16+i+1;
memcpy(sendpacket+4, buf+(i*58), len);
for(j=0;j<len+3;j++)
{
xorcode^=sendpacket[j+1];
}
sendpacket[len+4] = (char)xorcode;
sendpacket[len+5] = 0x23;
PurgeComm(m_gphdCom[index],PURGE_RXCLEAR|PURGE_TXCLEAR);
// Sleep(10);
fWriteStat = WriteFile(m_gphdCom[index], sendpacket, len+6,&ret, NULL);
if (!fWriteStat)
{
if(GetLastError() == ERROR_IO_PENDING)
{
dwError = GetLastError();
// an error occurred, try to recover
wsprintf( szError, "\n\r <CE-%u>", dwError ) ;
OutputDebugString(szError);
ClearCommError(m_gphdCom[index], &dwErrorFlags, &ComStat ) ;
if (dwErrorFlags >0)
{
wsprintf( szError, "\n\r <CE-%u>", dwErrorFlags ) ;
OutputDebugString(szError);
}
}
else
{
// some other error occurred
ClearCommError(m_gphdCom[index], &dwErrorFlags, &ComStat ) ;
if (dwErrorFlags > 0)
{
wsprintf( szError, "\n\r <CE-%u>", dwErrorFlags ) ;
OutputDebugString(szError);
}
return FALSE;
}
}
if (i != packet-1)
{
// should be receive ack
if (ReceivePacketAnswer(index) != 0)
{
return FALSE;
}
}
}
    
return TRUE;
}
    
// 读
int Readstr(char *buf,int nMaxLength, int index)
{
BOOL fReadStat ;
COMSTAT ComStat;
DWORD dwErrorFlags;
DWORD dwLength;
DWORD dwError;
char szError[ 10 ];
    
if (fCOMMOpened==0)
{
return FALSE; //串口未打开
}
    
// only try to read number of bytes in queue
ClearCommError(m_gphdCom[index], &dwErrorFlags, &ComStat) ;
//dwLength = min( (DWORD) nMaxLength, ComStat.cbInQue ) ;
    
dwLength=nMaxLength;
if (dwLength > 0)
{
if (olap==TRUE)
{
fReadStat = ReadFile(m_gphdCom[index],buf, dwLength, &dwLength,&READ_OS) ;
if (!fReadStat)
{
if (GetLastError() == ERROR_IO_PENDING)
{
OutputDebugString("\n\rIO Pending");
while(!GetOverlappedResult(m_gphdCom[index], &READ_OS,
&dwLength, TRUE ))
{
dwError = GetLastError();
if(dwError == ERROR_IO_INCOMPLETE) continue;
else
{
// an error occurred, try to recover
ClearCommError(m_gphdCom[index],&dwErrorFlags, &ComStat ) ;
break;
}
}
}
else // end-----if (GetLastError() == ERROR_IO_PENDING)
{
// some other error occurred
dwLength = 0 ;
ClearCommError(m_gphdCom[index], &dwErrorFlags, &ComStat ) ;
if (dwErrorFlags >0)
{
wsprintf( szError, "\n\r <CE-%u>", dwErrorFlags ) ;
OutputDebugString(szError);
}
}
} // end-----if (!fReadStat)
} // end-----if (olap==TRUE)
else
{
fReadStat = ReadFile( m_gphdCom[index],buf, dwLength, &dwLength, NULL ) ;
if (!fReadStat)
{
dwError = GetLastError();
ClearCommError(m_gphdCom[index],&dwErrorFlags, &ComStat ) ;
    
if (dwErrorFlags >0)
{
wsprintf( szError, "\n\r <CE-%u>", dwErrorFlags ) ;
OutputDebugString(szError);
}
}
PurgeComm(m_gphdCom[index],PURGE_RXCLEAR|PURGE_TXCLEAR);
}
}
    
return dwLength;
}
    
浅谈QT打印功能实现
- 抽象文档打印对话框类,提供配置打印机的打印对话框基本实现;
 - 页面设置对话框类,和打印页面相关参数的配置对话框;
 - 打印对话框类,指定打印机配置的对话框;
 - 打印引擎类,定义了QPrinter类如何与打印子系统交互的接口;
 - 打印预览对话框类,用来预览和配置页面布局的对话框;
 - 打印预览控件类,预览页面布局的控件;
 - 打印机类,指示打印机如何工作。
 
    
Qt 打印功能
- if(index == 1)
 - {
 - QPrinterInfo info;
 - QStringList list = info.availablePrinterNames(); // 所有打印机名字
 - ui->cB_print->clear();
 - ui->cB_print->setEnabled(true);
 - foreach (QString str, list) {
 - ui->cB_print->addItem(str);
 - }
 - }
 - else
 - {
 - QPrinterInfo info;
 - QString name = info.defaultPrinterName(); // 默认打印机名字
 - ui->cB_print->clear();
 - ui->cB_print->setEnabled(false);
 - ui->cB_print->addItem(name);
 - }
 
- QPrinter printer(QPrinter::HighResolution);
 - //自定义纸张大小,特别重要,不然预览效果极差
 - printer.setPageSize(QPrinter::Custom);
 - printer.setPaperSize(QSizeF(600, 800),
 - QPrinter::Point);
 - QPrintPreviewDialog preview(&printer, this);// 创建打印预览对话框
 - preview.setMinimumSize(1000,600);
 - /*
 - * QPrintPreviewDialog类提供了一个打印预览对话框,里面功能比较全,
 - * paintRequested(QPrinter *printer)是系统提供的,
 - * 当preview.exec()执行时该信号被触发,
 - * drawPic(QPrinter *printer)是自定义的槽函数,图像的绘制就在这个函数里。
 - */
 - connect(&preview, SIGNAL(paintRequested(QPrinter*)), SLOT(drawPic(QPrinter*)));
 - preview.exec();
 - 然后drawPic定义:
 - //在预览窗口显示图片
 - void MainWindow::drawPic(QPrinter *printerPixmap)
 - {
 - QPixmap pix = QPixmap(800,600);
 - //这个函数算是画模板的函数吧,毕竟打印时有模板的
 - createPix(&pix);
 - pix.save(sFilePix);
 - //纵向:Portrait 横向:Landscape
 - printerPixmap->setOrientation(QPrinter::Landscape);
 - //获取界面的图片
 - QPainter painterPixmap(this);
 - painterPixmap.begin(printerPixmap);
 - QRect rect = painterPixmap.viewport();
 - int x = rect.width() / pix.width();
 - int y = rect.height() / pix.height();
 - //设置图像长宽是原图的多少倍
 - painterPixmap.scale(x, y);
 - painterPixmap.drawPixmap(0, 0, pix);
 - painterPixmap.end();
 - }
 - void MainWindow::createPix(QPixmap *pix)
 - {
 - QPainter *painter = new QPainter(this);
 - painter->begin(pix);
 - painter->setRenderHint(QPainter::Antialiasing, true);
 - // 设置画笔颜色、宽度
 - painter->setPen(QPen(QColor(255, 255, 255), 2));
 - // 设置画刷颜色
 - painter->setBrush(QColor(255, 255, 255));
 - QRect rect(0,0,800,600);
 - //整张图设置画刷白底
 - painter->fillRect(rect,QColor(255, 255, 255));
 - painter->drawRect(rect);
 - //画数据部分的线条
 - painter->setPen(QPen(QColor(0, 0, 0), 1));
 - QVector<QLine> lines;
 - lines.append(QLine(QPoint(50,50),QPoint(750,50)));//上边
 - lines.append(QLine(QPoint(750,50),QPoint(750,550)));//右边
 - lines.append(QLine(QPoint(50,550),QPoint(750,550)));//下边
 - lines.append(QLine(QPoint(50,50),QPoint(50,550)));//左边
 - lines.append(QLine(QPoint(50,120),QPoint(750,120)));//名称下边
 - lines.append(QLine(QPoint(50,180),QPoint(750,180)));//信息下边
 - lines.append(QLine(QPoint(50,200),QPoint(750,200)));//条目下边
 - lines.append(QLine(QPoint(50,490),QPoint(750,490)));//数据下边
 - lines.append(QLine(QPoint(120,180),QPoint(120,200)));//类型分割边
 - lines.append(QLine(QPoint(190,180),QPoint(190,200)));//类型分割边
 - lines.append(QLine(QPoint(260,180),QPoint(260,200)));//类型分割边
 - lines.append(QLine(QPoint(330,180),QPoint(330,200)));//类型分割边
 - lines.append(QLine(QPoint(400,180),QPoint(400,490)));//结果和曲线分割边
 - painter->drawLines(lines);
 - QFont font;
 - font.setPointSize(13);
 - font.setFamily("黑体");
 - font.setItalic(true);
 - painter->setFont(font);
 - //第一部分
 - painter->drawText(50,50,700,40,Qt::AlignCenter,ui->lE_unit->text());//单位名称
 - painter->drawText(QPoint(650,110),"No:");
 - font.setPointSize(20);
 - painter->setFont(font);
 - painter->drawText(50,80,700,40,Qt::AlignCenter,ui->lE_report->text());//报告名称
 - font.setPointSize(10);
 - painter->setFont(font);
 - //第二部分
 - painter->drawText(50,120,700,60,Qt::AlignVCenter,QString("样本ID: ")+QString("11111111"));
 - painter->drawText(210,120,700,60,Qt::AlignVCenter,QString("标本类型: ")+QString("ABC"));
 - painter->drawText(370,120,700,60,Qt::AlignVCenter,QString("检测方法: ")+ui->lE_means->text());
 - painter->drawText(600,120,700,60,Qt::AlignVCenter,QString("仪器: ")+ui->lE_instrument->text());
 - //第三部分
 - painter->drawText(50,180,70,20,Qt::AlignCenter,"序号");
 - painter->drawText(120,180,70,20,Qt::AlignCenter,"检测项目");
 - painter->drawText(190,180,70,20,Qt::AlignCenter,"Ct");
 - painter->drawText(260,180,70,20,Qt::AlignCenter,"检测下限");
 - painter->drawText(330,180,70,20,Qt::AlignCenter,"结果");
 - //第四部分
 - painter->drawText(50,210,70,20,Qt::AlignCenter,"1");
 - painter->drawText(120,210,70,20,Qt::AlignCenter,"我");
 - painter->drawText(190,210,70,20,Qt::AlignCenter,"真的");
 - painter->drawText(260,210,70,20,Qt::AlignCenter,"不知道");
 - painter->drawText(330,210,70,20,Qt::AlignCenter,"写啥");
 - //第五部分
 - painter->drawText(50,490,700,30,Qt::AlignVCenter,QString("送检者: ")+ui->lE_inspect->text());
 - painter->drawText(230,490,700,30,Qt::AlignVCenter,QString("代码: ")+ui->lE_code->text());
 - painter->drawText(410,490,700,30,Qt::AlignVCenter,QString("检验者: ")+ui->lE_detection->text());
 - painter->drawText(590,490,700,30,Qt::AlignVCenter,QString("审核者: ")+ui->lE_audit->text());
 - painter->drawText(50,520,700,30,Qt::AlignVCenter,QString("送检日期: ")+ui->lE_inspectDate->text());
 - painter->drawText(410,520,700,30,Qt::AlignVCenter,QString("报告日期: ")+ui->lE_reportDate->text());
 - painter->end();
 - }
 
- this->close();
 - //将文件保存
 - writeFile();
 - // 创建打印机对象
 - QPrinter printerPixmap;
 - QPixmap pix = QPixmap(800,600);
 - //将生成图片并保存,保不保存无所谓
 - createPix(&pix);
 - pix.save(sFilePix);
 - //纵向:Portrait 横向:Landscape
 - printerPixmap.setOrientation(QPrinter::Landscape);
 - //设置纸张大小
 - printerPixmap.setPageSize(QPrinter::A4);
 - QPainter painterPixmap;
 - //选取打印机,特别重要
 - printerPixmap.setPrinterName(ui->cB_print->currentText());
 - //开始打印
 - painterPixmap.begin(&printerPixmap);
 - //设置图像在A4中的开始坐标是什么
 - painterPixmap.drawPixmap(0, 0 , pix);
 - painterPixmap.end();
 - /*
 - * QPrintDialog print(&printerPixmap, this);
 - * 这个是点击会会出现弹框的打印,太low放弃
 - * 用法:
 - * QPrintDialog print(&printerPixmap, this);
 - * if (print.exec())
 - {
 - QPainter painterPixmap;
 - painterPixmap.begin(&printerPixmap);
 - QRect rect = painterPixmap.viewport();
 - int x = rect.width() / pixmap.width();
 - int y = rect.height() / pixmap.height();
 - painterPixmap.scale(x, y);
 - painterPixmap.drawPixmap(0, 0, pixmap);
 - painterPixmap.end();
 - }
 - */
 
程序界面:
    
预览效果:
    
    
    
Qt调用打印机和打印机预览代码
    
- #ifndef MAINWINDOW_H
 - #define MAINWINDOW_H
 - #include <QMainWindow>
 - namespace Ui {
 - class MainWindow;
 - }
 - class QPrinter;
 - class MainWindow : public QMainWindow
 - {
 - Q_OBJECT
 - public:
 - explicit MainWindow(QWidget *parent = 0);
 - ~MainWindow();
 - private:
 - Ui::MainWindow *ui;
 - private slots:
 - void OnTestPrint();
 - void OnTestPrintPreview();
 - void printDocument(QPrinter *printer);
 - };
 - #endif // MAINWINDOW_H
 
- #include "mainwindow.h"
 - #include "ui_mainwindow.h"
 - #include <QMessageBox>
 - #include <QDebug>
 - #include <QPrinter>
 - #include <QPrintDialog>
 - #include <QPrintPreviewDialog>
 - #include <QPainter>
 - /*
 - * Qt5打印支持 QT += printsupport
 - * */
 - MainWindow::MainWindow(QWidget *parent) :
 - QMainWindow(parent),
 - ui(new Ui::MainWindow)
 - {
 - ui->setupUi(this);
 - //打印
 - connect(ui->pbTestPrint,SIGNAL(released()),this,SLOT(OnTestPrint()));
 - //打印预览
 - connect(ui->pbTestPrintPreview,SIGNAL(released()),this,SLOT(OnTestPrintPreview()));
 - }
 - MainWindow::~MainWindow()
 - {
 - delete ui;
 - }
 - void MainWindow::OnTestPrint()
 - {
 - QPrinter printer(QPrinter::HighResolution);
 - QPrintDialog dialog(&printer, this);
 - if (dialog.exec() != QDialog::Accepted)
 - return;
 - //默认为零,如果用户选择了打印范围,以1为基数。
 - //printer.fromPage();
 - //printer.toPage();
 - //设置打印范围,以1为基数。
 - //printer.setFromTo(1, LastNumberOfPage);
 - qDebug("The user has choiced printer.");
 - printDocument(&printer);
 - }
 - //测试打印预览功能
 - void MainWindow::OnTestPrintPreview()
 - {
 - QPrinter printer(QPrinter::HighResolution);
 - QPrintPreviewDialog preview(&printer, this);
 - connect(&preview, SIGNAL(paintRequested(QPrinter*)),
 - this, SLOT(printDocument(QPrinter*)));
 - preview.exec();
 - }
 - void MainWindow::printDocument(QPrinter *printer)
 - {
 - //http://doc.qt.io/qt-5/qpainter.html
 - QPainter painter;
 - painter.begin(printer);
 - QString family("Arial");
 - QString style("Normal");
 - //
 - QFont font(family, 32, 50, false);
 - font.setStyleName(style);
 - font = QFont(font, painter.device());
 - //
 - QFontMetricsF fontMetrics(font);
 - QRectF rect = fontMetrics.boundingRect(QString("%1 %2").arg(family).arg(style));
 - //如果不scale的话,会因为打印的字太小而看不见。
 - qreal xScale = printer->pageRect().width() / rect.width();
 - qreal yScale = printer->pageRect().height() / rect.height();
 - double scale = qMin(xScale, yScale);
 - //
 - //Saves the current painter state (pushes the state onto a stack).
 - painter.save();
 - //Translates the coordinate system by the given offset;
 - painter.translate(printer->pageRect().width() / 2.0, printer->pageRect().height() / 2.0);
 - //Scales the coordinate system by (sX, sY).
 - painter.scale(scale, scale);
 - //Background x character for assure the bound and string draw orientation.
 - painter.setBrush(QBrush(Qt::white));
 - painter.drawRect(0,0,rect.width()/2,rect.height());
 - painter.setBrush(QBrush(Qt::black));
 - painter.drawLine(0, 0, rect.width()/2, rect.height());
 - painter.drawLine(0, rect.height(), rect.width()/2, 0);
 - //Notice string vertical orientation in printer is negative from screen.
 - painter.drawText(QPointF(0,0),
 - QString("%1-%2").arg(family).arg(style));
 - //Restores the current painter state (pops a saved state off the stack).
 - painter.restore();
 - //before begin new page.
 - //printer->newPage();
 - //after all done.
 - painter.end();
 - }