【问题标题】:How to use QStackedWidget()如何使用 QStackedWidget()
【发布时间】:2022-12-10 12:17:41
【问题描述】:

我正在尝试使用 QStackedWidget() 切换到我的下一个窗口,但是当我这样做时,我得到了一些错误,这些错误在我单独运行我的“.py”文件时没有。

我的应用程序应该做的是......点击激活我的组框,然后如果我点击按钮,一个新的透明窗口应该弹出一个鼠标交叉监听器,然后当你点击某些东西时它应该停止返回鼠标光标恢复正常并关闭透明窗口。

窗口1.py

from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QColor, QKeySequence, QIcon, QCursor
from window2 import *

class Ui_Form(QtWidgets.QWidget):
    def __init__(self):
        super(Ui_Form, self).__init__()

    ##if i use this method, it does not show my transparent window, also it shows an error that i dont get when run it separately.

    def goToTransparentWindowMethod(self):
        self.goToTransparentWindow = TransparentWindowClass()
        myWindow.addWidget(self.goToTransparentWindow)
        myWindow.setCurrentIndex(myWindow.currentIndex()+1)

    def setupUi(self, myWindow):
        myWindow.setObjectName("myWindow")
        myWindow.resize(627, 327)

        self.horizontalLayoutWidget = QtWidgets.QWidget(myWindow)
        self.horizontalLayoutWidget.setGeometry(QtCore.QRect(10, 10, 300, 270))
        self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")

        self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget)
        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout.setObjectName("horizontalLayout")

        self.gpb_main = QtWidgets.QGroupBox(self.horizontalLayoutWidget)
        self.gpb_main.setCheckable(True)
        self.gpb_main.setChecked(False)
        self.gpb_main.setObjectName("gpb_spell_main")

        self.btn_main = QtWidgets.QPushButton(self.gpb_main)
        self.btn_main.setGeometry(QtCore.QRect(10, 40, 88, 27))
        self.btn_main.setObjectName("btn_main")
        self.btn_main.clicked.connect(self.goToTransparentWindowMethod)

        self.horizontalLayout.addWidget(self.gpb_main)

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

    def retranslateUi(self, myWindow):
        _translate = QtCore.QCoreApplication.translate
        myWindow.setWindowTitle(_translate("myWindow", "Window1"))
        self.gpb_main.setTitle(_translate("myWindow", "example"))
        self.btn_main.setText(_translate("myWindow", "click me"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    myWindow = QtWidgets.QStackedWidget()
    ui = Ui_Form()
    ui.setupUi(myWindow)
    myWindow.show()
    sys.exit(app.exec_())

窗口2.py

from PyQt5 import QtCore, QtGui, QtWidgets
from pynput.mouse import Listener
import pyautogui


class TransparentWindowThreadClass(QtCore.QObject):

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

    @QtCore.pyqtSlot()
    def on_click_main(self, x, y, button, pressed):
        try:
            if pressed:
                self.pos_main = pyautogui.position()
                self.get_rgb_main = pyautogui.pixel(self.pos_main[0], self.pos_main[1])
                r = self.get_rgb_main.red
                g = self.get_rgb_main.green
                b = self.get_rgb_main.blue
                self.get_rgb_main = r,g,b

                Transparent_Window.unsetCursor()#error here when is called from window1
                Transparent_Window.close()#error here when is called from window1
             
                #Pressed
                self.pressed_Msg = 'Pressed at x:{0}  y:{1} RGB:{2}'.format(x, y, self.get_rgb_main)
                print(self.pressed_Msg)
            else: 
                #Released msg
                self.released_Msg = 'Released at x:{0} y:{1} RGB:{2}'.format(x, y, self.get_rgb_main)
                print(self.released_Msg)

            if not pressed:
                return False

        except KeyboardInterrupt:
            print('you pressed ctrl+c')
        except NameError:
            print("Error on_click_main")
        except RuntimeError:
            print('run time error')
        except TypeError:
            print('ype error')
        except AttributeError:
            print('Attribute Error')

    @QtCore.pyqtSlot()
    def loop_onclick_listener(self):
        try:
            with Listener(on_click=self.on_click_main) as listener:             
                listener.join()
        except KeyboardInterrupt:
            print('you pressed ctrl+c')
        except NameError:
            print("Error onclick_listener")
        except RuntimeError:
            print('run time error')
        except TypeError:
            print('ype error')
        except AttributeError:
            print('Attribute Error')

class TransparentWindowClass(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(TransparentWindowClass, self).__init__()

        self.monitorResolution = pyautogui.size()

        # create a QThread and start the thread that handles
        self.thread = QtCore.QThread()
        self.thread.start()

        # create the worker without a parent so you can move it
        self.worker = TransparentWindowThreadClass()## my custom thread class
        # the worker is moved to another thread
        self.worker.moveToThread(self.thread)

        # if the thread started, connect it
        self.thread.started.connect(self.worker.loop_onclick_listener)


    def setupUi(self, Transparent_Window):
        Transparent_Window.setObjectName("Transparent_Window")
        Transparent_Window.resize(self.monitorResolution[0], self.monitorResolution[1])
        Transparent_Window.setWindowFlags(QtCore.Qt.FramelessWindowHint)
        Transparent_Window.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
        Transparent_Window.setCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))

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

    def retranslateUi(self, Transparent_Window):
        _translate = QtCore.QCoreApplication.translate
        Transparent_Window.setWindowTitle(_translate("Transparent", "Transparent Window"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Transparent_Window = QtWidgets.QWidget()
    ui = TransparentWindowClass()
    ui.setupUi(Transparent_Window)
    Transparent_Window.show()
    sys.exit(app.exec_())

【问题讨论】:

  • 我在这里看到很多错误的选择,从您试图编辑/合并 pyuic 生成的代码这一事实开始(这在很大程度上被认为是一种糟糕的做法,除了他们自己的标题 cmets 明显不鼓励)。此外,你能澄清一下你为什么使用 pyinput 和 pyautogui 吗?
  • 嗨,我正在为侦听器使用 pyinput 和 pyautogui 来更轻松地获取像素。对不起
  • 这不是一个充分的解释,我知道那些模块的作用,我问过为什么你使用它们,而不是 Qt 已经提供的。
  • 嗨 @musicamantex 关于 Listener 是因为我需要在我的屏幕上获取位置,无论它是在我的透明窗口小部件上还是在它之外,对于 pyautogui ...我正在使用它来获取屏幕监视器大小而不是限制区域,并获取我的 x、y 位置的像素颜色(在小部件内部或外部,而不是限制区域)。如果你有什么建议,请告诉我

标签: python-3.x pyqt5


【解决方案1】:

你让事情变得太复杂了。

此外,即使假设没有其他可能的解决方案可以使用,您也必须记住小部件是不是线程安全的,不能直接从外部线程访问。线程之间唯一安全和正确的通信方式是使用信号和槽。

也就是说,如果您只想获取屏幕上像素的颜色,则不需要 pyautogui 或 pynput。

如果要抓取屏幕上的一个像素,可以使用QScreen函数grabWindow(),使用0作为window id(匹配整个屏幕),单像素区域。

然后你可以使用grabMouse()来确保你总是接收到鼠标事件,即使鼠标在小部件之外并且没有按下鼠标按钮。请注意,grabMouse() 只能在可见的小部件上工作,因此我们需要通过将窗口移出屏幕来“隐藏”该窗口。

然后,覆盖mousePressEvent()你可以使用grabWindow()和鼠标的全局位置,它会返回一个可以转换为QImage的QPixmap并得到上面抓取的pixelColor()

按下可以取消抓取Esc键.

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class GrabTest(QWidget):
    def __init__(self):
        super().__init__()
        self.resize(200, 200)

        self.button = QPushButton('Grab!')

        self.colorLabel = QLabel('No color', alignment=Qt.AlignCenter)
        self.colorLabel.setFixedSize(120, 30)
        self.colorLabel.setStyleSheet('border: 1px solid black;')

        layout = QVBoxLayout(self)
        layout.addStretch()
        layout.addWidget(self.button, alignment=Qt.AlignCenter)
        layout.addWidget(self.colorLabel, alignment=Qt.AlignCenter)
        layout.addStretch()

        self.button.clicked.connect(self.startGrab)

    def mousePressEvent(self, event):
        if QWidget.mouseGrabber() == self:
            self.getPixel(event.globalPos())
        else:
            super().mousePressEvent(event)

    def keyPressEvent(self, event):
        if QWidget.mouseGrabber() == self and event.key() == Qt.Key_Escape:
            self.stopGrab()
        else:
            super().keyPressEvent(event)

    def startGrab(self):
        self.grabMouse(Qt.CrossCursor)
        self.oldPos = self.pos()
        deskRect = QRect()
        for screen in QApplication.screens():
            deskRect |= screen.geometry()
        # move the window off screen while keeping it visible
        self.move(deskRect.bottomRight())


    def stopGrab(self):
        self.releaseMouse()
        self.move(self.oldPos)

    def getPixel(self, pos):
        screen = QApplication.screens()[0]
        pixmap = screen.grabWindow(0, pos.x(), pos.y(), 1, 1)
        color = pixmap.toImage().pixelColor(0, 0)
        if color.lightnessF() > .5:
            textColor = 'black'
        else:
            textColor = 'white'
        self.colorLabel.setStyleSheet('''
            color: {};
            background: {};
        '''.format(textColor, color.name()))
        self.colorLabel.setText(color.name())
        self.stopGrab()


if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    grabber = GrabTest()
    grabber.show()
    sys.exit(app.exec())

【讨论】:

    猜你喜欢
    • 2018-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-08
    • 1970-01-01
    • 1970-01-01
    • 2013-01-20
    相关资源
    最近更新 更多