现在数据库和数据都已经准备好了,怎么在mfc的滚动视图当中画表格和填充数据库里的数据呢?或者问题再说得直白一点,怎么用pDC画横线画竖线来构建表格呢?怎么用pDC画文字填充到表格里呢?如果是这样的话,那岂不是一笔一划对位置的精度要求特别高吗?每一笔一划都要我们自己处理,这pDC能做到吗?还有打印一页打不完需要的数据,打印和打印预览的上一页,下一页 按钮要怎么写代码呢?
3条回答 默认 最新
关注让【宝码香车】来帮您解答,本回答参考DeepSeek编写,并整理提供。
如果答案让您满意,请采纳、点赞、关注,非常感谢!
.
每日一句正能量,让它带给您好心情:你现在的努力,是为了以后能有更多的自由。
.在MFC中绘制表格并实现打印功能确实需要精确的坐标计算,但通过合理的设计可以很好地实现。下面我将详细解答你的问题:
1. 使用pDC绘制表格基础
绘制横线和竖线
void CMyView::OnDraw(CDC* pDC) { // 设置表格参数 int rowHeight = 30; // 行高 int colWidth = 100; // 列宽 int rows = 10; // 行数 int cols = 5; // 列数 CPoint startPoint(50, 50); // 起始点 // 保存原来的画笔,创建新画笔 CPen* pOldPen = pDC->SelectObject(&m_gridPen); // 绘制横线 for (int i = 0; i <= rows; i++) { int y = startPoint.y + i * rowHeight; pDC->MoveTo(startPoint.x, y); pDC->LineTo(startPoint.x + cols * colWidth, y); } // 绘制竖线 for (int j = 0; j <= cols; j++) { int x = startPoint.x + j * colWidth; pDC->MoveTo(x, startPoint.y); pDC->LineTo(x, startPoint.y + rows * rowHeight); } // 恢复原来的画笔 pDC->SelectObject(pOldPen); }在表格中填充文字
void CMyView::DrawTableData(CDC* pDC) { // 设置字体 CFont font; font.CreatePointFont(90, _T("宋体")); // 9号字 CFont* pOldFont = pDC->SelectObject(&font); // 设置文字颜色和对齐方式 pDC->SetTextColor(RGB(0, 0, 0)); pDC->SetBkMode(TRANSPARENT); pDC->SetTextAlign(TA_LEFT | TA_TOP); CStringArray data; // 假设这是从数据库获取的数据 // 填充数据到data数组... int rowHeight = 30; int colWidth = 100; CPoint startPoint(50, 50); // 绘制表格数据 for (int i = 0; i < data.GetSize(); i++) { for (int j = 0; j < cols; j++) { CRect cellRect( startPoint.x + j * colWidth + 2, // 留2像素边距 startPoint.y + i * rowHeight + 2, startPoint.x + (j + 1) * colWidth - 2, startPoint.y + (i + 1) * rowHeight - 2 ); CString text = GetCellData(i, j); // 从数据库获取单元格数据 pDC->DrawText(text, cellRect, DT_LEFT | DT_TOP | DT_SINGLELINE); } } pDC->SelectObject(pOldFont); }2. 坐标精度处理技巧
使用精确的坐标计算类
class CTableCalculator { public: CTableCalculator() : m_dpiX(96), m_dpiY(96) {} void SetDPI(int dpiX, int dpiY) { m_dpiX = dpiX; m_dpiY = dpiY; } CPoint LogicalToDevice(CDC* pDC, CPoint logicalPoint) { pDC->LPtoDP(&logicalPoint); return logicalPoint; } CRect CalculateCellRect(int row, int col, int rowHeight, int colWidth, CPoint start) { return CRect( start.x + col * colWidth, start.y + row * rowHeight, start.x + (col + 1) * colWidth, start.y + (row + 1) * rowHeight ); } private: int m_dpiX, m_dpiY; };3. 打印和打印预览的分页处理
在View类中添加分页支持
// 在头文件中添加 class CMyView : public CScrollView { protected: int m_nPageHeight; // 每页高度 int m_nPageWidth; // 每页宽度 int m_nCurrentPage; // 当前页 int m_nTotalPages; // 总页数 afx_msg void OnPrepareDC(CDC* pDC, CPrintInfo* pInfo = NULL); DECLARE_MESSAGE_MAP() };实现分页逻辑
void CMyView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo) { CScrollView::OnPrepareDC(pDC, pInfo); if (pDC->IsPrinting() && pInfo != NULL) { // 设置映射模式为MM_LOENGLISH (0.01英寸) pDC->SetMapMode(MM_LOENGLISH); // 计算每页能显示的行数 CRect rectPrint; pDC->GetClipBox(&rectPrint); m_nPageHeight = abs(rectPrint.Height()); m_nPageWidth = abs(rectPrint.Width()); // 计算总页数 int totalRows = GetTotalRows(); // 从数据库获取总行数 int rowsPerPage = m_nPageHeight / m_nRowHeight; m_nTotalPages = (totalRows + rowsPerPage - 1) / rowsPerPage; pInfo->SetMaxPage(m_nTotalPages); } } void CMyView::OnPrint(CDC* pDC, CPrintInfo* pInfo) { m_nCurrentPage = pInfo->m_nCurPage; // 设置映射模式 pDC->SetMapMode(MM_LOENGLISH); // 计算当前页的起始行 int rowsPerPage = m_nPageHeight / m_nRowHeight; int startRow = (m_nCurrentPage - 1) * rowsPerPage; int endRow = min(startRow + rowsPerPage, GetTotalRows()); // 绘制当前页的表格 DrawTablePage(pDC, startRow, endRow); // 绘制页眉页脚 DrawHeaderFooter(pDC, pInfo); } void CMyView::DrawTablePage(CDC* pDC, int startRow, int endRow) { // 绘制当前页的表格部分 int rowHeight = m_nRowHeight; int colWidth = 100; CPoint startPoint(100, -100); // MM_LOENGLISH坐标系Y轴向下为负 // 绘制表头 DrawTableHeader(pDC, startPoint); // 绘制数据行 for (int i = startRow; i < endRow; i++) { int y = startPoint.y - (i - startRow + 1) * rowHeight; DrawTableRow(pDC, i, y, colWidth, startPoint.x); } }打印预览的导航按钮处理
void CMyView::OnPreviewPrev() { CPrintPreviewState* pState = GetParentFrame()->GetPrintPreviewState(); if (pState && pState->m_nCurrentPage > 1) { pState->m_nCurrentPage--; Invalidate(); } } void CMyView::OnPreviewNext() { CPrintPreviewState* pState = GetParentFrame()->GetPrintPreviewState(); if (pState && pState->m_nCurrentPage < m_nTotalPages) { pState->m_nCurrentPage++; Invalidate(); } } void CMyView::OnUpdatePreviewPrev(CCmdUI* pCmdUI) { CPrintPreviewState* pState = GetParentFrame()->GetPrintPreviewState(); pCmdUI->Enable(pState && pState->m_nCurrentPage > 1); } void CMyView::OnUpdatePreviewNext(CCmdUI* pCmdUI) { CPrintPreviewState* pState = GetParentFrame()->GetPrintPreviewState(); pCmdUI->Enable(pState && pState->m_nCurrentPage < m_nTotalPages); }4. 实用建议
- 使用MM_LOENGLISH映射模式进行打印,避免DPI差异问题
- 预先计算所有坐标,避免在绘制过程中重复计算
- 创建表格绘制辅助类来管理坐标计算和样式
- 使用数据库游标逐页读取数据,避免内存溢出
- 在OnPrepareDC中统一处理坐标变换
通过以上方法,你可以构建一个功能完整的MFC表格绘制和打印系统。虽然需要精确的坐标处理,但通过合理的封装和计算,完全可以实现稳定的表格显示和打印功能。
本回答被题主选为最佳回答 , 对您是否有帮助呢?解决 无用评论 打赏 举报