Как ограничить мышь QGraphicsScene в PySide?

Или, может быть, QGraphicsView? Я до сих пор не понимаю картографию. Смотрите комментарий

# I'm not computing x and y correctly. mapTo/From/Global/Scene/???

в myview.py ниже. Идея состоит в том, что когда вы один раз щелкаете по кольцу, оно переключает мобильность, привязывая его к движению мыши, пока вы не щелкнете снова, то есть первый щелчок устанавливает его на «перетаскивание», а второй — на «бросание».

Это работает нормально, но когда я выхожу из «кадра» (вид/сцена), а затем снова вхожу в другое место, кольцо переходит в новое место. Я хочу предотвратить выход, пока кольцо «мобильно» или находится в режиме «перетаскивания». .

основной код:

# Form implementation generated from reading ui file 'frames.ui'
# ...and then adjusted by hand... a lot

from PySide.QtCore import *
from PySide.QtGui  import *
from myview        import *


class Frames(QDialog):
    def __init__(self, parent=None):
        super(Frames, self).__init__(parent)

        self.verticalLayout = QVBoxLayout()

        self.setWindowFlags(Qt.FramelessWindowHint)

        self.topBox = QGroupBox()
        sizePolicy = QSizePolicy(QSizePolicy.Preferred,
                                 QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(1)
        sizePolicy.setHeightForWidth(self.topBox
                                     .sizePolicy().hasHeightForWidth())
        self.topBox.setSizePolicy(sizePolicy)
        self.verticalLayout.addWidget(self.topBox)

        self.middleBox = QGroupBox()
        sizePolicy = QSizePolicy(QSizePolicy.Preferred,
                                 QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(10)
        sizePolicy.setHeightForWidth(self.middleBox
                                     .sizePolicy().hasHeightForWidth())
        self.middleBox.setSizePolicy(sizePolicy)
        self.horizontalLayout = QHBoxLayout(self.middleBox)

        self.view = MyView(self)
        self.horizontalLayout.addWidget(self.view)

        self.rightBox = QGroupBox(self.middleBox)
        sizePolicy = QSizePolicy(QSizePolicy.Preferred,
                                 QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(1)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.rightBox
                                     .sizePolicy().hasHeightForWidth())
        self.rightBox.setSizePolicy(sizePolicy)
        self.horizontalLayout.addWidget(self.rightBox)
        self.verticalLayout.addWidget(self.middleBox)

        self.bottomBox = QGroupBox()
        sizePolicy = QSizePolicy(QSizePolicy.Preferred,
                                 QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(1)
        sizePolicy.setHeightForWidth(self.bottomBox
                                     .sizePolicy().hasHeightForWidth())
        self.bottomBox.setSizePolicy(sizePolicy)
        self.verticalLayout.addWidget(self.bottomBox)
        self.setLayout(self.verticalLayout)
        self.showFullScreen()

        QMetaObject.connectSlotsByName(self)


def main():
    import sys
    app = QApplication(sys.argv)
    frames = Frames()
    frames.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

И myview.py:

from PySide.QtCore import *
from PySide.QtGui  import *


class Ring(QGraphicsEllipseItem):

    def __init__(self, parent=None):
        super(Ring, self).__init__(0, 0, 80, 80, parent)
        self.mobile   = 0     # Initially immobile

        self.setFlags(QGraphicsItem.ItemIsMovable)
        self.setAcceptsHoverEvents(True)

    def mousePressEvent(self, event):
        super(Ring, self).mousePressEvent(event)
        self.mobile = (self.mobile + 1) % 2  # Toggle mobility


class MyView(QGraphicsView):

    def __init__(self, parent=None):
        super(MyView, self).__init__(parent)
        self.installEventFilter(self)

        sizePolicy = QSizePolicy(QSizePolicy.Expanding,
                                 QSizePolicy.Expanding)
        sizePolicy.setHorizontalStretch(2)
        sizePolicy.setVerticalStretch(1)
        sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth())
        self.setSizePolicy(sizePolicy)

        self.scene = QGraphicsScene(self)
        self.ring  = Ring()
        self.scene.addItem(self.ring)
        self.curse = self.cursor()

    def eventFilter(self, obj, event):
        super(MyView, self).eventFilter(obj, event)
        if event.type() == QEvent.WindowActivate:

            self.setWindowFlags(Qt.FramelessWindowHint)
            self.setFrameShape(QFrame.NoFrame)

            bounds = self.geometry()

            self.X1, self.Y1, self.w,  self.h  = bounds.getRect()
            self.X1, self.Y1, self.X2, self.Y2 = bounds.getCoords()

            self.scene.setSceneRect(self.X1, self.Y1,
                                    self.w, self.h)

            self.cx  = bounds.center().x()
            self.cy  = bounds.center().y()

            self.ring.setPos(self.cx - 40, self.cy - 40)

            self.setScene(self.scene)
            brush = QBrush(QColor(255, 255, 127))
            brush.setStyle(Qt.SolidPattern)
            self.setBackgroundBrush(brush)

            self.removeEventFilter(obj)
        return False

    def mouseMoveEvent(self, event):
        super(MyView, self).mouseMoveEvent(event)
        if self.ring.mobile:

# I'm not computing x and y correctly. mapTo/From/Global/Scene/???

            x = min(max(event.pos().x(), self.X1), self.X2)
            y = min(max(event.pos().y(), self.Y1), self.Y2)
#           self.curse.setPos(x, y)

            self.ring.setPos(event.pos())

person Ubuntourist    schedule 23.02.2017    source источник


Ответы (1)


Настоящим курсором мыши управляет оконная среда, а не Qt, поэтому я не думаю, что есть способ сделать это на этом уровне. По крайней мере, не кроссплатформенным образом. Однако вы можете быть в состоянии подделать его.

  • Скройте настоящий курсор, возможно, установите его на Qt::BlankCursor.
  • Отслеживайте фактическое положение курсора относительно области, которой вы хотите его ограничить.
  • Нарисуйте свой собственный виртуальный курсор в виде графического объекта в Qt.
  • Управляйте положением виртуального курсора самостоятельно.

Однако это не помешает реальному курсору «щелкнуть» из вашего приложения и взаимодействовать с другими приложениями. Возможно, вам придется обнаружить, что это происходит, и курсор щелкает обратно в ваше приложение, и оно возобновляет управление вашим виртуальным курсором. Таким образом, когда реальный курсор «возвращается», вы можете возобновить движение вашего виртуального курсора из его предыдущей последней позиции вместо текущей позиции реального курсора.

person Simon Hibbs    schedule 24.02.2017
comment
Блеа! Что ж, если это правда, по крайней мере, я чувствую себя менее глупо, не придумав, как это сделать. Всегда смотрите на светлую сторону... - person Ubuntourist; 24.02.2017
comment
Меня не беспокоит взаимодействие пользователей с другими приложениями. Мое приложение открывается в полноэкранном режиме, и пользователям будет предложено не играть с помощью Alt-‹TAB›, Command-‹TAB›, ‹ESC› или чего-либо еще. Если они игнорируют такие инструкции, это не моя проблема. - person Ubuntourist; 24.02.2017