So I'm making a music player in python but I'm having trouble when passing variables into my function and I get this error message:
TypeError: next() takes exactly 3 arguments (2 given)
I've searched on google for an anwser but their programmes and solutions were to different for me to understand how it works and why it works. Anyway here is my code:
import sys
import os
import pygame
from PyQt4 import QtGui, QtCore
from time import sleep
class Window(QtGui.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.setGeometry(50, 50, 500, 300)
self.setWindowTitle("Music Player Alpha")
AutoPlay = True
Play = True
SongQueue = []
Song = os.listdir('/home/pi/Desktop/Muziek/' )
Song = sorted(Song)
CurrentSong = 0
pygame.mixer.init()
pygame.mixer.music.load('/home/pi/Desktop/Muziek/' + Song[0])
pygame.mixer.music.play()
self.home()
def home(self):
btnQuit = QtGui.QPushButton("Quit", self)
btnQuit.clicked.connect(self.close)
btnPlay = QtGui.QPushButton("Play", self)
btnPlay.clicked.connect(self.play)
btnPlay.move(100, 100)
btnPause = QtGui.QPushButton("Pause", self)
btnPause.clicked.connect(self.pause)
btnPause.move(200, 100)
btnNext = QtGui.QPushButton("Next", self)
btnNext.clicked.connect(self.next)
btnNext.move(300, 100)
btnPrevious = QtGui.QPushButton("Previous", self)
btnPrevious.clicked.connect(self.previous)
btnPrevious.move(0, 100)
self.show()
def close(self):
print("Closing application")
sys.exit()
def play(self, Play):
pygame.mixer.music.unpause()
Play = True
def pause(self, Play):
pygame.mixer.music.pause()
play = False
def next(self, CurrentSong, Song):
print("1")
CurrentSong = CurrentSong + 1
if CurrentSong > len(Song) + 1:
CurrentSong = 0
pygame.mixer.music.load('/home/pi/Desktop/Muziek/' + Song[CurrentSong])
pygame.mixer.music.play()
else:
pygame.mixer.music.load('/home/pi/Desktop/Muziek/' + Song[CurrentSong])
pygame.mixer.music.play()
def previous(self, CurrentSong, Song):
CurrentSong = CurrentSong - 1
if CurrentSong < 0:
CurrentSong = len(Song) -1
pygame.mixer.music.load('/home/pi/Desktop/Muziek/' + Song[CurrentSong])
pygame.mixer.music.play()
else:
pygame.mixer.music.load('/home/pi/Desktop/Muziek/' + Song[CurrentSong])
pygame.mixer.music.play()
app = QtGui.QApplication(sys.argv)
GUI = Window()
sys.exit(app.exec_())
This is where a call is defined:
btnNext.clicked.connect(self.next)
So when the button is clicked you run self.next(mouse_event) This is the function signature:
def next(self, CurrentSong, Song):
So when a button is clicked you send two parameters: self, from the self.next, and an event which has nothing to do with songs, it has info on the click. You were expecting 3 parameters self,CurrentSong,Song, and not an event - so two mistakes. A workaround is to not accept parameters besides self to next, and save the current song in the class:
def next(self,event):
currentSong = self.currentSong
etc... If you want to forego the event you can lambda hide it:
btnNext.clicked.connect(lambda e:self.next)
and change next accordingly.
Related
I have been working on a music player app that uses VLC to play songs directly from the internet and has features like seeking and a progress bar. But as the normal tkinter progress bar looks kinda old so I used customtkinter.CTkSlider widget but using this causes buffering. The song plays smoothly on using Tk.Scale.
Here, is the code:
# import external libraries
import vlc
import tkinter as Tk
from tkinter import ttk
import pyautogui
import customtkinter
import pafy
# import standard libraries
import os
from threading import Thread, Event
import time
import platform
import requests
class ttkTimer(Thread):
"""a class serving same function as wxTimer... but there may be better ways to do this
"""
def __init__(self, callback, tick):
Thread.__init__(self)
self.callback = callback
self.stopFlag = Event()
self.tick = tick
self.iters = 0
def run(self):
while not self.stopFlag.wait(self.tick):
self.iters += 1
self.callback()
def stop(self):
self.stopFlag.set()
def get(self):
return self.iters
class Player(Tk.Frame):
"""The main window has to deal with events.
"""
def __init__(self, parent, title=None):
Tk.Frame.__init__(self, parent)
self.parent = parent
if title == None:
title = "tk_vlc"
self.parent.title(title)
# Menu Bar
# File Menu
menubar = Tk.Menu(self.parent)
self.parent.config(menu=menubar)
fileMenu = Tk.Menu(menubar)
fileMenu.add_command(label="Open", underline=0, command=self.OnOpen)
fileMenu.add_command(label="Exit", underline=1, command=_quit)
menubar.add_cascade(label="File", menu=fileMenu)
# The second panel holds controls
self.player = None
self.videopanel = ttk.Frame(self.parent)
self.canvas = Tk.Canvas(self.videopanel).pack(fill=Tk.BOTH,expand=1)
self.videopanel.pack(fill=Tk.BOTH,expand=1)
ctrlpanel = ttk.Frame(self.parent)
pause = ttk.Button(ctrlpanel, text="Pause", command=self.OnPause)
play = ttk.Button(ctrlpanel, text="Play", command=self.OnPlay)
stop = ttk.Button(ctrlpanel, text="Stop", command=self.OnStop)
volume = ttk.Button(ctrlpanel, text="Volume", command=self.OnSetVolume)
pause.pack(side=Tk.LEFT)
play.pack(side=Tk.LEFT)
stop.pack(side=Tk.LEFT)
volume.pack(side=Tk.LEFT)
self.volume_var = Tk.IntVar()
self.volslider = Tk.Scale(ctrlpanel, variable=self.volume_var, command=self.volume_sel,
from_=0, to=100, orient=Tk.HORIZONTAL, length=100)
self.volslider.pack(side=Tk.LEFT)
ctrlpanel.pack(side=Tk.BOTTOM)
ctrlpanel2 = ttk.Frame(self.parent)
self.scale_var = Tk.DoubleVar()
self.timeslider_last_val = ""
self.timeslider = customtkinter.CTkSlider(ctrlpanel2, variable=self.scale_var, command=self.scale_sel,
from_=0, to=1000, orient=Tk.HORIZONTAL) # This causes buffer
self.timeslider.pack(side=Tk.BOTTOM, fill=Tk.X,expand=1)
self.timeslider_last_update = time.time()
ctrlpanel2.pack(side=Tk.BOTTOM,fill=Tk.X)
# VLC player controls
self.Instance = vlc.Instance()
self.player = self.Instance.media_player_new()
self.timer = ttkTimer(self.OnTimer, 1.0)
self.timer.start()
self.parent.update()
#self.player.set_hwnd(self.GetHandle()) # for windows, OnOpen does does this
def Extract(self,topic):
"""Will play video on following topic, takes about 10 to 15 seconds to load"""
url = 'https://www.youtube.com/results?q=' + topic
count = 0
cont = ''
try:
cont = requests.get(url)
except:
print('Error','Cannot Connect.. Internet not connected or invalid URL or id.')
cont = ''
data = cont.content
data = str(data)
lst = data.split('"')
for i in lst:
count+=1
if i == 'WEB_PAGE_TYPE_WATCH':
break
if lst[count-5] == "/results":
print("Error","No video found.")
return "https://www.youtube.com"+lst[count-5]
def OnExit(self, evt):
"""Closes the window.
"""
self.Close()
def OnOpen(self):
"""Pop up a new dialow window to choose a file, then play the selected file.
"""
# if a file is already running, then stop it.
self.OnStop()
fullname = pafy.new(self.Extract(pyautogui.password(mask="", title="Enter Song Name:", text="Enter Song Name:"))).getbest().url
self.Media = self.Instance.media_new(fullname)
self.player.set_media(self.Media)
# set the window id where to render VLC's video output
if platform.system() == 'Windows':
self.player.set_hwnd(self.GetHandle())
else:
self.player.set_xwindow(self.GetHandle()) # this line messes up windows
# FIXME: this should be made cross-platform
self.OnPlay()
# set the volume slider to the current volume
#self.volslider.SetValue(self.player.audio_get_volume() / 2)
self.volslider.set(self.player.audio_get_volume())
def OnPlay(self):
"""Toggle the status to Play/Pause.
If no file is loaded, open the dialog window.
"""
# check if there is a file to play, otherwise open a
# Tk.FileDialog to select a file
if not self.player.get_media():
self.OnOpen()
else:
# Try to launch the media, if this fails display an error message
if self.player.play() == -1:
self.errorDialog("Unable to play.")
def GetHandle(self):
return self.videopanel.winfo_id()
#def OnPause(self, evt):
def OnPause(self):
"""Pause the player.
"""
self.player.pause()
def OnStop(self):
"""Stop the player.
"""
self.player.stop()
# reset the time slider
self.timeslider.set(0)
def OnTimer(self):
"""Update the time slider according to the current movie time.
"""
if self.player == None:
return
# since the self.player.get_length can change while playing,
# re-set the timeslider to the correct range.
length = self.player.get_length()
dbl = length * 0.001
self.timeslider.config(to=dbl)
# update the time on the slider
tyme = self.player.get_time()
if tyme == -1:
tyme = 0
dbl = tyme * 0.001
self.timeslider_last_val = ("%.0f" % dbl) + ".0"
# don't want to programatically change slider while user is messing with it.
# wait 2 seconds after user lets go of slider
if time.time() > (self.timeslider_last_update + 2.0):
self.timeslider.set(dbl)
def scale_sel(self, evt):
if self.player == None:
return
nval = self.scale_var.get()
sval = str(nval)
if self.timeslider_last_val != sval:
self.timeslider_last_update = time.time()
mval = "%.0f" % (nval * 1000)
self.player.set_time(int(mval)) # expects milliseconds
def volume_sel(self, evt):
if self.player == None:
return
volume = self.volume_var.get()
if volume > 100:
volume = 100
if self.player.audio_set_volume(volume) == -1:
self.errorDialog("Failed to set volume")
def OnToggleVolume(self, evt):
"""Mute/Unmute according to the audio button.
"""
is_mute = self.player.audio_get_mute()
self.player.audio_set_mute(not is_mute)
# update the volume slider;
# since vlc volume range is in [0, 200],
# and our volume slider has range [0, 100], just divide by 2.
self.volume_var.set(self.player.audio_get_volume())
def OnSetVolume(self):
"""Set the volume according to the volume sider.
"""
volume = self.volume_var.get()
# vlc.MediaPlayer.audio_set_volume returns 0 if success, -1 otherwise
if volume > 100:
volume = 100
if self.player.audio_set_volume(volume) == -1:
self.errorDialog("Failed to set volume")
def errorDialog(self, errormessage):
"""Display a simple error dialog.
"""
Tk.tkMessageBox.showerror(self, 'Error', errormessage)
def Tk_get_root():
if not hasattr(Tk_get_root, "root"): #(1)
Tk_get_root.root= Tk.Tk() #initialization call is inside the function
return Tk_get_root.root
def _quit():
print("_quit: bye")
root = Tk_get_root()
root.quit() # stops mainloop
root.destroy() # this is necessary on Windows to prevent
# Fatal Python Error: PyEval_RestoreThread: NULL tstate
os._exit(1)
if __name__ == "__main__":
# Create a Tk.App(), which handles the windowing system event loop
root = Tk_get_root()
root.protocol("WM_DELETE_WINDOW", _quit)
player = Player(root, title="tkinter vlc")
# show the player window centred and run the application
root.mainloop()
Kindly help
Regards.
I am using a simple GUI with PyQt5 in which I have 3 buttons to record, stop and play the audio. I have some know-how of the Tkinter GUI, but I am totally confused here in PyQt5. In Tkinter Buttons, I am using commands something like this:
record_btn = Button(voice_rec, text="Record Audio", command=lambda m=1: threading_rec(m))
# Stop button
stop_btn = Button(voice_rec, text="Stop Recording", command=lambda m=2: threading_rec(m))
# Play button
play_btn = Button(voice_rec, text="Play Recording", command=lambda m=3: threading_rec(m))
I tried this in Pyqt5 Buttons, but still not working:
self.record_btn = QPushButton('Record', self)
self.record_btn.clicked.connect(lambda: self.threading_rec(x=1))
self.record_btn.move(100, 70)
self.stop_btn = QPushButton('Stop', self)
self.stop_btn.clicked.connect(lambda: self.threading_rec(x=2))
self.stop_btn.move(200, 70)
self.play_btn = QPushButton('Play', self)
self.play_btn.clicked.connect(lambda: self.threading_rec(x=3))
self.play_btn.move(300, 70)
Here is my complete code:
import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot
import sounddevice as sd
import queue
import soundfile as sf
import threading
class App(QWidget):
def __init__(self):
super().__init__()
self.title = 'Voice Recorder'
self.left = 400
self.top = 300
self.width = 500
self.height = 200
self.initUI()
# Create a queue to contain the audio data
q = queue.Queue()
# Declare variables and initialise them
recording = False
file_exists = False
# Fit data into queue
def callback(indata, frames, time, status):
q.put(indata.copy())
def threading_rec(x):
if x == 1:
# If recording is selected, then the thread is activated
t1 = threading.Thread(target=record_audio)
t1.start()
elif x == 2:
# To stop, set the flag to false
global recording
recording = False
messagebox.showinfo(message="Recording finished")
elif x == 3:
# To play a recording, it must exist.
if file_exists:
# Read the recording if it exists and play it
data, fs = sf.read("trial.wav", dtype='float32')
sd.play(data, fs)
sd.wait()
else:
# Display and error if none is found
messagebox.showerror(message="Record something to play")
def record_audio(self):
# Declare global variables
global recording
# Set to True to record
recording = True
global file_exists
# Create a file to save the audio
messagebox.showinfo(message="Recording Audio. Speak into the mic")
with sf.SoundFile("trial.wav", mode='w', samplerate=44100,
channels=2) as file:
# Create an input stream to record audio without a preset time
with sd.InputStream(samplerate=44100, channels=2, callback=callback):
while recording == True:
# Set the variable to True to allow playing the audio later
file_exists = True
# write into file
file.write(q.get())
# Button to record audio
record_btn = Button(voice_rec, text="Record Audio", command=lambda m=1: threading_rec(m))
# Stop button
stop_btn = Button(voice_rec, text="Stop Recording", command=lambda m=2: threading_rec(m))
# Play button
play_btn = Button(voice_rec, text="Play Recording", command=lambda m=3: threading_rec(m))
def initUI(self):
self.setWindowTitle(self.title)
self.setGeometry(self.left, self.top, self.width, self.height)
record_btn = QPushButton('Record', self)
record_btn.move(100, 70)
stop_btn = QPushButton('Stop', self)
stop_btn.move(200, 70)
play_btn = QPushButton('Play', self)
play_btn.move(300, 70)
button.clicked.connect(self.on_click)
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = App()
sys.exit(app.exec_())
Someone please help me with this code!
I'll try to answer this in a simple way.
Let's say you have a button like this:
def init_UI(self):
self.sum_button = QPushButton(text='sum')
self.sum_button.clicked.connect(lambda: self.get_sum(int_a, int_b))
def get_sum(self, int_a, int_b):
return int_a + int_b
So, Recently I was trying to make an audio player using PyQt5, pygame, and mutagen. The program works pretty fine. But when I'm playing a song and try to quit the program, the program stops responding and the song continues to play. But this doesn't happen when a song is not playing, it works fine then.
Here is the Code:
from PyQt5 import QtWidgets, QtGui
from PyQt5.QtWidgets import QApplication, QMainWindow, QSlider
from PyQt5.QtGui import QColor
from PyQt5.QtCore import Qt
import sys
import pygame as pg
from mutagen.mp3 import MP3
import os
import threading
pg.init()
#33206
class window(QMainWindow):
def __init__(self):
super(window, self).__init__()
self.setGeometry(425, 65, 400, 190)
self.setWindowIcon(QtGui.QIcon("icon"))
self.setWindowTitle("MultiMedia Player")
# MenuBar
file = QtWidgets.QAction("&Open Mp3", self)
file.setShortcut("Ctrl + O")
file.triggered.connect(self.open_mp3)
# Quit
quit = QtWidgets.QAction("&Quit", self)
quit.setShortcut("Q")
quit.triggered.connect(self.close_app)
# Add Items
items = QtWidgets.QAction("&Add Items", self)
items.setShortcut("Ctrl + P")
mainmenu = self.menuBar()
filemenu = mainmenu.addMenu("&Open")
filemenu.addAction(file)
add_items = mainmenu.addMenu("&Add Items")
add_items.addAction(items)
filemenu.addAction(quit)
self.flag = 0
self.home()
def home(self):
# colors
black = (13, 13, 13)
light_black = (36, 36, 36)
# Pause Button
self.pause_btn = QtWidgets.QPushButton(self)
self.pause_btn.setText("Pause")
self.pause_btn.setShortcut("p")
self.pause_btn.move(0, 120)
self.pause_btn.clicked.connect(self.pause)
# Play Button
self.play_btn = QtWidgets.QPushButton(self)
self.play_btn.setText("Play")
self.play_btn.setShortcut("Space")
self.play_btn.move(150, 120)
self.play_btn.clicked.connect(self.play)
# Stop Button
self.stop_btn = QtWidgets.QPushButton(self)
self.stop_btn.setText("Stop")
self.stop_btn.setShortcut("s")
self.stop_btn.move(300, 120)
self.stop_btn.clicked.connect(self.stop)
# color for the window
color = QColor(70, 70, 70)
# Volume_Up Button
self.vup_btn = QtWidgets.QPushButton(self)
self.vup_btn.setText("V(+)")
self.vup_btn.setShortcut("+")
self.vup_btn.move(300, 160)
self.vup_btn.clicked.connect(self.volume_up)
# Volume_Down Button
self.vdown_btn = QtWidgets.QPushButton(self)
self.vdown_btn.setText("V(-)")
self.vdown_btn.setShortcut("-")
self.vdown_btn.move(0, 160)
self.vdown_btn.clicked.connect(self.volume_down)
# Seek Slider
self.slider = QSlider(Qt.Horizontal, self)
self.slider.setGeometry(20, 75, 350, 20)
# Volume Slider
self.v_slider = QSlider(Qt.Horizontal, self)
self.v_slider.setGeometry(120, 165, 160, 20)
self.v_slider.setMinimum(0)
self.v_slider.setMaximum(100)
self.v_slider.setValue(70)
self.volume_value = self.v_slider.value()
self.v_slider.valueChanged.connect(self.slider_value_changed)
print(self.v_slider.value() / 100)
def msg(self, title, message):
msg1 = QtWidgets.QMessageBox()
msg1.setWindowIcon(QtGui.QIcon("icon"))
msg1.setWindowTitle(title)
msg1.setText(message)
msg1.setStandardButtons(QtWidgets.QMessageBox.Ok)
msg1.exec_()
def open_mp3(self):
name = QtWidgets.QFileDialog.getOpenFileName(self)
format = os.path.splitext(name[0])
if format[1] == ".mp3":
self.audio = MP3(name[0])
self.duration = self.audio.info.length//1
self.min = int(self.duration // 60)
self.sec = int(self.duration % 60)
self.total_time = str(self.min) + ":" + str(self.sec)
print(self.total_time)
self.slider.setMaximum(self.duration)
self.slider.setMinimum(0)
time = []
time.append(self.total_time)
self.label = QtWidgets.QLabel(self)
self.label.setText(self.total_time)
self.label.setFont(QtGui.QFont("Arial", 9))
self.label.adjustSize()
self.label.move(373, 77)
song = name[0]
pg.mixer.music.load(song)
pg.mixer.music.play(1)
pg.mixer.music.set_volume(self.v_slider.value()/100)
self.label = QtWidgets.QLabel(self)
self.label.setText(song)
self.label.setFont(QtGui.QFont("Arial", 15))
self.label.adjustSize()
self.label.move(0, 36)
self.label.show()
threading_1 = threading.Thread(target=self.cur_time).start()
else:
self.msg("Invalid Format", "Choose A .Mp3 File Only!")
volume_level = pg.mixer.music.get_volume()
print(volume_level)
def cur_time(self):
true = 1
while true == 1:
if self.flag == 0:
self.m_time = pg.mixer.music.get_pos()
self.mm_time = self.m_time * 0.001
self.s_time = self.mm_time // 1
self.slider.setValue(self.s_time)
print(self.s_time)
self.slider.sliderMoved.connect(self.seek_changed)
if self.s_time == -1:
self.slider.setValue(0)
true = 2
if self.flag == 1:
print(self.s_time)
def seek_changed(self):
print(self.slider.value())
pg.mixer.music.set_pos(self.slider.value())
def slider_value_changed(self):
self.volume_value = self.v_slider.value()
pg.mixer.music.set_volume(self.v_slider.value()/100)
def volume_up(self):
self.volume_value = self.volume_value + 10
self.v_slider.setValue(self.volume_value)
if self.volume_value >= 100:
self.volume_value = 100
pg.mixer.music.set_volume(self.v_slider.value() / 100)
print(self.v_slider.value() / 100)
def volume_down(self):
self.volume_value = self.volume_value - 10
self.v_slider.setValue(self.volume_value)
if self.volume_value <= 0:
self.volume_value = 0
pg.mixer.music.set_volume(self.v_slider.value() / 100)
print(self.v_slider.value() / 100)
def pause(self):
pg.mixer.music.pause()
self.flag = 1
def stop(self):
pg.mixer.music.stop()
self.flag = -1
def play(self):
pg.mixer.music.unpause()
self.flag = 0
def close_app(self):
choice = QtWidgets.QMessageBox.question(
self, "QUIT", "You Sure You Wanna Quit?", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No)
if choice == QtWidgets.QMessageBox.Yes:
sys.exit()
else:
pass
def items(self):
layout = QtWidgets.QVBoxLayout(self)
song_name = QtWidgets.QFileDialog.getOpenFileName(self)
widget = QtWidgets.QListWidget()
widget.setAlternatingRowColors(True)
widget.setDragDropMode(
QtWidgets.QAbstractItemView.InternalMove)
widget.addItems([str(i) for i in range(1, 6)])
layout.addWidget(widget)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = window()
win.show()
sys.exit(app.exec_())
Thanks In Advance.
The main problem is that you're still having the threading.Thread running, so while the QtApplication is "closed", the program is still alive.
You should really avoid using a while loop to check for the current position, as it will call request that value each time the loop cycles, consuming a lot of unnecessary CPU resources.
Also, you're connecting the sliderMoved signal to seek_changed each time the loops cycles, which is bad.
Use a QTimer instead, which will update the cursor position without overloading the process:
# create a timer in the window __init__
self.cursor_updater = QtCore.QTimer(interval=100, timeout=self.cur_time)
#...
def cur_time(self):
# ignore the update if the user is seeking
if self.slider.isSliderDown():
return
self.slider.setValue(pg.mixer.music.get_pos() * .001)
Then you just need to start the timer everytime the music starts (or unpauses) and stop whenever you stop or pause.
That said, there are other issues with your code.
pygame and Qt run their own event loops, so you can't easily and gracefully quit via sys.exit(), nor their own quit() functions, as it's possible that one or both of them would just hang in their own loop without being able to actually quit, keeping the process running (looping doing almost nothing) and consuming a lot of resources. I'm no expert in using pygame and PyQt but, as far as I know, you can call os._exit(0) instead.
the window closeEvent() should be taken care of, because if the user just closes the window without quitting, there won't be any confirmation dialog and the exit procedure described above won't be called.
pygame.mixer.music.get_pos() "only represents how long the music has been playing; it does not take into account any starting position offsets". So you'll need to keep track of the position whenever you use set_pos() and compute the actual value accordingly.
you should really consider using layouts, or ensure that the window size is fixed, otherwise the user will be able to resize it to a size smaller than the interface is.
I have a situation where a Gui is active and a QThread.
The QThread is getting and saving data in the background all the time, it should not stop doing this.
Now I want to process the latest data from the QThread without interrupting the QThread or freezing the Gui.
So I think I need another thread to do this?!
How can I pass its data to another thread and do something with it?
import sys, random, time
from PyQt5 import QtWidgets
from PyQt5.QtCore import *
class Ui(QtWidgets.QMainWindow):
def __init__(self):
super(Ui, self).__init__()
self.setWindowTitle('Window')
#getData
self.myGetData = getData()
self.myGetData.start()
self.show()
class getData(QThread):
#This Thread should run all the time
def run(self):
while True:
myNumber = random.randint(0, 100)
#He 'processData Thread'!! Do Something with mynumber!!
time.sleep(1)
class processData(QThread):
def processNumber(self, myNumber):
#Extremly complex code will execute while 'getData' is doing its thing.
newNumber = myNumber * 10
return newNumber
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Ui()
sys.exit(app.exec_())
Found a lot of examples on how to pass data from a QThread to the interface (signals).. But not the other way around.
The signals are confusing me a bit in this case..
I would like to propose do next:
import sys, random, time
from PyQt5 import QtWidgets
from PyQt5.QtCore import *
from PyQt5 import Qt #+
class getData(QThread):
#This Thread should run all the time
threadSignalGetData = pyqtSignal(int)
def __init__(self, myNumber):
super().__init__()
self.myNumber = myNumber
def run(self):
#myNumber = 0
while True:
#He 'processData Thread'!! Do Something with mynumber!!
Qt.QThread.msleep(1000)
self.myNumber += 1
self.threadSignalGetData.emit(self.myNumber)
class MsgBoxGetData(Qt.QDialog):
def __init__(self):
super().__init__()
layout = Qt.QVBoxLayout(self)
self.label = Qt.QLabel("")
layout.addWidget(self.label)
close_btn = Qt.QPushButton("Close window GetData")
layout.addWidget(close_btn)
close_btn.clicked.connect(self.close)
self.setGeometry(900, 65, 400, 80)
self.setWindowTitle('MsgBox GetData')
self.setStyleSheet("""QLabel{
font-family:'Consolas';
color: green;
font-size: 16px;}""")
class processData(QThread):
threadSignalProcessData = pyqtSignal(int, int)
def __init__(self, myNumber):
super().__init__()
self.newNumber = myNumber
def run(self):
flagProcessData = True
while flagProcessData:
#Extremly complex code will execute while 'getData' is doing its thing.
newNumber = self.newNumber * 10
self.threadSignalProcessData.emit(self.newNumber, newNumber)
flagProcessData = False
class MsgBoxProcessData(Qt.QDialog):
def __init__(self):
super().__init__()
layout = Qt.QVBoxLayout(self)
self.label = Qt.QLabel("")
layout.addWidget(self.label)
close_btn = Qt.QPushButton("Close window ProcessData")
layout.addWidget(close_btn)
close_btn.clicked.connect(self.close)
self.setGeometry(900, 200, 400, 80)
self.setWindowTitle('MsgBox ProcessData')
self.setStyleSheet("""QLabel{
font-family:'Consolas';
color: red;
font-size: 24px;}""")
class Ui(Qt.QWidget):
def __init__(self, parent=None):
super(Ui, self).__init__(parent)
layout = Qt.QVBoxLayout(self)
self.lbl = Qt.QLabel("process GUI")
layout.addWidget(self.lbl)
self.btnA = Qt.QPushButton("Start getData")
layout.addWidget(self.btnA)
self.btnB = Qt.QPushButton("Start processData")
layout.addWidget(self.btnB)
self.setGeometry(550, 65, 300, 300)
self.setWindowTitle('Window')
self.btnA.clicked.connect(self.usingGetData)
self.btnB.clicked.connect(self.usingProcessData)
self.myNumber = 0
self.newNumber = None
self.msgGetData = MsgBoxGetData()
self.threadGetData = None
self.msgProcessData = MsgBoxProcessData()
self.threadProcessData = None
self.counter = 0
self.timer = Qt.QTimer()
self.timer.setInterval(1000)
# -------- timeout -------> def recurring_timer(self):
self.timer.timeout.connect(self.recurring_timer)
self.timer.start()
self.setStyleSheet("""QLabel{
font-family:'Consolas';
color: blue;
font-size: 20px;}""")
self.show()
def recurring_timer(self):
self.counter += 1
self.lbl.setText("process GUI: %d" % self.counter)
# ---- getData(QThread) -----------------------------------------------------#
def usingGetData(self):
if self.threadGetData is None:
self.threadGetData = getData(self.myNumber)
self.threadGetData.threadSignalGetData.connect(self.on_threadSignalGetData)
self.threadGetData.finished.connect(self.finishedGetData)
self.threadGetData.start()
self.btnA.setText("Stop getData(QThread)")
else:
self.threadGetData.terminate()
self.threadGetData = None
self.btnA.setText("Start getData(QThread)")
def finishedGetData(self):
self.threadGetData = None
self.btnA.setText("Start getData(QThread)")
def on_threadSignalGetData(self, value):
self.myNumber = value
self.msgGetData.label.setText(str(self.myNumber))
if not self.msgGetData.isVisible():
self.msgGetData.show()
# --END-- getData(QThread) -------------------#
# ---- processData(QThread) -----------------------------------------------------#
def usingProcessData(self):
if self.threadProcessData is None:
self.threadProcessData = processData(self.myNumber)
self.threadProcessData.threadSignalProcessData.connect(self.on_threadSignalProcessData)
self.threadProcessData.finished.connect(self.finishedProcessData)
self.threadProcessData.start()
self.btnB.setText("Stop processData(QThread)")
else:
self.threadProcessData.terminate()
self.threadProcessData = None
self.btnB.setText("Start processData(QThread)")
def finishedProcessData(self):
self.threadProcessData = None
self.btnB.setText("Start processData(QThread)")
def on_threadSignalProcessData(self, value1, value2):
self.newNumber = value2
self.msgProcessData.label.setText(str(value1)+" * 10 = "+str(self.newNumber))
if not self.msgProcessData.isVisible():
self.msgProcessData.show()
# --END-- processData(QThread) -------------------#
# -------------------- closeEvent --------------------------------------- #
def closeEvent(self, event):
reply = Qt.QMessageBox.question\
(self, 'Question',
"QUIT ?",
Qt.QMessageBox.Yes,
Qt.QMessageBox.No)
if reply == Qt.QMessageBox.Yes:
# close getData(QThread)
if self.threadGetData:
self.threadGetData.terminate()
self.msgGetData.close()
# close processData(QThread)
if self.threadProcessData:
self.threadProcessData.terminate()
self.msgProcessData.close()
#event.accept()
super().closeEvent(event)
else:
event.ignore()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Ui()
sys.exit(app.exec_())
So I'm making a music player and I want a section where can see my songs, Page by page. The page switching works but the text doesn't update. I've tried googleing but i coudn't find a fitting/working anwser. For the people that want it, this is what my idle says:
1
0
2
3
n1
n2
1
1
2
3
Anyway here is my code:
import sys
import os
import pygame
from PyQt4 import QtGui, QtCore
from time import sleep
class Window(QtGui.QMainWindow):
def __init__(self):
super(Window, self).__init__()
self.setGeometry(50, 50, 500, 300)
self.setWindowTitle("Music Player Alpha")
AutoPlay = True
Song = os.listdir('/home/pi/Desktop/Muziek/' )
Song = sorted(Song)
self.Song = Song
self.CurrentSong = 0
self.PageNum = 0
pygame.mixer.init()
pygame.mixer.music.load('/home/pi/Desktop/Muziek/' + Song[0])
pygame.mixer.music.play()
self.home()
def home(self):
print("1")
print(self.PageNum)
btnQuit = QtGui.QPushButton("Quit", self)
btnQuit.clicked.connect(self.close)
btnQuit.move(400,270)
btnPlay = QtGui.QPushButton("Play", self)
btnPlay.clicked.connect(self.play)
btnPlay.move(100, 270)
btnPause = QtGui.QPushButton("Pause", self)
btnPause.clicked.connect(self.pause)
btnPause.move(200, 270)
btnNext = QtGui.QPushButton("Next", self)
btnNext.clicked.connect(self.next)
btnNext.move(300, 270)
btnPrevious = QtGui.QPushButton("Previous", self)
btnPrevious.clicked.connect(self.previous)
btnPrevious.move(0, 270)
btnPrevPage = QtGui.QPushButton("Prev Page", self)
btnPrevPage.clicked.connect(self.PrevPage)
btnPrevPage.move(0,160)
btnNextPage = QtGui.QPushButton("Next Page", self)
btnNextPage.clicked.connect(self.NextPage)
btnNextPage.move(100, 160)
try:
txtNum1 = QtGui.QLabel(self.Song[0 + 10*self.PageNum], self)
txtNum1.resize(500, 30)
txtNum2 = QtGui.QLabel(self.Song[1 + 10*self.PageNum], self)
txtNum2.move(0, 15)
txtNum2.resize(500, 30)
txtNum3 = QtGui.QLabel(self.Song[2 + 10*self.PageNum], self)
txtNum3.move(0, 30)
txtNum3.resize(500, 30)
txtNum4 = QtGui.QLabel(self.Song[3 + 10*self.PageNum], self)
txtNum4.move(0, 45)
txtNum4.resize(500, 30)
txtNum5 = QtGui.QLabel(self.Song[4 + 10*self.PageNum], self)
txtNum5.move(0, 60)
txtNum5.resize(500, 30)
txtNum6 = QtGui.QLabel(self.Song[5 + 10*self.PageNum], self)
txtNum6.move(0, 75)
txtNum6.resize(500, 30)
txtNum7 = QtGui.QLabel(self.Song[6 + 10*self.PageNum], self)
txtNum7.move(0, 90)
txtNum7.resize(500, 30)
txtNum8 = QtGui.QLabel(self.Song[7 + 10*self.PageNum], self)
txtNum8.move(0, 105)
txtNum8.resize(500, 30)
txtNum9 = QtGui.QLabel(self.Song[8 + 10*self.PageNum], self)
txtNum9.move(0, 120)
txtNum9.resize(500, 30)
txtNum10 = QtGui.QLabel(self.Song[9 + 10*self.PageNum], self)
txtNum10.move(0, 135)
txtNum10.resize(500, 30)
print("2")
except IndexError:
print("2.5")
self.show()
print("3")
def close(self):
sys.exit()
def play(self):
pygame.mixer.music.unpause()
def pause(self):
pygame.mixer.music.pause()
def next(self, event):
self.CurrentSong = self.CurrentSong + 1
if self.CurrentSong > len(self.Song) + 1:
self.CurrentSong = 0
pygame.mixer.music.load('/home/pi/Desktop/Muziek/' + self.Song[self.CurrentSong])
pygame.mixer.music.play()
return self.CurrentSong;
def previous(self, event):
self.CurrentSong = self.CurrentSong - 1
if self.CurrentSong < 0:
self.CurrentSong = len(self.Song) -1
pygame.mixer.music.load('/home/pi/Desktop/Muziek/' + self.Song[self.CurrentSong])
pygame.mixer.music.play()
def PrevPage(self, event):
print("p1")
self.PageNum = self.PageNum - 1
if self.PageNum < 0 :
print("p<0")
self.PageNum = 0
print("p2")
self.home()
return self.PageNum;
def NextPage(self, event):
print("n1")
self.PageNum = self.PageNum + 1
if self.PageNum > len(self.Song) / 10:
print("n>0")
self.PageNum = self.PageNum - 1
print("n2")
self.home()
return self.PageNum;
app = QtGui.QApplication(sys.argv)
GUI = Window()
sys.exit(app.exec_())
The problem is that every time you call the home() function you are creating new labels, what you have to do is just update the text, for this we create a list of labels. Avoid using try and except since the program may have errors, it is better to verify that the index of the list is in the range.
When closing the window it is better to release the sound resource with pygame.mixer.quit() before closing the window, for this it is better to overwrite closeEvent().
import sys
import os
import pygame
from PyQt4 import QtGui, QtCore
from time import sleep
class Window(QtGui.QMainWindow):
song_per_page = 10
directory = '/home/pi/Desktop/Muziek/'
def __init__(self):
super(Window, self).__init__()
self.setGeometry(50, 50, 500, 300)
self.setWindowTitle("Music Player Alpha")
AutoPlay = True
Song = os.listdir(self.directory)
Song = sorted(Song)
self.Song = Song
self.CurrentSong = 0
self.PageNum = 0
pygame.mixer.init()
self.txtNums = []
self.home()
self.song()
def home(self):
btnQuit = QtGui.QPushButton("Quit", self)
btnQuit.clicked.connect(self.close)
btnQuit.move(400, 270)
btnPlay = QtGui.QPushButton("Play", self)
btnPlay.clicked.connect(self.play)
btnPlay.move(100, 270)
btnPause = QtGui.QPushButton("Pause", self)
btnPause.clicked.connect(self.pause)
btnPause.move(200, 270)
btnNext = QtGui.QPushButton("Next", self)
btnNext.clicked.connect(self.next)
btnNext.move(300, 270)
btnPrevious = QtGui.QPushButton("Previous", self)
btnPrevious.clicked.connect(self.previous)
btnPrevious.move(0, 270)
btnPrevPage = QtGui.QPushButton("Prev Page", self)
btnPrevPage.clicked.connect(self.PrevPage)
btnPrevPage.move(0, 160)
btnNextPage = QtGui.QPushButton("Next Page", self)
btnNextPage.clicked.connect(self.NextPage)
btnNextPage.move(100, 160)
for i in range(self.song_per_page):
txtNum = QtGui.QLabel(self)
txtNum.resize(500, 30)
txtNum.move(0, 15 * i)
self.txtNums.append(txtNum)
self.updateLabels()
self.show()
def updateLabels(self):
print(self.CurrentSong, self.PageNum)
for i in range(len(self.txtNums)):
index = i + self.song_per_page * self.PageNum
self.txtNums[i].clear()
if index < len(self.Song):
self.txtNums[i].setText(self.Song[i + self.song_per_page * self.PageNum])
def closeEvent(self, event):
pygame.mixer.quit()
QtGui.QMainWindow.closeEvent(self, event)
def play(self):
pygame.mixer.music.unpause()
def pause(self):
pygame.mixer.music.pause()
def song(self):
try:
pygame.mixer.music.load(self.directory + self.Song[self.CurrentSong])
pygame.mixer.music.play()
except pygame.error:
print("Module format not recognized")
self.updateLabels()
def next(self, event):
self.CurrentSong = (self.CurrentSong + 1) % len(self.Song)
self.song()
def previous(self, event):
self.CurrentSong = (self.CurrentSong - 1) % len(self.Song)
self.song()
def PrevPage(self, event):
self.PageNum = self.PageNum - 1
if self.PageNum < 0:
self.PageNum = 0
self.updateLabels()
def NextPage(self, event):
if self.song_per_page * (self.PageNum + 1) - 1 < len(self.Song):
self.PageNum = self.PageNum + 1
self.updateLabels()
app = QtGui.QApplication(sys.argv)
GUI = Window()
sys.exit(app.exec_())