【问题标题】:Printing to a Printer DC with MFC使用 MFC 打印到打印机 DC
【发布时间】:2016-04-22 15:51:54
【问题描述】:

我已按照 Microsoft 的有关创建设备上下文的教程进行操作,并尝试在 Internet 上寻找合适的来源(显然,MFC 是一个神秘的东西)。下面成功打印出“Hello, World!”;除了它非常小。

如何向打印机发送 CImage 而不是文本? 我怎样才能让文本的大小大于几毫米? 我已经搜索了 MSDN,但所有内容要么已经过时(例如我正在使用的示例代码),要么没有很好的文档记录。

 // get the default printer
  CPrintDialog dlg(FALSE);
  dlg.GetDefaults();

  // is a default printer set up?
  HDC hdcPrinter = dlg.GetPrinterDC();
  if (hdcPrinter == NULL)
  {
    //MessageBox(_T("Buy a printer!"));
  }
  else
  {
    // create a CDC and attach it to the default printer
    CDC dcPrinter;
    dcPrinter.Attach(hdcPrinter);

    // call StartDoc() to begin printing
    DOCINFO docinfo;
    memset(&docinfo, 0, sizeof(docinfo));
    docinfo.cbSize = sizeof(docinfo);
    docinfo.lpszDocName = _T("CDC::StartDoc() Code Fragment");

    // if it fails, complain and exit gracefully
    if (dcPrinter.StartDoc(&docinfo) < 0)
    {
      //MessageBox(_T("Printer wouldn't initalize"));
    }
    else
    {
      // start a page
      if (dcPrinter.StartPage() < 0)
      {
        //MessageBox(_T("Could not start page"));
        dcPrinter.AbortDoc();
      }
      else
      {
        // actually do some printing
        //CGdiObject* pOldFont = dcPrinter.SelectStockObject(SYSTEM_FONT);

        dcPrinter.SetMapMode(MM_HIENGLISH);
      auto font = CreateFont(
      3'000,                        // nHeight
      1'500,                         // nWidth
      0,                         // nEscapement
      0,                         // nOrientation
      FW_NORMAL,                 // nWeight
      FALSE,                     // bItalic
      FALSE,                     // bUnderline
      0,                         // cStrikeOut
      ANSI_CHARSET,              // nCharSet
      OUT_DEFAULT_PRECIS,        // nOutPrecision
      CLIP_DEFAULT_PRECIS,       // nClipPrecision
      DEFAULT_QUALITY,           // nQuality
      DEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily
      _T("Arial"));                 // lpszFacename
      dcPrinter.SelectObject(&font);
        dcPrinter.TextOut(450, 450, _T("Hello World!"), 12);
        dcPrinter.EndPage();
        dcPrinter.EndDoc();
        //dcPrinter.SelectObject(pOldFont);
      }
    }
  }

【问题讨论】:

  • 这是常见的 win32 打印优先问题。如果您要花费超过几个小时来添加打印支持,我建议您花一个小时左右阅读 Petzold 中的相关章节。它牵着你的手,非常清楚地解释了它的一切;您稍后要做的就是将其映射到微不足道的 MFC 概念。您可以花几美元购买二手副本,或下载它。不过,我仍然建议您购买硬拷贝 - 这是为数不多的几本书之一,您经常会因为这些小细节而翻阅。
  • 我周五早上订购了几本书,但我不反对再添加一本书!我用谷歌搜索了Petzold MFCthis is what came up;这是“The Petzold”吗?
  • 不,实际上是这样的:charlespetzold.com/pw5。它不适用于 MFC,它是 win32,但您的问题本质上是关于 win32 概念的。 MFC 打印支持只是其上的一个薄 OO 层。这本书有一整章是关于打印的(确切地说是第 13 章):什么是打印设备上下文、什么是 DEVCAPS、打印对话框等。Adrian 解释了这个问题,这本书描述了将所有内容组合在一起的基础知识。

标签: c++ printing mfc


【解决方案1】:

小文本问题

问题在于,默认情况下,字体的大小以设备相关单位指定,打印机的分辨率通常比屏幕高得多。因此,如果您在尝试在打印机上使用该字体(每英寸可能有 300 或 600 个点)时在屏幕上创建了 20 像素高的字体(每英寸可能有 96 像素),那么您的文本看起来真的小。

正如另一个答案所示,一个想法是更改映射模式,以便打印机使用更接近屏幕上的单位。

另一种方法是根据打印机的 DPI 创建具有适当大小的新字体(LOGFONT 结构中的 lfHeight 字段),您可以使用GetDeviceCaps 函数来确定。如果您需要特定的字体大小(例如 14 磅文本),这会很方便。

