PyQt5 переместить окно при перетаскивании кадра - PullRequest
0 голосов
/ 17 апреля 2020

надеюсь, что у вас все хорошо в эти трудные времена.

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

Мой код выглядит следующим образом

from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.setWindowModality(QtCore.Qt.NonModal)
        MainWindow.resize(909, 544)
        MainWindow.setAnimated(True)
        MainWindow.setWindowFlags(QtCore.Qt.FramelessWindowHint)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.centralwidget.sizePolicy().hasHeightForWidth())
        self.centralwidget.setSizePolicy(sizePolicy)
        self.centralwidget.setObjectName("centralwidget")
        self.backgroundFrame = QtWidgets.QFrame(self.centralwidget)
        self.backgroundFrame.setEnabled(True)
        self.backgroundFrame.setGeometry(QtCore.QRect(-1, -1, 941, 551))
        self.backgroundFrame.setStyleSheet("QLabel {\n"
"font-family: \"Microsoft Sans Serif\", sans-serif;\n"
"color: white;\n"
"}\n"
"\n"
"#backgroundFrame\n"
"{\n"
"background-color: #060321;\n"
"}\n"
"\n"
"#infoBar\n"
"{\n"
"background-color: #0F0334;\n"
"}")
        self.backgroundFrame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.backgroundFrame.setFrameShadow(QtWidgets.QFrame.Raised)
        self.backgroundFrame.setObjectName("backgroundFrame")
        self.infoBar = QtWidgets.QFrame(self.backgroundFrame)
        self.infoBar.setGeometry(QtCore.QRect(-10, -10, 921, 71))
        self.infoBar.setFrameShape(QtWidgets.QFrame.StyledPanel)
        self.infoBar.setFrameShadow(QtWidgets.QFrame.Raised)
        self.infoBar.setObjectName("infoBar")
        self.exitButton = QtWidgets.QPushButton(self.infoBar)
        self.exitButton.setGeometry(QtCore.QRect(874, 26, 31, 31))
        self.exitButton.setText("")
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap("Resources/Exit.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.exitButton.setIcon(icon)
        self.exitButton.setIconSize(QtCore.QSize(32, 32))
        self.exitButton.setObjectName("exitButton")
        self.pushButton = QtWidgets.QPushButton(self.infoBar)
        self.pushButton.setGeometry(QtCore.QRect(827, 30, 31, 31))
        self.pushButton.setText("")
        icon1 = QtGui.QIcon()
        icon1.addPixmap(QtGui.QPixmap("Resources/Minimize.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.pushButton.setIcon(icon1)
        self.pushButton.setIconSize(QtCore.QSize(32, 32))
        self.pushButton.setObjectName("pushButton")
        self.pushButton_2 = QtWidgets.QPushButton(self.infoBar)
        self.pushButton_2.setGeometry(QtCore.QRect(26, 26, 34, 31))
        self.pushButton_2.setText("")
        icon2 = QtGui.QIcon()
        icon2.addPixmap(QtGui.QPixmap("Resources/Settings.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        self.pushButton_2.setIcon(icon2)
        self.pushButton_2.setIconSize(QtCore.QSize(32, 32))
        self.pushButton_2.setObjectName("pushButton_2")
        self.label = QtWidgets.QLabel(self.infoBar)
        self.label.setGeometry(QtCore.QRect(390, 23, 145, 40))
        self.label.setText("")
        self.label.setPixmap(QtGui.QPixmap("Resources/Titan Window.png"))
        self.label.setObjectName("label")
        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "Titan"))

    def mousePressEvent(self, event):
        self.offset = event.pos()

    def mouseMoveEvent(self, event):
        x=event.globalX()
        y=event.globalY()
        x_w = self.offset.x()
        y_w = self.offset.y()
        self.move(x-x_w, y-y_w)


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

Спасибо за помощь и надеюсь, что вы и ваши друзья и семья будут в безопасности в это время <3 </p>

1 Ответ

1 голос
/ 17 апреля 2020

Источник вашей проблемы состоит в том, что вы, вероятно, редактируете код, сгенерированный pyuic (или пытаетесь имитировать его поведение), что никогда * не должно будет сделано. Эти файлы должны быть импортированы только как модули и не должны изменяться без всякой причины. Чтобы узнать, как правильно использовать ui файлы, созданные с помощью Designer, читайте подробнее о с помощью Designer .

Результатом применения такого подхода, как вы это сделали, является то, что mousePressEvent и mouseMoveEvent никогда не будут вызваны * 1014. *

Причина этого заключается в том, что в вашем коде эти методы принадлежат Ui_MainWindow class instance (ui, созданный ближе к концу), который является ничем иным, как базовым c Python object подклассом: он почти ничего не делает, кроме сборки UI на экземпляре QMainWindow в его setupUi(); что Экземпляр QMainWindow должен получать эти события вместо этого, и эти методы должны быть реализованы там.
Или, по крайней мере, теоретически . Это связано с тем, что mousePressEvent и mouseMoveEvent, которые вы хотите перехватить, должны быть получены из объекта infoBar, а не из главного окна.

Распространенным решением является создание подкласса виджета, который будет получать эти события, и реализации этих методов, но так как вы, вероятно, используете пользовательский интерфейс, созданный в Designer, он не так быстр, как кажется (подробнее об этом позже).

Самый прямой подход - установить фильтр событий на наблюдаемом виджете, чтобы мы могли фильтровать эти события и реагировать на них, если мы хотим.

В следующем примере я предполагаю, что вы воссоздали файл с помощью pyuic с именем ui_mainwindow.py:

from PyQt5 import QtCore, QtGui, QtWidgets
from ui_mainwindow import Ui_MainWindow

class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)

        self.offset = None
        # install the event filter on the infoBar widget
        self.infoBar.installEventFilter(self)

    def eventFilter(self, source, event):
        if source == self.infoBar:
            if event.type() == QtCore.QEvent.MouseButtonPress:
                self.offset = event.pos()
            elif event.type() == QtCore.QEvent.MouseMove and self.offset is not None:
                # no need for complex computations: just use the offset to compute
                # "delta" position, and add that to the current one
                self.move(self.pos() - self.offset + event.pos())
                # return True to tell Qt that the event has been accepted and
                # should not be processed any further
                return True
            elif event.type() == QtCore.QEvent.MouseButtonRelease:
                self.offset = None
        # let Qt process any other event
        return super().eventFilter(source, event)

Об использовании подклассов в Designer, упомянутом выше: можно создавать собственные подклассы и «использовать» их в Designer. Вы должны создать подкласс в своем коде, а затем добавить к своему пользовательскому интерфейсу его самого близкого предка (в вашем случае, QFrame), который будет работать как своего рода заполнитель, а затем продвигать его. Проведите некоторое исследование о «продвигаемых виджетах», чтобы узнать больше.

Важное предложение: использование фиксированных размеров и позиций не является хорошим выбором, и менеджеры по расположению должны всегда быть предпочтительным вместо этого. Причина этого заключается в том, что то, что вы видите на своем компьютере, почти всегда будет отображаться очень по-разному в других (среди самых распространенных причин: различные размеры экрана, настройки по умолчанию, DPI, шрифты и т. Д. c), и это может привести к ваш GUI становится непригодным для использования, так как виджеты могут стать невидимыми, перекрывающимися или нечитаемыми. Есть очень, очень редкие ситуации, в которых можно использовать фиксированные геометрии (но когда программисты понимают, что они им нужны, это, возможно, связано с плохим дизайном кода / пользовательского интерфейса), и это, конечно, не ваш случай.
Например, если я Попробуйте изменить размер окна до меньшего размера, чем оригинал, верхние правые кнопки станут недоступны. Кроме того, кнопка справа рядом с кнопкой «выход» неправильно выровнена. Если вы используете менеджер макетов (например, горизонтальный макет в виджете infoBar), он автоматически решит все эти проблемы.

...