前文链接:QGraphicsView实现简易地图9『层级缩放显示底图』
自适应窗口大小
当地图窗口放大或缩小的时候,需要地图能够动态覆盖整个视口。
1、动态演示效果
2、核心代码
注:WHMapView继承自MapView
void WHMapView::resize()
{if (m_curLevel >= 0)moveScene();
}void MapView::moveScene()
{QString appPath = QApplication::applicationDirPath();QString dirPath = QString("%1/MapData/GaoDeMap/Map/MapPng/L0%2").arg(appPath).arg(m_curLevel + 1);// 视口宽度和高度int vw = viewport()->width();int vh = viewport()->height();// 计算呈现的瓦片地图左上角的场景坐标和视口坐标、呈现的瓦片地图右下角的场景坐标和视口坐标QPoint topLeftScenePos(m_topLeftTileCoord.x * PIXMAP_SIZE, m_topLeftTileCoord.y * PIXMAP_SIZE);QPointF topLeftViewPos = mapFromScene(topLeftScenePos);QPoint bottomRightScenePos(m_bottomRightTileCoord.x * PIXMAP_SIZE, m_bottomRightTileCoord.y * PIXMAP_SIZE);QPointF bottomRightViewPos = mapFromScene(bottomRightScenePos);int mapSideCount = pow(2, m_curLevel);if (MapUtility::sceneSize(m_curLevel) > vw){// 1、水平瓦片坐标控制:判断最左侧瓦片是否完全进入视口、最右侧瓦片是否完全离开视口if (topLeftViewPos.x() > 0){int count = qCeil(topLeftViewPos.x() / PIXMAP_SIZE); // 左侧进入视口瓦片数量m_topLeftTileCoord.x = qMax(m_topLeftTileCoord.x - count, 0); // 更新现左侧瓦片坐标X}if (bottomRightViewPos.x() > vw){int count = qFloor((bottomRightViewPos.x() - vw) / PIXMAP_SIZE) + 1; // 右侧离开视口瓦片数量m_bottomRightTileCoord.x = qMax(m_bottomRightTileCoord.x - count, 0); // 更新现右侧瓦片坐标X}// 2、水平瓦片坐标控制:判断最右侧瓦片是否完全进入视口、最左侧瓦片是否完全离开视口if (bottomRightViewPos.x() + PIXMAP_SIZE < vw){int count = qCeil((vw - (bottomRightViewPos.x() + PIXMAP_SIZE)) / PIXMAP_SIZE); // 右侧进入视口瓦片数量m_bottomRightTileCoord.x = qMin(m_bottomRightTileCoord.x + count, mapSideCount - 1); // 保存现右侧瓦片坐标X}if (topLeftViewPos.x() + PIXMAP_SIZE < 0){int count = qFloor(fabs(topLeftViewPos.x()) / PIXMAP_SIZE); // 左侧离开视口瓦片数量m_topLeftTileCoord.x = qMin(m_topLeftTileCoord.x + count, mapSideCount - 1); // 保存现左侧瓦片坐标X}}if (MapUtility::sceneSize(m_curLevel) > vh){// 3、垂直瓦片坐标控制:判断最上侧瓦片是否完全进入视口,最下侧瓦片是否完全离开视口if (topLeftViewPos.y() > 0){int count = qCeil(topLeftViewPos.y() / PIXMAP_SIZE); // 上侧进入视口瓦片数量m_topLeftTileCoord.y = qMax(m_topLeftTileCoord.y - count, 0); // 保存现上侧瓦片坐标Y}if (bottomRightViewPos.y() > vh){int count = qFloor((bottomRightViewPos.y() - vh) / PIXMAP_SIZE) + 1; // 下侧离开视口瓦片数量m_bottomRightTileCoord.y = qMax(m_bottomRightTileCoord.y - count, 0); // 保存现下侧瓦片坐标Y}// 4、垂直瓦片坐标控制:判断最下侧瓦片是否完全进入视口,最上侧瓦片是否完全离开视口if (bottomRightViewPos.y() + PIXMAP_SIZE < vh){int count = qCeil((vh - (bottomRightViewPos.y() + PIXMAP_SIZE)) / PIXMAP_SIZE); // 下侧进入视口瓦片数量m_bottomRightTileCoord.y = qMin(m_bottomRightTileCoord.y + count, mapSideCount - 1); // 保存现下侧瓦片坐标Y}if (topLeftViewPos.y() + PIXMAP_SIZE < 0){int count = qFloor(fabs(topLeftViewPos.y()) / PIXMAP_SIZE); // 上侧离开视口瓦片数量m_topLeftTileCoord.y = qMin(m_topLeftTileCoord.y + count, mapSideCount - 1); // 保存现上侧瓦片坐标Y}}// 获取移动前瓦片集合vector<TileCoord> vecOldTileCoord;for (int row = m_viewAndAroundTileRect.top(); row <= m_viewAndAroundTileRect.bottom(); ++row){for (int col = m_viewAndAroundTileRect.left(); col <= m_viewAndAroundTileRect.right(); ++col){vecOldTileCoord.push_back(TileCoord(col, row));}}// 获取移动后瓦片集合vector<TileCoord> vecNewTileCoord, vecAddTileCoord;m_viewAndAroundTileRect = CommonUtility::getViewAndAroundTileCoords(m_topLeftTileCoord.y, m_topLeftTileCoord.x, m_bottomRightTileCoord.y, m_bottomRightTileCoord.x, m_curLevel, vecNewTileCoord);for (const auto &tc : vecNewTileCoord){// ①筛除已加载过的瓦片 ②线程加载存在滞后性,第二次移动时可能第一次m_tileItems还没有加载完毕,所以需要前一次范围作为过滤if (!m_tileItems.contains(tc) && std::find(vecOldTileCoord.begin(), vecOldTileCoord.end(), tc) == vecOldTileCoord.end()){vecAddTileCoord.push_back(tc);}}//showTileCoord();showGraticules();// 上方即为计算瓦片索引的核心代码,省略下方加载瓦片的代码...// 加载瓦片代码...
}