Автозаполнение из .ui

#python #qt #pyqt5

Вопрос:

Я работаю над приложением, использующим Python3 и PyQt5, с моим макетом пользовательского интерфейса, определенным в файле Qt .ui и загруженным в мой класс QDialog во время выполнения. Поэтому экземпляры моих элементов пользовательского интерфейса, таких как кнопка QPUSH, автоматически назначаются в качестве переменных экземпляра моего класса QDialog при загрузке пользовательского интерфейса.

Проблема в том, что, когда я использую эти переменные для изменения элементов, я не получаю никаких подсказок типа Intellisense или автозаполнения, потому что Python и моя IDE понятия не имеют, что такое класс объекта.

В Java вы можете использовать явное сужение приведения объекта к правильному типу, после чего intellisense может начать предоставлять автозаполнение, поскольку он знает тип.

Например, в Java и Android SDK:

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

В этом примере findViewById возвращает представление, поэтому вы можете использовать приведение типов, чтобы убедиться, что оно приведено к текстовому представлению.


В Python я хотел бы сделать то же самое, чтобы убедиться, что элементы пользовательского интерфейса, к которым я обращаюсь, имеют правильный тип, и иметь возможность использовать методы автозаполнения, например.

Вот моя текущая ситуация:

 """ 
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 нет реального «приведения» объектов, но есть ли способ сделать что-то похожее в Python на сужение приведения, как показано выше, в Java?

Комментарии:

1. Это функция вашей среды разработки. В PyCharm вы можете использовать assert операторы.

2. Нам нужно будет знать, какую среду разработки вы на самом деле используете.

3. 1 за то, что сказал Мартийн, но также вы можете ввести подсказку на python. Также вы правы в том, что «он дублирует исходный объект и выполняет». Если вы хотите проверить типы, вы можете сделать что-то вроде isinstance(self.my_push_button, QPushButton) , но я бы не рекомендовал этого. Python-сильный типизированный язык, пусть он обрабатывает типы, не пытайтесь его форсировать.

4. @AndrewFink Я бы не стал пытаться делать то, что вы делаете. Не пытайтесь превратить python в слабый типизированный язык, такой как Java или C#, python намного мощнее, когда вы позволяете ему оставаться динамичным. Ваша среда IDE должна отлично вводить подсказку. Пайлинт также отлично справляется с этим.

5. Я знаю, что ни одна среда IDE не может обнаруживать динамически генерируемые атрибуты, что делает uic (аналогично setattr и getattr), поэтому я вижу решение, которое вы преобразуете .ui в .py с помощью pyuic, который создаст класс, который вы можете использовать в своем виджете: riverbankcomputing.com/static/Docs/PyQt5/…

Ответ №1:

Завершение кода не работает для динамически генерируемых элементов, как это делает uic.

Одним из возможных решений является преобразование .ui в .py с помощью pyuic, а затем использование этого класса, указанного в разделе Использование сгенерированного кода.

Ответ №2:

Аннотации типов могут помочь вам здесь, просто объявите переменную для каждого виджета с его типом, как это

 myBtn: QPushButton = self.ui.myBtn
 

Затем вы получите все автозаполнения intelisence, как если бы вы конвертировали пользовательский интерфейс в файл py

Ответ №3:

Вот обходной путь для автозаполнения кода. Протестировано в Pycharm Python38 с pyqt5. Просто убедитесь, что ни в одном из ваших виджетов графического интерфейса нет имени «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)