在QSceneView中拖动线条时出现刷新错误。

问题描述 投票:0回答:1

我需要在一个文件中的两个项目之间画一个连接器。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;
  }
}

逻辑工作:当我激活拖动时,我可以看到线条,而且它一直在更新,直到鼠标按钮被按下。但你可以在附图中看到,我有一个渲染问题。

dragline defect

线条的渲染没有正常工作;我看到了线条过去的图像痕迹,比如: QGraphicsView 没有正常更新。

我感觉到代码的味道,当在 TransitionDragLine::setEndPoint 我需要打电话 update() 设置线的终点后(否则线不显示),但我没有找到解决这个问题的方法。

我到底做错了什么?

EDIT:

我在这里看到了一个解决方案。

当修改一个自定义的QGraphicsItem时显示出工件

我试着打过电话 prepareGeometryChange() 每次我更新终点,但工件仍然存在。

void TransitionDragLine::setEndPoint(const QPointF& endPoint) {
  m_endPoint = endPoint;
  prepareGeometryChange();
  update();
}
c++ qt canvas qgraphicsview artifacts
1个回答
1
投票

看起来你的 QRectF TransitionDragLine::boundingRect() const 是不正确的.由于涉及到多个坐标系,所以要把它弄对可能有点棘手。

正确的解决方法是把边界框弄对,但对于小场景,通常只要设置好 QGraphicsView::updateModeQGraphicsView::FullViewportUpdate...那就是, QGraphicsView 将重新绘制整个视口,而不仅仅是边界框区域。

© www.soinside.com 2019 - 2024. All rights reserved.