PyCharm / PyQt:如何通过动态加载的 ui 文件获得代码补全

     2023-03-25     232

关键词:

【中文标题】PyCharm / PyQt:如何通过动态加载的 ui 文件获得代码补全【英文标题】:PyCharm / PyQt: How to obtain code completion with dynamically loaded ui files 【发布时间】:2022-01-21 01:52:18 【问题描述】:

假设我在 Qt Designer 中创建了一个 ui 文件,我想动态加载该文件以操作小部件,例如:

example.py:

from PyQt5 import QtWidgets, uic

class MyWidget(QtWidgets.QWidget):

    def __init__(self, parent=None):
        super(MyWidget, self).__init__(parent)
        uic.loadUi('example.ui', self)

        # No code completion here for self.myPushButton:
        self.myPushButton.clicked.connect(self.handleButtonClick)

        self.show()

在 PyCharm (2017.1.4) 中以这种方式加载的小部件是否有标准/便捷的方式来启用代码完成?

目前我正在使用这个(在ui文件加载后写在构造函数中):

self.myPushButton = self.myPushButton  # type: QtWidgets.QPushButton
# Code completion for myPushButton works at this point

我也想过这个,但是好像不行:

assert isinstance(self.myPushButton, QtWidgets.QPushButton)
# PyCharm does not even recognise myPushButton as an attribute of self at this point

最后我也想到了用python stubs,比如:

example.pyi:

class MyWidget(QtWidgets.QWidget):

    def __init__(self):
        self.myPushButton: QtWidgets.QPushButton = ... 

但是,myPushButton 在 example.py 外部的代码中被正确识别,但在 example.py 本身的代码中却没有被正确识别,这与我想要的相反。

我也在考虑采用我的第一种方法,但所有这些行都放在一个永远不会被调用的私有方法中,例如:

example.py:

from PyQt5 import QtWidgets, uic

class MyWidget(QtWidgets.QWidget):

    def __init__(self, parent=None):
        super(MyWidget, self).__init__(parent)
        uic.loadUi('example.ui', self)

        # Code completion now works here for self.myPushButton:
        self.myPushButton.clicked.connect(self.handleButtonClick)

        self.show()

    def __my_private_method_never_called():
        self.myPushButton = self.myPushButton  # type: QtWidgets.QPushButton

        # Or even this (it should have the same effect if this
        # function is never called, plus it is less verbose):
        self.myPushButton = QtWidgets.QPushButton()

        # If I want to make sure that this is never called
        # could raise an error at some point:
        raise YouShouldNotHaveCalledThisError()

这似乎工作正常,它还允许我将所有类型提示代码组合在一起,与其他代码隔离。我什至可以通过解析 ui 文件来编写一些脚本来为我编写所有这些行。我只是想知道阅读我的代码的人是否会觉得这种方法非常不正统,即使我清楚地评论了为什么我要编写一个技术上无用的私有函数。

【问题讨论】:

Pycharm 无法识别 .ui 文件 【参考方案1】:

如果有人感兴趣,我制作了我提到的脚本来解析 .ui 文件并生成准备复制到我的班级的存根代码:

ui_stub_generator.py:

from __future__ import print_function

import os
import sys
import xml.etree.ElementTree


def generate_stubs(file):
    root = xml.etree.ElementTree.parse(file).getroot()
    print('Stub for file: ' + os.path.basename(file))
    print()
    print('    def __stubs(self):')
    print('        """ This just enables code completion. It should never be called """')

    for widget in root.findall('.//widget'):
        name = widget.get('name')
        if len(name) > 3 and name[:2] == 'ui' and name[2].isupper():
            cls = widget.get('class')
            print('        self. = QtWidgets.()'.format(
                name, cls
            ))

    print('        raise AssertionError("This should never be called")')
    print()


def main():
    for file in sys.argv[1:]:
        generate_stubs(file)


if __name__ == '__main__':
    main()

这仅解析名称以“ui”开头后跟大写字母的小部件,例如“uiMyWidget”,这是我在 Qt 设计器中通常遵循的命名约定。通过这样做,Qt 设计器自动生成名称的小部件将被忽略(如果我关心这些,我会给它们一个正确的名称)。为任何其他命名约定或其他类型的对象(例如操作)更新它应该很简单。

