How to use QFile with Python VLC MediaPlayer - python

I can simply play a wav file from a file with the code below:
media = vlc.MediaPlayer('c.wav')
media.audio_set_volume(50)
media.play()
How can I do the same with qrc resource file? I tried this code but doesn't seem to work:
mediafile = QFile(':/sounds/c.wav')
media = vlc.Instance().media_player_new()
media.set_media(mediafile)
media.audio_set_volume(50)
media.play()

You need to use vlc.media_new_callbacks for this so that you can wrap the QFile and use its methods. Below is a demo script that shows how to implement that:
import sys, vlc
from PyQt5.QtCore import QFile, QCoreApplication
#vlc.CallbackDecorators.MediaOpenCb
def open_cb(opaque, data, size):
data.contents.value = opaque
size.value = sys.maxsize
return 0
#vlc.CallbackDecorators.MediaReadCb
def read_cb(opaque, buffer, length):
data = qfile.read(length)
for index, char in enumerate(data):
buffer[index] = char
return len(data)
#vlc.CallbackDecorators.MediaSeekCb
def seek_cb(opaque, offset):
qfile.seek(offset)
return 0
#vlc.CallbackDecorators.MediaCloseCb
def close_cb(opaque):
qfile.close()
if __name__ == '__main__':
import time, signal
signal.signal(signal.SIGINT, signal.SIG_DFL)
print('Press Ctrl+C to Quit')
player = vlc.Instance().media_player_new()
qfile = QFile(sys.argv[1])
qfile.open(QFile.ReadOnly)
player.set_media(vlc.Instance().media_new_callbacks(
open_cb, read_cb, seek_cb, close_cb, None))
player.play()
app = QCoreApplication(sys.argv)
app.exec_()
UPDATE:
It's somewhat tricky to get this working correctly in a more typical PyQt application, because the callbacks have to be static functions. Here is an extended example that shows how it can be done:
import sys, ctypes, vlc
from PyQt5 import QtCore, QtWidgets
class VLCPlayer(QtCore.QObject):
def __init__(self, parent=None):
super().__init__()
self._player = vlc.Instance().media_player_new()
#staticmethod
#vlc.CallbackDecorators.MediaOpenCb
def _open_cb(voidptr, data, size):
data.contents.value = voidptr
size.value = sys.maxsize
return 0
#staticmethod
#vlc.CallbackDecorators.MediaReadCb
def _read_cb(voidptr, buffer, length):
stream = ctypes.cast(
voidptr, ctypes.POINTER(ctypes.py_object)).contents.value
data = stream.read(length)
for index, char in enumerate(data):
buffer[index] = char
return len(data)
#staticmethod
#vlc.CallbackDecorators.MediaSeekCb
def _seek_cb(voidptr, offset):
stream = ctypes.cast(
voidptr, ctypes.POINTER(ctypes.py_object)).contents.value
stream.seek(offset)
return 0
#staticmethod
#vlc.CallbackDecorators.MediaCloseCb
def _close_cb(voidptr):
stream = ctypes.cast(
voidptr, ctypes.POINTER(ctypes.py_object)).contents.value
stream.close()
def play(self):
self._player.play()
def stop(self):
self._player.stop()
def load(self, path):
file = QtCore.QFile(path)
file.open(QtCore.QIODevice.ReadOnly)
voidptr = ctypes.cast(ctypes.pointer(
ctypes.py_object(file)), ctypes.c_void_p)
self._player.set_media(vlc.Instance().media_new_callbacks(
self._open_cb, self._read_cb,
self._seek_cb, self._close_cb, voidptr))
class Window(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.buttonPlay = QtWidgets.QPushButton('Play')
self.buttonPlay.clicked.connect(self.handlePlay)
self.buttonStop = QtWidgets.QPushButton('Stop')
self.buttonStop.clicked.connect(self.handleStop)
self.buttonOpen = QtWidgets.QPushButton('Open')
self.buttonOpen.clicked.connect(self.handleOpen)
layout = QtWidgets.QHBoxLayout(self)
layout.addWidget(self.buttonOpen)
layout.addWidget(self.buttonPlay)
layout.addWidget(self.buttonStop)
self.player = VLCPlayer(self)
def handlePlay(self):
self.player.play()
def handleStop(self):
self.player.stop()
def handleOpen(self):
path, ok = QtWidgets.QFileDialog.getOpenFileName(
self, filter='Audio Files (*.wav)')
if ok:
self.player.load(path)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.setWindowTitle('VLC Player')
window.setGeometry(600, 100, 200, 80)
window.show()
sys.exit(app.exec_())

Related

change parameters during sounddevice processing in Pyqt dial

I want to turn the dial on pyqt's GUI to change parameters while sounddevice's outputstream is processing, but the GUI freezes. I've tried everything I could find, and I've pieced together a bunch of code, but I'd like to know what the solution is.
I want to change the equalizer of the music being played in near real time by changing the parameters of the pedalboard that grants the equalizer.
import sys
import time
from PyQt5.QtCore import QObject, QThread, pyqtSignal
from PyQt5.QtWidgets import *
from PyQt5.QtMultimedia import QSound
from pedalboard import *
import sounddevice as sd
import librosa
from threading import *
import threading
import soundfile as sf
def long_running_function(update_ui,board):
event = threading.Event()
try:
data, fs = sf.read('continue.wav', always_2d=True)
current_frame = 0
def callback(outdata, frames, time, status):
nonlocal current_frame
if status:
print(status)
chunksize = 2024
#print(chunksize, current_frame,len(data),frames)
outdata[:chunksize] = board(data[current_frame:current_frame + chunksize])
if chunksize < 2024:
outdata[chunksize:] = 0
raise sd.CallbackStop()
current_frame += chunksize
stream = sd.OutputStream(
samplerate=fs, blocksize=2024 , channels=data.shape[1],
callback=callback, finished_callback=event.set)
with stream:
event.wait()
except KeyboardInterrupt:
exit('\nInterrupted by user')
class Worker(QObject):
finished = pyqtSignal()
progress = pyqtSignal(int)
def __init__(self, main_window):
self.main_window = main_window
super(Worker, self).__init__(main_window)
def run(self):
long_running_function(self.update_progress,self.main_window.make_board())
self.finished.emit()
def update_progress(self, percent):
self.progress.emit(percent)
class MainWindow(QMainWindow):
def __init__(self):
super(self.__class__, self).__init__()
self.progress = QProgressBar()
self.button = QPushButton("Start")
self.dial = QDial()
self.init_ui()
self.qsound = None
self.qsound2 = None
self.effected_audio = None
self.audio = None
self.sr = None
self.dial.valueChanged.connect(self.make_board)
self.button.clicked.connect(self.execute)
self.show()
def init_ui(self):
self.setGeometry(100, 100, 250, 250)
layout = QVBoxLayout()
layout.addWidget(self.progress)
layout.addWidget(self.button)
layout.addWidget(self.dial)
self.setWindowTitle('Audio Player')
button_play = QPushButton("環境音を再生")
button_play2 = QPushButton("音楽と環境音を再生")
button_stop = QPushButton("Stop")
button_dialog = QPushButton("音楽を選択")
button_dialog2 = QPushButton("環境音を選択")
dial = QDial()
live = QPushButton("LIVE")
self.label = QLabel(self)
self.label2 = QLabel(self)
layout.addWidget(button_dialog)
layout.addWidget(button_dialog2)
layout.addWidget(button_play)
layout.addWidget(button_stop)
layout.addWidget(button_play2)
layout.addWidget(live)
layout.addWidget(self.dial)
layout.addWidget(self.label)
layout.addWidget(self.label2)
button_dialog.clicked.connect(self.button_openfile)
button_dialog2.clicked.connect(self.button_openfile2)
button_play.clicked.connect(self.button_play)
button_play2.clicked.connect(self.button_play2)
button_stop.clicked.connect(self.button_stop)
live.clicked.connect(self.start)
self.dial.valueChanged.connect(self.sliderMoved)
self.dial.valueChanged.connect(self.make_board)
self.dial.setMinimum(0)
self.dial.setMaximum(20)
self.dial.setValue(5)
w = QWidget()
w.setLayout(layout)
self.setCentralWidget(w)
def sliderMoved(self):
number = self.dial.value()
print(number)
return number
def make_board(self):
board = Pedalboard([
Compressor(ratio=10, threshold_db=-20),
Gain(gain_db=self.dial.value()),
Phaser(),
Reverb()
],sample_rate=44100)
return board
def button_play(self):
print("")
def button_play2(self):
if self.qsound is not None:
board = self.make_board(self.effects)
self.effected_audio = board(self.audio,self.sr)
sd.play(self.effected_audio)
self.qsound2.play()
def button_stop(self):
if self.qsound is not None:
sd.stop()
self.qsound2.stop()
def button_openfile(self):
filepath, _ = QFileDialog.getOpenFileName(self, 'Open file','c:\\',"Audio files (*.wav)")
filepath = os.path.abspath(filepath)
self.qsound = QSound(filepath)
self.filename = os.path.basename(filepath)
self.audio, self.sr = librosa.load(self.filename, sr=44100)
self.label.setText(self.filename)
self.label.adjustSize()
def button_openfile2(self):
filepath2, _ = QFileDialog.getOpenFileName(self, 'Open file','c:\\',"Audio files (*.wav)")
filepath2 = os.path.abspath(filepath2)
self.qsound2 = QSound(filepath2)
self.filename2 = os.path.basename(filepath2)
self.label2.setText(self.filename2)
self.label2.adjustSize()
def start(self):
self.thread.start()
def execute(self):
self.update_progress(0)
self.thread = QThread()
self.worker = Worker(self)
self.worker.moveToThread(self.thread)
self.thread.started.connect(self.worker.run)
self.worker.finished.connect(self.thread.quit)
self.worker.finished.connect(self.worker.deleteLater)
self.thread.finished.connect(self.thread.deleteLater)
self.worker.progress.connect(self.update_progress)
self.thread.start()
self.button.setEnabled(False)
def update_progress(self, progress):
self.progress.setValue(progress)
self.button.setEnabled(progress == 100)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
app.exec_()
Qt Docs for moveToThread() say:
Changes the thread affinity for this
object and its children. The object
cannot be moved if it has a parent.
I cannot see where Worker instance gets started. Maybe you wanted to derive Worker from QThread, and call self.worker.start()?
OutputStream and the Qt GUI both have their own internal main loops which are responsible for handling their respective events. When you execute both on the same thread, one or the other might freeze.

Showing a Progress Bar in a QMainWindow from a Callback, boto3.s3

I am creating a program that uploads a folder into a bucket. Right now I have the program and UI all set I would just like to add a progress bar showing which file is being uploaded.
I am wondering if there is a way to use the
s3.upload_file(fileName, bucketName, objectName, Callback=ProgressPercentage(path.text())) to get a progress bar on my QMainWindow. Or if I need to go about this a different way.
class ProgressPercentage(object):
def __init__(self, filename):
self._filename = filename
self._size = float(os.path.getsize(filename))
self._seen_so_far = 0
self._lock = threading.Lock()
def __call__(self, bytes_amount):
# To simplify, assume this is hooked up to a single filename
with self._lock:
self._seen_so_far += bytes_amount
percentage = (self._seen_so_far / self._size) * 100
sys.stdout.write(
"\r%s %s / %s (%.2f%%)" % (
self._filename, self._seen_so_far, self._size,
percentage))
sys.stdout.flush()
The logic in this case is to create a QObject that has a signal that indicates the progress, in addition the upload task must be executed in a secondary thread so that the GUI does not freeze:
import math
import os
import sys
import threading
import boto3
from PyQt5 import QtCore, QtWidgets
class S3Worker(QtCore.QObject):
started = QtCore.pyqtSignal()
finished = QtCore.pyqtSignal()
percentageChanged = QtCore.pyqtSignal(int)
def __init__(self, parent=None):
super().__init__(parent)
self._s3 = boto3.client("s3")
#property
def s3(self):
return self._s3
def upload(self, filename, bucketname, objectname):
self._size = float(os.path.getsize(filename))
self._seen_so_far = 0
threading.Thread(
target=self._execute, args=(filename, bucketname, objectname), daemon=True
).start()
def _execute(self, fileName, bucketName, objectName):
self.started.emit()
self.s3.upload_file(fileName, bucketName, objectName, Callback=self._callback)
self.finished.emit()
def _callback(self, bytes_amount):
self._seen_so_far += bytes_amount
percentage = (self._seen_so_far / self._size) * 100
self.percentageChanged.emit(math.floor(percentage))
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.filename_le = QtWidgets.QLineEdit()
self.upload_btn = QtWidgets.QPushButton("Upload")
self.percentage_pb = QtWidgets.QProgressBar()
lay = QtWidgets.QGridLayout(self)
lay.addWidget(QtWidgets.QLabel("filename:"))
lay.addWidget(self.filename_le, 0, 1)
lay.addWidget(self.upload_btn, 0, 2)
lay.addWidget(self.percentage_pb, 1, 0, 1, 3)
self.qs3 = S3Worker()
self.upload_btn.clicked.connect(self.start_upload)
self.qs3.started.connect(lambda: self.upload_btn.setEnabled(False))
self.qs3.finished.connect(lambda: self.upload_btn.setEnabled(True))
self.qs3.percentageChanged.connect(self.percentage_pb.setValue)
def start_upload(self):
filename = self.filename_le.text()
if os.path.exists(filename):
self.qs3.upload(filename, "mybucket", "foobject")
def main():
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

Windump via a python subprocess and PyQt Button

The simple idea is that user inputs duration in seconds, and presses a PyQt button, that calls a function that creates a python subprocess and runs windump via it. Then time sleep is used to wait for user defined duration and then process.terminate(), terminates it (code below)
def windump_exec(duration):
p = s.Popen(['windump', '-i', '3', '-w', 'packets.pcap'], stdout=s.PIPE)
time.sleep(duration)
p.terminate()
Now once this is done, scapy reads .pcap file and I show stuff on the screen in short. While this is happening QWaitingSpinner is running, and to handle this I run the above logic (including scapy) using QRunnable (code below)
class ThreadRunnable(QRunnable):
def __init__(self, _time, filler):
QRunnable.__init__(self)
self.time = _time
self.filler = filler
self.signal = RunnableSignal()
def run(self):
windump_exec(self.time)
packets = parse_data()
self.filler(packets)
self.signal.result.emit()
The Problem is that the windump code works fine on it's own, but inside the QThread it doesn't create an output file and hence scapy has nothing to read (open), and it gives error.
Instead of using Popen with QThread you can use QProcess, in my test I have used tcpdump but I suppose that changing to windump should have the same behavior:
import os
from PyQt5 import QtCore, QtGui, QtWidgets
from scapy.all import rdpcap
import psutil
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
class DumpProcesor(QtCore.QObject):
started = QtCore.pyqtSignal()
finished = QtCore.pyqtSignal()
def __init__(self, parent=None):
super().__init__(parent)
self._process = QtCore.QProcess()
self._timer = QtCore.QTimer(singleShot=True)
self._timer.timeout.connect(self.handle_timeout)
self._pid = -1
#property
def process(self):
return self._process
#property
def timer(self):
return self._timer
#QtCore.pyqtSlot()
def start(self):
self.started.emit()
status, self._pid = self._process.startDetached()
if status:
self._timer.start()
else:
self.finished.emit()
#QtCore.pyqtSlot()
def handle_timeout(self):
if self._pid > 0:
p = psutil.Process(self._pid)
p.terminate()
QtCore.QTimer.singleShot(100, self.finished.emit)
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.log_te = QtWidgets.QTextEdit(readOnly=True)
self.time_sb = QtWidgets.QSpinBox(minimum=1)
self.start_btn = QtWidgets.QPushButton(self.tr("Start"))
grid_layout = QtWidgets.QGridLayout(self)
grid_layout.addWidget(self.log_te, 0, 0, 1, 3)
grid_layout.addWidget(QtWidgets.QLabel("Time (seg):"), 1, 0)
grid_layout.addWidget(self.time_sb, 1, 1)
grid_layout.addWidget(self.start_btn, 1, 2)
self.dump_procesor = DumpProcesor(self)
self.dump_procesor.process.setProgram("tcpdump")
filename = os.path.join(CURRENT_DIR, "packets.pcap")
self.dump_procesor.process.setArguments(["-i", "3", "-w", filename])
self.start_btn.clicked.connect(self.start)
self.dump_procesor.finished.connect(self.on_finished)
#QtCore.pyqtSlot()
def start(self):
self.log_te.clear()
self.start_btn.setDisabled(True)
self.dump_procesor.timer.setInterval(self.time_sb.value() * 1000)
self.dump_procesor.start()
#QtCore.pyqtSlot()
def on_finished(self):
self.start_btn.setDisabled(False)
filename = os.path.join(CURRENT_DIR, "packets.pcap")
packets = rdpcap(filename)
for packet in packets:
t = packet.show(dump=True)
self.log_te.append(t)
def main():
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

Python, reference class instance/method in decorated function

I'm having a hard time finding a way to reference class instances in a decorator function.
import json
import time
import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from main_UI import Ui_ApplicationWindow
from slack import RTMClient
class WorkerThread(QThread):
finished = pyqtSignal(str)
def __init__(self):
QThread.__init__(self)
self.rtm_client = RTMClient(token="xoxp...")
def run(self):
self.rtm_client.start()
#RTMClient.run_on(event="message")
def say_hello(**payload):
data = payload['data']
if (len(data) != 0):
if "text" in data:
text = data['text']
self.finished.emit(str(text))
class ApplicationWindow(QMainWindow):
def __init__(self):
super(ApplicationWindow, self).__init__()
self.ui = Ui_ApplicationWindow()
self.ui.setupUi(self)
self.ui.pushButton.clicked.connect(self.start_rtm)
def start_rtm(self):
self.thread = WorkerThread()
self.thread.finished.connect(self.update)
self.thread.start()
#pyqtSlot(str)
def update(self, data):
self.ui.label.setText(data)
if __name__ == "__main__":
app = QApplication(sys.argv)
myWindow = ApplicationWindow()
myWindow.show()
app.exec_()
So in say_hello since it can't take self as an argument, I'm not able to use self.finished.emit(text) at the end of the function.
How can I reference a class instance/function using self in say_hello?
No, You can not. Instead of using the #RTMClient.run_on() decorator, use the RTMClient.on() function to register it.
import threading
import asyncio
from slack import RTMClient
from PyQt5 import QtCore, QtWidgets
class SlackClient(QtCore.QObject):
textChanged = QtCore.pyqtSignal(str)
def start(self):
RTMClient.on(event="message", callback=self.say_hello)
threading.Thread(target=self._start_loop, daemon=True).start()
def _start_loop(self):
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
slack_token = "xoxb-...."
rtm_client = RTMClient(token=slack_token)
rtm_client.start()
def say_hello(self, **payload):
data = payload["data"]
if data:
if "text" in data:
text = data["text"]
self.textChanged.emit(text)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
client = SlackClient()
button = QtWidgets.QPushButton("Start")
textedit = QtWidgets.QPlainTextEdit()
button.clicked.connect(client.start)
client.textChanged.connect(textedit.appendPlainText)
w = QtWidgets.QWidget()
lay = QtWidgets.QVBoxLayout(w)
lay.addWidget(button)
lay.addWidget(textedit)
w.show()
sys.exit(app.exec_())
Update:
import sys
import threading
import asyncio
from slack import RTMClient
from PyQt5 import QtCore, QtWidgets
from main_UI import Ui_ApplicationWindow
class SlackClient(QtCore.QObject):
textChanged = QtCore.pyqtSignal(str)
def start(self):
RTMClient.on(event="message", callback=self.say_hello)
threading.Thread(target=self._start_loop, daemon=True).start()
def _start_loop(self):
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
slack_token = "xoxb-...."
rtm_client = RTMClient(token=slack_token)
rtm_client.start()
def say_hello(self, **payload):
data = payload["data"]
if data:
if "text" in data:
text = data["text"]
self.textChanged.emit(text)
class ApplicationWindow(QtWidgets.QMainWindow):
def __init__(self):
super(ApplicationWindow, self).__init__()
self.ui = Ui_ApplicationWindow()
self.ui.setupUi(self)
self.client = SlackClient()
# connections
self.ui.pushButton.clicked.connect(self.client.start)
self.client.textChanged.connect(self.ui.label.setText)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
myWindow = ApplicationWindow()
myWindow.show()
sys.exit(app.exec_())
Actually you cannot self since that is a global variable, not a class one.
from slack import RTMClient
class WorkerThread(QThread):
finished = pyqtSignal(dict)
def __init__(self):
QThread.__init__(self)
self.rtm_client = RTMClient(token="xoxp-....")
def run(self):
self.rtm_client.start()
#RTMClient.run_on(event="message")
def say_hello(**payload):
data = payload['data']
if (len(data) != 0):
if "text" in data:
text = data['text']
WorkerThread.finished.emit(text) <--- using self impossible
I suggest that you make such variable private by appending two underscores at the beginning (__my_private_var)

PyQt5 - Why is progress bar not showing a file copy progress?

I am trying to copy a file with a progress bar included in PyQt5. I can see in a console with print("Copied: {}".format(percent)) that 100% is copied.
However, my progress bar does not update my copy process. How can I check that the signal was sent? Where did I make mistake?
import os, sys
from PyQt5 import QtWidgets, QtCore
class Extended(QtCore.QThread):
def __init__(self):
super().__init__()
self.src_file = 'test.txt'
self.dst_file = 'test_copy.txt'
self.copyfileobj(self.src_file, self.dst_file, self.cb)
copied_percent = QtCore.pyqtSignal(int)
def cb(self, temp_file_size):
self.file_size = os.stat(self.src_file).st_size
percent = int(temp_file_size/self.file_size*100)
print("Copied: {}".format(percent))
self.copied_percent.emit(percent)
def copyfileobj(self, fsrc, fdst, callback, length=16*1024):
copied = 0
with open(fsrc, "rb") as fr, open(fdst, "wb") as fw:
while True:
buff = fr.read(length)
if not buff:
break
fw.write(buff)
copied += len(buff)
callback(copied)
class MyApp(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.w = QtWidgets.QWidget()
self.w.setWindowTitle("Progress bar copy test")
# Add widgets on the window
self.copy_button = QtWidgets.QPushButton("Copy", self)
self.copy_button.sizeHint()
self.progress_bar = QtWidgets.QProgressBar(self)
self.progress_bar.setGeometry(0, 40, 300, 25)
self.progress_bar.setMaximum(100)
self.copy_button.clicked.connect(self.on_button_click)
def on_button_click(self):
self.copy_button.setDisabled(True)
self.ext = Extended()
self.ext.copied_percent.connect(self.on_count_change)
self.ext.start()
def on_count_change(self, value):
self.progress_bar.setValue(value)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
prog = MyApp()
prog.show()
sys.exit(app.exec_())
Ok, I figured it out. There has to be a run method in a thread-supported class which is executed when you call a start() method on a instance object self.ext. I also added self.ext.join() method to not end a program before the thread is executed and finished.
import os, sys
from PyQt5 import QtWidgets, QtCore
class Extended(QtCore.QThread):
"""
For running copy operation
"""
copied_percent_signal= QtCore.pyqtSignal(int)
def __init__(self):
super().__init__()
self.src_file = 'test.txt'
self.dst_file = 'test_copy.txt'
self.file_size = os.stat(self.src_file).st_size
def run(self):
self.copyfileobj(self.src_file, self.dst_file, self.my_callback)
def my_callback(self, temp_file_size):
percent = int(temp_file_size/self.file_size*100)
print("Copiedd: {}".format(percent))
self.copied_percent_signal.emit(percent)
def copyfileobj(self, fsrc, fdst, callback, length=16*1024):
copied = 0
with open(fsrc, "rb") as fr, open(fdst, "wb") as fw:
while True:
buff = fr.read(length)
if not buff:
break
fw.write(buff)
copied += len(buff)
callback(copied)
class MyApp(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
# Instance attribute defined later in on_button_click()
self.ext = None
self.w = QtWidgets.QWidget()
self.w.setWindowTitle("Progress bar copy test")
# Add widgets on the window
self.copy_button = QtWidgets.QPushButton("Copy", self)
self.copy_button.sizeHint()
self.progress_bar = QtWidgets.QProgressBar(self)
self.progress_bar.setGeometry(0, 40, 300, 25)
self.progress_bar.setMaximum(100)
self.copy_button.clicked.connect(self.on_button_click)
def on_button_click(self):
self.copy_button.setDisabled(True)
self.ext = Extended()
self.ext.copied_percent_signal.connect(self.on_count_change)
self.ext.start()
self.ext.join()
def on_count_change(self, value):
self.progress_bar.setValue(value)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
prog = MyApp()
prog.show()
sys.exit(app.exec_())
My file is being copied and the progress bar is working.

Categories

Resources