创建长十字线光标(只要视口)的简单方法是创建十字线graphicsItem
,当鼠标移动时,设置项目的pos
属性。但是这种方式在场景复杂的时候会很慢,因为它要更新整个视口来更新光标的pos
.
另一种简单的方法是setCursor(QCursor(..))
,使用aQPixmap
来定义长十字线,这种方式会非常快,但光标会超出视口矩形。
还有另一种方法可以快速显示长十字线光标吗?
非常感谢!
创建长十字线光标(只要视口)的简单方法是创建十字线graphicsItem
,当鼠标移动时,设置项目的pos
属性。但是这种方式在场景复杂的时候会很慢,因为它要更新整个视口来更新光标的pos
.
另一种简单的方法是setCursor(QCursor(..))
,使用aQPixmap
来定义长十字线,这种方式会非常快,但光标会超出视口矩形。
还有另一种方法可以快速显示长十字线光标吗?
非常感谢!
如果我理解正确,您想绘制一条水平线和一条垂直线,在光标位置交叉,并且与视口一样大。
一个可行的解决方案是重新实现QGraphicsScene::drawForeground()以使用画家绘制两条线。
问题是场景不知道鼠标位置。这意味着视图必须跟踪它并在鼠标位置发生变化时通知场景。
为此,您必须创建自己的GraphicsScene
(继承QGraphicsScene
)和自己的GraphicsView
(继承QGraphicsView
)。
在您的GraphicsView
构造函数上,您必须开始鼠标跟踪。这将使您mouseMoveEvent
每次鼠标在视图内移动时都会收到一个:
GraphicsViewTrack::GraphicsViewTrack(QWidget* parent) : QGraphicsView(parent) {
setMouseTracking(true);
}
void GraphicsViewTrack::mouseMoveEvent(QMouseEvent* pEvent) {
QPointF MousePos = this->mapToScene(pEvent->pos());
emit mousePosChanged(MousePos.toPoint());
}
正如您在上面的代码片段中看到的,视图正在发出一个信号 ( mousePosChanged
),场景将连接到该信号。该信号包含鼠标位置,转换为场景坐标。
现在,在场景方面,您必须添加一个将在鼠标位置更改时调用的插槽,将新的鼠标位置存储在成员变量中并重新实现QGraphicsScene::drawForeground():
void GraphicsSceneCross::drawForeground(QPainter* painter, const QRectF& rect) {
QRectF SceneRect = this->sceneRect();
painter->setPen(QPen(Qt::black, 1));
painter->drawLine(SceneRect.left(), m_MousePos.y(), SceneRect.right(), m_MousePos.y());
painter->drawLine(m_MousePos.x(), SceneRect.top(), m_MousePos.x(), SceneRect.bottom());
}
void GraphicsSceneCross::onMouseChanged(QPoint NewMousePos) {
m_MousePos = NewMousePos; // Store the mouse position in a member variable
invalidate(); // Tells the scene it should be redrawn
}
最后要做的是将 GraphicsView 的信号连接到 GraphicsScene 插槽。
我会让你检查这个解决方案在性能方面是否可以接受。
基于 Jerome 的回答并使用 python,我在我的QGraphicsScene
子类中创建了这个代码:
def drawForeground(self, painter, rect):
if self.guidesEnabled:
painter.setClipRect(rect)
painter.setPen(self.guidePen)
painter.drawLine(self.coords.x(), rect.top(), self.coords.x(), rect.bottom())
painter.drawLine(rect.left(), self.coords.y(), rect.right(), self.coords.y())
def mouseMoveEvent(self, event):
self.coords = event.scenePos()
self.invalidate()
编写适当的 C++ 代码对您来说应该是直截了当的。请注意,我利用rect
Qt Api 框架传递的参数并将画家剪辑到该区域,因为它是要绘制的可见区域。
I also cache the pen object, since I realized in other experiments that creating objects while painting will penalty performace and doing it so you also give the user the chance to set a custom pen in your program options.
我找到了一种方法来做到这一点!我是在windows系统下开发的,所以可以使用从Qt的绘画系统中跳出来的下层GDI api。细节是获取 QGraphicsView 的 viewPort 的 HDC。然后在 QGraphicsView 的 QMouseEvent 中使用“MoveToEx”和“LineTo”在视口上画两条线,然后我应该做的是擦除“旧”光标,使用“setROP2(HDC dc,R2_NOT)”很容易做到这一点,然后再次绘制存储的旧光标。该方法不进入QPainter系统,因此光标下的GraphicsItems不会被重绘。
为了解决鼠标快速移动时的过滤问题,我不使用“双缓冲”。我使用 QTimer 在 CPU 空闲时更新光标。细节在 QMouseEvent 中,不及时更新光标,而是将位置存储到列表中,当 CPU 空闲时,在位置列表处绘制光标
我希望这将帮助其他遇到与我相同问题的人。感谢 Jérôme,他给了我有用的 QGraphicsScene 提示。