为方便起见,我也将其设置为 PyCharm 中的外部工具;请参阅屏幕截图here(根据需要更改路径)。这样,我只需要在项目窗口中右键单击我的 ui 文件,然后 External Tools -> Stub Generator for Qt UI Files,然后在运行窗口中就可以得到以下输出复制:

C:\ProgramData\Anaconda3\python.exe D:\MyProject\bin\ui_stub_generator.py D:\MyProject\my_ui_file.ui
Stub for file: my_ui_file.ui

    def __stubs(self):
        """ This just enables code completion. It should never be called """
        self.uiNameLabel = QtWidgets.QLabel()
        self.uiOpenButton = QtWidgets.QPushButton()
        self.uiSplitter = QtWidgets.QSplitter()
        self.uiMyCombo = QtWidgets.QComboBox()
        self.uiDeleteButton = QtWidgets.QPushButton()
        raise AssertionError("This should never be called")

Process finished with exit code 0

【讨论】:

这是个好主意。我遇到了自动完成无法识别的 ui 文件的相同问题。我没有想到。也欢迎您将脚本包含在外部工具中。我把它当作我自己的用途。谢谢。 @StephanePiriou 只是为了给你更多的想法:除了在控制台中显示__stubs 方法之外,我的脚本的最终版本会检查具有相同名称的 Python 文件/类(例如 @ 987654325@ / MyUiFile) 并直接替换该方法。然后,我使用.ui 文件观察器自动执行脚本。我在工作中这样做了,所以我不能在这里展示它,但我会在某个时候用一个简化的版本来编辑我的答案 @FenAndr 那么存根代码将被添加到哪里?在单独的 .pyi 文件中? PyCharm 似乎没有索引它.. @maicol07 在普通的.py 文件中,在类本身的某个地方。除非最新的 PyCharm 版本在这方面发生了巨大的变化,否则这个解决方案应该仍然有效。 AFAIK,.pyi 文件仅用于访问您的类的外部代码,而不是在类本身内,因此不能用于此。 @FernAndr 我实际上正在尝试 PySide2,所以我现在正在编写没有类的代码,只是主要的。我应该将 self 变量更改为我的窗口变量吗?

如何通过单击pyqt5中的按钮来制作qlineedit的动态行和列?

】如何通过单击pyqt5中的按钮来制作qlineedit的动态行和列?【英文标题】:Howtomakedynamicrowandcolumnsofqlineeditonaclickofpushbuttoninpyqt5?【发布时间】:2019-09-1420:53:05【问题描述】:我正在开发一个库存管理软件项目,其中我有一小部分... 查看详情

通过 pyqt5 动态添加和删除小部件

...及用于输入产品名称和重量的字段。我没有想法。告诉我如何实现此功能?这是代码(它只是一个没有实现来显示我正在使用的框架):imp 查看详情

pyqt系列:pycharm环境配置(代码片段)

...安装Python3,PyQt5,Qt5设置外部工具本文是在Mac系统下使用PyCharm编辑器,Windows环境也是类似的。主要添加3个外部工具,用于编辑和转换ui文件,转换qrc文件打开软件设置界面,选择[Tools]-[ExternalTools]并新建新的工具。1.PyUIC将ui文... 查看详情

PyQt4:如何获取 QlistWidget 的可见项目列表?

】PyQt4:如何获取QlistWidget的可见项目列表?【英文标题】:PyQt4:HowcanIgetalistofthevisibleitemsofaQlistWidget?【发布时间】:2014-03-2709:59:32【问题描述】:我正在尝试为QlistWidget中的项目动态加载(在其他线程中,因此它不会阻塞)不同... 查看详情

如何在cordova中动态加载CSS

】如何在cordova中动态加载CSS【英文标题】:HowtoloadaCSSdynamicallyincordova【发布时间】:2014-04-2609:57:48【问题描述】:我正在尝试通过xhr请求在cordova中动态加载CSS。CSS的加载不是问题,我可以通过xhr加载它并通过HTML5FileAPI将其存储... 查看详情

Laravel:如何通过javascript加载带有动态参数的命名路由

】Laravel:如何通过javascript加载带有动态参数的命名路由【英文标题】:Laravel:Howcanloadnamedroutewithdynamicargumentsbyjavascript【发布时间】:2021-01-2620:12:00【问题描述】:我有一个视频播放器,我想在视频结束后运行带参数的命名路由... 查看详情

