Инструменты пользователя

Инструменты сайта


products:pussy:other:dev_propertycontainer_gui

Различия

Показаны различия между двумя версиями страницы.

Ссылка на это сравнение

Предыдущая версия справа и слеваПредыдущая версия
Следующая версия
Предыдущая версия
products:pussy:other:dev_propertycontainer_gui [2023/12/08 23:49] – [Разработка интерфейса для Контейнера Свойств] ironmeshproducts:pussy:other:dev_propertycontainer_gui [2023/12/13 14:54] (текущий) – внешнее изменение 127.0.0.1
Строка 1: Строка 1:
 ====== Разработка интерфейса для Контейнера Свойств ====== ====== Разработка интерфейса для Контейнера Свойств ======
  
-FIXME 
  
-В данном уроке я расскажу как разработать альтернативный интерфейс для Контейнера свойств, по умолчанию он генерирует интерфейс единым списком без группировки, если свойств немного, то этого будет вполне достаточно, но если их десятки или даже больше сотни, то таким интерфейсом будет пользоваться не слишком удобно, также может возникнуть желание добавить дополнительные функции, например, сортировка или фильтр и т.п.  Ниже показана предопределенная форма+В данном уроке я расскажу как разработать альтернативный интерфейс для [[:products:pussy:concepts:propertycontainer|Контейнера свойств]], по умолчанию он генерирует интерфейс единым списком без группировки по разделам и прочего, если свойств немного, то этого будет вполне достаточно, но если их десятки или даже сотни, то таким интерфейсом будет пользоваться не слишком удобно, также может возникнуть желание добавить дополнительные функции, например, сортировкафильтр и т.п. Ниже показана предопределенная форма вывода свойств
  
 {{  :products:pussy:screenshots:2023-09-17_14_14_34-configurate_plugin_properties_demo.jpg?400  |Дефолтный интерфейс Контейнера свойств}}Подробнее о концепции свойств читайте [[:products:pussy:concepts:propertycontainer|здесь]]. {{  :products:pussy:screenshots:2023-09-17_14_14_34-configurate_plugin_properties_demo.jpg?400  |Дефолтный интерфейс Контейнера свойств}}Подробнее о концепции свойств читайте [[:products:pussy:concepts:propertycontainer|здесь]].
Строка 10: Строка 9:
 ===== Ставим задачу ===== ===== Ставим задачу =====
  
