пятница, 10 декабря 2021 г.

PyQt6 против PySide6

 PyQt6 против PySide6

Есть новая версия Qt (версия 6), а вместе с ней и новые версии PyQt и PySide, которые теперь называются PyQt6 и PySide6 соответственно. При подготовке к выпуску Qt6 моих книг PyQt5 и PySide2 я просматривал последние версии библиотек, чтобы определить различия между ними и найти решения для написания переносимого кода.

В этом кратком руководстве я расскажу, почему существуют две библиотеки, нужно ли вам заботиться (спойлер: нет), каковы различия и как их обойти. К концу вам должно быть удобно повторно использовать примеры кода из руководств PyQt6 и PySide6 для создания своих приложений, независимо от того, какой пакет вы используете.

Истоки

Почему две библиотеки?

PyQt разработан Филом Томпсоном из Riverbank Computing Ltd. и существует очень долгое время - поддерживая версии Qt, начиная с 2.x. В 2009 году Nokia, которой в то время принадлежал инструментарий Qt, захотела сделать привязки Python для Qt доступными в рамках более разрешительной лицензии LGPL.

Он называется PySide, потому что «side» по-фински означает «связующее».

Эти два интерфейса были в основном эквивалентными, но со временем разработка PySide отставала от PyQt. Это было особенно заметно после выпуска Qt 5 - версия PyQt (PyQt5) для Qt5 была доступна с середины 2016 года, а первая стабильная версия PySide была выпущена двумя годами позже. Однако проект Qt недавно принял PySide в качестве официального выпуска Qt для Python, что должно гарантировать его жизнеспособность в будущем. Когда был выпущен Qt6, вскоре после этого были доступны обе привязки Python.


PyQt6PySide6
First stable releaseJan 2021Dec 2020
Developed byRiverbank Computing Ltd.Qt
LicenseGPL or commercialLGPL
PlatformsPython 3Python 3

Что вам следует использовать? Ну, честно говоря, это не имеет значения.

Оба пакета содержат одну и ту же библиотеку - Qt6 - и поэтому имеют 99,9% идентичных API (некоторые различия см. Ниже). Все, что вы узнаете с помощью одной библиотеки, будет легко применить к проекту с использованием другой. Кроме того, независимо от того, какой из них вы выберете для использования, стоит ознакомиться с другим, чтобы вы могли наилучшим образом использовать все доступные онлайн-ресурсы - например, используя учебные пособия PyQt6 для создания приложений PySide6, и наоборот.

В этом кратком обзоре я рассмотрю несколько заметных различий между двумя пакетами и объясню, как написать код, который без проблем работает с обоими. Прочитав это, вы сможете взять любой пример PyQt6 в Интернете и преобразовать его для работы с PySide6.

Лицензирование

Основное заметное различие между двумя версиями - это лицензирование: PyQt6 доступен по лицензии GPL или коммерческой лицензии, а PySide6 - по лицензии LGPL.

Если вы планируете выпустить свое программное обеспечение под лицензией GPL или разрабатываете программное обеспечение, которое не будет распространяться, требование GPL для PyQt6 вряд ли станет проблемой. Однако, если вы хотите распространять свое программное обеспечение, но не делитесь своим исходным кодом, вам необходимо приобрести коммерческую лицензию на PyQt6 у Riverbank или использовать PySide6.

Сам Qt доступен по коммерческой лицензии Qt, лицензиям GPL 2.0, GPL 3.0 и LGPL 3.0.


Пространства имен и перечисления

Одним из основных изменений, внесенных в PyQt6, является необходимость использования полностью определенных имен для перечислений и флагов. Раньше как в PyQt5, так и в PySide2 вы могли использовать ярлыки, например Qt.DecorationRole, Qt.AlignLeft. В PyQt6 теперь это Qt.ItemDataRole.DisplayRole и Qt.Alignment.AlignLeft соответственно. Это изменение затрагивает все перечисления и группы флагов в Qt. В PySide6 по-прежнему поддерживаются как длинные, так и короткие имена.

