如何拆分QPainter,实现游戏中Space类仅绘制自身对应屏幕区域?
实现方案
1. 调整Space绘制逻辑
保持Space的render方法签名不变,让它只按**本地坐标系(0,0 → 100,100)**绘制内容,无需关心实际屏幕位置:
class Space { // ... public: virtual void render(QPainter *painter); };
2. 实现Board的坐标变换与绘制分发
在Board的render方法中,遍历所有Space,计算每个Space对应的屏幕矩形,通过QPainter的坐标变换将本地坐标系映射到屏幕区域,复用同一个QPainter实例完成绘制:
void Board::render(QPainter *painter) { // 示例:每个Space在屏幕上的实际尺寸,可根据需求动态调整 const int tileScreenSize = 60; const int rowCount = mLstBoard.size(); if (rowCount == 0) return; const int colCount = mLstBoard.first().size(); for (int row = 0; row < rowCount; ++row) { for (int col = 0; col < colCount; ++col) { // 计算当前Space的屏幕绘制区域 QRect screenRect(col * tileScreenSize, row * tileScreenSize, tileScreenSize, tileScreenSize); // 保存当前Painter状态,避免变换影响后续绘制 painter->save(); // 坐标变换:平移到目标区域左上角 + 缩放适配屏幕尺寸 painter->translate(screenRect.topLeft()); painter->scale(static_cast<qreal>(screenRect.width()) / 100.0, static_cast<qreal>(screenRect.height()) / 100.0); // 调用Space的render,此时它的(0,0)对应屏幕区域的左上角 mLstBoard[row][col].render(painter); // 恢复Painter原始状态 painter->restore(); } } }
3. GamePanel的绘制入口
在GamePanel中重写paintEvent,创建QPainter并传递给Board的render方法:
void GamePanel::paintEvent(QPaintEvent *event) { QPainter painter(this); // 可在此绘制棋盘背景等全局元素 if (mBoard) { mBoard->render(&painter); } }
核心优势
- 复用QPainter:全程使用同一个实例,通过
save()/restore()隔离每个Space的绘制状态,避免资源浪费与状态污染。 - 解耦绘制逻辑:Space只需关注自身本地坐标系内的绘制,无需适配屏幕尺寸;调整棋盘布局或Space大小只需修改
Board中的屏幕区域计算逻辑。 - 扩展性强:后续支持不同大小的Space、棋盘缩放等需求时,无需修改Space的绘制代码。
内容的提问来源于stack exchange,提问作者Seth D. Fulmer
相关产品推荐
相关产品推荐

