Ive tried looking for an answer to this without much luck.
Im trying to build an application in kivy that starts and stops a sound as the button is toggled. The sound does what I want the first time the button is toggled, but the second time the button only starts the sound, but does not stop the sound.
Here is my code so far.
'''code'''
class MainApp(App):
def build(self):
layout = BoxLayout(padding=10)
self.oceanButton = ToggleButton(text='Ocean',
background_normal='C:/Users/micha/Desktop/Code/Soothing Sounds/picture/oceanpic.jpg')
self.oceanButton.bind(on_press=self.on_press_button)
layout.add_widget(self.oceanButton)
return layout
def on_press_button(self, *args):
waveSound = SoundLoader.load(
'C:/Users/micha/Desktop/Code/Soothing Sounds/sounds/ocean.wav'
)
if self.oceanButton.state == 'down':
waveSound.play()
waveSound.loop = True
print('On')
else:
waveSound.stop()
print('Off')
The problem is that your on_press_button() method always creates a new instance of Sound (using SoundLoader). So, when the ToggleButton state is not down, it calls the stop() method on that new instance, and the Sound that was created on the previous call continues to play.
You can fix that by keeping a reference to the created Sound instance, and using that instance to call stop():
def on_press_button(self, *args):
if self.oceanButton.state == 'down':
self.waveSound = SoundLoader.load(
'C:/Users/micha/Desktop/Code/Soothing Sounds/sounds/ocean.wav'
)
self.waveSound.play()
self.waveSound.loop = True
print('On')
else:
self.waveSound.stop()
print('Off')
Related
I am trying to design a gui which is related to my computer vision project. In that, the video I want to stop the web camera feed and I want to resume it by pressing a button. I managed to stop the feed, but I cannot resume it. The camera gets turned on but it is not working. This is the code for the program.
from PyQt5 import uic
from PyQt5 import QtCore, QtWidgets, QtGui
import cv2
import sys
class opencv_feed(QtWidgets.QMainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.ui = uic.loadUi('../designs/design5_flexible_opencv_window2.ui', self) #change this whenever u want... keep the ui file with you
self.resize(900,600)
self.worker1 = worker1() #creating an instance
self.worker1.start()
self.worker1.ImgUpdate.connect(self.ImageUpdateSlot)
self.but_stop.clicked.connect(self.cancel_feed)
self.but_resume.clicked.connect(self.resume_feed)
def ImageUpdateSlot(self, Image):
self.label.setPixmap(QtGui.QPixmap.fromImage(Image))
def cancel_feed(self):
self.worker1.stop()
def resume_feed(self):
self.__init__()
#self.worker1.ImgUpdate.connect(self.ImageUpdateSlot)
class worker1(QtCore.QThread):
ImgUpdate = QtCore.pyqtSignal(QtGui.QImage)
#QtCore.pyqtSlot()
def run(self): #put self in every variable to stop crashing the gui, when we interact with gui
self.ThreadActive = True
self.feed = cv2.VideoCapture(0)
while self.ThreadActive:
self.ret, self.frm = self.feed.read()
if self.ret:
self.img = cv2.cvtColor(self.frm, cv2.COLOR_BGR2RGB)
#print(img1.shape)
self.img = cv2.flip(self.img,1)
self.qtformat_conv_img = QtGui.QImage(self.img.data, self.img.shape[1], self.img.shape[0], QtGui.QImage.Format_RGB888)
#print(self.img.shape)
self.pic = self.qtformat_conv_img.scaled(self.img.shape[1],self.img.shape[0],QtCore.Qt.KeepAspectRatio) #keep this as an attribute, else when resizing the app stops
self.ImgUpdate.emit(self.pic)
def stop(self):
self.ThreadActive = False
self.feed.release()
self.quit()
#os._exit(0)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
wind = opencv_feed()
wind.show()
sys.exit(app.exec_())
Can someone explain me what am I doing wrong.
Link to the UI file..
https://drive.google.com/file/d/1UP8RjQML1GzFA75eGURgWt4Y0o_Ip3sU/view?usp=sharing
You can only start a thread once. Once it finishes you need to create another thread object to actually run. I would add another flag after self.ThreadActive called something like "pause" to keep the thread alive, just without doing anything.
#QtCore.pyqtSlot()
def run(self): #put self in every variable to stop crashing the gui, when we interact with gui
self.ThreadActive = True
self.paused = False
self.feed = cv2.VideoCapture(0)
while self.ThreadActive:
if not self.paused:
self.ret, self.frm = self.feed.read()
if self.ret:
self.img = cv2.cvtColor(self.frm, cv2.COLOR_BGR2RGB)
#print(img1.shape)
self.img = cv2.flip(self.img,1)
self.qtformat_conv_img = QtGui.QImage(self.img.data,
self.img.shape[1],
self.img.shape[0],
QtGui.QImage.Format_RGB888)
#print(self.img.shape)
self.pic = self.qtformat_conv_img.scaled(self.img.shape[1],self.img.shape[0],QtCore.Qt.KeepAspectRatio) #keep this as an attribute, else when resizing the app stops
self.ImgUpdate.emit(self.pic)
this way when you want to pause the thread you can pause and unpause using that flag
Either that or you need to always create another instance of the worker. Does it work if you create the instance outside of the init ? I'm unsure what happens to the GUI if the init is called twice.
EDIT:
You'll also have to change the way you pause and start again
def cancel_feed(self):
self.worker1.paused = True
def resume_feed(self):
self.worker1.paused = False
I want to create multiple small games in pygame zero, with a main window on which you have buttons to click - when clicking a button it would start a new window and a new subgame (coded on its own in another file). The secondary games should be able to return if the game was won or lost. Is this possible using pygame-zero? I am thinking the subgame should be encapsulated in some function to be able to give a return value, but I am not sure if this is doable in pygame-zero since it calls some functions itself... any idea?
Or am I better off adding some kind of game state in the main program and do everything there like this?
def update():
if state == 'game1':
#all of the game1 update code here
elif state == 'game2':
#all of the game2 update code here
#etc
def draw():
if state == 'game1':
#all of the game1 draw code here
elif state == 'game2':
#all of the game2 draw code here
#etc
I think you are definitely better off by implementing a game state. I'd use an object-oriented approach like:
class GameState:
def update():
pass
def draw():
pass
class Game1(GameState):
def update():
# ...
def draw():
# ...
class GameChooser(GameState):
def update():
# choose game here
global state
if ...:
state = Game1()
def draw():
# ...
state = GameChooser()
def update():
state.update()
def draw():
state.draw()
How can I start again when pressing image?
I want it to start again when I press the last images or 2/3 second later
class MyButton(ButtonBehavior, Image):
def __init__(self, **kwargs):
super(MyButton, self).__init__(**kwargs)
self.source = 's'
def on_press(self):
a = (random.randint(1, 1014124315124124))
if (int(a) % 2 == 0):
self.source = 's'
else:
self.source = 'd'
class SampleApp(App):
def build(self):
return MyButton()
SampleApp().run()
Look into kivy's Clock.schedule_once. The basic idea is, when the button is pressed, you will set it to a new image, and schedule another function (let's call it resetImage) to run in 2/3 seconds. Then when resetImage is called, it sets the button's image back to normal.
You'd want something like Clock.schedule_once(resetImage, 0.66).
Based on Classes, i have window which contain a button and progressbar, whenever the button is clicked there two things should happen :
1 - should entried value from dialog pass to class ABCD
2 - While our class ABCD() do his stuff, should our progressbar do regular pulsing untill the class ABCD() finish process.
So the problem is that the progressbar pulse only one time,then stucked there till the class ABCD() finished, then its start pulsing regulary later.
Here is my try:
import gi,time
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GObject
class DialogExample(Gtk.Dialog):
def __init__(self, parent):
Gtk.Dialog.__init__(self, "My Dialog", parent, 0,
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
Gtk.STOCK_OK, Gtk.ResponseType.OK))
self.set_default_size(150, 100)
self.Myinput = Gtk.Entry()
box = self.get_content_area()
box.add(self.Myinput)
self.show_all()
class DialogWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Dialog Example")
self.set_border_width(6)
Hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
self.add(Hbox)
self.button = Gtk.Button("Open dialog")
self.button.connect("clicked", self.on_button_clicked)
Hbox.pack_start(self.button, True, True, 0)
self.progressbar = Gtk.ProgressBar()
Hbox.pack_start(self.progressbar, True, True, 0)
#~~~~~~ Progress Bar
def on_timeout(self, user_data):
"""
Update value on the progress bar
"""
if self.activity_mode:
self.progressbar.pulse()
else:
new_value = self.progressbar.get_fraction() + 0.01
if new_value > 1:
new_value = 0
self.progressbar.set_fraction(new_value)
# As this is a timeout function, return True so that it
# continues to get called
return True
def on_button_clicked(self, widget):
dialog = DialogExample(self)
response = dialog.run()
if response == Gtk.ResponseType.OK:
variable = dialog.Myinput.get_text()
print("start")
dialog.destroy()
#ProgressBar time function
self.timeout_id = GObject.timeout_add(50, self.on_timeout, None)
self.activity_mode = False
self.progressbar.pulse()
#this for Updating the Windows and make the progressbar pulsing while waiting
# the class ABCD finish his stuff, finally should stop pulsing.
while Gtk.events_pending():
Gtk.main_iteration_do(False)
passing_instance = ABCD(variable)
class ABCD(object):
def __init__(self,value_of_dialog):
self.get_value = value_of_dialog
self.for_add = "______ add was done"
self.final_value = self.get_value+self.for_add
time.sleep(10)
print("gonna be finished")
print(self.final_value)
win = DialogWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
As we can see here i already try to make pulse and refresh the windows in this part of code
self.timeout_id = GObject.timeout_add(50, self.on_timeout, None)
self.activity_mode = False
self.progressbar.pulse()
#this for Updating the Windows and make the progressbar pulsing while waiting
# the class ABCD finish his stuff, finally should stop pulsing.
while Gtk.events_pending():
Gtk.main_iteration_do(False)
Otherwise because in my class ABCD() i have time.sleep(10) should
the progress bar pulse only for that time 10 seconds later only then
stop.
How should this code gonna be, i need someone provide me the correct code, with little explain.
The issue with using sleep in order to emulate the passing of time is that sleep will stop everything that is happening in the thread which in this case prevents the thread to reach Gtk.main() which is needed to make your progressbar pulse or update.
So in order to do this properly there are 2 options:
Run ABCD in a separate thread such that the main thread can reach Gtk.main(). Which than will make sure that the progressbar moves as expected. A quick example of this looks like this:
self.abcd_thread = ABCD(variable)
self.abcd_thread.start()
class ABCD(Thread):
def __init__(self, value_of_dialog):
super(ABCD, self).__init__()
self.get_value = value_of_dialog
self.for_add = "______ add was done"
self.final_value = self.get_value+self.for_add
def run(self):
print "Starting " + self.name
time.sleep(10)
print("gonna be finished")
print(self.final_value)
print "Exiting " + self.name
When using this you can use self.abcd_thread.isAlive() to see whether the thread is still computing things. The way to return information heavily depends on the job placed in the thread.
Replace the time.sleep with the following fragment:
now = time.time()
while time.time() - now < 10:
# Insert any code here
Gtk.main_iteration_do(False)
This will still emulate ABCD doing stuff for 10 seconds but because we call Gtk.main_iteration_do(False) in each iteration of the loop GTK is able to update the interface during the loop.
In general the second option is the easiest as it only involves making Gtk.main_iteration_do(False) call during whatever your doing. The first option on the other hand is more useful when dealing with complex computations where adding Gtk calls doesn't fit in easily.
I was looking for a solution to play mp3 files in python and many stackoverflow answers (to other questions) seemed to recommend pyglet. I am writing a program that takes a piece of text, breaks it into individual words and then downloads mp3s of those words (if they aren't already downloaded) using gTTs and plays them.
from pyglet import media, app, clock
from gtts import gTTS
import os
import time
from num2words import num2words
cwd = os.getcwd()
beep = media.load('beep.mp3', streaming = False)
def get_mp3(text):
player = media.Player()
lowertext = text.lower()
words = lowertext.split()
player.queue(beep)
for word in words:
save_path = cwd + '\\tts_downloads\\{}.mp3'.format(word)
if os.path.isfile(save_path) == False:
tts = gTTS(word, 'en-us')
tts.save(save_path)
mp3 = media.load(save_path)
player.queue(mp3)
player.queue(beep)
player.play()
app.run()
However I find that after playing the files pyglet won't let my program progress. How can I exit the pyglet app after playback has finished, so that my code can progress?
Alternatively is there some other way that I can play mp3 files in python?
This is souly because app.run() is a never-ending loop in order to keep the GL context alive. There's only one way around this and that is to create your own class that inherits the Pyglet properties.
I'll give you a sample code and if you have any questions feel free to ask away.
import pyglet
from pyglet.gl import *
# Optional audio outputs (Linux examples):
# pyglet.options['audio'] = ('alsa', 'openal', 'silent')
key = pyglet.window.key
class main(pyglet.window.Window):
def __init__ (self):
super(main, self).__init__(800, 800, fullscreen = False)
self.x, self.y = 0, 0
self.bg = pyglet.sprite.Sprite(pyglet.image.load('background.jpg'))
self.sprites = {}
self.player = pyglet.media.Player()
self.alive = 1
def on_draw(self):
self.render()
def on_close(self):
self.alive = 0
def on_key_press(self, symbol, modifiers):
# Do something when a key is pressed?
# Pause the audio for instance?
# use `if symbol == key.SPACE: ...`
# This is just an example of how you could load the audio.
# You could also do a standard input() call and enter a string
# on the command line.
if symbol == key.ENTER:
self.player.queue(media.load('beep.mp3', streaming = False))
if nog self.player.playing:
self.player.play()
if symbol == key.ESC: # [ESC]
self.alive = 0
def render(self):
self.clear()
self.bg.draw()
# self.sprites is a dictionary where you store sprites
# to be rendered, if you have any.
for sprite_name, sprite in self.sprites.items():
sprite.draw()
self.flip()
def run(self):
while self.alive == 1:
self.render()
# -----------> This is key <----------
# This is what replaces pyglet.app.run()
# but is required for the GUI to not freeze
#
event = self.dispatch_events()
self.player.delete() # Free resources. (Not really needed but as an example)
x = main()
x.run()
Now this is just the most basic example of how to load audio sources and play them. You press Enter and that triggers beep.mp3.
Normally, you'd also want to hook a function to self.player.eos() that does something when you run out of sources.
Also note that it only calls play() once if it's not already playing. These are attributes you want to honor.
Ah and Escape exits the application.