tl: dr;
Используйте менеджеры по расположению.
Объяснение
Что ж, похоже, вы случайно обнаружили ( возможную ) ошибку, выполнив что-то действительно не так.
QVideoWidget - это виджет, который на более сложен, чем кажется , поскольку он взаимодействует с базовой графической системой ОС и, чтобы правильно отображать его содержимое (видео), он имеет , чтобы быть активно уведомленным о его геометрии.
Проще говоря, QVideoWidget напрямую не показывает «картинки» видео, которое показывает QMediaPlayer, но сообщает операционной системе сделать это (ну, не совсем, но мы не будем обсуждать это здесь). Это связано с тем, что для отображения видео может использоваться некоторое аппаратное ускорение или некоторая обработка (например, для HDR-видео), аналогично тому, что делает графика 3D / OpenGL.
Когда программа собирается отображать некоторые данные ( Управляемое системой) видео, оно имеет , чтобы сообщить ОС о доступной геометрии для этого видео, чтобы ОС могла показывать его в правильных координатах и, возможно, применять изменение размера, некоторую форму «отсечения» (если наложено другое окно, например) или любой другой уровень [post] обработки.
«Что-то действительно неправильное», о котором я говорил ранее, основано на том факте, что вы используете исправленный геометрии (размеры и позиции) для обоих виджетов видео, и я думаю , что Qt не может уведомить систему об этих геометриях сразу для нескольких виджетов, если это происходит за до окно видео фактически отображается (как в «показанном»).
Почему это действительно неправильно, кроме рассматриваемой проблемы?
* 103 1 * Каждое из наших устройств в основном
уникально : то, что вы видите на своем устройстве, будет отображаться (возможно, радикально) иначе, чем на других.
Существует множество причин, в том числе:
- Операционная система (и версии) и ее поведение;
- Размер экрана и DPI (например, я не смог просмотреть полное окно вашего кода, так как я меньший экран);
- по умолчанию / настраиваемый размер системного шрифта; наиболее важно, если шрифт по умолчанию очень большой, виджеты могут перекрываться;
- дальнейшая настройка (например, поля по умолчанию и интервалы);
- , если интерфейс «адаптивный», пользователь должен иметь возможность изменять размер интерфейса:
- , если у пользователя экран меньшего размера, пользовательский интерфейс должен быть изменяемого размера, чтобы все было видно, вместо того, чтобы иметь необходимость перемещать окно за пределы экрана (что-то, что иногда невозможно: например, на Windows вы не можете переместить окно выше верхнего поля экрана);
- , если у пользователя экран большего размера (или используется настройка с очень высоким DPI), интерфейс будет слишком маленьким, а некоторые элементы могут быть трудными для чтения или взаимодействия;
Это причина, по которой почти любой современный веб-сайт использует «отзывчивые» макеты, которые адаптируют содержимое в соответствии с экраном устройства, на котором они будут отображаться.
Решение очень простое, и также решит большой вопрос о GUI: избегайте фиксированной геометрии для GUI и используйте вместо этого менеджеры компоновки.
Обратите внимание, что вы все еще можете использовать фиксированные размеры (не позиции, размеры!): это не такая уж большая проблема, но использование менеджеров компоновки поможет вам с этим, переместив все элементы в соответствии с доступным пространством.
Причина в том, что менеджеры компоновки гарантируют, что любой операция изменения размера (то, что также происходит много раз, как только окно показывается в первый раз) также уведомляется системой, когда это требуется (как, например, адаптация вывода QVideoWidget).
Если вы Если вы хотите сохранить макет «нижний правый / верхний левый», вы все равно можете это сделать: установить основной QGridLayout для виджета (DNN_Viewer
), создать другой макет сетки для каждого игрока и добавить этот макет в основной.
Структура будет выглядеть примерно так:
+------------------------- DNN_Viewer -------------------------+
| | +------ player2Layout ------+ |
| | | | |
| | | vw2 | |
| | | | |
| | +-------+-------------------+ |
| | | pb2 | sld1 | |
| | +-------+-------------------+ |
+------------------------------+-------------------------------+
| +------ player1Layout------+ | |
| | | | |
| | vw1 | | |
| | | | |
| +-------+------------------+ | |
| | pb1 | sld2 | | |
| +-------+------------------+ | |
+------------------------------+-------------------------------+
class DNN_Viewer(QWidget):
# ...
def init_gui(self):
# create a grid layout for the widget and automatically set it for it
layout = QtWidgets.QGridLayout(self)
player1Layout = QtWidgets.QGridLayout()
# add the layout to the second row, at the first column
layout.addLayout(player1Layout, 1, 0)
# video for weights and gradients
self.vw1 = QVideoWidget(self)
# add the video widget at the first row and column, but set its column
# span to 2: we'll need to add two widgets in the second row, the play
# button and the slider
player1Layout.addWidget(self.vw1, 0, 0, 1, 2)
# ...
self.pb2 = QPushButton(self)
# add the button to the layout; if you don't specify rows and columns it
# normally means that the widget is added to a new grid row
player1Layout.addWidget(self.pb2)
# ...
self.sld1 = QSlider(Qt.Horizontal,self)
# add the slider to the second row, besides the button
player1Layout.addWidget(self.sld1, 1, 1)
# ...
player2Layout = QtWidgets.QGridLayout()
# add the second player layout to the first row, second column
layout.addLayout(player2Layout, 0, 1)
self.vw2 = QVideoWidget(self)
# same column span as before
player2Layout.addWidget(self.vw2, 0, 0, 1, 2)
# ...
self.pb3 = QPushButton(self)
player2Layout.addWidget(self.pb3, 1, 0)
# ...
self.sld2 = QSlider(Qt.Horizontal,self)
player2Layout.addWidget(self.sld2, 1, 1)
Это решит вашу главную проблему (и многие другие, которые вы не рассмотрели).
Некоторые дополнительные предложения:
- использовать более описательные имена переменных; такие вещи, как
pb2
или lb23
кажутся более простыми в использовании, и вы можете подумать, что короткие переменные равны меньшему времени, затрачиваемому на набор текста. На самом деле, есть нет заключительного преимущества в этом: хотя может быть верно, что более короткие имена переменных могут улучшить скорость компиляции (особенно для интерпретируемых языков, таких как Python), в конце почти нет никаких преимуществ; напротив, вам придется помнить, что означает «sld2», в то время как что-то вроде «player2Slider» намного более наглядно и проще для чтения (что означает, что вы будете читать и отлаживать быстрее, и люди, читающие ваш код, поймут это и поможет вам гораздо проще) - по той же причине, что и выше, используйте более описательные имена функций: имена вроде
cb_mp1_3
буквально ничего не значат; наименование действительно важно, и улучшение скорости запуска, о котором говорилось выше, практически невозможно на современных компьютерах; это также помогает вам получить помощь от других: потребовалось больше времени, чтобы понять, в чем заключалась ваша проблема, чем понять, что делает ваш код, поскольку все эти имена были для меня почти бессмысленными; читайте больше на официальном руководстве по стилю для Python кода (он же, PEP 8); - используйте комментарии с умом:
- избегайте чрезмерного комментирования, это отвлекает внимание теряя при этом большую часть своей цели (в то время как «пусть код будет документацией» - хорошая идея, не переоценивайте ее)
- избегайте «причудливых» отформатированных комментариев: они могут показаться крутыми, но в конец, с которым они раздражают; если вы хотите прокомментировать функцию, чтобы лучше описать, что она делает, используйте функцию тройных кавычек, которую Python уже предоставляет; также учтите, что многие службы совместного использования кода имеют ограничения по столбцам (и среди них StackOverflow): людям нужно будет прокрутить каждую строку , чтобы прочитать соответствующий комментарий;
- , если вам нужно описание для однострочная функция, возможно, что функция не является описательной, как могла бы или должна быть, как объяснено выше;
- в большей степени соответствует разделению пустых строк между функциями или классами: Python был создан для удобства чтения, и хорошо следовать этому принципу;
- не перезаписывать существующие имена атрибутов:
self.width()
и self.height()
являются базовыми свойствами всех QWidgets, и вам, возможно, потребуется часто обращаться к ним; - более согласованно с импортом, который вы используете, особенно со сложными модулями, такими как Qt: вам следует либо импортировать субмодули (
from PyQt5 import QtWidgets, ...
) или отдельные классы (from PyQt5.QtWidgets import QApplication, ...
); обратите внимание, что, хотя последний может считаться более "pythoni c", с Qt это обычно сложно, так как он имеет сотни классов (и вам может понадобиться десятки из них в каждом скрипте), тогда вам всегда нужно помнить, чтобы добавить каждый класс каждый раз, когда вам это нужно, и вы можете импортировать ненужные классы, которые больше не используете; этот подход не сильно улучшит производительность, по крайней мере, с Qt, особенно если вы забудете удалить ненужный импорт (в вашем случае возможное преимущество импорта отдельных классов полностью отменяется тем фактом, что существует как минимум 10 импортированных классов, которые фактически никогда не используется); - избегайте ненужного импорта из других платформ, если они не являются абсолютно необходимыми: если вам нужно знать геометрию экрана, используйте
QApplication.screens()
, не импортируйте Tk просто за это;