PyQt, How to switch transparent-setting for subwindow - pyqt5

I want switch WindowTransparentForInput statement of sub-window.
At following code, I wrote, subwindow will close instead switch the statement.
Could you please to point the problem?
import sys
from PyQt5 import QtWidgets as qtw, QtGui as qtg, QtCore as qtc
class Main(qtw.QWidget):
def __init__(self):
super().__init__()
self.mainWindow = qtw.QWidget(self)
self.mainWindow.setGeometry(100,100,200,200)
label = qtw.QLabel('Main window', self)
self.switch = qtw.QCheckBox('Transparent for input on sub window', self)
self.switch.setChecked(False)
self.switch.stateChanged.connect(self.switchAction)
mainLayout = qtw.QVBoxLayout()
self.setLayout(mainLayout)
mainLayout.addWidget(label)
mainLayout.addWidget(self.switch)
self.subwindow = qtw.QWidget()
self.subwindow.setGeometry(150,100,200,200)
sublabel = qtw.QLabel('Sub window', self.subwindow)
self.show()
self.subwindow.show()
def switchAction(self):
if self.switch.isChecked:
self.subwindow.setWindowFlags(qtc.Qt.WindowTransparentForInput | qtc.Qt.FramelessWindowHint)
else:
self.subwindow.setWindowFlags(qtc.Qt.FramelessWindowHint)
if __name__ == '__main__':
app = qtw.QApplication(sys.argv)
mw = Main()
sys.exit(app.exec())

It was solved by modifying switchAction() as follow.
I'm sorry for your notation.
def switchAction(self):
if self.switch.isChecked():
self.subwindow.close()
self.subwindow.setWindowFlags(self.subwindow.windowFlags() | qtc.Qt.WindowTransparentForInput)
self.subwindow.show()
else:
self.subwindow.close()
self.subwindow.setWindowFlags(self.subwindow.windowFlags() & ~qtc.Qt.WindowTransparentForInput)
self.subwindow.show()

Related

How to get log and show it on GUI from multiprocessing work?