Ситуация несколько осложняется тем фактом, что PyQt6 и PySide6 используют несколько разные соглашения об именах для флагов. В PySide6 (и v5) флаги сгруппированы под объектами флагов с суффиксом «Flag», например Qt.AlignmentFlag - флаг выравнивания по левому краю - Qt.AlignmentFlag.AlignLeft. Та же группа флагов в PyQt6 называется просто «Qt.Alignment». Это означает, что вы не можете просто выбрать длинную или краткую форму и сохранить совместимость между PyQt6 и PySide6.

UI файлы

Еще одно важное различие между двумя библиотеками заключается в их обработке загрузки файлов .ui, экспортированных из Qt Creator / Designer. PyQt6 предоставляет подмодуль uic, который можно использовать для непосредственной загрузки файлов пользовательского интерфейса для создания объекта. Это выглядит довольно Pythonic (если не обращать внимания на camelCase).

PYTHON
import sys
from PyQt6 import QtWidgets, uic

app = QtWidgets.QApplication(sys.argv)

window = uic.loadUi("mainwindow.ui")
window.show()
app.exec()

Эквивалент с PySide6 на одну строку длиннее, так как вам нужно сначала создать объект QUILoader. К сожалению, API этих двух интерфейсов тоже различается (.load и .loadUI).


PYTHON
import sys
from PySide6 import QtCore, QtGui, QtWidgets
from PySide6.QtUiTools import QUiLoader

loader = QUiLoader()

app = QtWidgets.QApplication(sys.argv)
window = loader.load("mainwindow.ui", None)
window.show()
app.exec_()

Чтобы загрузить пользовательский интерфейс в существующий объект в PyQt6, например, в вашем QMainWindow .__ init__, вы можете вызвать uic.loadUI, передав self (существующий виджет) в качестве второго параметра.

PYTHON
import sys
from PyQt6 import QtCore, QtGui, QtWidgets
from PyQt6 import uic


class MainWindow(QtWidgets.QMainWindow):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        uic.loadUi("mainwindow.ui", self)


app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()

Загрузчик PySide6 не поддерживает это - второй параметр .load - это родительский виджет того виджета, который вы создаете. Это предотвращает добавление пользовательского кода в блок __init__ виджета, но вы можете обойти это с помощью отдельной функции.

PYTHON
import sys
from PySide6 import QtWidgets
from PySide6.QtUiTools import QUiLoader

loader = QUiLoader()

def mainwindow_setup(w):
    w.setWindowTitle("MainWindow Title")

app = QtWidgets.QApplication(sys.argv)

window = loader.load("mainwindow.ui", None)
mainwindow_setup(window)
window.show()
app.exec()

Преобразование файлов UI в Python

Обе библиотеки предоставляют идентичные сценарии для создания импортируемых модулей Python из файлов .ui Qt Designer. Для PyQt6 скрипт называется pyuic6 -

BASH
pyuic6 mainwindow.ui -o MainWindow.py

Затем вы можете импортировать объект UI_MainWindow, подкласс, используя множественное наследование из базового класса, который вы используете (например, QMainWIndow), а затем вызвать self.setupUI (self) для настройки пользовательского интерфейса.

PYTHON
import sys
from PyQt6 import QtWidgets
from MainWindow import Ui_MainWindow

class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setupUi(self)


app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()

Для PySide6 он называется pyside6-uic -

BASH
pyside6-uic mainwindow.ui -o MainWindow.py

Последующая настройка идентична.

PYTHON
import sys
from PySide6 import QtWidgets
from MainWindow import Ui_MainWindow

class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.setupUi(self)


app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()

Компилятор пользовательского интерфейса PyQt имеет флаг -x, который можно использовать для создания исполняемой демонстрации из файла пользовательского интерфейса. Это недоступно в версии PySide.

exec() или exec_()

Метод .exec () используется в Qt для запуска цикла обработки событий вашего QApplication или диалоговых окон. В Python 2.7 exec было ключевым словом, что означало, что его нельзя было использовать для имен переменных, функций или методов. Решение, используемое как в PyQt4, так и в PySide, заключалось в переименовании использования .exec в .exec_ (), чтобы избежать этого конфликта.

Python 3 удалил ключевое слово exec, освободив имя для использования. В результате из PyQt6 вызовы .exec () именуются так же, как в Qt. Однако PySide6 по-прежнему использует .exec_ ().

 Slots и Signals