Angularjs - 动态页面,相同的模板,如何通过 id 访问和加载文章

】Angularjs-动态页面,相同的模板,如何通过id访问和加载文章【英文标题】:Angularjs-dynamicpages,sametemplate,howtoaccessandloadarticlebyid【发布时间】:2013-12-1204:53:51【问题描述】:我对如何使用angularjs构建一个类似博客的网站有点疑惑... 查看详情

pycharm中在andconda环境中配置pyqt环境

...,自带pyqt5在pipinstallpyqt5之后,需要安装pyqt5_tools。对于pycharm需要配置pyqtDesigner和pyqtUIC。Designer生成的.ui文件需要通过pyqtUIC转化为.py文件但有时会出现具体是python3.dllismissing安装的Python缺少了python3.dll,可以通过去python.org 下... 查看详情

在 PyQt 中动态调整视频大小

...0-08-0311:27:28【问题描述】:我正在用头撞墙,试图弄清楚如何调整我在RaspberryPi上构建的相机应用程序的大小和重新排列。我希望能够通过点击视频来调整窗口大小,从全屏应用程序到将显示在我的触摸屏一角的较小版本。https:/... 查看详情

用python抓取动态加载的网站

】用python抓取动态加载的网站【英文标题】:Scrapedynamicallyloadedwebsitewithpython【发布时间】:2020-04-0607:50:43【问题描述】:我是抓取动态加载网站的新手,我一直在尝试抓取该网站的团队名称和几率https://www.cashpoint.com/de/fussball/deu... 查看详情

如何使用 PyQt 加载图片资源?

】如何使用PyQt加载图片资源?【英文标题】:HowtoloadimageresourceswithPyQt?【发布时间】:2012-08-0709:09:39【问题描述】:我的应用程序中有这个结构:|-App||-functions||-ui|--ui.py||images||main.py我有一个带有一些脚本的函数文件夹和一个带... 查看详情

如何在 QML 中创建 PyQT 注册类型的动态实例

】如何在QML中创建PyQT注册类型的动态实例【英文标题】:HowtocreatedynamicinstancesofPyQTregisteredtypesinQML【发布时间】:2020-11-0122:50:36【问题描述】:以RegisteringPythonTypes为基础:https://www.riverbankcomputing.com/static/Docs/PyQt5/qml.html我希望能... 查看详情

如何动态编程使用 PyQt 创建的按钮?

】如何动态编程使用PyQt创建的按钮?【英文标题】:HowtoprogramdynamicallyabuttoncreatedwithPyQt?【发布时间】:2016-03-0813:21:04【问题描述】:所以我有一个名为RunButton的按钮。当我按下它时,我希望它在10秒范围内达到3秒标记时将按钮... 查看详情

pyqt5资源加载总结

一、概述在QtDesigner中要使用图片资源有三种方法:通过图像文件指定、通过资源文件指定、通过theme主题方式指定,对应的设置界面在需要指定图像的属性栏如QLabel的pixmap属性通过点击属性设置栏的倒三角按钮触发,... 查看详情

pyqt5-数据库加载错误解决

1.无法连接postgresql 直接在pycharm上安装pyqt5没有QT这个文件夹,在ancanda中装好使用。切换加载环境,或者将第二个ptqt5拷贝替换第一个环境中的pyqt5  查看详情

pycharm集成pyqt5以及使用(代码片段)

文章目录PyCharm安装PyQt5PyQt5在Pycharm配置PyCharm安装PyQt5在Pycharm中安装软件时比较方便的,直接File->Settings…接着进入Project->ProjectInterpreter,然后点击右上角的加号。在检索文本框中输入PyQt5和pyqt5-tools,并安装对应模块安... 查看详情

Pycharm 不显示“PyQt5”程序的错误信息(例如“TypeError”)

】Pycharm不显示“PyQt5”程序的错误信息(例如“TypeError”)【英文标题】:Pycharmdoesn\'tshowerrorinformationfor`PyQt5`program(e.g.`TypeError`)【发布时间】:2015-10-3107:51:02【问题描述】:在Pycharm4.5.2中,如果我在PyQt5插槽中出现错误,当调用... 查看详情

如何在 PyQt 容器中运行视频?

...频只显示一帧而没有其他内容。可能是什么问题呢?使用PyCharm、Python3.7制作。fromPy 查看详情