Qt - Определить абсолютный виджет и позицию курсора

У меня есть QWidget, который содержит несколько детей. Конечная цель - иметь возможность перетаскивать из одного виджета в другой, перемещая что-то между виджетами. Я получил сигнал на контроллер родительского виджета и могу определить, когда перетаскивание начинается и заканчивается правильно. Моя текущая проблема заключается в определении, находится ли мышь над целевым виджетом при наведении мыши вверх.

Я был взволнован, когда увидел underMouse в документах, но он не работает во время событий перетаскивания (когда я тестировал, казалось, он возвращал неправильные значения). В противном случае моей целью было найти прямоугольник, содержащий целевой виджет, и определить, содержит ли он координаты мыши при наведении курсора вверх. Я не могу просто использовать contentRect, так как он возвращает позиции относительно виджета, к которому он вызывается. Я думал, что mapToGlobal даст мне абсолютные значения пикселей экрана, но он также не работает. Я попытался вызвать mapTo в окне родительского виджета, но это также, похоже, не удалось.

Ниже приведен код, показывающий различные QRects и QPoints, которые я получил с помощью различных методов. Может быть, с одним из них произошла простая ошибка, поэтому я предоставил их все.

QRect relativeWidgetRect = targetWidget->contentsRect();
QRect *absoluteWidgetRect = new QRect(QWidget::mapToGlobal(relativeWidgetRect.topLeft()), QWidget::mapToGlobal(relativeWidgetRect.bottomRight()));
QRect *widgetRect = new QRect(mapTo(window(), relativeWidgetRect.topLeft()), mapTo(window(), relativeWidgetRect.bottomRight()));
QPoint relativeMousePos = QCursor::pos();
QPoint absoluteMousePos = QWidget::mapToGlobal(relativeMousePos);
QPoint widgetMousePos = mapTo(window(), relativeMousePos);

mapToParent не будет работать для моих целей, так как целевой виджет на самом деле является потомком родительского элемента верхнего уровня.

Обновление Вот код, который в итоге получился. В моем виджете верхнего уровня (который был предком как исходного, так и целевого виджетов) я добавил это:

QRect widgetRect = targetWidget->Geometry();
QPoint mousePos = targetWidget->mapFromGlobal(QCursor::pos());
if(widgetRect.contains(mousePos))
{
// Logic
}

3 ответа

Решение

Как уже говорилось, вы должны скорее использовать targetWidget->geometry() вместо contentsRect() в этом особом случае.

Далее мне интересно, к какому классу принадлежит код, который вы опубликовали. Метод QWidget::mapToGlobal() должен вызываться из QWidget, к которому относятся ваши координаты. Если я вас правильно понял, это должно выглядеть примерно так:

QRect widgetRect = targetWidget->geometry();
widgetRect.moveTopLeft(targetWidget->parentWidget()->mapToGlobal(widgetRect.topLeft()));

Затем обратите внимание QCursor::pos() уже возвращает глобальные экранные координаты, поэтому здесь не нужно ничего отображать:

if (widgetRect.contains(QCursor::pos())) {
    /* swap widgets */
}

РЕДАКТИРОВАТЬ: Вероятно, даже лучше не отображать прямоугольник на глобальный, а отображать глобальную позицию курсора на виджет:

if (targetWidget->rect().contains(targetWidget->mapFromGlobal(QCursor::pos()))) {
    /* do stuff */
}

Может быть, вы ищете geometry() или же frameGeometry() в QWidget. Смотрите здесь для более подробной информации.

Этот метод PyQt вернет True, если позиция мыши находится внутри прямоугольника виджета, включая случаи, когда мышь находится над комбинированным видом внутри виджета

def underMouse(self):
    pos = QtGui.QCursor.pos()
    rect = self.rect()
    leftTop     = self.mapToGlobal(QtCore.QPoint(rect.left(),rect.top()))
    rightBottom = self.mapToGlobal(QtCore.QPoint(rect.right(),rect.bottom()))
    globalRect = QtCore.QRect(leftTop.x(), leftTop.y(), rightBottom.x(), rightBottom.y() )
    return globalRect.contains(self.mapToGlobal(pos))
Другие вопросы по тегам