在QQuickWidget内更新/重新绘制仪表

时间:2018-05-22 21:08:17

标签: python pyqt qml pyqt5

我的应用中无法解决2天的问题,所以我在这里发帖。 我有用pyqt5(Qt设计器)编写的UI,主窗口的一部分包含QML对象(在QQuickWidget内)。

我的问题是在QQuickWidget中刷新规范对象。

例如,如果我使用QML文件作为ApplicationWindow运行应用程序,一切正常,我可以操作数据:

Gauge令人耳目一新

但是当我将这个对象(并将QML中的对象更改为Rectangle)放入QQuickWidget时,我无法更新此对象的状态。

在python UI应用程序中测量 - 不刷新

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = GUI_MainWindow()    #Main window written in pyqt5
    qmlRegisterType(RadialBar, "SDK", 1,0, "RadialBar")

    # Setting source for QML Widget
    # batteryCWidget is the QQUickWidget object (4 of them are on main window)
    window.batteryCWidget.setSource(QUrl('qml_widget.qml'))

    batteryWidget = MyClass() # Class with function to update data in QML
    engine = QQmlApplicationEngine()
    context = engine.rootContext()
    context.setContextProperty("batteryWidget", batteryWidget)
    engine.load('qml_widget.qml')
    root = engine.rootObjects()[0]

    timer = QTimer()
    timer.start(200)

    #Every 200ms I generate new number in function random_value 
    timer.timeout.connect(batteryWidget.random_value)
    #and then update value in QML
    batteryWidget.randomValue.connect(root.setValue)

是否可以更新/重绘/刷新QQuickWidget内的对象状态?

这是qml_widget.qml:

import QtQuick 2.4
import SDK 1.0
import QtQuick.Layouts 1.1


