how to set the QDockWidget Group color? - qt

The picture bellow is a pyside6 application's capture, I move all QDockWidget into a single group, but the group's header's background has two different color. How to change them into a single color(qss or code)? Thanks very much!
Environment:
macos 11.6.5
python 3.9.12
pyside6 6.3.1
Reproduction Code:
# coding: utf-8
import sys
import platform
from PySide6.QtWidgets import QApplication, QMainWindow, QDockWidget, QTextEdit
from PySide6.QtCore import Qt, QSysInfo
def main():
app: QApplication = QApplication(sys.argv)
window = QMainWindow()
dock1 = QDockWidget("dock1")
dock2 = QDockWidget("dock2")
for dock in [dock1, dock2]:
dock.setFeatures(dock.DockWidgetFloatable | dock.DockWidgetMovable)
window.addDockWidget(Qt.LeftDockWidgetArea, dock1)
window.addDockWidget(Qt.RightDockWidgetArea, dock2)
os_info = QTextEdit()
os_info.setText(platform.version())
dock1.setWidget(os_info)
qt_info = QTextEdit()
info = QSysInfo()
qt_info.setText(f"{info.kernelVersion()}, {info.prettyProductName()}, {info.productVersion()}")
dock2.setWidget(qt_info)
window.show()
app.exec()
if __name__ == '__main__':
main()

I have solve it with the signal method myself:
# coding: utf-8
import sys
import platform
from PySide6.QtWidgets import QApplication, QMainWindow, QDockWidget, QTextEdit, QTabBar
from PySide6.QtCore import Qt, QSysInfo
def main():
app: QApplication = QApplication(sys.argv)
window = QMainWindow()
dock1 = QDockWidget("dock1")
dock2 = QDockWidget("dock2")
for dock in [dock1, dock2]:
dock.setFeatures(dock.DockWidgetFloatable | dock.DockWidgetMovable)
window.addDockWidget(Qt.LeftDockWidgetArea, dock1)
window.addDockWidget(Qt.RightDockWidgetArea, dock2)
os_info = QTextEdit()
os_info.setText(platform.version())
dock1.setWidget(os_info)
qt_info = QTextEdit()
info = QSysInfo()
qt_info.setText(f"{info.kernelVersion()}, {info.prettyProductName()}, {info.productVersion()}")
dock2.setWidget(qt_info)
style = """
QTabBar {
background-color: #ff0000;
}
"""
app.setStyleSheet(style)
# force update theme on dock change
for w in window.children():
if isinstance(w, QDockWidget):
w.dockLocationChanged.connect(lambda: app.setStyleSheet(style))
window.show()
app.exec()
if __name__ == '__main__':
main()

Related

Qt: QMediaPlayer.setSource() was blocking the GUI so I moved it to a separate thread; am I doing this right?

