QSoundEffect() doesn't play sounds when it's out of global scope - python

I'm making an app which copy files from one directory to another. I want it to produce sound when the process finishes. I can't figure out how to make QSoundEffect produce sounds when it's inside some function or class. The only time it works is when the code looks like the following:
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtMultimedia import *
app = QApplication(sys.argv)
win = QMainWindow()
filepath = "C:\Windows\Media\Windows Error.wav"
sound = QSoundEffect()
sound.setSource(QUrl.fromLocalFile(filepath))
sound.play()
win.show()
sys.exit(app.exec_())
Why doesn't it work when code looks like that? How to make it work in a function or a class?
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtMultimedia import *
def play_sound():
filepath = "C:\Windows\Media\Windows Error.wav"
sound = QSoundEffect()
sound.setSource(QUrl.fromLocalFile(filepath))
sound.play()
app = QApplication(sys.argv)
win = QMainWindow()
play_sound()
win.show()
sys.exit(app.exec_())

The problem is that "sound" is a local variable of the play_sound function so it will be eliminated when that method finishes executing which is almost instantaneous.
The solution is to extend the life cycle:
Python style: use a global variable
sound = None
def play_sound():
filepath = "C:\Windows\Media\Windows Error.wav"
global sound
sound = QSoundEffect()
sound.setSource(QUrl.fromLocalFile(filepath))
sound.play()
Qt style: set a parent
def play_sound():
filepath = "C:\Windows\Media\Windows Error.wav"
sound = QSoundEffect(QCoreApplication.instance())
sound.setSource(QUrl.fromLocalFile(filepath))
sound.play()

Related

why mne raw.plot doesn't block in a Qt Application on macOS?

I'm a beginner to Pyside6 and mne-python. I want the raw.plot to block so I can interact with the figure. However, the program continue to run and print 'after window close' after the figure opened. According to mne documentation, https://mne.tools/stable/generated/mne.viz.plot_raw.html?highlight=plot_raw#mne.viz.plot_raw
I have set the parameter block to True, but it doesn't work.
import matplotlib
import mne, sys
from PySide6.QtWidgets import QMainWindow, QPushButton, QApplication
matplotlib.rcParams['font.sans-serif'] = ['Arial Unicode MS']
matplotlib.rcParams['axes.unicode_minus'] = False
matplotlib.use('qtAgg')
class Test(QMainWindow):
def __init__(self):
super(Test, self).__init__()
self.button = QPushButton('Plot raw')
self.button.clicked.connect(self.Show)
self.setCentralWidget(self.button)
def Show(self):
sample_data_folder = mne.datasets.sample.data_path()
sample_data_raw_file = (sample_data_folder / 'MEG' / 'sample' /
'sample_audvis_filt-0-40_raw.fif')
raw = mne.io.read_raw_fif(sample_data_raw_file)
raw.plot(block=True)
print('after window close')
app = QApplication(sys.argv)
main = Test()
main.show()
app.exec()
sys.exit()
When the program is running, it shows some information like this:
CoreApplication::exec: The event loop is already running.
I search for it, but don't find a solution to my problem. Is this an waring or error and can anyone give me a solution?

Play audio with PyQt5

