> 文章列表 > PyQt Custom Widget

PyQt Custom Widget

PyQt Custom Widget

pyuic/pyside6-uic

pip install PyQt6 pyqt6-tools

或者

pip install PySide6

假设你的自定义控件时from vtk.test2.testhead import testfaQ

首先拉一个QWidget
右键Promote to…

PyQt Custom Widget
在header file里写上 vtk.test2.testhead(写vtk/test2/testhead.h或者vtk/test2/testhead或者vtk.test2.testhead.h都是可以的)

在promoted class name里写testfaQ

然后点Add,最后Promote
PyQt Custom Widget
最后pyuic/pyside6-uic
可以看到最后那一句就是from vtk.test2.testhead import testfaQ
就实现了自定义控件了
PyQt Custom Widget

原理

miniconda3/envs/qt_test/lib/python3.8/site-packages/PyQt6/uic/uiparser.py
其中header指promoted widgets里的Headfile,
classname指的是promoted widgets里的promoted class name

可以看出来
foo/bar/baz.h->foo.bar.baz
foo.bar.baz.h->foo.bar.baz
foo.bar.baz->foo.bar.baz

class UIParser(object):def _handle_custom_widgets(self, el):""" Handle the <customwidgets> element. """def header2module(header):"""header2module(header) -> stringConvert paths to C++ header files to according Python modules>>> header2module("foo/bar/baz.h")'foo.bar.baz'"""if header.endswith(".h"):header = header[:-2]mpath = []for part in header.split('/'):# Ignore any empty parts or those that refer to the current# directory.if part not in ('', '.'):if part == '..':# We should allow this for Python3.raise SyntaxError("custom widget header file name may not contain '..'.")mpath.append(part)return '.'.join(mpath)for custom_widget in el:classname = custom_widget.findtext("class")self.factory.addCustomWidget(classname,custom_widget.findtext("extends") or "QWidget",header2module(custom_widget.findtext("header")))

miniconda3/envs/qt_test/lib/python3.8/site-packages/PyQt6/uic/Compiler/qobjectcreator.py

addCustomWidget对应着上面的addCustomWidget

widgetClass指的是promoted widgets里的promoted class name
module指promoted widgets里的Headfile

最后会调用_writeImportCode,
得到from module import widgetClass

class _CustomWidgetLoader(object):def __init__(self):self._widgets = {}self._usedWidgets = set()def addCustomWidget(self, widgetClass, baseClass, module):assert widgetClass not in self._widgets self._widgets[widgetClass] = (baseClass, module)def _writeImportCode(self):imports = {}for widget in self._usedWidgets:_, module = self._widgets[widget]imports.setdefault(module, []).append(widget)for module, classes in sorted(imports.items()):write_code("from %s import %s" % (module, ", ".join(sorted(classes))))

QUiLoader()

ui的写法与uic里一样

然后用QUiLoader()的load加载ui
如果你是pyside,一定要写registerCustomWidget将对应的类加载进来

#!/usr/bin/env python
# _*_ coding:utf-8 _*_
import osfrom PySide6 import QtCore
from PySide6.QtUiTools import QUiLoader
from PySide6.QtWidgets import QApplication
from pyqtgraph import PlotWidgetos.environ["PYSIDE_DESIGNER_PLUGINS"] = "."class Stock:def __init__(self):loader = QUiLoader()loader.registerCustomWidget(PlotWidget)self.ui = loader.load('my_mainwindow.ui')hour = list(range(1, 11))temperature = [30, 32, 34, 32, 33, 31, 29, 32, 35, 45]self.ui.graphWidget.plot(hour, temperature)if __name__ == '__main__':QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_ShareOpenGLContexts)app = QApplication([])stock = Stock()stock.ui.show()# window = MainWindow()# window.show()app.exec()

参考:

https://www.pythonguis.com/tutorials/pyqt6-embed-pyqtgraph-custom-widgets-qt-app/
https://doc.qt.io/qtforpython/PySide6/QtUiTools/QUiLoader.html#PySide6.QtUiTools.PySide6.QtUiTools.QUiLoader.registerCustomWidget
https://stackoverflow.com/questions/68528717/environment-variable-pyside-designer-plugins-is-not-set-bailing-out
https://doc-snapshots.qt.io/qtforpython-dev/tutorials/basictutorial/uifiles.html#custom-widgets-in-qt-designer

https://blog.csdn.net/feiyangqingyun/article/details/123005373
https://blog.csdn.net/panchang199266/article/details/104249647