I try to get logs from multiprocessing work and show them on GUI.
Based on this document
gui.py:
from PyQt5 import QtCore, QtWidgets
import logging
from log_test import main
Signal = QtCore.pyqtSignal
Slot = QtCore.pyqtSlot
class Signaller(QtCore.QObject):
signal = Signal(str, logging.LogRecord)
class QtHandler(logging.Handler):
def __init__(self, slotfunc, *args, **kwargs):
super().__init__(*args, **kwargs)
self.signaller = Signaller()
self.signaller.signal.connect(slotfunc)
def emit(self, record):
s = self.format(record)
self.signaller.signal.emit(s, record)
class Worker(QtCore.QObject):
finished = Signal()
#Slot()
def start(self):
main()
self.finished.emit()
class Ui_Dialog(QtCore.QObject):
def __init__(self):
super().__init__()
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.setEnabled(True)
Dialog.resize(530, 440)
self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
self.verticalLayout.setObjectName("verticalLayout")
self.button = QtWidgets.QPushButton(Dialog)
self.button.setText("start working")
self.verticalLayout.addWidget(self.button)
self.logWidget = QtWidgets.QPlainTextEdit(Dialog)
self.logWidget.setReadOnly(True)
self.verticalLayout.addWidget(self.logWidget)
self.handler = QtHandler(self.update_log_gui)
logging.getLogger('log').addHandler(self.handler)
self.button.clicked.connect(self.start_work)
#Slot(str, logging.LogRecord)
def update_log_gui(self, status, record):
self.logWidget.appendPlainText(status)
def config_thread(self):
self.worker_thread = QtCore.QThread()
self.worker_thread.setObjectName('WorkerThread')
self.worker = Worker()
self.worker.moveToThread(self.worker_thread)
self.worker_thread.started.connect(self.worker.start)
self.worker.finished.connect(self.worker_thread.quit)
self.worker.finished.connect(self.worker.deleteLater)
self.worker_thread.finished.connect(self.worker_thread.deleteLater)
self.worker_thread.finished.connect(lambda: self.button.setEnabled(True))
pass
def start_work(self):
self.config_thread()
self.worker_thread.start()
self.button.setEnabled(False)
if __name__ == "__main__":
import sys
QtCore.QThread.currentThread().setObjectName('MainThread')
app = QtWidgets.QApplication(sys.argv)
Dialog = QtWidgets.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
log_test.py (where multiprocessing work happens)
import logging
import time
from multiprocessing import Pool
def f(name):
logger = logging.getLogger('log.' + name)
logger.error('hello there 1')
time.sleep(0.5)
logger.error('hello there 2')
time.sleep(0.5)
logger.error('hello there 3')
time.sleep(0.5)
def main():
with Pool(5) as p:
p.map(f, ['aaa', 'bbb', 'ccc'])
At first time, I thought working in single thread causing the problem. So I added QThread to this.
Later I discovered in debug, it seems to QtHandler.emit() works fine at receiving log messages. But the connected slot function, update_log_gui() does not work somehow.
I solved it myself.
#Alexander was right. Indeed my QtHandler has a problem when multiprocessing but I don't know exactly why. Rather, you wanna implement QueueHandler. An example in this article (Written in Korean) helped me.
from PyQt5 import QtCore, QtWidgets
import logging
import multiprocessing
from log_test import main
Signal = QtCore.pyqtSignal
Slot = QtCore.pyqtSlot
QThread = QtCore.QThread
class Signaller(QtCore.QObject):
signal = Signal(logging.LogRecord)
class Worker(QtCore.QObject):
finished = Signal()
def __init__(self, q):
super().__init__()
self.q = q
#Slot()
def start(self):
main(self.q)
self.finished.emit()
class Consumer(QThread):
popped = Signaller()
def __init__(self, q):
super().__init__()
self.q = q
self.setObjectName('ConsumerThread')
def run(self):
while True:
if not self.q.empty():
record = self.q.get()
self.popped.signal.emit(record)
class Ui_Dialog(QtCore.QObject):
def __init__(self, app):
super().__init__()
self.app = app
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.setEnabled(True)
Dialog.resize(530, 440)
self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
self.verticalLayout.setObjectName("verticalLayout")
self.button = QtWidgets.QPushButton(Dialog)
self.button.setText("start working")
self.verticalLayout.addWidget(self.button)
self.logWidget = QtWidgets.QPlainTextEdit(Dialog)
self.logWidget.setReadOnly(True)
self.verticalLayout.addWidget(self.logWidget)
self.button.clicked.connect(self.start_work)
self.q = multiprocessing.Manager().Queue()
self.consumer = Consumer(self.q)
self.consumer.popped.signal.connect(self.update_log_gui)
self.consumer.start()
app.aboutToQuit.connect(self.shutdown_consumer)
#Slot(logging.LogRecord)
def update_log_gui(self, record):
self.logWidget.appendPlainText(str(record.msg))
def config_thread(self):
self.worker_thread = QtCore.QThread()
self.worker_thread.setObjectName('WorkerThread')
self.worker = Worker(self.q)
self.worker.moveToThread(self.worker_thread)
self.worker_thread.started.connect(self.worker.start)
self.worker.finished.connect(self.worker_thread.quit)
self.worker.finished.connect(self.worker.deleteLater)
self.worker_thread.finished.connect(self.worker_thread.deleteLater)
self.worker_thread.finished.connect(lambda: self.button.setEnabled(True))
def start_work(self):
self.config_thread()
self.worker_thread.start()
self.button.setEnabled(False)
def shutdown_consumer(self):
if self.consumer.isRunning():
self.consumer.requestInterruption()
self.consumer.quit()
self.consumer.wait()
if __name__ == "__main__":
import sys
QtCore.QThread.currentThread().setObjectName('MainThread')
app = QtWidgets.QApplication(sys.argv)
Dialog = QtWidgets.QDialog()
ui = Ui_Dialog(app)
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())

Calling method from other class