If in playAudioFile is performed, icon has changed but play() method dosen't work. Every time the condition is false.
This code works in some files, but I can't see a rule. Format files and file's long doesn't matter. I tried with .wav, .mp3 and .mp4 for a try.
In windows player every files work.
import sys
import os
from PyQt5.QtCore import QUrl
from PyQt5.uic import loadUi
from PyQt5.QtWidgets import QApplication, QStackedWidget, QMainWindow, QStyle
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
class Term2(QMainWindow):
def __init__(self):
super().__init__()
loadUi('screen2.ui', self)
# create player
self.player = QMediaPlayer()
self.choose_music()
self.btn_play.clicked.connect(self.playAudioFile)
# play audio
def choose_music(self):
filepath = os.path.join(os.getcwd(), 'pc.wav')
url = QUrl.fromLocalFile(filepath)
content = QMediaContent(url)
self.player.setMedia(content)
print(filepath)
def playAudioFile(self):
if self.player.state() == QMediaPlayer.PlayingState:
self.player.pause()
self.btn_play.setIcon(
self.style().standardIcon(QStyle.SP_MediaPlay)
)
else:
self.player.play()
self.btn_play.setIcon(
self.style().standardIcon(QStyle.SP_MediaPause)
)
app = QApplication(sys.argv)
widget = QStackedWidget()
t2 = Term2()
widget.setWindowTitle('Project)
widget.setFixedWidth(700)
widget.setFixedHeight(400)
widget.addWidget(t2)
widget.show()
sys.exit(app.exec_())
I created button in Qt Designer and import in loadUi('screen2.ui', self)
I would use an audio player from a different library, that one appears quite old. I would recommend looking into playsound or the pygame audio mixer.
Playsound works like this:
from playsound import playsound
playsound(path_to_audio_file)
It is quite limited in abilities, but is simple, reliable, and works with all mp3 and wav formats. Here is a tutorial: https://www.geeksforgeeks.org/play-sound-in-python/
If you want something a little more advanced I would try out pygames audio mixer, you can play stuff, control volumes, timings and more. At its most basic:
from pygame import mixer
mixer.init()
mixer.music.load(path_to_audio_file)
mixer.music.play()
The best format for the mixer is wav, but others would probably work.
A tutorial for this one:
https://www.geeksforgeeks.org/python-playing-audio-file-in-pygame/

how to restart the app with single process?

I want to restart my app, but I follow the tutorial and add systemtray icon. every time restart the app, the systemtray not disappear, I found the app not really restart by some reason.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class MainWindow(QMainWindow):
EXIT_CODE_REBOOT = 122
def __init__(self):
super().__init__()
self.restart_button = QPushButton('restart')
self.restart_button.clicked.connect(self.onRestart)
self.setCentralWidget(self.restart_button)
self.systray = QSystemTrayIcon(self)
icon = self.style().standardIcon(QStyle.SP_TrashIcon)
self.systray.setIcon(icon)
self.systray.show()
def onRestart(self, checked):
QApplication.exit(self.EXIT_CODE_REBOOT)
if __name__ == '__main__':
currentExitCode = MainWindow.EXIT_CODE_REBOOT
while currentExitCode == MainWindow.EXIT_CODE_REBOOT:
app = QApplication(sys.argv)
mainwindow = MainWindow()
mainwindow.show()
currentExitCode = app.exec()
app = None
each time restart the app, the previous system tray always existing, it is like it start an other process, I want the only process and not consuming any resources.
I tried your code and it works fine on Linux, but I also found similar reports (like this) about persistent icon after quit on Windows.
While doing a self.systray.hide() before quitting should be fine enough, I think that deleting the object from Qt's side (not by using del) might be better:
def onRestart(self, checked):
self.systray.deleteLater()
QApplication.exit(self.EXIT_CODE_REBOOT)

PyQt5 Changing native dialog save text?

Is it possible to change the Save/Open/Cancel text of native file dialogs called by Qt, e.g.
from PyQt5.Qt import *
import sys
app = QApplication(sys.argv)
OpenFile = QFileDialog()
OpenFile.getExistingDirectory()
I've tried following some examples in C++, e.g. this, but it doesn't seem to have any effect. Maybe I'm doing something wrong?
Try it:
from PyQt5.Qt import *
import sys
app = QApplication(sys.argv)
OpenFile = QFileDialog()
#OpenFile.getExistingDirectory()
OpenFile.setFileMode(QFileDialog.DirectoryOnly)
OpenFile.setLabelText(QFileDialog.Accept, "+Accept+")
OpenFile.setLabelText(QFileDialog.Reject, "-REJECT-")
OpenFile.show()
sys.exit(app.exec_())

Screenshot of a window using python

I'm trying to take a screenshot of the curent window using a python script on linux.
I curently have a script which takes a screenshot of the entire screen:
import sys
from PyQt4.QtGui import QPixmap, QApplication
from datetime import datetime
date = datetime.now()
filename = date.strftime('%Y-%m-%d_%H-%M-%S.jpg')
app = QApplication(sys.argv)
QPixmap.grabWindow(QApplication.desktop().winId()).save(filename, 'jpg')
But a would like to have only the selected window. I know that the problem comes from grabWindow. But I don't know how to resolve it.
simply replace
QApplication.desktop()
with the widget you want to take the screenshot of.
import sys
from PyQt4.QtGui import *
from datetime import datetime
date = datetime.now()
filename = date.strftime('%Y-%m-%d_%H-%M-%S.jpg')
app = QApplication(sys.argv)
widget = QWidget()
# set up the QWidget...
widget.setLayout(QVBoxLayout())
label = QLabel()
widget.layout().addWidget(label)
def shoot():
p = QPixmap.grabWindow(widget.winId())
p.save(filename, 'jpg')
label.setPixmap(p) # just for fun :)
print "shot taken"
widget.layout().addWidget(QPushButton('take screenshot', clicked=shoot))
widget.show()
app.exec_()
Since Qt5, grabWindow and grabWidget are obsolete (see Obsolete Members for QPixmap)
Instead, you can use QWidget.grab()
p=widget.grab()
Alternatively, instead of
p = QPixmap.grabWindow(widget.winId())
you can also use
p = QPixmap.grabWidget(widget)
PyQt5 update
import sys
from PyQt5.QtWidgets import QApplication
from PyQt5.QtGui import QPixmap, QScreen
from datetime import datetime
date = datetime.now()
filename = date.strftime('%Y-%m-%d_%H-%M-%S.jpg')
app = QApplication(sys.argv)
QScreen.grabWindow(app.primaryScreen(),
QApplication.desktop().winId()).save(filename, 'png')

Categories

Resources