qq_41945416 2025-11-03 01:56 采纳率: 90.6%
浏览 7
已结题

关于mfc绘制并打印表格的问题

现在数据库和数据都已经准备好了,怎么在mfc的滚动视图当中画表格和填充数据库里的数据呢?或者问题再说得直白一点,怎么用pDC画横线画竖线来构建表格呢?怎么用pDC画文字填充到表格里呢?如果是这样的话,那岂不是一笔一划对位置的精度要求特别高吗?每一笔一划都要我们自己处理,这pDC能做到吗?还有打印一页打不完需要的数据,打印和打印预览的上一页,下一页 按钮要怎么写代码呢?

  • 写回答

3条回答 默认 最新

  • 宝码香车 优质创作者: JavaScript技术领域 2025-11-03 08:43
    关注

    让【宝码香车】来帮您解答,本回答参考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. 实用建议

    1. 使用MM_LOENGLISH映射模式进行打印,避免DPI差异问题
    2. 预先计算所有坐标,避免在绘制过程中重复计算
    3. 创建表格绘制辅助类来管理坐标计算和样式
    4. 使用数据库游标逐页读取数据,避免内存溢出
    5. 在OnPrepareDC中统一处理坐标变换

    通过以上方法,你可以构建一个功能完整的MFC表格绘制和打印系统。虽然需要精确的坐标处理,但通过合理的封装和计算,完全可以实现稳定的表格显示和打印功能。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

问题事件

  • 系统已结题 11月11日
  • 已采纳回答 11月3日
  • 创建了问题 11月3日