Добавить общую Qt-консоль с фильтрами и экспортом

This commit is contained in:
2026-10-17 14:43:12 +03:00
parent f613101124
commit 5af8a8e9c8
4 changed files with 347 additions and 0 deletions

View File

@@ -0,0 +1,46 @@
"""Три автономных примера общей консоли templates без подключения к аппаратуре.""" # Примеры показывают служебный текст, CAN и двоичный RS485 на одном компоненте.
import argparse # Ключ --kind выбирает один пример для отдельного запуска.
import time # Время в модели кадра соответствует обычному источнику пакетов приложения.
from set_devices.can485_board import BoardFrame # Штатная модель строит RS485-пакет с настоящим CRC.
from set_devices.can_monitor import decode_protocol # CAN расшифровывается действующим декодером templates.
from set_devices.can_transport import build_frame # Транспортный кадр не собирается вручную в UI.
from set_devices.qt_ports.console import ConsoleView # Все примеры используют ту же консоль, что SETGUI.
try: # Выбираем доступную версию Qt без зависимости от приложения SETGUI.
from PySide6.QtWidgets import QApplication, QTabWidget # Вкладки позволяют сравнить три независимых журнала.
except ImportError: # Сохраняем совместимость примера с портом Qt 5.
from PySide2.QtWidgets import QApplication, QTabWidget # Интерфейс запуска одинаков для обеих версий Qt.
def create_examples(): # Фабрика доступна также тесту и генератору снимков интерфейса.
service = ConsoleView(limit=4000) # Первый журнал показывает служебные ответы и команды платы.
service.append_message(">>> V", direction="TX", color="#8fd18f") # Метка отправки демонстрирует независимый фильтр TX.
service.append_message("#OK driver started", direction="RX", color="#6fa8dc") # Ответ устройства показывает цвет и фильтр RX.
service.append_message("#ERR transmit failed (no ack / bus busy)", color="#ff7b7b") # Ошибка остаётся видна независимо от фильтров направления.
can = ConsoleView(limit=4000, payloads=True) # Второй пример добавляет переключение представления настоящих байтов CAN.
frame = build_frame(0x701, b"\x05", ide=False, rtr=False) # ID 0x701 и байт 05 задают heartbeat CANopen узла 1 в Operational.
decoded = decode_protocol(frame, "deif") # Подпись события берётся из штатного протокольного декодера.
can.append_message("RX CAN 0x701 · " + decoded.summary, direction="RX", payload=b"\x05") # Исходный payload позволяет сравнить режимы HEX и ASCII.
rs485 = ConsoleView(limit=4000, payloads=True) # Третий пример показывает транспортный пакет платы отдельно от прикладного CAN.
packet = BoardFrame(time.time(), False, 0x701, False, 1, b"\x05", "RS485").rs485_packet() # Пакет AA55 и CRC8 формируются кодеком templates.
rs485.append_message("RX RS485 · пакет CAN485", direction="RX", payload=packet) # Консоль отображает байты, не повторяя алгоритм разбора пакета.
for console in (can, rs485): # Двоичные примеры сразу демонстрируют одновременно байты и печатное представление.
console.display.setCurrentText("HEX + ASCII") # Пользователь может вернуться к исходной подписи или выбрать один формат.
return (("Служебная консоль", service), ("CAN", can), ("RS485", rs485)) # Каждый журнал владеет своей историей и настройками просмотра.
def main(): # Точка входа запускается обычным Python с установленным Qt-портом templates.
parser = argparse.ArgumentParser(description=__doc__) # Справка объясняет назначение примеров без отдельного приложения.
parser.add_argument("--kind", choices=("all", "service", "can", "rs485"), default="all") # Один пример каждого источника доступен отдельной командой.
args = parser.parse_args() # Пользователь выбирает источник до создания окна.
app = QApplication.instance() or QApplication([]) # Одно приложение Qt обслуживает все примеры.
window = QTabWidget() # Общий просмотр не связывает состояния независимых консолей.
for key, (title, console) in zip(("service", "can", "rs485"), create_examples()): # Стабильные ключи соответствуют значениям --kind.
if args.kind in ("all", key): window.addTab(console.panel, title) # Выбранные примеры добавляются с общей панелью инструментов.
window.setWindowTitle("Примеры консоли templates") # Заголовок явно отличает демонстрацию от подключения к плате.
window.resize(1100, 480) # Начальный размер в логических пикселях позволяет видеть все инструменты.
window.show() # Окно появляется только при прямом запуске примера.
return app.exec() # Цикл Qt обрабатывает поиск, паузу, экспорт и изменение масштаба.
if __name__ == "__main__": # Импорт фабрики в тестах не должен открывать окно или запускать цикл событий.
raise SystemExit(main()) # Код завершения Qt возвращается вызывающему процессу.