PyQT4 GUI更新

时间:2015-06-21 13:09:09

标签: python user-interface pyqt python-multithreading

我有一个PyQT GUI代码,它从旋转框获取用户输入(角度)并以指定的角度更新GUI上的罗盘对象。我想使用for-loop(0到360)从代码内部而不是spinbox更新指南针对象,两者之间有一些延迟,以进行类似时钟的运动。请提出一些实现方法。

当前代码:

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *


#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
class CompassWidget(QWidget):

    angleChanged = pyqtSignal(float)

    def __init__(self, parent = None):

        QWidget.__init__(self, parent)

        self._angle = 0.0
        self._margins = 10
        self._pointText = {0: "N", 45: "NE", 90: "E", 135: "SE", 180: "S",
                           225: "SW", 270: "W", 315: "NW"}               

    def paintEvent(self, event):

        painter = QPainter()
        painter.begin(self)
        painter.setRenderHint(QPainter.Antialiasing)

        painter.fillRect(event.rect(), self.palette().brush(QPalette.Window))
        self.drawMarkings(painter)
        self.drawNeedle(painter)

        painter.end()

    def drawMarkings(self, painter):

        painter.save()
        painter.translate(self.width()/2, self.height()/2)
        scale = min((self.width() - self._margins)/120.0,
                    (self.height() - self._margins)/120.0)
        painter.scale(scale, scale)

        font = QFont(self.font())
        font.setPixelSize(10)
        metrics = QFontMetricsF(font)

        painter.setFont(font)
        painter.setPen(self.palette().color(QPalette.Shadow))

        i = 0
        while i < 360:
            if i % 45 == 0:
                painter.drawLine(0, -40, 0, -50)
                painter.drawText(-metrics.width(self._pointText[i])/2.0, -52,self._pointText[i])
            else:
                painter.drawLine(0, -45, 0, -50)
            painter.rotate(1)
            i += 1

        painter.restore()

    def drawNeedle(self, painter):

        painter.save()
        painter.translate(self.width()/2, self.height()/2)
        painter.rotate(self._angle)
        scale = min((self.width() - self._margins)/120.0,
                    (self.height() - self._margins)/120.0)
        painter.scale(scale, scale)

        painter.setPen(QPen(Qt.NoPen))
        painter.setBrush(self.palette().brush(QPalette.Shadow))

        painter.drawPolygon(
            QPolygon([QPoint(-10, 0), QPoint(0, -45), QPoint(10, 0),
                      QPoint(0, 45), QPoint(-10, 0)])
            )

        painter.setBrush(self.palette().brush(QPalette.Highlight))

        painter.drawPolygon(
            QPolygon([QPoint(-5, -25), QPoint(0, -45), QPoint(5, -25),
                      QPoint(0, -30), QPoint(-5, -25)])
            )

        painter.restore()

    def sizeHint(self):

        return QSize(600, 600)

    def angle(self):
        return self._angle

    @pyqtSlot(float)
    def setAngle(self, angle):

        if angle != self._angle:
            self._angle = angle
            self.angleChanged.emit(angle)
            self.update()

    angle = pyqtProperty(float, angle, setAngle)

#>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 

if __name__ == "__main__":

    app = QApplication(sys.argv)

    window = QWidget()
    compass = CompassWidget()
    spinBox = QSpinBox()
    spinBox.setRange(0, 359)

    #compass.angleChanged.connect(compass.setAngle)
    spinBox.valueChanged.connect(compass.setAngle)

    layout = QVBoxLayout()
    layout.addWidget(compass)
    layout.addWidget(spinBox)
    window.setLayout(layout)

    window.show()

    sys.exit(app.exec_())

3 个答案:

答案 0 :(得分:1)

QPropertyAnimation类专为此目的而设计,非常易于使用。有一系列内置easing-curves可以帮助使动画看起来更自然。

