Лучший способ создать курсор с длинной линией (или перекрестной линией) в Qt GraphicsView

Самый простой способ создать курсор с длинной перекрестной линией (длиной, равной области просмотра) — это создать перекрестную линию graphicsItem, при перемещении мыши установить свойство pos элемента. Но этот способ будет очень медленным, когда сцена сложная, потому что он должен обновить всю область просмотра, чтобы обновить pos курсора.

Другой простой способ - setCursor(QCursor(..)), используйте QPixmap для определения длинной поперечной линии, этот способ будет очень быстрым, но курсор будет выходить за пределы прямоугольника области просмотра.

Есть ли другой способ быстро показать длинный перекрестный курсор?

Большое спасибо!


person jnblue    schedule 15.01.2011    source источник
comment
В чем проблема с setCursor снова? Вы можете установить курсор на QWidget, чтобы вы могли установить курсор на виджет, возвращаемый QGraphicsView::viewport().   -  person ak.    schedule 15.01.2011
comment
Спасибо за ваш совет, функция setCursor не будет прикреплять курсор к виджету, поэтому курсор (длинная линия) будет выходить за пределы области просмотра, рисовать на рабочем столе и т. Д.   -  person jnblue    schedule 16.01.2011


Ответы (3)


Если я правильно понимаю, вы хотите нарисовать горизонтальную линию и вертикальную линию, пересекающуюся в позиции курсора и имеющую такой же размер, как окно просмотра.

Возможным решением было бы переопределить 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.

Я позволю вам проверить, приемлемо ли это решение с точки зрения производительности.

person Jérôme    schedule 17.01.2011
comment
Ваше решение лишь немного быстрее, чем мой первый метод, потому что drawforeground() не нужно воссоздавать BSPIndex всех элементов, но проблема в недействительном(), этот метод вызовет update(), поэтому все элементы в области просмотра будет перерисовываться. - person jnblue; 18.01.2011
comment
@ Жером: нет необходимости делать этот сигнал / слот. QGraphicsScene нужно только реализовать каждый метод, связанный с событием мыши. Необходимо только создать подкласс QGraphicsScene и реализовать mouseMoveEvent. См. эту документацию по API. . - person Sebastian; 16.09.2011
comment
@jnblue, вы можете вызвать invalidateScene и передать QGraphicsScene::ForegroundLayer. Это должно обновлять только слой переднего плана - person R. van Twisk; 08.04.2012

Основываясь на ответе Джерома и используя 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, и я обрезаю рисовальщик в этой области, поскольку это видимая область, которую нужно нарисовать.

Я также кэширую объект пера, так как в других экспериментах я понял, что создание объектов во время рисования снижает производительность, и вы также даете пользователю возможность установить пользовательское перо в параметрах вашей программы.

person Sebastian    schedule 16.09.2011

Я нашел способ сделать это! Я разрабатываю под систему Windows, поэтому могу использовать более низкий GDI API, выпрыгивая из системы рисования Qt. Деталь заключается в том, чтобы получить HDC порта просмотра QGraphicsView. Затем в QMouseEvent QGraphicsView используйте «MoveToEx» и «LineTo», рисуя две линии в области просмотра, затем я должен стереть «старый» курсор. Это легко сделать с помощью «setROP2 (HDC dc, R2_NOT)», затем нарисуйте старый курсор, сохраненный снова. Этот метод не входит в систему QPainter, поэтому элементы GraphicsItem под курсором не будут перерисовываться.

Чтобы решить проблему с фильтром, когда мышь движется быстро, я не использую «двойной буфер». Я использовал QTimer для обновления курсора при простое процессора. Детали находятся в QMouseEvent, не обновляйте курсор во время, а сохраняйте позицию в списке. Когда процессор простаивает, нарисуйте курсор в списке позиций

Я хочу, чтобы это помогло другим, кто сталкивается с той же проблемой, что и я. Спасибо Jérôme, который дал мне полезный совет по QGraphicsScene.

person jnblue    schedule 21.01.2011