Для определения пользовательских слотов и сигналов используется немного другой синтаксис между двумя библиотеками. PySide6 предоставляет этот интерфейс под именами Signal и Slot, тогда как PyQt6 предоставляет их как pyqtSignal и pyqtSlot соответственно. Поведение у них обоих идентично для определения и слотов, и сигналов.

Следующие примеры PyQt6 и PySide6 идентичны -

PYTHON
my_custom_signal = pyqtSignal()  # PyQt6
my_custom_signal = Signal()  # PySide6

my_other_signal = pyqtSignal(int)  # PyQt6
my_other_signal = Signal(int)  # PySide6

Или для слота -

PYTHON
@pyqtslot
def my_custom_slot():
    pass

@Slot
def my_custom_slot():
    pass

Если вы хотите обеспечить согласованность между PyQt6 и PySide6, вы можете использовать следующий шаблон импорта для PyQt6, чтобы использовать там стиль Signal и @Slot.

PYTHON
from PyQt6.QtCore import pyqtSignal as Signal, pyqtSlot as Slot

Конечно, вы могли бы сделать обратное из PySide6.QtCore import Signal как pyqtSignal, Slot как pyqtSlot, хотя это немного сбивает с толку.

QMouseEvent

В PyQt6 объекты QMouseEvent больше не имеют сокращенных методов свойств .pos (), .x () или .y () для доступа к позиции события. Вы должны использовать свойство .position (), чтобы получить объект QPoint и получить доступ к его методам .x () или .y (). Метод .position () также доступен в PySide6.

Свойства которые есть в PySide6 но нет в PyQt6

Начиная с Qt6 PySide поддерживает два флага Python __feature__, чтобы помочь сделать код более Pythonic с именами переменных snake_case и возможностью назначать свойства и обращаться к ним напрямую, вместо использования функций getter/setter. В приведенном ниже примере показано влияние этих изменений на код:

PYTHON
table = QTableWidget()
table.setColumnCount(2)

button = QPushButton("Add")
button.setEnabled(False)

layout = QVBoxLayout()
layout.addWidget(table)
layout.addWidget(button)

Тот же код, но с включенными snake_case и true_property.


PYTHON
from __feature__ import snake_case, true_property

table = QTableWidget()
table.column_count = 2

button = QPushButton("Add")
button.enabled = False

layout = QVBoxLayout()
layout.add_widget(table)
layout.add_widget(button)

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

Поддержка библиотек

Вам не нужно беспокоиться об этом, если вы пишете автономное приложение, просто используйте любой API, который вам больше нравится.

Если вы пишете библиотеку, виджет или другой инструмент, и хотите что бы они были совместимыми как с PyQt6, так и с PySide6, вы можете легко сделать это, добавив оба набора импорта.

PYTHON
import sys

if 'PyQt6' in sys.modules:
    # PyQt6
    from PyQt6 import QtGui, QtWidgets, QtCore
    from PyQt6.QtCore import pyqtSignal as Signal, pyqtSlot as Slot

else:
    # PySide6
    from PySide6 import QtGui, QtWidgets, QtCore
    from PySide6.QtCore import Signal, Slot
Это подход, используемый в нашей библиотеке пользовательских виджетов, где мы поддерживаем PyQt6 и PySide6 с помощью одного импорта библиотеки. Единственное предостережение заключается в том, что вы должны убедиться, что PyQt6 импортирован раньше (как в строке выше или ранее) при импорте этой библиотеки, чтобы убедиться, что он находится в sys.modules.

Чтобы учесть отсутствие сокращенного перечисления и флагов в PyQt6, вы можете сгенерировать их самостоятельно. Например, следующий код скопирует ссылки для каждого из элементов объектов перечисления до их родительского объекта, что сделает их доступными, как в PyQt5, PySide2 и PySide6. Код нужно будет запускать только под PyQt6.
PYTHON
enums = [
    (QtCore.Qt, 'Alignment'),
    (QtCore.Qt, 'ApplicationAttribute'),
    (QtCore.Qt, 'CheckState'),
    (QtCore.Qt, 'CursorShape'),
    (QtWidgets.QSizePolicy, 'Policy'),
]