LOGFONT lf = {0};
lf.lfHeight = -MulDiv(point_size, ::GetDeviceCaps(dcPrinter, LOGPIXELSY), 72);
// init other field of lf as you like
HFONT hfontPrinter = ::CreateFontIndirect(&lf);
HFONT hfontOld = ::SelectObject(hdcPrinter, hfontPrinter);

// now draw to the hdcPrinter

::SelectObject(hdcPrinter, hfontOld);
::DeleteObject(hfontPrinter);

发送 CImage

我不使用 MFC,但看起来您可以使用打印机 DC 调用 CImage::StretchBlt。再次强调,您在选择目标坐标时可能必须考虑打印机的高分辨率。

【讨论】:

  • 太棒了,这正是我想要的。您的代码示例只有一个问题——hfont 是什么?您在代码示例中的几个地方使用它,但您从未定义它(我假设 hfont 应该是 hfontPrinter?)
  • 是的。我现在已经修复了代码示例。很抱歉造成混乱;我很快就把它搞砸了。
【解决方案2】:

使用 CFont::CreatePointFont() 或 CFont::CreatePointFontIndirect() 创建合理的字体。大多数打印机是 600 DPI。大多数屏幕是 96 DPI。屏幕上的 12 点字体基本上是 2 点字体,在打印机上难以辨认。

创建字体并将其选择到您的 DC。不要忘记在使用它之后和销毁你的 DC(CDC 类)之前从 DC 中选择它。 (CDC 析构函数会自动删除 HDC)。

【讨论】:

    【解决方案3】:

    问题来了:

    dcPrinter.SetMapMode(MM_TEXT);
    

    MM_TEXT 将一个逻辑点映射到一个设备点;考虑到打印机的典型分辨率为 600 DPI,你的东西会比屏幕上的小几倍。

    使用 MM_HIENGLISH 或其他一些与设备无关的模式;这里是MSDN link

    【讨论】:

    • 如何放大文本的大小?我确定您的建议可以正常工作,但是当我切换到 MM_HIENGLISH 时,文本甚至都没有出现。当我注释掉这行 CGdiObject* pOldFont = dcPrinter.SelectStockObject(SYSTEM_FONT); 时,字体大小显示为可读大小 - 但我找不到任何信息说明为什么会这样,也不能告诉 pOldFont 增加大小。
    • pOldFont 指向先前选择到该 DC 中的字体;在从您的函数返回之前,除了恢复(通过将其重新选择到 DC)之外,您无需对其执行任何操作。要控制字体,您需要创建它并指定您需要的任何参数,尤其是大小。对于MM_HIENGLISH 模式,正如我的链接所解释的,每个逻辑单元都映射到 0.001 英寸;因此,对于 1 英寸高的字体,您将其高度设置为 1,000。
    • 我明白了。好吧,你有什么像样的资料可以进一步阅读吗?我创建了一个新字体,将它提供给打印机 DC,将映射模式设置为 MM_HIENGLISH,但它仍然显示错误的大小。如果您想看一下,我已经更新了代码,并且我意识到当映射模式设置为 MM_HIENGLISH 时,我在打印的页面上实际上什么都没有。我对 MFC 编程一无所知,所以我可以从任何可以在线获得的地方开始。
    【解决方案4】:

    我已使用以下成功打印“Hello World!”祝你有愉快的一天!”位于打印机页面原点的 200x200 单色位图 (MyLogo.bmp) 的右侧(我使用的是黑白热敏打印机):

    CDC printDC( GetMyPrintDC() );    // e.g. as per original code
    DOCINFO di( GetMyDocInfo() );     // e.g. as per original code
    printDC.StartDoc( &di );
      ATL::CImage logo;
      logo.Load( "MyLogo.bmp" );
      const BOOL result( logo.Draw( printDC.GetSafeHdc(), CPoint( 0, 0 ) ) );
    CFont myFont, *old;
    myFont.CreatePointFont(100, "Courier New", &printDC);
    old = printDC.SelectObject(&myFont);
    printDC.TextOut( 250, 50, "   Hello World!" );
    printDC.TextOut( 250, 150, "Have a nice Day!" );
    printDC.SelectObject( old );
    myFont.DeleteObject();
    printDC.EndPage();
    printDC.EndDoc();
    printDC.DeleteDC();
    

    三个缩进的行突出显示在我的打印机上呈现CImage 所需的所有内容。改变CreatePointFont() 中的参数以调整(否则很小)文本的大小以适合。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-08
      • 2011-04-12
      • 2020-06-10
      • 2013-01-22
      相关资源
      最近更新 更多