我需要在一个文件中的两个项目之间画一个连接器。QSceneView
. 我已经分包了 QGraphicsObject
用于创建这一行(这不是一个简单的 QGraphicsLineItem
因为我以后需要更新它的外观)。) 这就是这个类。
#ifndef TRANSITIONDRAGLINE_HPP_
#define TRANSITIONDRAGLINE_HPP_
#include "Style/CanvasTransitionDragLine.hpp"
#include <QGraphicsObject>
#include <QPointF>
#include <string>
class TransitionDragLine : public QGraphicsObject {
Q_OBJECT
public:
TransitionDragLine(const Style::CanvasTransitionDragLine& style, QGraphicsItem* parent = nullptr);
virtual ~TransitionDragLine();
void setStartPoint(const QPointF& startPoint);
void setEndPoint(const QPointF& endPoint);
public:
QRectF boundingRect() const override;
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override;
private:
Style::CanvasTransitionDragLine m_style;
QPointF m_startPoint;
QPointF m_endPoint;
};
#endif // !TRANSITIONDRAGLINE_HPP_
#include "TransitionDragLine.hpp"
#include <QPainter>
///////////////////////////////////////////////////////////////////////////////
// PUBLIC SECTION //
///////////////////////////////////////////////////////////////////////////////
TransitionDragLine::TransitionDragLine(const Style::CanvasTransitionDragLine& style, QGraphicsItem* parent) :
QGraphicsObject(parent),
m_style(style) {
}
TransitionDragLine::~TransitionDragLine() {
}
void TransitionDragLine::setStartPoint(const QPointF& startPoint) {
m_startPoint = startPoint;
}
void TransitionDragLine::setEndPoint(const QPointF& endPoint) {
m_endPoint = endPoint;
update();
}
///////////////////////////////////////////////////////////////////////////////
// VIRTUAL PUBLIC SECTION //
///////////////////////////////////////////////////////////////////////////////
QRectF TransitionDragLine::boundingRect() const {
qreal dx = m_endPoint.x() - m_startPoint.x();
qreal dy = m_endPoint.y() - m_startPoint.y();
qreal x{ 0.0 };
qreal y{ 0.0 };
qreal w{ 0.0 };
qreal h{ 0.0 };
qreal penHalfWidth{ m_style.getPen().widthF() * 0.5 };
if (dx >= 0.0 && dy >= 0.0) {
x = 0.0 - penHalfWidth;
y = 0.0 - penHalfWidth;
w = dx + penHalfWidth;
h = dy + penHalfWidth;
}
else if (dx >= 0.0 && dy < 0.0) {
x = 0.0 - penHalfWidth;
y = dy - penHalfWidth;
w = dx - penHalfWidth;
h = -dy - penHalfWidth;
}
else if (dx < 0.0 && dy >= 0.0) {
x = dx - penHalfWidth;
y = 0 - penHalfWidth;
w = -dx - penHalfWidth;
h = dy - penHalfWidth;
}
else {
x = dx - penHalfWidth;
y = dy - penHalfWidth;
w = -dx - penHalfWidth;
h = -dy - penHalfWidth;
}
return QRectF(x, y, w, h);
}
void TransitionDragLine::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
qreal px = m_endPoint.x() - m_startPoint.x();
qreal py = m_endPoint.y() - m_startPoint.y();
painter->setPen(m_style.getPen());
painter->drawLine(0.0, 0.0, px, py);
}
当我想使用它的时候,我在我的 Canvas
类,该类继承了 QGraphicsView
,我就更新它。当我按下鼠标键时,我设置了起始点,然后我设置了终点(并调用了 update()
),每次我移动鼠标直到左键被按下。基本上我把 startTransitionLineDrag
在轮询中,直到鼠标被按下,当我松开鼠标按钮时,我就调用 endTransitionLineDrag
在我的画布中(子类的 QGraphicsView
):
void Canvas::mouseMoveEvent(QMouseEvent* event) {
switch (m_currentState) {
case CurrentState::PressedOnTransition: {
if (event->buttons() == Qt::LeftButton) {
startTransitionLineDrag(event);
}
} break;
}
QGraphicsView::mouseMoveEvent(event);
}
void Canvas::mouseReleaseEvent(QMouseEvent* event) {
if (m_currentState == CurrentState::PressedOnTransition) {
if (true /* business logic here not useful for the problem */) {
endTransitionLineDrag(event);
}
}
QGraphicsView::mouseReleaseEvent(event);
}
void Canvas::startTransitionLineDrag(QMouseEvent* event) {
if (m_transitionDragLine == nullptr) {
m_transitionDragLine = new TransitionDragLine(m_style.getTransitionDragLineStyle());
m_transitionDragLine->setStartPoint(mapToScene(event->pos()));
m_scene->addItem(m_transitionDragLine);
m_transitionDragLine->setPos(mapToScene(event->pos()));
}
m_transitionDragLine->setEndPoint(mapToScene(event->pos()));
//repaint();
}
void Canvas::endTransitionLineDrag(QMouseEvent* event) {
/* other business logic */
deleteDragTransitionLine();
}
void Canvas::deleteDragTransitionLine() {
if (m_transitionDragLine) {
m_scene->removeItem(m_transitionDragLine);
delete m_transitionDragLine;
m_transitionDragLine = nullptr;
}
}
逻辑工作:当我激活拖动时,我可以看到线条,而且它一直在更新,直到鼠标按钮被按下。但你可以在附图中看到,我有一个渲染问题。
线条的渲染没有正常工作;我看到了线条过去的图像痕迹,比如: QGraphicsView
没有正常更新。
我感觉到代码的味道,当在 TransitionDragLine::setEndPoint
我需要打电话 update()
设置线的终点后(否则线不显示),但我没有找到解决这个问题的方法。
我到底做错了什么?
EDIT:
我在这里看到了一个解决方案。
我试着打过电话 prepareGeometryChange()
每次我更新终点,但工件仍然存在。
void TransitionDragLine::setEndPoint(const QPointF& endPoint) {
m_endPoint = endPoint;
prepareGeometryChange();
update();
}
看起来你的 QRectF TransitionDragLine::boundingRect() const
是不正确的.由于涉及到多个坐标系,所以要把它弄对可能有点棘手。
正确的解决方法是把边界框弄对,但对于小场景,通常只要设置好 QGraphicsView::updateMode
到 QGraphicsView::FullViewportUpdate
...那就是, QGraphicsView
将重新绘制整个视口,而不仅仅是边界框区域。