以下是基于示例脚本的演示。 (请注意,您需要在旋转框中按Enter键以更改值):

    Allocating common symbols
    Common symbol       size              file

    buddy_num           0x40              build/memory/page_alloc.c.o
    buddy_map           0x40              build/memory/page_alloc.c.o

    Discarded input sections

     .comment       0x0000000000000000       0x4e build/kernel/main.c.o
     .note.GNU-stack
                    0x0000000000000000        0x0 build/kernel/main.c.o
     .eh_frame      0x0000000000000000       0x70 build/kernel/main.c.o
     .comment       0x0000000000000000       0x4e build/memory/page_alloc.c.o
     .note.GNU-stack
                    0x0000000000000000        0x0 build/memory/page_alloc.c.o
     .eh_frame      0x0000000000000000       0xa8 build/memory/page_alloc.c.o
     .comment       0x0000000000000000       0x4e build/memory/virt_alloc.c.o
     .note.GNU-stack
                    0x0000000000000000        0x0 build/memory/virt_alloc.c.o
     .comment       0x0000000000000000       0x4e build/library/bitmap.c.o
     .note.GNU-stack
                    0x0000000000000000        0x0 build/library/bitmap.c.o
     .eh_frame      0x0000000000000000       0x50 build/library/bitmap.c.o
     .comment       0x0000000000000000       0x4e build/library/string.c.o
     .note.GNU-stack
                    0x0000000000000000        0x0 build/library/string.c.o
     .eh_frame      0x0000000000000000      0x150 build/library/string.c.o

    Memory Configuration

    Name             Origin             Length             Attributes
    *default*        0x0000000000000000 0xffffffffffffffff

    Linker script and memory map


    /DISCARD/
     *(.comment)
     *(.note.GNU-stack)
     *(.eh_frame)
     *(.comment)
     *(.note.GNU-stack)
     *(.eh_frame)
                    0x0000000000100000                . = 0x100000
                    0x0000000000100000                kernel_load_addr = .
                    0x0000000000100000                text_start_addr = .

    .text           0x0000000000100000     0x262f
                    0x0000000000100000                kernel_text_start = .
     *(.boot)
     .boot          0x0000000000100000       0x29 build/boot/boot.asm.o
     *(.text*)
     *fill*         0x0000000000100029        0x7 90
     .text          0x0000000000100030        0x0 build/boot/boot.asm.o
     .text          0x0000000000100030      0x14f build/boot/init.asm.o
                    0x0000000000100030                wheel_init
     *fill*         0x000000000010017f        0x1 90
     .text          0x0000000000100180      0x73c build/kernel/main.c.o
                    0x0000000000100180                raw_write
                    0x0000000000100210                read_info
                    0x00000000001005e0                wheel_main
     *fill*         0x00000000001008bc        0x4 90
     .text          0x00000000001008c0      0x974 build/memory/page_alloc.c.o
                    0x00000000001008c0                page_alloc_init
                    0x0000000000100cb0                find_free_pages
                    0x0000000000100ef0                alloc_pages
                    0x00000000001010c0                free_pages
     .text          0x0000000000101234        0x0 build/memory/virt_alloc.c.o
     *fill*         0x0000000000101234        0xc 90
     .text          0x0000000000101240      0x2ff build/library/bitmap.c.o
                    0x0000000000101240                bitmap_set
                    0x00000000001013c0                bitmap_clear
     *fill*         0x000000000010153f        0x1 90
     .text          0x0000000000101540     0x10ef build/library/string.c.o
                    0x0000000000101540                strlen
                    0x0000000000101650                strcpy
                    0x00000000001016c0                strncpy
                    0x0000000000101770                memcpy
                    0x0000000000101960                memset
                    0x0000000000101b60                u32_to_str
                    0x0000000000101c90                u64_to_str
                    0x0000000000101dd0                i32_to_str
                    0x0000000000101e60                i64_to_str
                    0x0000000000101ef0                vsprintf
                    0x00000000001025d0                sprintf
                    0x000000000010262f                kernel_text_end = .
                    0x000000000010262f                kernel_text_start = .
     *(.boot)
     *(.text*)
                    0x000000000010262f                kernel_text_end = .

    .data           0x0000000000102630      0x174
                    0x0000000000102630                kernel_data_start = .
     *(.rodata*)
     .rodata        0x0000000000102630        0x8 build/kernel/main.c.o
     .rodata.str1.1
                    0x0000000000102638       0x82 build/kernel/main.c.o
     *fill*         0x00000000001026ba        0x6 00000000
     .rodata        0x00000000001026c0       0xa5 build/library/string.c.o
     *(.data*)
     *fill*         0x0000000000102765        0x3 00000000
     .data          0x0000000000102768       0x3a build/boot/init.asm.o
     *fill*         0x00000000001027a2        0x2 00000000
     .data          0x00000000001027a4        0x0 build/kernel/main.c.o
     .data          0x00000000001027a4        0x0 build/memory/page_alloc.c.o
     .data          0x00000000001027a4        0x0 build/memory/virt_alloc.c.o
     .data          0x00000000001027a4        0x0 build/library/bitmap.c.o
     .data          0x00000000001027a4        0x0 build/library/string.c.o
                    0x00000000001027a4                kernel_data_end = .
                    0x00000000001027a4                kernel_data_start = .
     *(.rodata*)
     *(.data*)
                    0x00000000001027a4                kernel_data_end = .
                    0x00000000001027a4                data_end_addr = .

    .bss            0x0000000000103000     0x6000
                    0x0000000000103000                kernel_bss_start = .
     *(COMMON)
     COMMON         0x0000000000103000       0x80 build/memory/page_alloc.c.o
                    0x0000000000103000                buddy_num
                    0x0000000000103040                buddy_map
     *(.bss)
     *fill*         0x0000000000103080      0xf80 00000000
     .bss           0x0000000000104000     0x5000 build/boot/init.asm.o
                    0x0000000000104000                kernel_stack
                    0x0000000000105000                pml4t
     .bss           0x0000000000109000        0x0 build/kernel/main.c.o
     .bss           0x0000000000109000        0x0 build/memory/page_alloc.c.o
     .bss           0x0000000000109000        0x0 build/memory/virt_alloc.c.o
     .bss           0x0000000000109000        0x0 build/library/bitmap.c.o
     .bss           0x0000000000109000        0x0 build/library/string.c.o
                    0x0000000000109000                kernel_bss_end = .
                    0x0000000000109000                kernel_bss_start = .
     *(COMMON)
     *(.bss)
                    0x0000000000109000                kernel_bss_end = .
                    0x0000000000109000                bss_end_addr = .
                    0x0000000000109000                kernel_end = .
    LOAD build/boot/boot.asm.o
    LOAD build/boot/init.asm.o
    LOAD build/kernel/main.c.o
    LOAD build/memory/page_alloc.c.o
    LOAD build/memory/virt_alloc.c.o
    LOAD build/library/bitmap.c.o
    LOAD build/library/string.c.o
    LOAD link.lds
                    0x0000000000100000                . = 0x100000
                    0x0000000000100000                kernel_load_addr = .
                    0x0000000000100000                text_start_addr = .
                    0x0000000000100000                data_end_addr = .
                    0x0000000000100000                bss_end_addr = .
                    0x0000000000100000                kernel_end = .
    OUTPUT(build/kernel.bin binary)