# Look up using the long name (e.g. QtCore.Qt.CheckState.Checked, used
# in PyQt6) and store under the short name (e.g. QtCore.Checked, used
# in PyQt5, PySide2 & accepted by PySide6).
for module, enum_name in enums:
    for entry in getattr(module, enum_name):
        setattr(module, entry.name, entry)

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

PYTHON
def _enum(obj, name):
    parent, child = name.split('.')
    result = getattr(obj, child, False)
    if result:  # Found using short name only.
        return result

    obj = getattr(obj, parent)  # Get parent, then child.
    return getattr(obj, child)

При передаче объекта и длинного имени, совместимого с PyQt6, эта функция вернет правильное перечисление или флаг как для PyQt6, так и для PySide6.

PYTHON
>>> _enum(PySide6.QtCore.Qt, 'Alignment.AlignLeft')
PySide6.QtCore.Qt.AlignmentFlag.AlignLeft
>>> _enum(PyQt6.QtCore.Qt, 'Alignment.AlignLeft')
<Alignment.AlignLeft: 1>

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

PYTHON
def _exec(obj):
    if hasattr(obj, 'exec'):
        return obj.exec()
    else:
        return obj.exec_()

Затем вы можете использовать эту функцию для выполнения таких объектов, как QApplication и QDialog, переносимым способом как на PyQt6, так и на PySide6.

PYTHON
app = QApplication(sys.argv)
_exec(app)
Если вы делаете это в нескольких файлах, это может стать немного громоздким. Хорошее решение - переместить логику импорта и настраиваемые методы прокладки в отдельный файл, например с именем qt.py в корне вашего проекта. Этот модуль импортирует модули Qt (QtCore, QtGui, QtWidgets и т. Д.) Из одной из двух библиотек, а затем вы импортируете оттуда в свое приложение.

Содержимое qt.py такое же, как мы использовали ранее -
PYTHON
import sys

if 'PyQt6' in sys.modules:
    # PyQt6
    from PyQt6 import QtGui, QtWidgets, QtCore
    from PyQt6.QtCore import pyqtSignal as Signal, pyqtSlot as Slot


else:
    # PySide6
    from PySide6 import QtGui, QtWidgets, QtCore
    from PySide6.QtCore import Signal, Slot


def _enum(obj, name):
    parent, child = name.split('.')
    result = getattr(obj, child, False)
    if result:  # Found using short name only.
        return result

    obj = getattr(obj, parent)  # Get parent, then child.
    return getattr(obj, child)


def _exec(obj):
    if hasattr(obj, 'exec'):
        return obj.exec()
    else:
        return obj.exec_()

Вы должны не забыть добавить любые другие используемые вами модули PyQt6 (браузер, мультимедиа и т. Д.) В обе ветви блока if. Затем вы можете импортировать Qt6 в свое собственное приложение следующим образом:

PYTHON
from .qt import QtGui, QtWidgets, QtCore, _enum, _exec

... и он будет без проблем работать с любой библиотекой.

Это действительно то что нужно

Больше нечего сказать - две библиотеки действительно настолько похожи. Однако, если вы наткнетесь на какие-либо другие примеры или функции PyQt6 / PySide6, которые вы не можете легко преобразовать, напишите мне.

 

суббота, 4 декабря 2021 г.

Tcl/Tk 8.6.9 команда try

 

Tcl8.6.9/Tk8.6.9 Documentation > Tcl Commands, version 8.6.9 > try

НАИМЕНОВАНИЕ

try — Поймать и обработать ошибки и исключения

ОБЗОР

try body ?handler...? ?finally script?

ОПИСАНИЕ

Эта команда выполняет сценарий body и, в зависимости от результата этого сценария (нормальный выход, ошибка или какой-либо другой исключительный результат), запускает сценарий обработчика для обработки случая. Как только это все произойдет, если присутствует предложение finally , включаемый в него script будет запущен, и результат обработчика (или body если ни один обработчик не найден) может продолжить распространение. Обратите внимание, что предложение finally обрабатывается, даже если возникает ошибка, и независимо от того, какой из них используется, если таковой имеется, handler.

Каждое предложение handler выражается в виде нескольких слов и должно иметь одну из следующих форм:

