9
7

More than 3 years have passed since last update.

【PyQt】Qt Designerで作った画面にQMLを埋め込み、valueをセット

Last updated at Posted at 2019-11-05

はじめに

 普段ちょっとしたGUIを作るときにPyQtを使っているのですが、QMLの表示やプロパティの変更に手こずったので、その備忘録です。
 画面作成にはQtDesignerを使っています。QtDesignerの使い方はこちらを参考に。

環境

  • Windows 10
  • Qt Designer 5.11.1
  • Python 3.7.3
  • PyQt5 5.13.1

作成したサンプル

image.png

+ボタンを押すとゲージの値が増え、-ボタンを押すと減るというものです。

ファイルの構成

  • qml_gauge_sample_gui.py
    • 実行ファイル
  • MyGauge.qml
    • QMLファイル
  • my_gauge.py
    • QQuickWidgetを継承し、ソースにMyGauge.qmlをセット
  • qml_gauge_sample.ui
    • Designerで作成したuiファイル
  • qml_gauge_sample_ui.py
    • uiファイルからpyuicコマンドで作成したPythonファイル

各ファイルの詳細

MyGauge.qml
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Quick Extras module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/

import QtQuick 2.2
import QtQuick.Controls 1.4
import QtQuick.Controls.Styles 1.4
import QtQuick.Controls.Private 1.0
import QtQuick.Extras 1.4
import QtQuick.Extras.Private 1.0

Gauge {
    minimumValue: 0
    value: gauge.value
    maximumValue: 100
    tickmarkStepSize: 10
    orientation: Qt.Vertical
}

QtQuick.ExtrasのGaugeを使用します。
valueの値をgauge.valueとして、プログラムから更新できるようにします。

my_gauge.py
import os

from PyQt5.QtCore import pyqtProperty
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtCore import QObject
from PyQt5.QtCore import QUrl
from PyQt5.QtQuickWidgets import QQuickWidget


class GaugeProperty(QObject):
    _value_changed_signal = pyqtSignal(int)

    def __init__(self, parent=None):
        super(GaugeProperty, self).__init__(parent)
        self._value = 0

    @pyqtProperty(int, notify=_value_changed_signal)
    def value(self):
        return self._value

    @value.setter
    def value(self, value):
        if self._value == value:
            return
        self._value = value
        self._value_changed_signal.emit(value)


class MyGauge(QQuickWidget):
    def __init__(self, parent):
        super(MyGauge, self).__init__(parent)
        self._gauge = GaugeProperty(self)
        self.setResizeMode(self.SizeRootObjectToView)
        self.engine().rootContext().setContextProperty("gauge", self._gauge)
        directory = os.path.dirname(os.path.abspath(__file__))
        self.setSource(QUrl.fromLocalFile(os.path.join(directory,
                                                       "MyGauge.qml")))

    def increment(self):
        self._gauge.value += 1

    def decrement(self):
        self._gauge.value -= 1

 QQuickWidgetを継承したMyGaugeクラスと、ゲージのvalueプロパティを管理するGaugePropertyクラスを作成します。
 MyGaugeクラスは、画面作成時に格上げの対象先となります。

qml_gauge_sample.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>GaugeSampleWidget</class>
 <widget class="QWidget" name="GaugeSampleWidget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>94</width>
    <height>335</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Form</string>
  </property>
  <widget class="MyGauge" name="myGauge" native="true">
   <property name="geometry">
    <rect>
     <x>10</x>
     <y>10</y>
     <width>71</width>
     <height>291</height>
    </rect>
   </property>
  </widget>
  <widget class="QWidget" name="horizontalLayoutWidget">
   <property name="geometry">
    <rect>
     <x>10</x>
     <y>300</y>
     <width>71</width>
     <height>31</height>
    </rect>
   </property>
   <layout class="QHBoxLayout" name="_horizontalLayout">
    <item>
     <widget class="QPushButton" name="_plusButton">
      <property name="font">
       <font>
        <pointsize>9</pointsize>
        <weight>75</weight>
        <bold>true</bold>
       </font>
      </property>
      <property name="text">
       <string>+</string>
      </property>
     </widget>
    </item>
    <item>
     <widget class="QPushButton" name="_minusButton">
      <property name="font">
       <font>
        <weight>75</weight>
        <bold>true</bold>
       </font>
      </property>
      <property name="text">
       <string>-</string>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
 </widget>
 <customwidgets>
  <customwidget>
   <class>MyGauge</class>
   <extends>QWidget</extends>
   <header>my_gauge.h</header>
   <container>1</container>
  </customwidget>
 </customwidgets>
 <resources/>
 <connections>
  <connection>
   <sender>_plusButton</sender>
   <signal>pressed()</signal>
   <receiver>GaugeSampleWidget</receiver>
   <slot>increment_gauge_value()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>28</x>
     <y>314</y>
    </hint>
    <hint type="destinationlabel">
     <x>159</x>
     <y>310</y>
    </hint>
   </hints>
  </connection>
  <connection>
   <sender>_minusButton</sender>
   <signal>pressed()</signal>
   <receiver>GaugeSampleWidget</receiver>
   <slot>decrement_gauge_value()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>68</x>
     <y>313</y>
    </hint>
    <hint type="destinationlabel">
     <x>69</x>
     <y>394</y>
    </hint>
   </hints>
  </connection>
 </connections>
 <slots>
  <slot>increment_gauge_value()</slot>
  <slot>decrement_gauge_value()</slot>
 </slots>