Rectangle {
    id: root
    Layout.alignment: Layout.Center
    width: 160
    height: 145
    color: "#181818"
    property var suffix: "A"
    property int minVal: 0
    property int maxVal: 100
    property var actVal: 0

    function setValue(v) {
        actVal = v
    }
Rectangle {
        Layout.alignment: Layout.Center
        width: 160
        height: 145
        color: "#1d1d35"
        border.color: "#000000"
        border.width: 3
Text {
    id: name
    text: "Battery Current"
    anchors.horizontalCenter: parent.horizontalCenter
    anchors.top: parent.top
    anchors.topMargin: 5
    font.pointSize: 13
    color: "#6affcd"
}

RadialBar {
    anchors.horizontalCenter: parent.horizontalCenter
    anchors.bottom: parent.bottom
    width: parent.width / 1.4
    height: width - (0.001)*actVal
    penStyle: Qt.RoundCap
    progressColor: "#6affcd"
    foregroundColor: "#191a2f"
    dialWidth: 11
    minValue: minVal
    maxValue: maxVal
    value: actVal
    suffixText: suffix
    textFont {
        family: "Halvetica"
        italic: false
        pointSize: 18
    }
    textColor: "#00ffc1"
}}

MyClass的:

class MyClass(QObject):
    randomValue = pyqtSignal(float)
    def __init__(self, parent=None):
        super(MyClass, self).__init__(parent)

    def random_value(self):
        v = float(randrange(1, 100))
        self.randomValue.emit(v)

RadialBar类:

class RadialBar(QQuickPaintedItem):

    class DialType():
        FullDial = 0
        MinToMax = 1
        NoDial = 2

sizeChanged = pyqtSignal()
startAngleChanged = pyqtSignal()
spanAngleChanged = pyqtSignal()
minValueChanged = pyqtSignal()
maxValueChanged = pyqtSignal()
valueChanged = pyqtSignal()
dialWidthChanged = pyqtSignal()
backgroundColorChanged = pyqtSignal()
foregroundColorChanged = pyqtSignal()
progressColorChanged = pyqtSignal()
textColorChanged = pyqtSignal()
suffixTextChanged = pyqtSignal()
showTextChanged = pyqtSignal()
penStyleChanged = pyqtSignal()
dialTypeChanged = pyqtSignal()
textFontChanged = pyqtSignal()

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

    self.setWidth(200)
    self.setHeight(200)
    self.setSmooth(True)
    self.setAntialiasing(True)

    self._Size = 200
    self._StartAngle = 40
    self._SpanAngle = 280
    self._MinValue = 0
    self._MaxValue = 100
    self._Value = 50
    self._DialWidth = 25
    self._BackgroundColor = Qt.transparent
    self._DialColor = QColor(80,80,80)
    self._ProgressColor = QColor(135,26,50)
    self._TextColor = QColor(0, 0, 0)
    self._SuffixText = ""
    self._ShowText = True
    self._PenStyle = Qt.FlatCap
    self._DialType = RadialBar.DialType.MinToMax
    self._TextFont = QFont()

def paint(self, painter):
    painter.save()
    size = min(self.width(), self.height())
    self.setWidth(size)
    self.setHeight(size)
    rect = QRectF(0, 0, self.width(), self.height()) #self.boundingRect()
    painter.setRenderHint(QPainter.Antialiasing)
    pen = painter.pen()
    pen.setCapStyle(self._PenStyle)

    startAngle = -90 - self._StartAngle
    if RadialBar.DialType.FullDial != self._DialType:
        spanAngle = 0 - self._SpanAngle
    else:
        spanAngle = -360

    #Draw outer dial
    painter.save()
    pen.setWidth(self._DialWidth)
    pen.setColor(self._DialColor)
    painter.setPen(pen)
    offset = self._DialWidth / 2
    if self._DialType == RadialBar.DialType.MinToMax:
        painter.drawArc(rect.adjusted(offset, offset, -offset, -offset), startAngle * 16, spanAngle * 16)
    elif self._DialType == RadialBar.DialType.FullDial:
        painter.drawArc(rect.adjusted(offset, offset, -offset, -offset), -90 * 16, -360 * 16)
    else:
        pass
        #do not draw dial

    painter.restore()

    #Draw background
    painter.save()
    painter.setBrush(self._BackgroundColor)
    painter.setPen(self._BackgroundColor)
    inner = offset * 2
    painter.drawEllipse(rect.adjusted(inner, inner, -inner, -inner))
    painter.restore()

    #Draw progress text with suffix
    painter.save()
    painter.setFont(self._TextFont)
    pen.setColor(self._TextColor)
    painter.setPen(pen)
    if self._ShowText:
        painter.drawText(rect.adjusted(offset, offset, -offset, -offset), Qt.AlignCenter,str(self._Value) + self._SuffixText)
    else:
        painter.drawText(rect.adjusted(offset, offset, -offset, -offset), Qt.AlignCenter, self._SuffixText)
    painter.restore()

    #Draw progress bar
    painter.save()
    pen.setWidth(self._DialWidth)
    pen.setColor(self._ProgressColor)
    valueAngle = float(float(self._Value - self._MinValue)/float(self._MaxValue - self._MinValue)) * float(spanAngle)  #Map value to angle range
    painter.setPen(pen)
    painter.drawArc(rect.adjusted(offset, offset, -offset, -offset), startAngle * 16, valueAngle * 16)
    painter.restore()

@QtCore.pyqtProperty(str, notify=sizeChanged)
def size(self):
    return self._Size

@size.setter
def size(self, size):
    if self._Size == size:
        return
    self._Size = size
    self.sizeChanged.emit()

@QtCore.pyqtProperty(int, notify=startAngleChanged)
def startAngle(self):
    return self._StartAngle

@startAngle.setter
def startAngle(self, angle):
    if self._StartAngle == angle:
        return
    self._StartAngle = angle
    self.startAngleChanged.emit()

@QtCore.pyqtProperty(int, notify=spanAngleChanged)
def spanAngle(self):
    return self._SpanAngle

@spanAngle.setter
def spanAngle(self, angle):
    if self._SpanAngle == angle:
        return
    self._SpanAngle = angle
    self.spanAngleChanged.emit()

@QtCore.pyqtProperty(int, notify=minValueChanged)
def minValue(self):
    return self._MinValue

@minValue.setter
def minValue(self, value):
    if self._MinValue == value:
        return
    self._MinValue = value
    self.minValueChanged.emit()

@QtCore.pyqtProperty(int, notify=maxValueChanged)
def maxValue(self):
    return self._MaxValue

@maxValue.setter
def maxValue(self, value):
    if self._MaxValue == value:
        return
    self._MaxValue = value
    self.maxValueChanged.emit()

@QtCore.pyqtProperty(float, notify=valueChanged)
def value(self):
    return self._Value

@value.setter
def value(self, value):
    if self._Value == value:
        return
    self._Value = value
    self.valueChanged.emit()

@QtCore.pyqtProperty(float, notify=dialWidthChanged)
def dialWidth(self):
    return self._DialWidth

@dialWidth.setter
def dialWidth(self, width):
    if self._DialWidth == width:
        return
    self._DialWidth = width
    self.dialWidthChanged.emit()

@QtCore.pyqtProperty(QColor, notify=backgroundColorChanged)
def backgroundColor(self):
    return self._BackgroundColor

@backgroundColor.setter
def backgroundColor(self, color):
    if self._BackgroundColor == color:
        return
    self._BackgroundColor = color
    self.backgroundColorChanged.emit()

@QtCore.pyqtProperty(QColor, notify=foregroundColorChanged)
def foregroundColor(self):
    return self._ForegrounColor

@foregroundColor.setter
def foregroundColor(self, color):
    if self._DialColor == color:
        return
    self._DialColor = color
    self.foregroundColorChanged.emit()

@QtCore.pyqtProperty(QColor, notify=progressColorChanged)
def progressColor(self):
    return self._ProgressColor

@progressColor.setter
def progressColor(self, color):
    if self._ProgressColor == color:
        return
    self._ProgressColor = color
    self.progressColorChanged.emit()

@QtCore.pyqtProperty(QColor, notify=textColorChanged)
def textColor(self):
    return self._TextColor

@textColor.setter
def textColor(self, color):
    if self._TextColor == color:
        return
    self._TextColor = color
    self.textColorChanged.emit()

@QtCore.pyqtProperty(str, notify=suffixTextChanged)
def suffixText(self):
    return self._SuffixText

@suffixText.setter
def suffixText(self, text):
    if self._SuffixText == text:
        return
    self._SuffixText = text
    self.suffixTextChanged.emit()

@QtCore.pyqtProperty(str, notify=showTextChanged)
def showText(self):
    return self._ShowText

@showText.setter
def showText(self, show):
    if self._ShowText == show:
        return
    self._ShowText = show

@QtCore.pyqtProperty(Qt.PenCapStyle, notify=penStyleChanged)
def penStyle(self):
    return self._PenStyle

@penStyle.setter
def penStyle(self, style):
    if self._PenStyle == style:
        return
    self._PenStyle = style
    self.penStyleChanged.emit()

@QtCore.pyqtProperty(int, notify=dialTypeChanged)
def dialType(self):
    return self._DialType

@dialType.setter
def dialType(self, type):
    if self._DialType == type:
        return
    self._DialType = type
    self.dialTypeChanged.emit()

@QtCore.pyqtProperty(QFont, notify=textFontChanged)
def textFont(self):
    return self._TextFont

@textFont.setter
def textFont(self, font):
    if self._TextFont == font:
        return
    self._TextFont = font
    self.textFontChanged.emit()

1 个答案:

答案 0 :(得分:1)

如果您在Python/C++中创建了一个对象,并且想要将其连接到QML中创建的对象,则正确的选项是使用{{QML方面进行此操作3}},但为此你必须在MyClass中创建一个属性。

main.py

import sys

from random import randrange

from PyQt5 import QtCore, QtGui, QtWidgets, QtQml, QtQuick, QtQuickWidgets

from RadialBar import RadialBar

class MyClass(QtCore.QObject):
    randomValueChanged = QtCore.pyqtSignal(float)

    def __init__(self, parent=None):
        super(MyClass, self).__init__(parent)
        self.m_randomValue = 0

    @QtCore.pyqtProperty(float, notify=randomValueChanged)
    def randomValue(self):
        return self.m_randomValue

    @randomValue.setter
    def randomValue(self, v):
        if self.m_randomValue == v:
            return
        self.m_randomValue = v
        self.randomValueChanged.emit(v)

    def random_value(self):
        v = float(randrange(1, 100))
        self.randomValue = v

class GUI_MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        QtWidgets.QMainWindow.__init__(self, parent)
        self.batteryCWidget = QtQuickWidgets.QQuickWidget()
        self.setCentralWidget(self.batteryCWidget)
        self.batteryCWidget.setResizeMode(QtQuickWidgets.QQuickWidget.SizeRootObjectToView)

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    window = GUI_MainWindow()    #Main window written in pyqt5
    QtQml.qmlRegisterType(RadialBar, "SDK", 1,0, "RadialBar")
    batteryWidget = MyClass() # Class with function to update data in QML
    context = window.batteryCWidget.rootContext()
    context.setContextProperty("batteryWidget",batteryWidget)
    window.batteryCWidget.setSource(QtCore.QUrl.fromLocalFile('qml_widget.qml'))
    timer = QtCore.QTimer()
    timer.timeout.connect(batteryWidget.random_value)
    timer.start(200)
    window.show()
    sys.exit(app.exec_())

qml_widget.qml

import QtQuick 2.4
import SDK 1.0
import QtQuick.Layouts 1.1


Rectangle {
    id: root
    Layout.alignment: Layout.Center
    width: 160
    height: 145
    color: "#181818"
    property string suffix: "A"
    property int minVal: 0
    property int maxVal: 100
    property real actVal: 0

    Connections{
        target: batteryWidget
        onRandomValueChanged: root.actVal = batteryWidget.randomValue
    }

    Rectangle {
        Layout.alignment: Layout.Center
        width: 160
        height: 145
        color: "#1d1d35"
        border.color: "#000000"
        border.width: 3
        Text {
            id: name
            text: "Battery Current"
            anchors.horizontalCenter: parent.horizontalCenter
            anchors.top: parent.top
            anchors.topMargin: 5
            font.pointSize: 13
            color: "#6affcd"
        }

        RadialBar {
            anchors.horizontalCenter: parent.horizontalCenter
            anchors.bottom: parent.bottom
            width: parent.width / 1.4
            height: width - (0.001)*actVal
            penStyle: Qt.RoundCap
            progressColor: "#6affcd"
            foregroundColor: "#191a2f"
            dialWidth: 11
            minValue: minVal
            maxValue: maxVal
            value: actVal
            suffixText: suffix
            textFont {
                family: "Halvetica"
                italic: false
                pointSize: 18
            }
            textColor: "#00ffc1"
        }
    }
}

您可以在以下Connections中找到完整的代码。

link

正如enter image description here所说,一种更简单的方法是进行约束。

...
property real actVal: batteryWidget.randomValue

Rectangle {
...
相关问题