on code variableList script
Это предложение будет выбираться, если выполнение body завершилось с кодом исключения code. code может быть выражен как целое число или одно из следующих буквальных слов: ok, error , return, break или continue. Эти литералы соответствуют целым числам от 0 до 4 соответственно.
trap pattern variableList script
Это предложение соответствует, если оценка body привела к ошибке и префикс -errorcode из словаря статуса интерпретатора равен pattern. Количество префиксных слов, взятых из -errorcode, равно длине списка pattern, а межсловные пробелы нормализованы как в -errorcode и pattern перед сравнением.

Слово variableList в каждом handler всегда интерпретируется как список имен переменных. Если первое слово списка присутствует и не является пустым, оно именует переменную, в которую будет помещен результат оценки body (из основной try); это будет содержать информацию обо всех ошибках в удобочитаемой форме. Если второе слово списка присутствует и непусто, оно именует переменную, в которую будет помещен словарь опций интерпретатора на момент завершения выполнения body.

Слово script каждого обработчика также всегда интерпретируется одинаково: как сценарий Tcl для оценки соответствия предложения. Если script представляет собой литерал «-», а обработчик не последний, script следующего обработчика вызывается вместо этого (как и с командой switch).

Обратите внимание, что предложения handler сопоставляются по порядку, и что всегда выбирается первое совпадающее. Будет выбрано не более одного предложения handler . Как следствие, on error будет маскироваться любая последующая trap в try. Также обратите внимание, что on error эквивалентно trap {} .

Если исключение (то есть любой результат, отличный от ok ) возникает во время выполнения либо предложения handler, либо предложения finally, словарь состояния исходного исключения будет добавлен в словарь статусов нового исключения под ключом -during.

ПРИМЕРЫ

Убедитесь, что файл закрыт, несмотря ни на что:

set f [open /some/file/name a]
try {
    puts $f "some message"
    # ...
} finally {
    close $f
}

Обработка различных причин, по которым файл нельзя открыть для чтения:

try {
    set f [open /some/file/name w]
} trap {POSIX EISDIR} {} {
    puts "failed to open /some/file/name: it's a directory"
} trap {POSIX ENOENT} {} {
    puts "failed to open /some/file/name: it doesn't exist"
}
Copyright © 2008 Donal K. Fellows

воскресенье, 27 июня 2021 г.

Различия между PyQt6 и PyQt5

Различия между PyQt6 и PyQt5

Здесь приводится обзор различий между PyQt6 и PyQt5. Это не полный и детальный список, для детального описания различий обратитесь в справочник Qt v6 и Qt v5 APIs.

  • Все поименованные enums теперь применяются как подклассы стандартного класса языка Python Enum. (PyQt5 использует IntEnum для перечислений с ограниченной областью видимости и настраиваемого типа для традиционных именованных перечислений).

  • Qt предоставляет шаблонный класс QFlags как безопасный для типов способ использования значений перечисления, которые можно комбинировать как набор флагов. Имя класса часто является формой множественного числа от имени перечисления. PyQt5 реализует оба из них как отдельные типы. PyQt6 вместо этого объединяет их как один тип, используя имя перечисления в качестве подкласса Flag.

  • Класс декоратор Q_CLASSINFO() заменен  pyqtClassInfo().

  • Q_ENUM(), Q_ENUMS(),Q_FLAG() и Q_FLAGS() заменены на класс декоратор pyqtEnum().

  • Все  методы exec_() и print_() удалены.

  • qApp удален.

  • Словарь PYQT_CONFIGURATION удален.

  • Модуль Qt удален.

  • Привязки для классов Qt (под лицензией GPL), которые реализуют поддержку сетевой авторизации, перемещены в отдельный дополнительный проект PyQt6-NetworkAuth. Это означает, что все библиотеки, обернутые самим PyQt6, находятся под лицензией LGPL.

  • pylupdate6 это новое приложение, написанное полностью на языке Python. Оно может не читать файл .pro для того чтобы определить имена файлов .py для трансляции.

  • Поддержка для ресурсной системы Qt удалена (т.е. нет pyrcc6).

  • Требуется Python версии v3.6.1 или выше.

