MFC 文檔/視圖架構提供完善列印支援,但對話框應用或 CFormView 中的 CListCtrl(報表模式)列印卻相對繁瑣。本文提供一個即拿即用的 PrintListCtrl() 函數,支援自動欄寬計算、多頁分頁、列印對話框選項,適合嵌入各類專案。
CListCtrl 欄標題與資料PrintDlg 讓用戶選擇印表機、紙張、方向typedef struct tagColAtt {
int nColIndex; // 原始欄索引
CString strColText; // 欄標題文字
int nPrintX; // 列印 X 座標
int nSubItemIndex; // 子項索引
} COLATT;
PRINTDLG 取得 hDC,GetDeviceCaps 取得可列印區域解析度GetHeaderCtrl() 與 GetColumnOrderArray() 取得顯示順序與標題文字,計算初步欄寬StartDoc/StartPage 開啟列印任務TextOut 繪製欄標題EndPage/StartPage 換頁EndDoc、DeleteDC 釋放資源BOOL PrintListCtrl(CListCtrl &list) {
PRINTDLG pd = { sizeof(PRINTDLG) };
pd.Flags = PD_RETURNDC;
if (!PrintDlg(&pd)) return FALSE;
ASSERT(pd.hDC != NULL);
int nHorRes = GetDeviceCaps(pd.hDC, HORZRES);
int nVerRes = GetDeviceCaps(pd.hDC, VERTRES);
TEXTMETRIC tm; GetTextMetrics(pd.hDC, &tm);
int nCharHeight = tm.tmHeight, nCharWidth = tm.tmAveCharWidth;
CHeaderCtrl* pHeader = list.GetHeaderCtrl();
int nColCount = pHeader->GetItemCount();
int nLineCount = list.GetItemCount();
int ColOrderArray[100];
COLATT ca[100];
list.GetColumnOrderArray(ColOrderArray, nColCount);
// 1. 讀取欄標題與初步定位
int nColX = 2 * nCharWidth; // 左邊距
for (int i = 0; i < nColCount; i++) {
ca[i].nColIndex = ColOrderArray[i];
LVCOLUMN lvc = { LVCF_TEXT | LVCF_SUBITEM };
char text[100]; lvc.pszText = text; lvc.cchTextMax = 100;
list.GetColumn(ca[i].nColIndex, &lvc);
ca[i].strColText = lvc.pszText;
ca[i].nSubItemIndex = lvc.iSubItem;
ca[i].nPrintX = nColX;
nColX += nCharWidth * strlen(ca[i].strColText);
if (nColX > nHorRes) {
DeleteDC(pd.hDC);
AfxMessageBox(_T("欄位過多無法單行列印,請嘗試橫向或較大紙張。"));
return FALSE;
}
}
// 2. 開始列印文檔
DOCINFO di = { sizeof(DOCINFO), _T("ListCtrl Data Printing") };
StartDoc(pd.hDC, &di);
StartPage(pd.hDC);
// 3. 均勻分佈剩餘空間
int space = (nHorRes - 2 * nCharWidth - nColX) / (nColCount - 1);
for (int i = 1; i < nColCount; i++) ca[i].nPrintX += i * space;
// 4. 列印標題
for (int i = 0; i < nColCount; i++)
TextOut(pd.hDC, ca[i].nPrintX, 2, ca[i].strColText, ca[i].strColText.GetLength());
// 5. 列印資料分頁
int nMaxLinePerPage = nVerRes / nCharHeight - 3;
int nCurPage = 1;
for (int i = 0; i < nLineCount; i++) {
for (int j = 0; j < nColCount; j++) {
int lineOnPage = i + 1 - (nCurPage - 1) * nMaxLinePerPage;
if (lineOnPage > nMaxLinePerPage) {
EndPage(pd.hDC);
StartPage(pd.hDC);
nCurPage++;
lineOnPage = 1;
}
CString subitem = list.GetItemText(i, ca[j].nSubItemIndex);
TextOut(pd.hDC, ca[j].nPrintX, 2 + lineOnPage * nCharHeight,
subitem, subitem.GetLength());
}
}
EndPage(pd.hDC);
EndDoc(pd.hDC);
DeleteDC(pd.hDC);
return TRUE;
}
PrintListCtrl(m_myListCtrl);ExtTextOut 或 GDI+)此方案以精簡的 API 呼叫解決對話框類應用的列印難題,代碼結構清晰、易於維護擴展,是 MFC 開發者工具箱中的實用利器。