</ui>

Qt Designerで作成したuiファイル。
gauge_sample_widget.png

promoted_mygauge.png

MyGaugeクラスに格上げされたQWidgetと、ゲージのインクリメント/デクリメントを行うボタンが二つ配置されています。

qml_gauge_sample_ui.py
# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'qml_gauge_sample.ui'
#
# Created by: PyQt5 UI code generator 5.13.1
#
# WARNING! All changes made in this file will be lost!


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_GaugeSampleWidget(object):
    def setupUi(self, GaugeSampleWidget):
        GaugeSampleWidget.setObjectName("GaugeSampleWidget")
        GaugeSampleWidget.resize(94, 335)
        self.myGauge = MyGauge(GaugeSampleWidget)
        self.myGauge.setGeometry(QtCore.QRect(10, 10, 71, 291))
        self.myGauge.setObjectName("myGauge")
        self.horizontalLayoutWidget = QtWidgets.QWidget(GaugeSampleWidget)
        self.horizontalLayoutWidget.setGeometry(QtCore.QRect(10, 300, 71, 31))
        self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget")
        self._horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget)
        self._horizontalLayout.setContentsMargins(0, 0, 0, 0)
        self._horizontalLayout.setObjectName("_horizontalLayout")
        self._plusButton = QtWidgets.QPushButton(self.horizontalLayoutWidget)
        font = QtGui.QFont()
        font.setPointSize(9)
        font.setBold(True)
        font.setWeight(75)
        self._plusButton.setFont(font)
        self._plusButton.setObjectName("_plusButton")
        self._horizontalLayout.addWidget(self._plusButton)
        self._minusButton = QtWidgets.QPushButton(self.horizontalLayoutWidget)
        font = QtGui.QFont()
        font.setBold(True)
        font.setWeight(75)
        self._minusButton.setFont(font)
        self._minusButton.setObjectName("_minusButton")
        self._horizontalLayout.addWidget(self._minusButton)

        self.retranslateUi(GaugeSampleWidget)
        self._plusButton.pressed.connect(GaugeSampleWidget.increment_gauge_value)
        self._minusButton.pressed.connect(GaugeSampleWidget.decrement_gauge_value)
        QtCore.QMetaObject.connectSlotsByName(GaugeSampleWidget)

    def retranslateUi(self, GaugeSampleWidget):
        _translate = QtCore.QCoreApplication.translate
        GaugeSampleWidget.setWindowTitle(_translate("GaugeSampleWidget", "Form"))
        self._plusButton.setText(_translate("GaugeSampleWidget", "+"))
        self._minusButton.setText(_translate("GaugeSampleWidget", "-"))
from my_gauge import MyGauge

$ pyuic5 qml_gauge_sample.ui > qml_gauge_sample_ui.py
で作成した、Pythonファイル。

qml_gauge_sample_gui.py
import sys

from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QMainWindow

from qml_gauge_sample_ui import Ui_GaugeSampleWidget


class QmlGaugeSampleGui(QMainWindow, Ui_GaugeSampleWidget):
    def __init__(self, parent=None):
        super(QmlGaugeSampleGui, self).__init__(parent)
        self.setupUi(self)

    @pyqtSlot()
    def increment_gauge_value(self):
        self.myGauge.increment()

    @pyqtSlot()
    def decrement_gauge_value(self):
        self.myGauge.decrement()


if __name__ == '__main__':
    argvs = sys.argv
    app = QApplication(argvs)
    qml_gauge_sample_gui = QmlGaugeSampleGui()
    qml_gauge_sample_gui.show()
    sys.exit(app.exec_())

 Designerで作成した、Ui_GaugeSampleWidgetを継承したQmlGaugeSampleGuiクラスを作ります。
 QmlGaugeSampleGuiクラスにはincrement_gauge_value()関数とdecrement_gauge_value()関数を持っており、それぞれ+ボタン、-ボタンが押されると呼ばれるようにDesigner上でSignal/Slotの設定がされています。

あとは、
$ python qml_gauge_sample_gui.py
で実行すれば、ゲージQMLが埋め込まれた画面が表示されます。

参考URL

9
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
7