I'm very new to PyQt5, and I'm trying to make an interactive gui for plotting of data. However, this problem may well be completely unrelated to PyQt5 and more a problem with my understanding of object oriented programming in general.
I have a MainWindow class, a SupportClass1 and a SupportClass2. When I make an instance of SupportClass1, I want to call the method DoSomething in the MainWindow class by referring to the object window, but I get the error message NameError: name 'window' is not defined.
I have no problems creating a method in the SupportClass2 and calling that from the MainWindow class so I get the impression that I have not instantiated the MainWindow class correctly which I don't understand as I thought I had defined window as an instace of the MainWindow class.
Can anyone help me understand what is wrong in my logic and how to solve this problem?
from PyQt5 import QtWidgets, QtCore
from pyqtgraph import PlotWidget, plot
import pyqtgraph as pg
import sys
import os
from random import randint
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.graphWidget = pg.PlotWidget()
self.x = list(range(100))
self.y = [randint(0,100) for _ in range(100)]
self.graphWidget.setBackground('w')
pen = pg.mkPen(color=(255, 0, 0))
self.data_line = self.graphWidget.plot(self.x, self.y, pen=pen)
self.button = QPushButton('Test')
self.button.clicked.connect(self.InstantiateSupportClasses)
self.gui_box = QVBoxLayout()
self.gui_box.addWidget(self.graphWidget)
self.gui_box.addWidget(self.button)
self.setLayout(self.gui_box)
self.setGeometry(300, 300, 300, 150)
self.setWindowTitle('Test application')
self.show()
def InstantiateSupportClasses(self):
supp_class2 = SupportClass2()
print(supp_class2.GetVariable())
supp_class1 = SupportClass1()
def DoSomething(self):
print('I did something!')
class SupportClass1():
def __init__(self):
window.DoSomething
class SupportClass2():
def __init__(self):
self.some_variable = 5
def GetVariable(self):
return self.some_variable
def main():
app = QApplication(sys.argv)
app.setStyle('Fusion')
window = MainWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()```
I see that you are using the "window" object from the "SupportClass1" class.
but that class does not recognize this object one solution is to insert that object to the "SupportClass1()"
from PyQt5 import QtWidgets, QtCore
from pyqtgraph import PlotWidget, plot
import pyqtgraph as pg
import sys
import os
from random import randint
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.graphWidget = pg.PlotWidget()
self.x = list(range(100))
self.y = [randint(0,100) for _ in range(100)]
self.graphWidget.setBackground('w')
pen = pg.mkPen(color=(255, 0, 0))
self.data_line = self.graphWidget.plot(self.x, self.y, pen=pen)
self.button = QPushButton('Test')
self.button.clicked.connect(self.InstantiateSupportClasses)
self.gui_box = QVBoxLayout()
self.gui_box.addWidget(self.graphWidget)
self.gui_box.addWidget(self.button)
self.setLayout(self.gui_box)
self.setGeometry(300, 300, 300, 150)
self.setWindowTitle('Test application')
self.show()
def InstantiateSupportClasses(self):
supp_class2 = SupportClass2()
print(supp_class2.GetVariable())
supp_class1 = SupportClass1(self)
def DoSomething(self):
print('I did something!')
class SupportClass1():
def __init__(self, window):
window.DoSomething()
class SupportClass2():
def __init__(self):
self.some_variable = 5
def GetVariable(self):
return self.some_variable
def main():
app = QApplication(sys.argv)
app.setStyle('Fusion')
window = MainWindow()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

how to transmit true value to formal parameter in decorator function(pyqtSlot())?

first, see code below:
import sys
from PyQt5.QtCore import (Qt, pyqtSignal, pyqtSlot)
from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider,
QVBoxLayout, QApplication)
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def printLabel(self, str):
print(str)
#pyqtSlot(int)
def on_sld_valueChanged(self, value):
self.lcd.display(value)
self.printLabel(value)
def initUI(self):
self.lcd = QLCDNumber(self)
self.sld = QSlider(Qt.Horizontal, self)
vbox = QVBoxLayout()
vbox.addWidget(self.lcd)
vbox.addWidget(self.sld)
self.setLayout(vbox)
self.sld.valueChanged.connect(self.on_sld_valueChanged)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('Signal & slot')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
I'm a little puzzled about how the true value in sld is transmitted to the formal parameter 'value' in the slot function : def sld_valChanged(self, value).
Because i can't see something like this: self.sld.valueChanged.connect(partial(self.sld_valChanged, self.sld.value))
Could someone explain that?

how to get id of checked group radio from radio button in pyqt5

Is there any way to get value of grouped radio buttons?
this code dont work for me:
self.pb1.clicked.connect(lambda : self.rbtn_1_state(self.rb1_1.ischecked(),self.rb1_2.ischecked()))
def rbtn_1_state(self, rb1_1_chk,rb1_2_chk):
print("radio button 1 function is called")
if rb1_1_chk:
rb1_state=[1,0]
if rb1_2_chk:
rb1_state = [0, 1]
else:
rb1_state = [0, 0]
Try it:
from PyQt5 import QtGui, QtCore, QtWidgets
class Window(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.groupBox = QtWidgets.QGroupBox()
self.rb1_1 = QtWidgets.QRadioButton("rb1_1", self.groupBox)
self.rb1_1.setChecked(True)
self.rb1_2 = QtWidgets.QRadioButton("rb1_2", self.groupBox)
self.hLayout = QtWidgets.QHBoxLayout()
self.hLayout.addWidget(self.rb1_1)
self.hLayout.addWidget(self.rb1_2)
self.lb1 = QtWidgets.QLabel()
self.pb1 = QtWidgets.QPushButton("pb1")
self.pb1.clicked.connect(lambda : self.rbtn_1_state(
self.rb1_1.isChecked(),
self.rb1_2.isChecked()))
self.vLayout = QtWidgets.QVBoxLayout(self)
self.vLayout.addWidget(self.lb1)
self.vLayout.addLayout(self.hLayout)
self.vLayout.addWidget(self.pb1)
def rbtn_1_state(self, rb1_1_chk, rb1_2_chk):
self.lb1.setText("rb1_1-> {} , rb1_2-> {}".format(rb1_1_chk, rb1_2_chk))
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
qt_app = Window()
qt_app.show()
sys.exit(app.exec_())

pyqt5 videowidget not showing in layout

I am writing a program with pyqt5 where pressing a button first cycles through some pictures then cycles through some videos.
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtMultimedia import *
from PyQt5.QtMultimediaWidgets import *
import glob
import argparse
import sys
class MainWindow(QMainWindow):
def __init__(self,args):
super(MainWindow, self).__init__()
self.setWindowTitle('Navon test')
self.setWindowFlags(Qt.FramelessWindowHint)
# exit option for the menu bar File menu
self.exit = QAction('Exit', self)
self.exit.setShortcut('Ctrl+q')
# message for the status bar if mouse is over Exit
self.exit.setStatusTip('Exit program')
# newer connect style (PySide/PyQT 4.5 and higher)
self.exit.triggered.connect(app.quit)
self.setWindowIcon(QIcon('icon.ico'))
self.centralwidget = CentralWidget(args)
self.setCentralWidget(self.centralwidget)
def keyPressEvent(self, QKeyEvent):
if QKeyEvent.key() == Qt.Key_Escape:
QCoreApplication.instance().quit()
self.centralwidget.startvid()
class CentralWidget(QWidget):
def __init__(self,args):
super(CentralWidget, self).__init__()
self.layout = QVBoxLayout()
self.layout.setAlignment(Qt.AlignCenter)
self.setLayout(self.layout)
self.player = QMediaPlayer(None, QMediaPlayer.VideoSurface)
self.vw = QVideoWidget()
self.player.setVideoOutput(self.vw)
def startvid(self):
self.layout.addWidget(self.vw)
url= QUrl.fromLocalFile(glob.glob("videos/*")[0])
content= QMediaContent(url)
self.player.setMedia(content)
self.player.setVideoOutput(self.vw)
self.player.play()
if __name__== "__main__":
parser = argparse.ArgumentParser()
#~ parser.add_argument("-nb","--nobox",action="store_true", help="do not wait for the box connection")
args = parser.parse_args()
app = QApplication(sys.argv)
mainwindow = MainWindow(args)
#~ mainwindow.showFullScreen()
mainwindow.show()
sys.exit(app.exec_())
I tried to paste the minimal code. The thing is, I press the button nothing shows, although I used examples like this one PyQt5 - Can't play video using QVideoWidget to test if playing the video is ok, and these work. It's as if it is not adding the widget to the layout or something. Any idea what might be wrong?
I had to use QGraphicsView to achieve what I wanted, here is a fix:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtMultimedia import *
from PyQt5.QtMultimediaWidgets import *
import glob
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.setWindowTitle('Navon test')
self.setWindowFlags(Qt.FramelessWindowHint)
# exit option for the menu bar File menu
self.exit = QAction('Exit', self)
self.exit.setShortcut('Ctrl+q')
# message for the status bar if mouse is over Exit
self.exit.setStatusTip('Exit program')
# newer connect style (PySide/PyQT 4.5 and higher)
self.exit.triggered.connect(app.quit)
self.setWindowIcon(QIcon('icon.ico'))
self.centralwidget = VideoPlayer()
self.setCentralWidget(self.centralwidget)
def keyPressEvent(self, QKeyEvent):
if QKeyEvent.key() == Qt.Key_Escape:
self.centralwidget.phaseQuit(2)
self.centralwidget.play()
class VideoPlayer(QWidget):
def __init__(self, parent=None):
super(VideoPlayer, self).__init__(parent)
self.mediaPlayer = QMediaPlayer(None, QMediaPlayer.VideoSurface)
self.videoItem = QGraphicsVideoItem()
self.videoItem.setSize(QSizeF(640, 480))
scene = QGraphicsScene(self)
graphicsView = QGraphicsView(scene)
scene.addItem(self.videoItem)
layout = QVBoxLayout()
layout.addWidget(graphicsView)
self.setLayout(layout)
self.mediaPlayer.setVideoOutput(self.videoItem)
self.counter = 0
def play(self):
if self.mediaPlayer.state() == QMediaPlayer.PlayingState:
pass
else:
self.mediaPlayer.setMedia(QMediaContent(QUrl.fromLocalFile(glob.glob("videos/*")[self.counter])))
self.mediaPlayer.play()
self.counter += 1
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
player = MainWindow()
player.show()
sys.exit(app.exec_())