Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Qt GraphicsView中创建长线(或交叉线)光标的最佳方法_Qt_Qgraphicsview - Fatal编程技术网

在Qt GraphicsView中创建长线(或交叉线)光标的最佳方法

在Qt GraphicsView中创建长线(或交叉线)光标的最佳方法,qt,qgraphicsview,Qt,Qgraphicsview,创建长十字线光标(与视口一样长)的简单方法是创建十字线graphicsItem,当鼠标移动时,设置项目的pos属性。 但是当场景复杂时,这种方法会非常慢,因为它应该更新整个视口以更新光标的pos 另一种简单的方法是setCursor(QCursor(..),使用QPixmap定义长十字线,这种方法速度非常快,但光标将超过视口矩形 有没有其他快速显示长十字光标的方法 非常感谢 如果我理解正确,您希望绘制一条水平线和一条垂直线,在光标位置交叉,并与视口一样大 一个可行的解决方案是重新实现,与画家画两

创建长十字线光标(与视口一样长)的简单方法是创建十字线
graphicsItem
,当鼠标移动时,设置项目的
pos
属性。 但是当场景复杂时,这种方法会非常慢,因为它应该更新整个视口以更新光标的
pos

另一种简单的方法是
setCursor(QCursor(..)
,使用
QPixmap
定义长十字线,这种方法速度非常快,但光标将超过视口矩形

有没有其他快速显示长十字光标的方法


非常感谢

如果我理解正确,您希望绘制一条水平线和一条垂直线,在光标位置交叉,并与视口一样大

一个可行的解决方案是重新实现,与画家画两条线

问题是场景不知道鼠标的位置。这意味着视图必须跟踪它,并在鼠标位置更改时通知场景

为此,您必须创建自己的
graphicscene
(继承
qgraphicscene
)和自己的
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
),场景将连接到该信号。此信号包含转换为场景坐标的鼠标位置

现在,在场景端,您必须添加一个在鼠标位置更改时调用的插槽,将新鼠标位置存储在成员变量中,然后重新实现:

最后要做的事情是将GraphicsView的信号连接到Graphicscene插槽


我将让您检查此解决方案在性能方面是否可以接受。

我找到了一种方法! 我在Windows系统下开发,所以可以使用较低的GDIAPI跳出Qt的绘图系统。 详细信息是获取QGraphicsView视口的HDC。然后在QGraphicsView的QMouseEvent中使用“MoveToEx”和“LineTo”在视口上绘制两条线,然后我应该做的是擦除“旧”光标,使用“setROP2(HDC dc,R2_NOT)”很容易做到这一点,然后再次绘制存储的旧光标。 此方法不会进入QPaint系统,因此光标下的GraphicsSites不会被重新绘制

为了解决鼠标快速移动时的窃取问题,我没有使用“双缓冲区”。我使用QTimer在CPU空闲时更新光标。详细信息在QMouseEvent中,此时不更新光标,而是将位置存储到列表中,当CPU空闲时,在位置列表中绘制光标

我希望这能帮助其他遇到同样问题的人。
感谢Jérôme,他给了我关于QGraphicscene的有用提示。

基于Jerome的回答并使用python,我在我的
QGraphicscene
子类中创建了这段代码:

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++代码。注意,我利用了qtapi框架传递的
rect
参数,并将画师剪辑到该参数 面积,因为它是要绘制的可见区域


我还缓存笔对象,因为我在其他实验中意识到,在绘制时创建对象会影响性能,因此,用户也有机会在程序选项中设置自定义笔。

再次设置光标有什么问题?您可以在QWidget上设置光标,这样您就可以在QGraphicsView::viewport()返回的小部件上设置光标。感谢您的建议,setCursor函数不会将光标剪切到小部件上,因此光标(长线)将超出视口,在桌面上绘制等。您的解决方案只比我的第一个方法快一点,因为drawforeground()不需要重新创建所有项目的BSPIndex,但问题是invalidate(),此方法将调用update(),因此视口中的所有项目都将被重新绘制。@Jérôme:不需要执行信号/插槽之类的操作
qgraphicscene
只需要实现每个鼠标事件相关的方法。唯一需要的是子类化
qgraphicscene
并实现
mouseMoveEvent
请参见API文档。@jnblue,您可以调用invalidateScene并传入qgraphicscene::ForegroundLayer。这只会更新前景层
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()