答案 1 :(得分:0)

使用Python PySide and Progress Bar Threading中的示例

import sys
import time

from PyQt4.QtCore import *
from PyQt4.QtGui import *


class Worker(QThread):

    updateAngle = pyqtSignal(float)

    def __init__(self):
        QThread.__init__(self)

    def run(self):
        for i in range(360):
            self.updateAngle.emit(i)
            time.sleep(0.2)


class CompassWidget(QWidget):

    angleChanged = pyqtSignal(float)

    def __init__(self, parent = None):

        QWidget.__init__(self, parent)

        self._angle = 0.0
        self._margins = 10
        self._pointText = {0: "N", 45: "NE", 90: "E", 135: "SE", 180: "S",
                           225: "SW", 270: "W", 315: "NW"}               
        self._worker = Worker()
        self._worker.updateAngle.connect(self.setAngle)
        self._worker.start()

    def paintEvent(self, event):

        painter = QPainter()
        painter.begin(self)
        painter.setRenderHint(QPainter.Antialiasing)

        painter.fillRect(event.rect(), self.palette().brush(QPalette.Window))
        self.drawMarkings(painter)
        self.drawNeedle(painter)

        painter.end()

    def drawMarkings(self, painter):

        painter.save()
        painter.translate(self.width()/2, self.height()/2)
        scale = min((self.width() - self._margins)/120.0,
                    (self.height() - self._margins)/120.0)
        painter.scale(scale, scale)

        font = QFont(self.font())
        font.setPixelSize(10)
        metrics = QFontMetricsF(font)

        painter.setFont(font)
        painter.setPen(self.palette().color(QPalette.Shadow))

        i = 0
        while i < 360:
            if i % 45 == 0:
                painter.drawLine(0, -40, 0, -50)
                painter.drawText(-metrics.width(self._pointText[i])/2.0, -52,self._pointText[i])
            else:
                painter.drawLine(0, -45, 0, -50)
            painter.rotate(1)
            i += 1

        painter.restore()

    def drawNeedle(self, painter):

        painter.save()
        painter.translate(self.width()/2, self.height()/2)
        painter.rotate(self._angle)
        scale = min((self.width() - self._margins)/120.0,
                    (self.height() - self._margins)/120.0)
        painter.scale(scale, scale)

        painter.setPen(QPen(Qt.NoPen))
        painter.setBrush(self.palette().brush(QPalette.Shadow))

        painter.drawPolygon(
            QPolygon([QPoint(-10, 0), QPoint(0, -45), QPoint(10, 0),
                      QPoint(0, 45), QPoint(-10, 0)])
            )

        painter.setBrush(self.palette().brush(QPalette.Highlight))

        painter.drawPolygon(
            QPolygon([QPoint(-5, -25), QPoint(0, -45), QPoint(5, -25),
                      QPoint(0, -30), QPoint(-5, -25)])
            )

        painter.restore()

    def sizeHint(self):

        return QSize(600, 600)

    def angle(self):
        return self._angle

    @pyqtSlot(float)
    def setAngle(self, angle):

        if angle != self._angle:
            self._angle = angle
            self.angleChanged.emit(angle)
            self.update()

    angle = pyqtProperty(float, angle, setAngle)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = QWidget()
    compass = CompassWidget()
    spinBox = QSpinBox()
    spinBox.setRange(0, 359)

    spinBox.valueChanged.connect(compass.setAngle)

    layout = QVBoxLayout()
    layout.addWidget(compass)
    layout.addWidget(spinBox)
    window.setLayout(layout)

    window.show()

    sys.exit(app.exec_())

简而言之,如果您使用Qt,则应使用QThread而不是本机python线程。

答案 2 :(得分:0)

如何使用QTimer?将其timeout信号连接到一些增加计数器并告诉指南针小部件更新的方法。