从 .ui 自动完成

Autocomplete from .ui

我正在开发一个使用 Python3 和 PyQt5 的应用程序,我的 UI 布局开始在 Qt .ui 文件中定义并加载到我的 QDialog class在运行时。因此,当加载 UI 时,我的 UI 元素的实例(例如 QPushButton)会自动分配为我的 QDialog class 的实例变量。

问题在于,当我使用这些变量修改元素时,我没有得到任何类型的 Intellisense 类型提示或自动完成,因为 Python 和我的 IDE不知道对象的 class 是什么。

在 Java 中,您可以使用显式缩小转换将对象转换为正确的类型,此时智能感知可以开始提供自动完成功能,因为它知道类型。

例如,在 Java 和 Android SDK 中:

TextView name = (TextView) findViewById(R.id.name); 

在此示例中,findViewById returns 一个视图,因此您可以使用类型转换来确保它被转换为一个 TextView。


在 Python 中,我想做同样的事情,既要确保我访问的 UI 元素是正确的类型,又要能够使用自动完成例如方法。

这是我目前的情况:

""" 
Because Python doesn't know whether self.my_push_button is an instance 
of QPushButton, this may or may not work, but it won't know until runtime, 
so no autocompletion.
"""
self.my_push_button.setEnabled(False) 

我想做的是这样的:

( (QPushButton) self.my_push_button ).setEnabled(False) 

我试过这个:

QPushButton(self.my_push_button).setEnabled(False)

但据我所知,它复制了原始对象并在新对象上执行 setEnabled,这显然不是我想要的。

我还尝试将 assert 语句与 isinstance 函数一起使用:

assert isinstance(self.my_push_button, QPushButton)

"""
This works for providing the code completion and checking the type.
However, it only works within the scope of the assert statement, so adding an assert for each variable in each scope in which it is used would be unnecessarily verbose.
"""
self.my_push_button.setEnabled(False) 

我知道在 Python 中没有真正的 "casting" 对象,但它有任何方法可以在 Python 中进行类似的缩小转换,如上所示,在 Java?

代码完成不像 uic 那样对动态生成的元素起作用。

一种可能的解决方案是使用 pyuic 将 .ui 转换为 .py,然后使用 Using the Generated Code.[=11= 中指示的 class ]

这是代码自动完成的解决方法。使用 pyqt5 在 Pycharm Python38 中测试。只需确保 none 你的 gui 小部件中有名称“setupUi”。

from distutils.dep_util import newer
from PyQt5 import uic

    # check if UI file is new and needs to be translated to python
    if not newer(self.gui_dir + self.ui_file, self.gui_dir +
                 self.py_file):
        print("UI file has not changed!")
    else:
        # UI file has been updated, open .py file
        fp = open((self.gui_dir + self.py_file), "w")
        # compile .ui file into .py file
        uic.compileUi((self.gui_dir + self.ui_file), fp, execute=True, indent=4, from_imports=True)
        fp.close()
        
        #modify .py file to allow code autocompletion in pycharm
        #gives Ui_MainWindow a constructor so python can perform static analysis
        with open((self.gui_dir + self.py_file), "r") as fp:
            file_data = fp.read().replace('setupUi', '__init__')

        with open((self.gui_dir + self.py_file), 'w') as fp:
            fp.write(file_data)

类型注解可以帮助您解决这个问题,只需为每个小部件声明一个变量,就像这样

myBtn: QPushButton = self.ui.myBtn

然后你将获得所有智能自动完成,就像你将 ui 转换为 py 文件

我正在使用 Visual Studio 代码作为编辑器。刚花了几个小时谷歌搜索,我想我终于破解了这个。

我在 QT Designer 中创建了一个按钮并将其命名为 bob_button1(不知道为什么,但就是这样)。我正在使用 loadUi,因为我不想每次更改表单时都必须重新创建相应的 Python 命令:

uic.loadUi(r"C:\__ajb\test.ui",self)

我创建了一个变量,我可以用它来引用代码中的按钮:

self.bob_button1 =  self.findChild(QtWidgets.QPushButton, 'bob_button')

我现在希望在输入 self 时出现 Intellisense。bob_button1。 - 事实上是这样的:

问题是 - 如何让 VS Code 将按钮视为 QPushButton,而不是从 findChild 返回的更通用的 QObject?别处给出的答案是给出类型提示:

self.bob_button1 =  self.findChild(QtWidgets.QPushButton, 'bob_button')
self.bob_button1: QPushButton = self.bob_button1

请注意,您不能创建另一个将第一个按钮的类型转换为 QPushButton 的变量,因为这将创建第一个按钮的副本,并且信号和槽对其不起作用。

如果您在 VS Code 中尝试上述操作,它最初不起作用,所以我尝试安装 PyLint。但是,使用 VS Code 扩展时会出现发布版本错误消息。所以我在我的终端里输入了这个 window:

pip install pylint

最后我获得了 Intellisense,并且我的按钮点击有效!