【问题标题】:Pyqt: Change icon from buttonPyqt:从按钮更改图标
【发布时间】:2013-08-30 02:05:27
【问题描述】:

我刚开始使用 pyqt,我想从按钮更改图标。 但是我正在从另一个课程中删除它,而 pyqt 不喜欢那样。

错误是:QPixmap: 在 GUI 线程之外使用像素图是不安全的

我知道我必须使用信号 en 发射。 但我不知道我必须如何使用它来更改按钮的图标。

这是我现在的代码:

import sys
import time
from PyQt4 import QtGui, QtCore
from pymodbus.exceptions import ConnectionException
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from data.database import Tags, Query_Tags


class Example(QtGui.QMainWindow):

    def __init__(self):
        super(Example, self).__init__()

        self.db_engine = create_engine('mysql://modbususer:modbususer@localhost/modbus')

        self.db_session = sessionmaker(bind=self.db_engine)
        self.db_session = self.db_session()  

        self.status = 0
        self.initUI()

    def initUI(self):               

        self.button = QtGui.QPushButton('Aan', self)
        self.button.clicked.connect(self.run)     
        self.button.move(50,50)


        Uit = QtGui.QPushButton('Uit', self)
        Uit.clicked.connect(self.off)     
        Uit.move(150,50)

        self.setGeometry(300, 300, 500, 150)
        self.setWindowTitle('Quit button')    
        self.show()

        self.worker = WorkThread(self)
        self.worker.start()

    def run(self):

        add_tag = Query_Tags('18', '1')
        self.db_session.add(add_tag)
        self.db_session.commit()


    def off(self):

        add_tag = Query_Tags('18', '0')
        self.db_session.add(add_tag)
        self.db_session.commit()

        self.status = 0

        print self.store

    def change(self):

        print "test"
        #self.button.setIcon(QtGui.QIcon("/home/stijnb/test/icon.png"))
        #self.button.setIconSize(QtCore.QSize(16,16))

    def database(self, store):

        self.store = store

"""
    Thread
"""
class WorkThread(QtCore.QThread):

    def __init__(self, layout):

        QtCore.QThread.__init__(self)

        self.layout = layout

    def __del__(self):
        self.wait()

    def run(self):

        self.database = {}

        while True:

            self.db_engine = create_engine('mysql://modbususer:modbususer@localhost/modbus')

            self.db_session = sessionmaker(bind=self.db_engine)
            self.db_session = self.db_session() 

            for result in self.db_session.query(Tags):

                self.database[int(result.id)] = {'naam': result.name, 'value': result.value}

            self.change_icons()
            time.sleep(1)

        return 

        self.terminate()

    def change_icons(self):

        print self.database[21]['value']

        if self.database[21]['value'] == '1':

            self.layout.button.setIcon(QtGui.QIcon("/home/stijnb/test/aan.png"))
            self.layout.button.setIconSize(QtCore.QSize(16,16))

        else:

            self.layout.button.setIcon(QtGui.QIcon("/home/stijnb/test/uit.png"))
            self.layout.button.setIconSize(QtCore.QSize(16,16))

def main():

    app = QtGui.QApplication(sys.argv)

    ex = Example()

    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

【问题讨论】:

    标签: python pyqt


    【解决方案1】:

    您不能从除主 GUI 线程之外的任何其他线程触摸 GUI 元素。这就是 Qt 引入消息传递(信号和插槽)的原因。您可以从工作线程连接到将在主线程中捕获的信号,然后在主线程中您可以更改任何您想要的元素。

    这是一个非常简单的例子,我演示了这个概念。

    import sys
    from PyQt4 import QtGui, QtCore
    
    class Example(QtGui.QMainWindow):
        def __init__(self):
            super(Example, self).__init__()
            # Create a button and set it as a central widget
            self.button = QtGui.QPushButton('My Button', self)
            self.setCentralWidget(self.button)
            # Start the thread
            self.worker = WorkThread(self)
            self.worker.start()
            # Connect the thread's signal "change_text" to
            # "self.change_thread" function
            self.worker.change_text.connect(self.change_text)
    
        def change_text(self):
            # Slots are always executed in the GUI thread so it's safe to change
            # anything you want in a slot function. Here we just flip the button
            # text from foo to bar and back. But you can change the image or do
            # whatever you want.
            # Slots can also receive parameters so you can emit from your thread
            # which text should be set
            self.button.setText('bar' if self.button.text() == 'foo' else 'foo')
    
    
    class WorkThread(QtCore.QThread):
        # Define the signal
        change_text = QtCore.pyqtSignal()
    
        def __init__(self, layout):
            QtCore.QThread.__init__(self)
    
        def run(self):
            while True:
                # emit the signal every 3 seconds
                self.sleep(3)
                self.change_text.emit()
    
    
    app = QtGui.QApplication(sys.argv)
    ex = Example()
    ex.show()
    sys.exit(app.exec_())
    

    【讨论】:

    • @Stijnb 您是否尝试过与我发布的完全相同的代码?如果是,您使用的是哪个版本的 PyQt4?
    • 我这周安装了。我想我有最新版本。
    • 你能不能在 Python 解释器中输入:from PyQt4 import QtCore,然后是 print QtCore.Signal,最后是 print QtCore.__version__,然后将结果粘贴到这里。这真是一个奇怪的错误。
    • 这是 python 解释器的结果: >>> from PyQt4 import QtCore >>> print QtCore.Signal Traceback (last recent call last): File "", line 1, in AttributeError: 'module' object has no attribute 'Signal' >>> print QtCore.__version__ Traceback (last recent call last): File "", line 1, in AttributeError: 'module' object has no attribute 'version' >>> print QtCore.__version__ Traceback(最近一次调用最后):文件“”,第 1 行,在 AttributeError:'module' 对象没有属性'版本'
    • 好的,但是当您在终端中键入所有 3 行时,它们的确切输出是什么?
    猜你喜欢
    • 1970-01-01
    • 2018-09-11
    • 2018-03-11
    • 1970-01-01
    • 1970-01-01
    • 2017-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多