前言
国庆阅兵的时候,战斗机组成各种编队一起飞过天安门的场景很是壮观,让国人振奋。我们使用软件把编队的方式绘制出来,更加直观的展现给大家。
在一个编队中一般会有一架长机和多架僚机,长机一般处于编队居中或者靠前的位置,而僚机在会在长机的周围,编队的图形一般是对称。 软件实现了以下功能:
- 一架长机多架僚机;
- 鼠标点击选中飞机,具有高亮选中效果;
- 长机或者僚机可以自由的拖动;
- 长机由红色的五角星表示,僚机由不同的数据来表示;
- 按住Ctrl键同时点击鼠标左键选中长机然后拖动可以复制一架僚机;
- 可以通过右键菜单删除僚机;
- 可以设置僚机与长机的方位距离(每隔方格代表1000米*1000米);
- 最多可以展示100架飞机,还可以自由的扩展(修改代码)。
先看一下实现的效果:
开发环境
VS2010 + QT4.8.6 + x64
设计
以上功能使用Qt的GraphicsView和GraphicsScene、GraphicsItem绘制完成,GraphicsScene用来绘制场景,GraphicsView用来展示。每种类型的飞机对应的时候一种类型的Item,所有类型的Item都是通过统一的实体管理器进行管理的。
代码
宏定义 TeamSceneDef.h
#pragma once
#define SCENE_START_X (-300)
#define SCENE_START_Y (-300)
#define SCENE_WIDTH 600
#define SCENE_HEIGHT 600
#define GRID_WIDTH 50
#define GRID_HEIGHT 50
#define GRID_START_X (-250)
#define GRID_START_Y (-250)
#define GRID_END_X 250
#define GRID_END_Y 250
#define GRID_ROW_COUNT 10
#define GRID_COL_COUNT 10
#define LEADAIRCRAF_ORG_ROW ((GRID_ROW_COUNT - 1)/2)
#define LEADAIRCRAF_ORG_COL ((GRID_COL_COUNT - 1)/2)
#define ITEM_PIAMAP_OFFSET_X 10
#define ITEM_PIAMAP_OFFSET_Y 10
飞机实体定义 EntityPixmapItem.h
#ifndef ENTITYPIXMAPITEM_H
#define ENTITYPIXMAPITEM_H
#include <QGraphicsPixmapItem>
class EntityPixmapItem : public QGraphicsPixmapItem{
public:
EntityPixmapItem();
~EntityPixmapItem();
virtual void setGridPos(int r, int c);
void getGridPos(int&r, int&c){
r = _gridRow;
c = _gridCol;
}
int&getGridRow(){
return _gridRow;
}
int&getGridCol(){
return _gridCol;
}
void setLeadAircraft(bool b = false){
_isLeadAircraft = b;
}
bool&getLeadAircraft(){
return _isLeadAircraft;
}
void setSelected(bool b);
bool&getSelected(){
return _isSelected;
}
QRect&getRectRange(){
return _rectRange;
}
protected:
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)override;
protected:
int _gridRow, _gridCol;
int _offsetX,_offsetY;
QRect _rectRange;
bool _isLeadAircraft;
bool _isSelected;
};
#endif
#include <QPainter>
#include <QPen>
#include "EntityPixmapItem.h"
#include "TeamSceneDef.h"
EntityPixmapItem::EntityPixmapItem()
: QGraphicsPixmapItem(){
_gridRow = -1;
_gridCol = -1;
_offsetX = ITEM_PIAMAP_OFFSET_X;
_offsetY = ITEM_PIAMAP_OFFSET_Y;
_isLeadAircraft = false;
_isSelected = false;
}
EntityPixmapItem::~EntityPixmapItem(){
}
void EntityPixmapItem::setGridPos(int r, int c){
_gridRow = r;
_gridCol = c;
_rectRange = QRect(GRID_START_X + _gridRow * GRID_WIDTH, GRID_START_Y +_gridCol * GRID_HEIGHT , GRID_WIDTH, GRID_HEIGHT);
setPos(_rectRange.left(),_rectRange.top());
setOffset(_offsetX,_offsetY);
}
void EntityPixmapItem::setSelected(bool b){
_isSelected = b;
update();
}
void EntityPixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){
QGraphicsPixmapItem::paint(painter,option,widget);
QPixmap&pmp = pixmap();
if (_isSelected){
painter->setPen(Qt::NoPen);
QBrush brush(QColor(255,255,0,100));
painter->setBrush(brush);
painter->drawEllipse(_offsetX, _offsetY, pmp.width(), pmp.height());
}
}
长机定义 LeadAircraftEntityItem.h
#ifndef LEADAIRCRAFTENTITYITEM_H
#define LEADAIRCRAFTENTITYITEM_H
#include "EntityPixmapItem.h"
class QSvgRenderer;
class QPixmap;
class LeadAircraftEntityItem: public EntityPixmapItem{
public:
LeadAircraftEntityItem();
~LeadAircraftEntityItem();
protected:
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)override;
private:
QSvgRenderer* _svgRender;
QPixmap*_svgPixmap;
};
#endif
#include <QPainter>
#include <QSvgRenderer>
#include "LeadAircraftEntityItem.h"
LeadAircraftEntityItem::LeadAircraftEntityItem(){
_svgRender = nullptr;
_svgPixmap = nullptr;
}
LeadAircraftEntityItem::~LeadAircraftEntityItem(){
}
void LeadAircraftEntityItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){
EntityPixmapItem::paint(painter, option, widget);
if (_svgPixmap == nullptr){
_svgRender = new QSvgRenderer;
_svgRender->load(QString("lead.svg"));
_svgPixmap = new QPixmap(15,15);
_svgPixmap->fill(Qt::transparent);
QPainter p(_svgPixmap);
_svgRender->render(&p);
}
painter->drawPixmap(_offsetX , _offsetY , 15, 15, *_svgPixmap);
}
僚机定义:LeadAircraftEntityItem
#ifndef LEADAIRCRAFTENTITYITEM_H
#define LEADAIRCRAFTENTITYITEM_H
#include "EntityPixmapItem.h"
class QSvgRenderer;
class QPixmap;
class LeadAircraftEntityItem: public EntityPixmapItem{
public:
LeadAircraftEntityItem();
~LeadAircraftEntityItem();
protected:
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)override;
private:
QSvgRenderer* _svgRender;
QPixmap*_svgPixmap;
};
#endif
#include <QPainter>
#include <QSvgRenderer>
#include "LeadAircraftEntityItem.h"
LeadAircraftEntityItem::LeadAircraftEntityItem(){
_svgRender = nullptr;
_svgPixmap = nullptr;
}
LeadAircraftEntityItem::~LeadAircraftEntityItem(){
}
void LeadAircraftEntityItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget){
EntityPixmapItem::paint(painter, option, widget);
if (_svgPixmap == nullptr){
_svgRender = new QSvgRenderer;
_svgRender->load(QString("lead.svg"));
_svgPixmap = new QPixmap(15,15);
_svgPixmap->fill(Qt::transparent);
QPainter p(_svgPixmap);
_svgRender->render(&p);
}
painter->drawPixmap(_offsetX , _offsetY , 15, 15, *_svgPixmap);
}
场景定义 TeamGraphicsScene
#ifndef TEAMGRAPHICSSCENE_H
#define TEAMGRAPHICSSCENE_H
#include <QGraphicsPixmapItem>
#include <QGraphicsScene>
#include <QVector>
class QGraphicsSceneMouseEvent;
class MyDefinePlatformEntity;
class EntityPixmapItem;
class QMenu;
class QAction;
class GuiItemSetting;
class TeamGraphicsScene : public QGraphicsScene{
Q_OBJECT
public:
TeamGraphicsScene(QObject *parent = nullptr);
~TeamGraphicsScene();
void setEntity();
private:
void init();
void mousePressEvent(QGraphicsSceneMouseEvent *event)override;
void mouseMoveEvent(QGraphicsSceneMouseEvent *event)override;
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event)override;
void moveEntityItem(QPointF movePt);
void moveVirtualItem(QPointF movePt);
private slots:
void slotDelete();
void slotSetting();
private:
int _x, _y, _width, _hight;
QRect _gridTeam[10][10];
bool _leftBtnDown ;
QPointF _leftBtnDownPos;
QPointF _mouseMovePt;
EntityPixmapItem* _selectEntityItem;
QGraphicsPixmapItem* _virtualPixmap;
QMenu* _menu;
QAction* _actionDelete;
QAction* _actionSetting;
GuiItemSetting* _guiItemSetting;
};
#endif
#include <QApplication>
#include <QDebug>
#include <QMenu>
#include <QAction>
#include <QMessageBox>
#include <QGraphicsEllipseItem>
#include <QGraphicsSceneDragDropEvent>
#include "TeamGraphicsScene.h"
#include "EntityPixmapItem.h"
#include "LeadAircraftEntityItem.h"
#include "WingmanEntityItem.h"
#include "EntityItemManager.h"
#include "TeamSceneDef.h"
#include "GuiItemSetting.h"
TeamGraphicsScene::TeamGraphicsScene(QObject *parent)
: QGraphicsScene(parent){
_x = SCENE_START_X;
_y = SCENE_START_Y;
_width = SCENE_WIDTH;
_hight = SCENE_HEIGHT;
_leftBtnDown = false;
_selectEntityItem = nullptr;
_virtualPixmap = nullptr;
_menu = nullptr;
_actionDelete = nullptr;
_actionSetting = nullptr;
_guiItemSetting = nullptr;
init();
}
TeamGraphicsScene::~TeamGraphicsScene(){
}
void TeamGraphicsScene::setEntity(){
QPixmap* pixmap = new QPixmap(32,32);
pixmap->load("001.png");
QPixmap pmp = pixmap->scaled(32,32);
LeadAircraftEntityItem* jbItem = new LeadAircraftEntityItem;
jbItem->setPixmap(pmp);
jbItem->setGridPos(LEADAIRCRAF_ORG_ROW, LEADAIRCRAF_ORG_COL);
jbItem->setLeadAircraft(true);
EntityItemMgr()->setLeadAircraftItem(jbItem);
addItem(jbItem);
_virtualPixmap = new QGraphicsPixmapItem;
_virtualPixmap->setPixmap(pmp);
_virtualPixmap->setVisible(false);
addItem(_virtualPixmap);
}
void TeamGraphicsScene::init(){
setSceneRect(_x, _y, _width, _hight);
QPen pen;
pen.setColor(Qt::lightGray);
pen.setWidth(1);
QGraphicsEllipseItem* ellipCenter = new QGraphicsEllipseItem(-2, -2, 4, 4);
ellipCenter->setPen(pen);
addItem(ellipCenter);
QGraphicsLineItem* lineX = new QGraphicsLineItem(GRID_START_X, 0, GRID_END_X, 0);
lineX->setPen(pen);
addItem(lineX);
QGraphicsLineItem* lineXArrows1 = new QGraphicsLineItem(-GRID_START_X-10, 5, GRID_END_X, 0);
lineXArrows1->setPen(pen);
addItem(lineXArrows1);
QGraphicsLineItem* lineXArrows2 = new QGraphicsLineItem(-GRID_START_X-10, -5, GRID_END_X, 0);
lineXArrows2->setPen(pen);
addItem(lineXArrows2);
QFont font;
font.setFamily(QString::fromUtf8("微软雅黑"));
font.setPointSize(12);
QGraphicsTextItem* tX = new QGraphicsTextItem(QString::fromLocal8Bit("X(东)"));
tX->setDefaultTextColor(Qt::yellow);
tX->setFont(font);
tX->setPos(GRID_END_X + 3, 0);
addItem(tX);
QGraphicsLineItem* lineY = new QGraphicsLineItem(0, GRID_START_Y, 0, GRID_END_Y);
lineY->setPen(pen);
addItem(lineY);
QGraphicsLineItem* lineYArrows1 = new QGraphicsLineItem(0, GRID_START_Y, 5, -GRID_END_Y + 10);
lineYArrows1->setPen(pen);
addItem(lineYArrows1);
QGraphicsLineItem* lineYArrows2 = new QGraphicsLineItem(0, GRID_START_Y, -5, -GRID_END_Y + 10);
lineYArrows2->setPen(pen);
addItem(lineYArrows2);
QGraphicsTextItem* tY = new QGraphicsTextItem(QString::fromLocal8Bit("Y(北)"));
tY->setDefaultTextColor(Qt::yellow);
tY->setFont(font);
tY->setPos(3, GRID_START_Y - 3);
addItem(tY);
pen.setStyle(Qt::DashLine);
for (int row = 0; row < 11; row ++){
QGraphicsLineItem* lineRow = new QGraphicsLineItem(GRID_START_X, GRID_START_Y + row * GRID_HEIGHT, GRID_END_X, GRID_START_Y + row * GRID_HEIGHT);
lineRow->setPen(pen);
addItem(lineRow);
}
for (int col = 0; col < 11; col ++){
QGraphicsLineItem* lineRow = new QGraphicsLineItem(GRID_START_Y + col * GRID_WIDTH, GRID_START_Y, GRID_START_Y + col*GRID_WIDTH , GRID_END_Y);
lineRow->setPen(pen);
addItem(lineRow);
}
for (int row = 0; row < 10; row ++){
for (int col = 0; col < 10; col ++){
_gridTeam[row][col] = QRect( -250 + row * 50 , -250 + 50 * col , 50, 50);
#if 0
QGraphicsRectItem* rect = new QGraphicsRectItem(_gridTeam[row][col]);
pen.setColor(Qt::yellow);
rect->setPen(pen);
addItem(rect);
QGraphicsTextItem* t = new QGraphicsTextItem(QString("(%1,%2)").arg(row).arg(col));
t->setDefaultTextColor(Qt::yellow);
t->setFont(font);
t->setPos(_gridTeam[row][col].left() , _gridTeam[row][col].top());
addItem(t);
#endif
}
}
}
void TeamGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event){
if (event->button() & Qt::LeftButton) {
_leftBtnDown = true;
QPointF point = event->scenePos();
_selectEntityItem = EntityItemMgr()->clickItem(point);
if (_selectEntityItem!= nullptr){
if (_selectEntityItem->getLeadAircraft() && QApplication::keyboardModifiers() == Qt::ControlModifier){
WingmanEntityItem* copyItem = new WingmanEntityItem;
int copyItemRow = -1, copyItemCol = -1;
_selectEntityItem->getGridPos(copyItemRow, copyItemCol);
copyItem->setGridPos(copyItemRow, copyItemCol);
copyItem->setLeadAircraft(false);
copyItem->setPixmap(_selectEntityItem->pixmap());
copyItem->setRoleID(EntityItemMgr()->createRoleID());
EntityItemMgr()->addWingmanItem(copyItem);
addItem(copyItem);
_selectEntityItem = copyItem;
}
moveVirtualItem(point);
}
}
}
void TeamGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event){
QPointF movePt = event->scenePos();
if (_leftBtnDown && _selectEntityItem != nullptr){
moveEntityItem(movePt);
_virtualPixmap->setVisible(true);
moveVirtualItem(movePt);
}
}
void TeamGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event){
if (event->button() & Qt::LeftButton) {
_leftBtnDown = false;
_virtualPixmap->setVisible(false);
}else if (event->button() & Qt::RightButton) {
if (_selectEntityItem != nullptr && !_selectEntityItem->getLeadAircraft()){
QMenu popMenu;
QAction* actionDelete = popMenu.addAction(QString::fromLocal8Bit("删除"), this, SLOT(slotDelete()));
QAction* actionSetting = popMenu.addAction(QString::fromLocal8Bit("设置"), this, SLOT(slotSetting()));
popMenu.exec(QCursor::pos());
}
}
}
void TeamGraphicsScene::moveEntityItem(QPointF movePt){
int currentRow = -1, currentCol = -1;
_selectEntityItem->getGridPos(currentRow, currentCol);
for (int col = currentCol - 1; col <= currentCol + 1; col ++){
for (int row = currentRow - 1; row <= currentRow + 1; row ++){
if (row < 0 || row > GRID_ROW_COUNT - 1){
continue;
}
if (col < 0 || col > GRID_COL_COUNT - 1){
continue;
}
if (row == currentRow && col == currentCol){
continue;
}
if (_gridTeam[row][col].contains(movePt.toPoint())) {
_selectEntityItem->setGridPos(row, col);
_selectEntityItem->update();
EntityItemMgr()->resetGridLength(_selectEntityItem);
break;
}
}
}
}
void TeamGraphicsScene::moveVirtualItem(QPointF movePt){
QPixmap&pmp = _virtualPixmap->pixmap();
int w = pmp.width();
int h = pmp.height();
_virtualPixmap->setPos(movePt.x() - w/2, movePt.y() - h/2);
}
void TeamGraphicsScene::slotDelete(){
if (0 == QMessageBox::question(nullptr, QString::fromLocal8Bit("删除"), QString::fromLocal8Bit("确定要删除?"), QString::fromLocal8Bit("确定"), QString::fromLocal8Bit("取消"), QString::fromLocal8Bit(""), 1)) {
EntityItemMgr()->deleteWingmanItem(dynamic_cast<WingmanEntityItem*>(_selectEntityItem));
removeItem(_selectEntityItem);
_selectEntityItem = nullptr;
}
}
void TeamGraphicsScene::slotSetting(){
if (_guiItemSetting == nullptr){
_guiItemSetting = new GuiItemSetting;
}
_guiItemSetting->initEntityPixmapItem(dynamic_cast<WingmanEntityItem*>(_selectEntityItem));
_guiItemSetting->setAttribute(Qt::WA_ShowModal);
_guiItemSetting->show();
}
调用场景
void QtGuiTeam::setEntity(MyDefinePlatformEntity* myDefinePlatformEntity){
_myDefinePlatformEntity = myDefinePlatformEntity;
_teamGraphicsScene->setEntity();
}
void QtGuiTeam::init(){
ui.graphicsView->setBackgroundBrush(QBrush(QColor(64, 128, 128)));
ui.graphicsView->setRenderHint(QPainter::Antialiasing);
ui.graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
ui.graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
_teamGraphicsScene = new TeamGraphicsScene;
ui.graphicsView->setScene(_teamGraphicsScene);
}
设置僚机和长机的距离方位
void GuiItemSetting::slotOK(){
LeadAircraftEntityItem*leadAircraft = EntityItemMgr()->getLeadAircraftItem();
double x = ui.lineEditX->text().toDouble();
double y = ui.lineEditY->text().toDouble();
double z = ui.lineEditZ->text().toDouble();
_wingmanEntityItem->setOffsetLeadAircraftX(x);
int xOffset = (int)x/(int)EntityItemMgr()->getGridWidth() + ((int)x % (int)EntityItemMgr()->getGridWidth() == 0 ? 0 : 1);
_wingmanEntityItem->setOffsetLeadAircraftY(y);
int yOffset = (int)y/(int)EntityItemMgr()->getGridHeight() + ((int)y % (int)EntityItemMgr()->getGridHeight() == 0 ? 0 : 1);
_wingmanEntityItem->setGridPos(leadAircraft->getGridRow() + xOffset, leadAircraft->getGridCol() - yOffset);
_wingmanEntityItem->setOffsetLeadAircraftZ(z);
_wingmanEntityItem->update();
close();
}
aaa.
|