Running this code:
from PySide6 import QtWidgets as qtw
from PySide6 import QtMultimedia as qtm
from PySide6 import QtMultimediaWidgets as qtmw
from PySide6 import QtCore as qtc
app = qtw.QApplication()
path = "video.mp4"
video_widget = qtmw.QVideoWidget()
video_widget.show()
media_player = qtm.QMediaPlayer()
media_player.setVideoOutput(video_widget)
media_player.mediaStatusChanged.connect(media_player.play)
media_player.setSource(path)
qtc.QTimer.singleShot(2000, lambda: media_player.setSource(''))
app.exec()
, you will notice that when media_player.setSource('') is called after 2000 milliseconds, the GUI becomes unresponsive for a good second or so. And it seems like it is not possible to move only the setSource() call to a separate thread, I get a warning saying QObject::killTimer: Timers cannot be stopped from another thread (you can replicate this by replacing qtc.QTimer... call with qtc.QThreadPool.globalInstance().start(lambda: media_player.setSource(''))). So, after hours of pondering, as a work around, I moved the entire QMediaPlayer instance and all objects related to it to a thread of its own and used QVideoSink's videoFrameChanged signal to update the video on the video widget:
from PySide6 import QtWidgets as qtw
from PySide6 import QtMultimedia as qtm
from PySide6 import QtMultimediaWidgets as qtmw
from PySide6 import QtCore as qtc
path = "video.mp4"
class VideoPlayer(qtmw.QVideoWidget):
_stop_worker_signal = qtc.Signal()
_initialize_media_player_signal = qtc.Signal()
_set_media_source_signal = qtc.Signal(str)
_play_media_signal = qtc.Signal()
_stop_media_signal = qtc.Signal()
_pause_media_signal = qtc.Signal()
def __init__(self) -> None:
super().__init__()
self._worker = Worker()
self._worker_thread = qtc.QThread()
self._worker.moveToThread(self._worker_thread)
self._stop_worker_signal.connect(self._worker.stop)
self._initialize_media_player_signal.connect(self._worker.create_media_player)
self._worker.video_sink_frame_changed_signal.connect(lambda frame: self.videoSink().setVideoFrame(frame))
self._set_media_source_signal.connect(self._worker.set_media_source)
self._stop_media_signal.connect(self._worker.stop_media)
self._worker_thread.start()
self._initialize_media_player_signal.emit()
self._set_media_source_signal.emit(path)
self.show()
def keyPressEvent(self, event):
if event.key() == qtc.Qt.Key.Key_Q:
self._set_media_source_signal.emit('')
def closeEvent(self, event: qtc.QEvent):
loop = qtc.QEventLoop()
self._worker.stopped_signal.connect(loop.exit)
self._stop_worker_signal.emit()
loop.exec()
self._worker_thread.exit()
class Worker(qtc.QObject):
video_sink_frame_changed_signal = qtc.Signal(qtm.QVideoFrame)
stopped_signal = qtc.Signal()
def create_media_player(self):
self._audio_output = qtm.QAudioOutput(qtm.QMediaDevices.defaultAudioOutput())
self._video_sink = qtm.QVideoSink()
self._video_sink.videoFrameChanged.connect(self.video_sink_frame_changed_signal)
self._media_player = qtm.QMediaPlayer()
self._media_player.setAudioOutput(self._audio_output)
self._media_player.setVideoSink(self._video_sink)
self._media_player.mediaStatusChanged.connect(self._media_player.play)
def set_media_source(self, source: str) -> None:
self._media_player.setSource(source)
def stop_media(self) -> None:
if not self._media_player.playbackState() == qtm.QMediaPlayer.PlaybackState.StoppedState:
self._media_player.stop()
def stop(self):
self._media_player.stop()
self._audio_output.deleteLater()
self._video_sink.deleteLater()
self._media_player.deleteLater()
self.stopped_signal.emit()
app = qtw.QApplication()
vp = VideoPlayer()
app.exec()
Now, there's no unresponsiveness in the GUI when setSource() is called but, as one can see, it's a pretty convoluted way to do this. Is there a better way?

How to overlay transparent image on qt camera?

Im trying to overlay an image with transparency on QCameraViewfinder. The following code works fine on windows, but ignores the transparency on raspberry pi.
Im using pyside2 version 5.11.2 on RPI4 and tried tranparent PNG and SVG files.
As an alternative, if Im using paintEvent to draw shapes, the viewfinder doesnt show video. My QPainter code is attached too.
from PySide2.QtMultimedia import QCamera, QCameraInfo
from PySide2.QtMultimediaWidgets import QCameraViewfinder
from PySide2 import QtCore, QtGui
from PySide2.QtWidgets import *
from PySide2.QtGui import *
from PySide2.QtCore import *
import sys
class ExampleWindow(QMainWindow):
def __init__(self, windowsize):
super().__init__()
self.windowsize = windowsize
self.initUI()
def initUI(self):
self.setFixedSize(self.windowsize)
widget = QWidget()
self.setCentralWidget(widget)
self.view_finder = QCameraViewfinder()
camerainfo = QCameraInfo.availableCameras()[0]
self.camera = QCamera(camerainfo)
self.camera.setViewfinder(self.view_finder)
self.camera.start()
layout_box = QHBoxLayout(widget)
layout_box.setContentsMargins(0, 0, 0, 0)
layout_box.addWidget(self.view_finder)
pixmap = QPixmap('crosshair3.png')
self.image = QLabel(widget)
self.image.setPixmap(pixmap)
self.image.setFixedSize(pixmap.size())
hw = pixmap.size().width()/2
hh = pixmap.size().height()/2
self.image.move(self.rect().center().x()-hw, self.rect().center().y()-hh)
if __name__ == '__main__':
app = QApplication(sys.argv)
screensize = app.desktop().availableGeometry().size()
ex = ExampleWindow(screensize)
ex.show()
sys.exit(app.exec_())
When using QPainter there is no video on the viewfinder:
class MyQCameraViewfinder(QCameraViewfinder):
def __init__(self, parent=None):
super().__init__(parent)
def paintEvent(self, event):
paint = QtGui.QPainter()
paint.begin(self)
paint.setRenderHint(QtGui.QPainter.Antialiasing)
paint.setPen(QtCore.Qt.black)
paint.setBrush(QtCore.Qt.white)
paint.drawEllipse(QtCore.QRect(17, 22, 50, 50))
paint.end()
on windows 11:
on rpi 4:

