Windows自定义打印的实现

来源:互联网 发布:网络商学院 编辑:程序博客网 时间:2024/06/07 00:23

Windows自定义打印的实现之一

其实在Windwos中调用Windows API实现打印是比较简单的,而且具有代码紧凑、实现灵活的优点。我们只要掌握了几个要点,就可以随心所欲的打印了。下面我们将一一讨论:

  • 打印机的选择,打印设置对话框的调用
  • 在程序中设置打印选项
  • 打印单位的转换
  • 打印基本流程
  • 打印字体的设置

打印机的选择,打印设置对话框的调用

这个不多说了,相关的主要API只有一个--PrintDlg(LPPRINTDLG lppd)--看例子代码。

    PRINTDLG printInfo;    ZeroMemory(&printInfo,sizeof(printInfo));  //清空该结构    printInfo.lStructSize = sizeof(printInfo);       printInfo.hwndOwner = 0;       printInfo.hDevMode = 0;    printInfo.hDevNames = 0;    //这个是关键,PD_RETURNDC 如果不设这个标志,就拿不到hDC了    //            PD_RETURNDEFAULT 这个就是得到默认打印机,不需要弹设置对话框    printInfo.Flags = PD_RETURNDC | PD_RETURNDEFAULT;      //调用API拿出默认打印机    PrintDlg(&printInfo);    //看看出错没有    DWORD rst = CommDlgExtendedError();    if(rst != 0)    {        //出错了,清空标志再次调用API,此时就会弹出打印设置对话框供用户选择了        printInfo.Flags = 0;        PrintDlg(&printInfo);    }

从上面的代码,我们就知道弹不弹对话框的关键是设置PRINTDLG结构的Flags字段。

在程序中设置打印选项

要想在程序中定制我们的打印选项,DEVMODE结构就是关键了。在这里我们只举例如何为打印设定自定义纸张。更详细的设置信息可以查询MSDN。

    //首先得到DEVMODE结构,同时申请系统锁定,我们要修改它了    LPDEVMODE lpDevMode = (LPDEVMODE)::GlobalLock(printInfo.hDevMode);    if(lpDevMode)  //成功得到该结构了    {        lpDevMode->dmPaperSize = DMPAPER_USER;  //自定义纸张                //设定自定义纸张标志        lpDevMode->dmFields = lpDevMode ->dmFields | DM_PAPERSIZE | DM_PAPERLENGTH | DM_PAPERWIDTH;                 lpDevMode->dmPaperWidth = (short)width; //纸宽多少        lpDevMode->dmPaperLength = (short)height; //纸高多少                //顺便设定纸张走纸方向,横向还是纵向        lpDevMode->dmOrientation = DMORIENT_PORTRAIT;    }    //记住要解锁    GlobalUnlock(printInfo.hDevMode);        //这个也不能忘了,否则更改不会生效    ResetDC(printInfo.hDC, lpDevMode);

Windows自定义打印的实现之二

打印单位的转换

这个的关键是我们要得到显示设备的DPI,即每英寸设备支持的点数。有了DPI我们就可以在我们习惯的单位和设备单位之间转换了,用到的API是GetDeviceCaps(),这个函数功能强大,具体可参考MSDN,在这里我们只用来得到设备DPI。看示例代码:

    //某些设备水平和垂直方向的DPI可能不同,所以要分别得到。        //得到水平方向的转换比例    float getXScale(HDC printDC)  //printDC: 打印机DC设备句柄    {        //得到打印机水平方向的DPI        int xDPI = GetDeviceCaps(printDC, LOGPIXELSX);                //254.0: 每英寸25.4毫米        float xScale = (float)(254.0 / xDPI);                return xScale;    }        //得到垂直方向的转换比例    float getYScale(HDC printDC)  //printDC: 打印机DC设备句柄    {        //得到打印机垂直方向的DPI        int yDPI = GetDeviceCaps(printDC, LOGPIXELSY);                float yScale = (float)(254.0 / yDPI);                return yScale;    }    //厘米转换为设备像素,水平方向    double cm2Unit_W(float xScale, double w) //w单位为厘米    {        return w*100/xScale;    }    //厘米转换为设备像素,垂直方向    double cm2Unit_H(float yScale, double h) //h单位为厘米    {        return h*100/yScale;    }

上面代码中,如果将printDC换为显示器设备DC句柄,即可得到厘米转换为显示器像素单位,打印预览时使用。得到显示器设备句柄可用::GetDC(NULL)得到。

打印基本流程

有了前面的知识,现在我们就可以打印了。Windows打印是有着固定的流程的,流程也比较简单。按照固定的顺序调用打印API即可:StartDoc() -> StartPage() -> 打印具体内容 -> EndPage() -> EndDoc()。如果要打印多页,循环StartPage()至EndPage()即可。

示例代码:

    DOCINFO   doc;       ZeroMemory(&doc,sizeof(doc));       doc.cbSize = sizeof(doc);       doc.lpszDocName = (LPCTSTR)"Print Test File";        StartDoc(printDC, &doc);  //准备打印    StartPage(printDC);  //开始打印页        //在(2.5cm, 2.5cm)处打印文本    char* text = "打印测试文本";        float xScale = getXScale(printDC);    float yScale = getYScale(printDC);        double x = cm2Unit_W(xScale, 2.5);    double y = cm2Unit_H(yScale, 2.5);        //在指定位置打印文本    TextOut(printDC, (int)x, (int)y, (LPTSTR)text, strlen(text));        EndPage(printDC);  //结束打印页        EndDoc(printDC);  //结束打印

打印字体的设置

很多时候我们希望能控制打印字体,下面的代码可以创建你想要的字体格式:

    /*  创建自定义打印字体        fontFace:字体名称,如果为NULL,默认采用“宋体”        fontHeight:字体高度,单位为厘米        isBold:是否加粗        isItalic:是否斜体        isUnderLine:是否下划线        isStrikeOut:是否删除线    */    HFONT getFont(LPCTSTR fontFace, double fontHeight, bool isBold, bool isItalic, bool isUnderLine, bool isStrikeOut)    {        int width = 0; //字体宽度由系统决定        int weight = FW_NORMAL;        DWORD italic = 0;        DWORD underLine = 0;        DWORD strikeOut = 0;        DWORD charSet = DEFAULT_CHARSET;        LPCTSTR face = (LPCTSTR)"宋体";                float height = cm2Unit_H(fontHeight);                if(fontFace != 0)        {            face = fontFace;        }        if(isBold)        {            weight = FW_BOLD;        }                if(isItalic)        {            italic = 1;        }                if(isUnderLine)        {            underLine = 1;        }                if(isStrikeOut)        {            strikeOut = 1;        }        HFONT font = CreateFont((int)height, width, 0, 0,                                  weight, italic, underLine, strikeOut, charSet,                                 OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY,                                  DEFAULT_PITCH | FF_DONTCARE, face );        return font;    }

小结

以上就是我们在实现打印中遇到的常见问题,相信理解了这些,在我们自己的程序中实现打印就不再是什么困难的事情了。