-Для начала разберемся с тем, что мы хотим получить. Допустим у нас есть перечень свойств, которые имеют имена с суфиксами _s1,_s2..._s5, зная этот факт я хочу сгруппировать их все в пяти секциях, для этого я выберу виджет, который позволяет разделять макет на страницы, к примеру, возьмем [[https://doc.qt.io/qtforpython-6/PySide6/QtWidgets/QToolBox.html#PySide6.QtWidgets.PySide6.QtWidgets.QToolBox|QToolBox]], далее на каждой странице будут собраны свойства, имена которых будут иметь суффикс "_sX", форма страниц будет аналогичная той, которую имеет дефолтный интерфейс: в поле с полосой прокрутки (QScrollArea) будут собраны свойства в макете-сетке (QGridLayout), где в левом столбце будут виджеты QLable  с именами свойст, а в правом виджеты самих свойств.+Для начала разберемся с тем, что мы хотим получить. Допустим у нас есть перечень свойств, которые имеют имена с суфиксами _s1,_s2..._s5, зная этот факт я хочу сгруппировать их все в пяти секциях, для этого я выберу виджет, который позволяет разделять макет на страницы, к примеру, возьмем [[https://doc.qt.io/qtforpython-6/PySide6/QtWidgets/QToolBox.html#PySide6.QtWidgets.PySide6.QtWidgets.QToolBox|QToolBox]], далее на каждой странице будут собраны свойства, имена которых будут иметь суффикс "_sX", форма страниц будет аналогичная той, которую имеет дефолтный интерфейс: в поле с полосой прокрутки (QScrollArea) будут собраны свойства в макете-форме (QFormLayout), где в левом столбце будут виджеты QLable  с именами свойств, а в правом виджеты самих свойств.
  
 ===== Решаем задачу ===== ===== Решаем задачу =====
Строка 36: Строка 35:
  
 </code> </code>
 +
  
 заметьте, что после определения класса метод //generate_properties()// нужно вызвать, чтобы свойства были созданы. Теперь, можно посмотреть как будет выглядеть дефолтная форма с сгенерированными свойствами заметьте, что после определения класса метод //generate_properties()// нужно вызвать, чтобы свойства были созданы. Теперь, можно посмотреть как будет выглядеть дефолтная форма с сгенерированными свойствами
  
-{{  :products:pussy:screenshots:lessons:def_propcontainer_gui_1.jpg?200  }}выглядит она не очень презентабельно, тут собрано порядка 500 свойств, пользователю будет непросто. Напомню, что имена свойств определяют, на какую страницу оно попадет.+{{  :products:pussy:screenshots:lessons:def_propcontainer_gui_1.jpg?200  |def_propcontainer_gui_1.jpg}}выглядит она не очень презентабельно, тут собрано порядка 500 свойств, на практике с этим было бы трудно работать. 
 + 
 +Напомню, что в новом интерфейсе имя свойства определяет, на какую страницу оно попадет, то есть свойства с префиксом "s1" попадают на первую страницу, с "s2" на вторую и так далее. У [[:products:pussy:api:pyub:types:propertycontainer|]] за вывод интерфейса отвечает метод //[[http://wiki.mig-ironmesh.ru/products;pussy;api;pyub;types;propertycontainer#render_layout|render_layout()]]// , а метод //[[http://wiki.mig-ironmesh.ru/products;pussy;api;pyub;types;propertycontainer#retranslate|retranslate()]] // отвечает за перевод отображаемой информации, Менеджер автоматически вызывает данные методы, поэтому //retranslate() // не нужно вызывать в коде, как это делается в Свойствах. Если перевод не нужен, то заполнение интерефейса можно произвести в методе //render_layout(), // а в методе //retranslate() // вписать ключевое слов//о pass//. 
 + 
 +Итак, в итоге у меня получился следующий код для методов// render_layout() // и// retranslate()// 
 + 
 + 
 +<code python> 
 +@classmethod 
 +    def render_layout(cls) -> QToolBox: 
 +        cls._lable_list = {} 
 +        cls._tool_box = QToolBox() 
 + 
 +        def render_page(suffix:str) ->QScrollArea: 
 +            scroll_area = QScrollArea() 
 +            scroll_area.setWidgetResizable(True) 
 +            widget_content = QWidget() 
 +            layout = QFormLayout(widget_content) 
 +            layout.setVerticalSpacing(15) 
 +            layout.setLabelAlignment(Qt.AlignRight | Qt.AlignTrailing | Qt.AlignVCenter) 
 +            row: int = 0 
 +            for key, prop in cls.__annotations__.items(): 
 +                if not key.endswith(suffix): continue 
 +                cls._lable_list[key] = QLabel() 
 +                cls._lable_list[key].setWordWrap(True) 
 +                layout.setWidget(row, QFormLayout.LabelRole, cls._lable_list[key]) 
 +                layout.setWidget(row, QFormLayout.FieldRole, prop.get_input_widget()) 
 +                row += 1 
 +            scroll_area.setWidget(widget_content) 
 +            return scroll_area 
 + 
 +        for i in range(1, 6): 
 +            cls._tool_box.addItem(render_page(f"s{i}"), ""
 + 
 +        return cls._tool_box 
 + 
 +    @classmethod 
 +    def retranslate(cls) -> None: 
 +        for key, label in cls._lable_list.items(): 
 +            label.setText(cls.get_property(key).get_name()) 
 +            cls.__annotations__[key].retranslate() 
 + 
 +        for i in range(cls._tool_box.count()): 
 +            cls._tool_box.setItemText(i, QCoreApplication.translate("properties", f"Section {i+1}")) 
 +</code> 
 + 
 +А вот так выглядит новый интерфейс, уже намного лучше. Это только один из вариант группировки свойств по разделам, также можно для таких целей использовать виджеты: [[:products:pussy:other:qtabwidget|QTabWidget]], [[:products:pussy:other:qstackedwidget|QStackedWidget]] совместно с виджетом для выбора элементов, например, [[:products:pussy:other:qlistwidget|QListWidget]], [[:products:pussy:other:qcombobox|QComboBox]] и другие.{{  :products:pussy:screenshots:lessons:def_propcontainer_gui_2.jpg?200  |def_propcontainer_gui_2.jpg}}Теперь, попробую объяснить код, который я написал, начну с метода// render_layout()//, в самом начале определяем словарь //_lable_list//, в котором будут содержаться все подписи для свойств, которые представляют из себя экземпляры виджета QLable, а в переменной //_tool_box // будет находиться экземпляр [[:products:pussy:other:qtoolbox|QToolBox]], обе эти переменные сохраняются в классе, чтобы был к ним доступ из других методовЗатем я ввел вспомогательную вложенную функцию //render_page()//которая отбирает свойства, имена которых имеют указанный суффикс и упаковывает их в форму ([[:products:pussy:other:qformlayout|QFormLayout]]) внутри виджета, который в свою очередь вложен в область ([[:products:pussy:other:qscrollarea|QScrollArea]]), затем функция возвращает сформированный интерфейс; в цикле //for // производится обход всех Свойств, которые хранятся в словаре //_ _annotations_ _//, имена свойств, которые не имеют нужный суффикс игнорируются, а те что соответствуют, у них берется виджет для ввода методом //get_input_widget()//, затем он добавляется в форму layout([[:products:pussy:other:qformlayout|QFormLayout]]) в правый столбец (роль //[[:products:pussy:other:qformlayout|QFormLayout]].[[:products:pussy:other:fieldrole|FieldRole]]), // а подписи для свойств (экземпляры QLable) помещаются в левый столбец (роль //[[:products:pussy:other:qformlayout|QFormLayout]].[[:products:pussy:other:labelrole|LabelRole]]//). Заметьтечто для подписей Свойств текст не устанавливается, это будет сделано позднее. В конце производится добавление страниц в //_tool_box//, для этого вызыватся метод //addItem()//, которому передается результат функции //render_page(), // которой передаются строки с суффиксами, определенные нами ранее. 
 + 
 +В методе //retranslate() // выполняется перевод отображаемой информации, а именно: подписи разделов для //_tool_box//, подписей Свойств и самих Свойств. Для перевода подписей свойств мы обходим все элементы в //_lable_list // и устанавливаем текст, которые вернет метод свойства //get_name()//, заметьте, что в качестве ключей использованы имена свойств в контейнере; также у каждого свойства вызывается метод //retranslate()//, чтобы перевести отображаемую информацию; в конце производится обход всех элементов в //_tool_box// и устанавливает их текст на предопределенный, для поиска перевода используется команда //[[:products:pussy:other:qcoreapplication|QCoreApplication]].translate(<контекст>, <текст>).// 
 + 
 +Подытожу все вышесказанное. Для того чтобы определить свой вариант интерефейса нужно переопределить всего 2 метода:// render_layout() // и// retranslate()//, первый метод должен вернуть виджет с сгенерированным интерфесом, а второй выполнить перевод отображаемой информации. Элементы для интерефейса мы извлекаем из самих свойст, вызовом метода //get_input_widget(), // а текст с именем свойства нам вернет метод //get_name()//; сами свойства хранятся в классе, в поле //_ _annotations_ _,  // которое представляет из себя обычный словар, где ключ - идентификатор свойства, а значение - ссылка на само свойство.
  
-Ну, вот и все, урок по разработке собственного класса свойства подошел к концу, как вы могли убедиться это очень простой процесс, который не займет много времени и сил, но перед использованием не забывайте тестировать свой код. Если что-то не понятно, то можно задать вопрос в [[http://discord.gg/JD5yKPrKCk|Discord]].+Ну, вот и все, урок по разработке альтернативного интерфейса для Контейнера свойств подошел к концу, как вы могли убедиться это очень простой процесс, который не займет много времени и сил, при наличии опыта разработки интерфейсов, если опыта мало, то можно сверстать его в [[:products:pussy:other:qtdesigner|QtDesigner]], а затем посмотреть как устроен код и перенести его в свой проект с некоторыми изменениями или импортировать его целиков. Кстати, перед использованием не забывайте тестировать свой код. Если что-то не понятно, то можно задать вопрос в [[http://discord.gg/JD5yKPrKCk|Discord]].
  
  
products/pussy/other/dev_propertycontainer_gui.1702068591.txt.gz · Последнее изменение: (внешнее изменение)