How to import __feature__ of PySide6?

from PySide6.__feature__ import snake_case, true_property
from PySide6.QtWidgets import QMainWindow, QWidget, QHBoxLayout, QApplication
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.main_layout = QHBoxLayout()
self.container = QWidget()
self.container.set_layout(self.main_layout)
if __name__ == '__main__':
app = QApplication([])
main_window = MainWindow()
main_window.show()
app.exec()
I got an error message when trying to run the above code:
ModuleNotFoundError: No module named 'PySide6.__feature__'
If I break the first line into
import PySide6
from __feature__ import snake_case, true_property
the code could run but PyCharm complains that
Unresolved reference: __feature__
How could I fix it?
Thanks for your help.

Pyside: QNetworkAccessManager sends no Request

I tried to establish a network connection with PySide (Ubuntu 15.04, Python3.4, PySide 1.2.4). I used the example code from the documentation.
The QNetworkAccessManager does not send the request and I recieve no answer. I checked the Network state with QNetworkSession(QNetworkConfigurationManager().defaultConfiguration()).State() but it says the State is invalid. This seems to make no sense since I am on a desktop pc with a network connection via ethernet cable.
My complete example for the test is the following code:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PySide.QtGui import QApplication
from PySide.QtCore import QUrl
from PySide.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkSession, QNetworkConfigurationManager
def replyFinished(reply):
print(reply)
if __name__ == "__main__":
app = QApplication(sys.argv)
manager = QNetworkAccessManager()
manager.finished.connect(replyFinished)
print(QNetworkSession(QNetworkConfigurationManager().defaultConfiguration()).State())
print("Sending request")
print(manager.get(QNetworkRequest(QUrl("http://www.heise.de/ct/"))))
This prints
PySide.QtNetwork.QNetworkSession.State.Invalid
Sending request
<PySide.QtNetwork.QNetworkReply object at 0x7f4b59c9af08>
but it should display the PySide.QtNetwork.QNetworkReply object twice.
My example was too small. I realized this because of the comment of Pavel Strakhov. I extended it to display a window with a button. By clicking the button it connects successfully. QNetworkSession(QNetworkConfigurationManager().defaultConfiguration()).State() is still invalid but it works.
This is the working code:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PySide.QtGui import QApplication, QWidget, QBoxLayout, QPushButton
from PySide.QtCore import QUrl
from PySide.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkSession, QNetworkConfigurationManager
class Window(QWidget):
def __init__(self):
super().__init__()
self.manager = QNetworkAccessManager()
self.manager.finished.connect(self.reply_finished)
layout = QBoxLayout(QBoxLayout.TopToBottom)
button = QPushButton("connect")
button.clicked.connect(self.network_connect)
layout.addWidget(button)
self.setLayout(layout)
self.setWindowTitle("Network test")
self.setGeometry(100, 100, 200, 150)
self.show()
def network_connect(self):
print(QNetworkSession(QNetworkConfigurationManager().defaultConfiguration()).State())
request = QNetworkRequest(QUrl("http://example.org"))
print("Sending request")
self.manager.get(request)
def reply_finished(self, reply):
print(reply)
print(reply.readData(500))
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
app.exec_()

PyQT5 menu not visible

When executing this little PyQT5 script, I can't see the menu; it just displays an empty window (no errors or warnings) on ubuntu 14.04.
from PyQt5 import QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow,self).__init__()
self.createUI()
def doAction(self):
print('action')
def createUI(self):
self.setWindowTitle('Test')
menu = self.menuBar().addMenu('File')
action = menu.addAction('Action')
action.triggered.connect(self.doAction)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
window.setGeometry(400, 200, 200, 200)
sys.exit(app.exec_())
Any ideas?
I had the same problem
Try to set native menu bar flag as false like this:
menu.setNativeMenuBar(False)

Resources