В Qt версии v6 некоторые функции из Qt v5 помечены как устаревшие. Эти функции не поддерживаются в PyQt6.

 

понедельник, 6 апреля 2020 г.

Использование навигационных карт в X-Plane 11

Использование навигационных карт в X-Plane 11

Навигационные карты X-Plane представлены в нескольких различных вариантах, каждая из которых полезна для определенной ситуации. Эти навигационные карты открываются нажатием клавиши «m» или щелчком значка маркера карты в меню. Вы можете выбрать один из трех режимов: VFR секционный, IFR Low Enroute и IFR High Enroute.
Карта VFR Sectional предназначена для использования в соответствии с визуальными правилами полета. Карта IFR Low Enroute используется в качестве навигационной карты правил полетов по приборам на малых высотах пилотами воздушных судов с поршневыми (воздушными винтами). Карта IFR High Enroute, по сути, такая же, как и IFR Low Enroute, но отображает авиационные пути среднего и высокого уровня вместо низкоуровневых. Он показывает только информацию, представляющую интерес для пилотов, летящих выше 18 000 футов и использующих векторные воздушные трассы, которые намного длиннее, на основе больших VOR с более длинными дистанциями.
Карты предоставляют много информации о районе, где расположен ваш самолет, включая топографию и выбираемые NAVAID. Каждая карта состоит из отмеченных тонкими черными линиями, которые делают «коробки» официально названными «Четырехугольниками». Каждое поле составляет 1/4 градуса широты и долготы. Толстые синие и серые линии, проходящие через карты, являются воздушными трассами, которые в основном похожи на шоссе в небе. Этим воздушным трассам присваиваются имена (например, V503), и они используются органами управления воздушным движением для назначения разрешений. Треугольники вдоль них - это «исправления».
Небольшие аэропорты обозначены кружочками с надписями, тогда как крупные аэропорты с полными взлетно-посадочными полосами. Аэропорты, выделенные синим цветом на карте сечения VFR, имеют контрольные башни в реальном мире. Обратите внимание, что обсуждение навигационных средств (NAVAID) этих карт (маяки ILS, VOR и NDB) можно найти ниже, в разделе «Современные средства навигации».
Чтобы переместить вид вокруг карты, вы можете щелкнуть карту и перетащить. Вы также можете увеличивать и уменьшать масштаб с помощью колеса прокрутки мыши. Кроме того, вы можете использовать кнопки управления просмотром, расположенные в верхнем левом углу окна карты, чтобы изменить вид. Используйте значки плюс или минус для увеличения или уменьшения соответственно.
Нажмите значок цели, чтобы центрировать вид на самолете. Это также заблокирует вид карты на самолет, так что во время полета карта будет прокручиваться под ним, и самолет будет оставаться в центре. Перетащите в любое место на карте, чтобы сломать замок. Коснитесь значка со стрелкой, чтобы изменить положение верхней части карты на север или курс самолета. Во втором случае, если самолет летит на юг, верх карты будет на юге. Если самолет наклонится к востоку, карта будет автоматически поворачиваться, а восток будет сверху.
Нажмите на что-нибудь на карте, чтобы получить больше информации об этом. Например, если вы щелкнете по своему самолету, появится окно Инспектора с его названием, курсом, высотой, скоростью и углом набора высоты, большинство из которых вы также можете редактировать из окна. Нажатие на аэропорт позволит вам выбрать новую взлетно-посадочную полосу или последний заход на посадку, или просмотреть детали, такие как погодные условия и частоты связи. Нажмите на NAVAID, такой как VOR, чтобы настроить радио одним нажатием кнопки.
В правой части окна карты вы можете изменить то, что отображается на карте. В разделе «Слои» вы можете использовать выпадающие меню для отображения ветра или облаков и осадков в режиме реального времени на карте. Вы можете установить флажки, чтобы переключить траекторию полета, поднять компас вокруг вашего самолета или отключить маяки ILS с подветренной стороны.
Наконец, переключение слайдера «Glideslope» отобразит вертикальный профиль полета в нижней части экрана карты. Вы можете изменить подход, отображаемый там, используя раскрывающееся меню «Подход».

X-Plane 11, 12 - любитель, Фото любитель со стажем

Постоянные читатели

Архив блога