问题前提描述:
自定义了BlockItem类(继承至QGraphicsItem);
自定义了BlockWindowScene(继承至QGraphicsScene);
自定义了BlockWindow(继承至QMainWindow);
问题描述:
当把BlockItem放进BlockWindowScene后,必须要调用”ui->graphicsView->viewport()->update()“刷新一下,BlockItem的paint才会被调用,才会显示正常矩形。但是将view的滚动条滚动,把BlockItem滚动到view以外再滚动回来,此时BlockItem又显示不完整了,如下图所示。必须在调用一次”ui->graphicsView->viewport()->update()“刷新一下view才行。
BlockItem.h
#pragma once
#include <QGraphicsItem>
#include <qdebug.h>
#include "publicheader.h"
#include <qpainter.h>
#include <QRectF>
#include <QSizeF>
#include <qpoint.h>
class BlockItem :public QObject, public QGraphicsItem
{
Q_OBJECT
public:
explicit BlockItem(QGraphicsItem *parent = nullptr);
BlockItem(QString itemType);
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr);
~BlockItem();
//将item页面中配置的内容存放到item的map容器中
void setKeyValue_Map(QString key,QString value);
void setKeyValue_Map(QMap<QString, QString> map);
//设置四边形的坐标
void setPos(QPointF curPos);
//测试keyValue_Map
void initKeyValue_Map();
protected:
//鼠标按压事件
void mousePressEvent(QGraphicsSceneMouseEvent* event);
//鼠标双击事件
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event);
private:
//存Item的类别
QString itemType;
//存放配置的key和value
QMap<QString, QString> keyValue_Map;
//存来自Scene中的鼠标坐标
QPointF pos;
};
BlockItem.cpp
#include "blockitem.h"
#include <qmimedata.h>
BlockItem::BlockItem(QGraphicsItem *parent)
: QGraphicsItem(parent)
{
setFlag(QGraphicsItem::ItemIsFocusable);
setFlag(QGraphicsItem::ItemIsMovable);
setFlag(QGraphicsItem::ItemIsSelectable);
}
BlockItem::BlockItem(QString itemType)
{
setFlag(QGraphicsItem::ItemIsFocusable);
setFlag(QGraphicsItem::ItemIsMovable);
setFlag(QGraphicsItem::ItemIsSelectable);
//接收看item是什么类型
this->itemType = itemType;
}
//item在Scene中的边界大小
QRectF BlockItem::boundingRect() const
{
qreal adjust = 1;
return QRectF(0 - adjust, 0 - adjust, 150 + adjust, 80 + adjust);
}
//将item页面中配置的内容存放到item的map容器中
void BlockItem::setKeyValue_Map(QString key, QString value)
{
this->keyValue_Map.insert(key, value);
}
//将item页面中配置的内容存放到item的map容器中
void BlockItem::setKeyValue_Map(QMap<QString, QString> map)
{
this->keyValue_Map.clear();
this->keyValue_Map = QMap<QString, QString>(map);
}
//被QGraphicsView调用
void BlockItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
//画个矩形
painter->drawRect(this->pos.x(),this->pos.y(),110,70);
}
//Item鼠标按压事件
void BlockItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
//鼠标按压时设置其为焦点图元
setFocus();
}
//鼠标双击事件
void BlockItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* event)
{
}
//设置四边形的坐标
void BlockItem::setPos(QPointF curPos)
{
this->pos = curPos;
}
BlockItem::~BlockItem()
{
keyValue_Map.clear();
}
//测试KeyValue_Map
void BlockItem::initKeyValue_Map()
{
setKeyValue_Map("Kp", "1");
setKeyValue_Map("Ki", "20");
setKeyValue_Map("Kd", "0.01");
}
BlockWindowScene.h
#pragma once
#include <QGraphicsScene>
#include <qgraphicsitem.h>
#include <qmap.h>
#include <qlist.h>
#include <qdebug.h>
#include "publicheader.h"
#include "itemtypeenum.h"
#include "blockitem.h"
#include <QGraphicsSceneMouseEvent>
class BlockWindowScene :public QGraphicsScene
{
Q_OBJECT
public:
explicit BlockWindowScene(QObject *parent = nullptr);
~BlockWindowScene();
static BlockWindowScene* getIntance();
//将item绘画在Scene中
void itemPaint(QString itemType,QPointF pos);
private slots:
void slot_ReceiveData(QString data);
protected:
//鼠标进入场景
void dragEnterEvent(QGraphicsSceneDragDropEvent *event);
//鼠标释放
void mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent);
private:
//单例
static BlockWindowScene* blockWindowScene;
//存放每个图元(QGraphicsItem)的对应的输入框
QMap<QGraphicsItem*, QGraphicsTextItem*> itemToText_Map;
//存放图元(QGraphicsItem)的指针
QList<QGraphicsItem*> item_List;
//当前BlockItem的类别名称
QString currentItemName;
};
BlockWindowScene.cpp
#include "blockwindowscene.h"
#include <QMetaEnum>
BlockWindowScene::BlockWindowScene(QObject *parent)
: QGraphicsScene(parent)
{
}
BlockWindowScene::~BlockWindowScene()
{
//delete掉blockWindowScene所有的Item
blockWindowScene->clear();
blockWindowScene = nullptr;
}
//鼠标进入场景
void BlockWindowScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
{
QGraphicsScene::dragEnterEvent(event);
qDebug() << "dragEnterEvent鼠标进去了";
}
//鼠标释放
void BlockWindowScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
if (mouseEvent->button() == Qt::RightButton)
{
//运行父类的鼠标按压事件
QGraphicsScene::mousePressEvent(mouseEvent);
qDebug() << "mouseReleaseEvent鼠标释放了";
//记录场景中鼠标的坐标位置
QPointF pos = mouseEvent->scenePos();
itemPaint(this->currentItemName, pos);
}
}
//使用信号和槽机制获取信息值
void BlockWindowScene::slot_ReceiveData(QString data)
{
//正则表达式,为了去掉data非字母和数字的字符
QRegExp ex("[^a-zA-Z0-9]");
currentItemName = data.replace(ex, "");
}
//获取单例
BlockWindowScene* BlockWindowScene::blockWindowScene = nullptr;
BlockWindowScene* BlockWindowScene::getIntance()
{
if (blockWindowScene == nullptr)
{
blockWindowScene = new BlockWindowScene();
}
return blockWindowScene;
}
//将item绘画在Scene中
void BlockWindowScene::itemPaint(QString itemType,QPointF pos)
{
if (itemType == "BusSelector")
{
}
else if (itemType == "Subsystem")
{
}
else if (itemType == "DataTypeConversion")
{
}
else if (itemType == "Derivative")
{
BlockItem* blockItem = new BlockItem;
QGraphicsSimpleTextItem* textItem = new QGraphicsSimpleTextItem;
textItem->setText("Derivative"); // 纯文本
QFont font = textItem->font();
font.setPixelSize(20); // 像素大小
//font.setItalic(true); // 斜体
//font.setUnderline(true); // 下划线
textItem->setFont(font); //
textItem->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
//设置此item在场景中的位置,pos为鼠标的位置
blockItem->setPos(pos);
//根据blockItem位置将textitem放置在其下方
int textItem_X = (pos.x() + 0.5*(blockItem->boundingRect().width())) - (0.5*(textItem->boundingRect().width()));
textItem_X = (textItem_X < 0 ? 0 : textItem_X);
textItem->setPos(textItem_X, blockItem->boundingRect().height() + pos.y());
//设置此Item可以被鼠标点击选中,选中后周围会有矩形的虚线
blockItem->setFlag(QGraphicsItem::ItemIsSelectable);
//设置此item是活动的
blockItem->setEnabled(true);
//使得pixmapItem只接受左键按钮事件
blockItem->setAcceptedMouseButtons(Qt::LeftButton);
blockItem->setEnabled(true);
blockItem->setVisible(true);
this->addItem(blockItem);
this->addItem(textItem);
qDebug() << "pos:" << pos;
}
else if (itemType == "DescriptorStateSpace")
{
}
else if (itemType == "EntityTransportDelay")
{
}
else if (itemType == "CallbackButton")
{
}
else if (itemType == "CheckBox")
{
}
else if (itemType == "CircularGauge")
{
}
}
BlockWindow.h
#pragma once
#include <QMainWindow>
#include <blockwindowscene.h>
#include <QWheelEvent>
namespace Ui { class BlockWindow; };
class BlockWindow : public QMainWindow
{
Q_OBJECT
public:
explicit BlockWindow(QWidget *parent = nullptr);
//获取单例的公有函数
static BlockWindow* getIntance();
~BlockWindow();
BlockWindowScene* blockWindowScene;
protected:
void enterEvent(QEvent* event);
private:
Ui::BlockWindow *ui;
//静态成员,存放单例
static BlockWindow* blockWindow;
};
BlockWindow.cpp
#include "blockwindow.h"
#include "ui_blockwindow.h"
#include "publicheader.h"
#include <qdebug.h>
BlockWindow::BlockWindow(QWidget *parent)
: QMainWindow(parent)
{
ui = new Ui::BlockWindow();
ui->setupUi(this);
blockWindowScene = BlockWindowScene::getIntance();
blockWindowScene->setSceneRect(0, 0, 6000, 1200);
ui->graphicsView->setScene(blockWindowScene);
//初始化时,让view显示scene(0,0)处
ui->graphicsView->centerOn(0, 0);
//graphicsView开启鼠标跟踪:鼠标没有按下也会接收鼠标移动事件
ui->graphicsView->setMouseTracking(true);
}
//获取单例
BlockWindow* BlockWindow::blockWindow = nullptr;
BlockWindow* BlockWindow::getIntance()
{
if (blockWindow == nullptr)
{
blockWindow = new BlockWindow();
}
return blockWindow;
}
//鼠标进入事件
void BlockWindow::enterEvent(QEvent* event)
{
qDebug() << "lockWindow::enterEvent-鼠标进来了";
//更新view
ui->graphicsView->viewport()->update();
}
BlockWindow::~BlockWindow()
{
delete blockWindowScene;
delete ui;
blockWindowScene = nullptr;
ui = nullptr;
}