pyqt4 seg fault sequential app start stop - python

I'm trying to read webpages using pyqt. I need to call a method multiple times with different URLs. I am currently using code similar to: http://blog.sitescraper.net/2010/06/scraping-javascript-webpages-in-python.html#comment-form
However when I try I get seg faults. Any suggestions welcome.
import sys
from time import clock
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from PyQt4.QtWebKit import *
from PyQt4.QtNetwork import *
class Render(QWebPage):
def __init__(self):
self.app = QApplication(sys.argv)
QWebPage.__init__(self)
self.networkAccessManager().finished.connect(self.handleEnd)
self.loadFinished.connect(self._loadFinished)
self.mainFrame().setScrollBarPolicy(Qt.Horizontal, Qt.ScrollBarAlwaysOff)
self.mainFrame().setScrollBarPolicy(Qt.Vertical, Qt.ScrollBarAlwaysOff)
def loadURL(self, url):
self.mainFrame().load(QUrl(url))
self.app.exec_()
def savePageImage (self, width, height, Imagefile):
pageSize = self.mainFrame().contentsSize();
if width == 0:
pageWidth = pageSize.width()
else:
pageWidth = width
if height == 0:
pageHeight = pageSize.height()
else:
pageHeight = height
self.setViewportSize(QSize(pageWidth, pageHeight))
Img = QImage(self.viewportSize(), QImage.Format_ARGB32)
painter = QPainter(Img)
self.mainFrame().render(painter)
painter.end()
Img.save(Imagefile)
def _loadFinished(self, result):
print "load finish"
self.frame = self.mainFrame()
self.returnVal = result
self.app.quit()
def handleEnd (self, reply):
# get first http code and disconnect
# could add filter to listen relevant responses
self.httpcode = reply.attribute(QNetworkRequest.HttpStatusCodeAttribute)
self.networkAccessManager().finished.disconnect(self.handleEnd)
jsrurl = 'http://www.w3resource.com/javascript/document-alert-confirm/four.html'
badurl='something.or.other'
badhttp = 'http://eclecticself.com/test2.html'
testurl = 'http://www.nydailynews.com/entertainment/index.html'
testurl2 = 'http://www.palmbeachpost.com/'
testurl3 = 'http://www.nydailynews.com/news/politics/2011/08/03/2011-08-03_pat_buchanan_downplays_controversy_after_calling_president_obama_your_boy_to_rev.html'
url = testurl
start = clock()
r = Render()
r.loadURL(url)
html = r.frame.toHtml()
elapsed = clock() - start
print elapsed
if (r.returnVal == True):
if (r.httpcode.toInt()[0] != 404):
#print html.toUtf8()
start = clock()
r.savePageImage(1024, 0, "pageSnapshot.png")
elapsed = clock() - start
print elapsed
else:
print 'page not found'
else:
print 'badurl'
s = Render()
s.loadURL(jsrurl)
html = s.frame.toHtml()
elapsed = clock() - start
print elapsed
if (s.returnVal == True):
if (s.httpcode.toInt()[0] != 404):
print html.toUtf8()
start = clock()
s.savePageImage(1024, 0, "pageSnapshot.png")
elapsed = clock() - start
print elapsed
else:
print 'page not found'
else:
print 'badurl'

PyQt is often forgetting to keep references to objects. Workarounds:
Try to use PySide instead of PyQt, it is easy, since the API is almost completely the same as PyQt. I would try PySide first, it might solve your problem immediately or at least make it predictable and reproducible.
Try to keep references to all the Qt objects you are using and remove those references when you're done with the objects. You can also try to explicitly close them or navigate to "about:blank" before going to the next Web page.
It usually helps. If not, then you need to narrow it down as utdemir suggested it above. Debugging usually not help, since such issues are often timing related as well. Logging without an output buffer usually helps you get closer to the source of the problem.
I'm with you in soul, such issues are hard to track down!

Related

Problem to reload a loop with Qdial, signal & subprocess

I am trying to record and use data with a Qdial.
For the recording every thing seems to be fine, but in order to use this data in while loop I have to reload the while loop. When I do so with signal and a subprocess, the loop seems to use every data recorded, another problem is that the loop don’t stop at the end of the process.
I have no doubt I am using the wrong method.
Sorry for my bad English, and thank you very much for your help.
So I am using 3 scripts: Qdial.py, Data.py, Loop.py.
The Data.py is an accumulation of data, here I use just one:
A1 = 10
The Loop.py is in deed my main script, here I resume:
import time
from Data import *
def loop():
while True:
print('A1 = ', A1)
time.sleep(0.1)
loop()
[edit] Instead of this Loop.py I will not use from Data import *,
but this one witch don't raise errors (but there is always the problem of the continuous looping after the exit on Qdial.py):
import time
def loop():
with open('/address/Data.py', 'r') as file:
lines = file.readlines()
A1 = lines[0]
A1 = float(A1[4:-1])
print('A1 = ', A1)
while True:
loop()
time.sleep(0.09)
[/edit]
The Qdial.py is a common one, with the signal and a subprocess that raise false values:
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import *
from Data import *
import sys, signal, subprocess, time
[edit] This line is no longer needed, and cause an endless loop.
I launch Loop.py with a subprocess:
proc = subprocess.Popen(['python3', '/address/Loop.py'])
[/edit]
Then it’s the writing for the Qdial:
class Window(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(300, 300, 150, 150)
vbox = QVBoxLayout()
self.a1 = QDial(self)
self.value = int(A1)
self.a1.setValue(self.value)
self.value = self.a1.value()
self.lab1 = QtWidgets.QLabel(self)
self.lab1.setText('A1 = ' + str(A1) + 's')
self.a1.valueChanged.connect(self.dial)
vbox.addWidget(self.a1)
vbox.addWidget(self.lab1)
self.setLayout(vbox)
self.show()
def dial(self):
val1 = self.a1.value()
self.lab1.setText('A1 = ' + str(val1) + 's')
with open('/address/data.py', 'r') as file:
lines = file.readlines()
lines[0] = 'A1 = ' + str(val1) + '\n'
with open('/address/data.py', 'w') as file:
for line in lines:
file.write(line)
file.close()
[edit] Thoses lines are no longer define or needed.
Here I use signal and subprocess in order to reload the data in Loop.py:
proc.send_signal(signal.SIGINT)
subprocess.Popen(['python3', '/address/Loop.py'])
[/edit]
And I finish:
app = QApplication(sys.argv)
window = Window()
sys.exit(app.exec_())
[edit] A solution to escape the endless loop was to run both scripts (Qdial.py & Loop.py) as subprocess from a main script and use Popen.wait(), Main.py:
import subprocess, signal
Qd = subprocess.Popen(['python3', '/address/Qdial.py'])
Lo = subprocess.Popen(['python3', '/address/Loop.py'])
if Qd.wait() != None:
Lo.send_signal(signal.SIGINT)
[/edit]
Of course I don’t understand what is wrong, sorry for the length of this post...Thanks again.

Trouble with connecting functions to GUI generated with PyQt

I am currently working on a project of simple spectrum analyzer that cooperates with PlutoSDR, which is programmable radio.
I created a simple GUI with QTDesigner, then pyuic'ed it into python code (my version is 3.8)
Here's my code: (I've cut out some irrelevant parts)
# Form implementation generated from reading ui file 'signal_analyzer.ui'
#
# Created by: PyQt5 UI code generator 5.15.6
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
import pyqtgraph
from PyQt5 import QtCore, QtGui, QtWidgets
from pyqtgraph.Qt import QtCore, QtGui
from pyqtgraph.widgets import PlotWidget
import sys
import numpy as np
import argparse
import adi
import time
import threading
import pyqtgraph as pg
np.seterr(divide='ignore')
class FakePluto:
# this is the class that simulates the radio if it's not connected to my computer
"""
perform some operations
"""
# output vector of data
return samples[:self.rx_buffer_size]
class SpectrumAnalyzerThread(threading.Thread):
def __init__(self, sdr, *args, **kwargs):
super().__init__(*args, **kwargs)
"""
set some initial parmeters
"""
self.sdr = sdr
elf.start_freq = int(70e6)
self.end_freq = int(150e6)
self.settings_changed = True
self.result = None
#property
def steps_per_scan(self):
return (self.end_freq - self.start_freq) // self.step_size
def setStop(self):
self.stop = True
print("stop")
def setStart(self):
self.stop = False
print("start")
def setStopFreq(self, win):
self.stop_freq = int(win.lineEdit.text)
self.start_freq += (self.stop_freq - self.start_freq) % self.step_size
def setStartFreq(self, win):
self.start_freq = int(win.lineEdit_2.text)
self.stop_freq += (self.stop_freq - self.start_freq) % self.step_size
def reconfigure(self, start_freq, end_freq, step_size):
self.start_freq = int(start_freq)
self.end_freq = int(end_freq)
self.step_size = int(step_size)
if (self.end_freq - self.start_freq) % self.step_size != 0:
raise Exception('range is not a multiple of the step size')
self.settings_changed = True
def run(self):
while not self.stop:
print("2", end = "\r")
if self.settings_changed:
self._current_freq = self.start_freq
self.result = np.zeros(self.steps_per_scan * self.samples_per_step)
self.sdr.gain_control_mode_chan0 = 'manual'
self.sdr.rx_hardwaregain_chan0 = self.gain
self.sdr.sample_rate = self.step_size
self.sdr.rx_rf_bandwidth = self.step_size
self.sdr.rx_buffer_size = self.samples_per_step
self.settings_changed = False
else:
if self._current_freq + self.step_size >= self.end_freq:
self._current_freq = self.start_freq
else:
self._current_freq += self.step_size
self.sdr.rx_lo = self._current_freq + self.step_size//2
self.sdr.rx() # skip one sample
rx_samples = self.sdr.rx()
psd = np.abs(np.fft.fftshift(np.fft.fft(rx_samples))) ** 2
assert len(psd) == self.samples_per_step
start_idx = (self._current_freq - self.start_freq) // self.step_size * self.samples_per_step
self.result[start_idx:start_idx + self.samples_per_step] = psd
#print(self.result.tolist())
class Ui_MainWindow(QtWidgets.QMainWindow):
def setupUi(self, MainWindow, analyzer_thread):
"""
define UI elements - this part was generated from .UI file
"""
self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit.setGeometry(QtCore.QRect(800, 140, 231, 25))
self.lineEdit.setObjectName("lineEdit")
self.runButton = QtWidgets.QPushButton(self.centralwidget)
self.runButton.setGeometry(QtCore.QRect(790, 310, 161, 51))
self.runButton.setObjectName("runButton")
self.stopButton = QtWidgets.QPushButton(self.centralwidget)
self.stopButton.setGeometry(QtCore.QRect(790, 380, 161, 51))
self.stopButton.setObjectName("stopButton")
self.retranslateUi(MainWindow)
# connect gui elements with functions
self.stopButton.clicked.connect(analyzer_thread.setStop) # type: ignore
self.runButton.clicked.connect(analyzer_thread.setStart) # type: ignore
self.lineEdit.textChanged[str].connect(analyzer_thread.setStartFreq)
#self.lineEdit_2.textChanged[str].connect(analyzer_thread.setStopFreq)
#self.sweepButton.clicked.connect(self.widget.singleSweep) # type: ignore
#self.lineEdit_3.modified.connect()
QtCore.QMetaObject.connectSlotsByName(self)
# function below is just for testing
def tomatoes(self, analyzer_thread):
print(analyzer_thread.start_freq)
def retranslateUi(self, MainWindow):
"""
UI retranslation
"""
def main():
# this part checks input script arguments, currently I'm using --simulate
parser = argparse.ArgumentParser(description='SDR Spectrum Analyzer for PlutoSDR')
parser.add_argument('pluto_uri', nargs='?', default=adi.Pluto._uri_auto,
help=f'URI of the PlutoSDR device (default: "{adi.Pluto._uri_auto}")')
parser.add_argument('--simulate', action='store_true',
help='Simulate by generating random noise instead of querying the Pluto device')
args = parser.parse_args()
if args.simulate:
sdr = FakePluto()
else:
sdr = adi.Pluto(args.pluto_uri)
# create and start the thread
analyzer_thread = SpectrumAnalyzerThread(sdr)
analyzer_thread.start()
app = QtGui.QApplication(sys.argv)
win = Ui_MainWindow()
win.show()
win.setupUi(win, analyzer_thread)
# this is the function that refreshes the plotWindow in GUI
def update():
if analyzer_thread.result is not None and not analyzer_thread.settings_changed:
print("1", end = "\r")
psd = analyzer_thread.result
num_bins = analyzer_thread.samples_per_step
if len(psd) % num_bins != 0:
raise Exception('num_bins is not a multiple of sample count')
binned = psd.reshape((-1, len(psd) // num_bins)).sum(axis=1)
binned_dB = 10 * np.log10(binned)
f = np.linspace(analyzer_thread.start_freq, analyzer_thread.end_freq, len(binned_dB))
#spectrum_trace.setData(f, binned_dB)
win.graphicsView.clear()
win.graphicsView.plot(f, binned_dB)
dispMax = str(np.amax(binned_dB))
win.currentMaxAmp.display(dispMax[0:5])
# update function is connected to the timer
timer = QtCore.QTimer()
timer.timeout.connect(update)
timer.start(1)
win.tomatoes(analyzer_thread)
app.exec()
analyzer_thread.stop = True
analyzer_thread.join()
if __name__ == '__main__':
main()
Now, I have two independent problems.
First
When I press "Stop" on the GUI, which sets analyzer_thread stop value to 'true', this works correctly (i. e. run function from analyzer_thread stops executing), though the update function is still running - the plot keeps refreshing but with the same values. Yet when I hit "start", the analyzer_thread doesn't start over. I have no idea what causes that.
Second
When I try to change stop frequency value, which should call analyzer_thread.setStopFreq I get this message:
Traceback (most recent call last):
File "main_window_ui.py", line 77, in setStopFreq
self.stop_freq = int(win.lineEdit.text)
AttributeError: 'str' object has no attribute 'lineEdit'
which I think is my mistake while connecting GUI objects to functions, but I couldn't figure out how to fix it. It seems there's a problem with function's arguments, yet when I call tomatoes function from main, it works despite having the same argument (analyzer_thread).
I know that my code is messy and sorry for that. The processing part was done by another person, my role is to make it work with GUI. I am attaching the main window view:
https://i.stack.imgur.com/vUZjj.png
I'll be thankful for any help :)
Your code wont resume running, because when you set self.stop to True once, whole ,,run'' loop terminates and self.run function ends its job, terminating thread. You should rather try something like:
while True:
if not self.stop:
#do your code
else:
time.sleep(0.001) #
And add other possibility to terminate thread completly.
Your functions should rather be named suspend/resume, not stop and start.

Python only prints to one cell in a csv

I am trying to make a print button for a GUI I am making. Right now when I click the print button it will store all the data to one cell for each variable I am trying to print. Right now I am trying to print the time, rpms, torque, and horsepower. It will give me each of those in their own separate cell, but it will not start a new row. With in this cell the format is: [1,2,3,4,5,...]. The brackets are in the cells as well. I would like for them to be separated into rows that way the user of the GUI can take the data for post processing. What I have mostly found on this matter is people are trying to get words into different cells and I know that characters act differently than numbers, pr that people want the values to be in a single cell, not the opposite like in my case.
What I have right now is that the print button will print a file with a unique time stamp. That way the users can keep this data for safe keeping.
Thank You in advance!
"""
SCSU DYNO GUI PROGRAM
created 11/10/2017
"""
import sys
import time
from time import gmtime, localtime, strftime
import csv
import numpy as np
import warnings
import serial
import serial.tools.list_ports
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QThread,QTimer, pyqtSignal
from PyQt5.QtWidgets import QMessageBox,QWidget, QApplication,QHBoxLayout
from PyQt5.QtGui import QColor
from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
import random
from DynoTest1 import Ui_DynoTest1
__author__ = 'Matt Munn'
pg.setConfigOption('background', None)
pg.setConfigOption('foreground', 'k')
class GetData(QThread):
dataChanged = pyqtSignal(float, float, float, float, float, float, float, float)
#Distance = 0.5 #This is dependent on the lever arm.
def __init__(self, parent=None):
QThread.__init__(self, parent)
arduino_ports = [ # automatically searches for an Arduino and selects the port it's on
p.device
for p in serial.tools.list_ports.comports()
if 'Arduino' in p.description
]
if not arduino_ports:
raise IOError("No Arduino found - is it plugged in? If so, restart computer.")
if len(arduino_ports) > 1:
warnings.warn('Multiple Arduinos found - using the first')
self.Arduino = serial.Serial(arduino_ports[0], 9600, timeout=1)
def __del__(self): # part of the standard format of a QThread
self.wait()
def run(self): # also a required QThread function, the working part
self.Arduino.close()
self.Arduino.open()
self.Arduino.flush()
self.Arduino.reset_input_buffer()
start_time = time.time()
Distance = 1 #This is dependent on the lever arm.
Max_RPM = 0
Max_Horsepower = 0
Max_Torque = 0
#This is what does the work to get the data from the arduino and then converts it to the other needed values.
while True:
while self.Arduino.inWaiting() == 0:
pass
try:
data = self.Arduino.readline()
dataarray = data.decode().rstrip().split(',')
self.Arduino.reset_input_buffer()
Force = round(float(dataarray[0]), 3)
RPM = round(float(dataarray[1]), 0)
if Max_RPM < RPM:
Max_RPM = RPM
Torque = round(Force * Distance, 2)
if Max_Torque < Torque:
Max_Torque = Torque
Horsepower = round(Torque * RPM / 5252, 2)
if Max_Horsepower < Horsepower:
Max_Horsepower = Horsepower
Run_Time = round(time.time() - start_time, 1)
print(Force, 'Grams', ",", RPM, 'RPMs', ",", Torque, "ft-lbs", ",", Horsepower, "hp", Run_Time,
"Time Elasped")
self.dataChanged.emit(Force, RPM, Max_RPM, Torque, Max_Torque, Horsepower, Max_Horsepower, Run_Time)
except (KeyboardInterrupt, SystemExit, IndexError, ValueError):
pass
class GUI(QWidget, Ui_DynoTest1):
def __init__(self, parent=None, border = None):
# This is what is used to make the graph.
QWidget.__init__(self, parent)
self.setupUi(self)
self.thread = GetData(self)
self.thread.dataChanged.connect(self.onDataChanged)
self.thread.start()
self.rpm = []
self.torque = []
self.horse_power = []
self.time = []
self.counter = 0
layout = QHBoxLayout()
self.plot = pg.PlotWidget()
layout.addWidget(self.plot)
self.plot.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
self.graphicsView.setLayout(layout)
self.p1 = self.plot.plotItem
self.p1.setLabels(left='Torque (ft-lbs)', bottom= 'Time (sec)')
self.TorqueCurve = self.p1.plot()
self.TorqueCurve.setPen(pg.mkPen(QColor(0,0,0), width=2.5))
self.p2 = pg.ViewBox()
self.HorsePowerCurve = pg.PlotCurveItem()
self.HorsePowerCurve.setPen(pg.mkPen(QColor(0, 0, 255), width=2.5))
self.p2.addItem(self.HorsePowerCurve)
self.p1.scene().addItem(self.p2)
self.p1.showAxis('right')
self.p1.getAxis('right').setLabel('HorsePower', color='#0000ff')
self.p1.getAxis('right').linkToView(self.p2)
self.p1.vb.sigResized.connect(self.updateViews)
#This is where the buttons will be set up at.
self.pushButton_4.clicked.connect(self.Print_Out)
def Print_Out(self):
#This gives a unique time stamp for each file made.
outputFileName = "DynoData_#.csv"
outputFileName = outputFileName.replace("#", strftime("%Y-%m-%d_%H %M %S", localtime()))
with open(outputFileName, 'w',newline='') as outfile:
outfileWrite = csv.writer(outfile, delimiter=',')
#test = self.torque
#test2 = self.torque , self.rpm
outfileWrite.writerow([self.torque,self.horse_power,self.rpm,self.time])
def updateViews(self):
self.p2.setGeometry(self.p1.vb.sceneBoundingRect())
self.p2.linkedViewChanged(self.p1.vb, self.p2.XAxis)
def onDataChanged(self, Force, RPM, Max_RPM, Torque, Max_Torque, Horsepower, Max_Horsepower, Run_Time):
#These tell the program to display the values to the LCDs
self.lcdNumber.display(Max_RPM)
self.lcdNumber_2.display(Max_Torque)
self.lcdNumber_3.display(Max_Horsepower)
self.lcdNumber_4.display(RPM)
self.lcdNumber_5.display(Torque)
self.lcdNumber_6.display(Horsepower)
self.lcdNumber_7.display(Run_Time)
if self.counter < 50:
self.torque.append(Torque)
self.horse_power.append(Horsepower)
self.time.append(Run_Time)
self.rpm.append(RPM)
else:
self.torque = self.torque[1:] + [Torque]
self.horse_power = self.horse_power[1:] + [HorsePower]
self.time = self.time[1:] + [Run_Time]
self.rpm = self.rpm[1:] + [RPM]
self.HorsePowerCurve.setData(self.time, self.horse_power)
self.TorqueCurve.setData(np.array(self.time), self.torque)
self.updateViews()
#This is part of a standard closing script
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
Dyno = GUI()
Dyno.show()
sys.exit(app.exec_())
Since your data is in lists, you need to form rows of each instance of data items. One way is to transpose the lists with zip:
>>> hp = [1,2,3]
>>> rpm = [4,5,6]
>>> time = [7,8,9]
>>> for row in zip(hp,rpm,time):
... print(row)
...
(1, 4, 7)
(2, 5, 8)
(3, 6, 9)
Note how the first item in each list is printed, then the second, etc. You can use this to get your data into rows. Here's a standalone example:
import csv
class Test:
def __init__(self):
self.torque = [10,20,30]
self.horse_power = [100,200,300]
self.rpm = [1000,2000,3000]
self.time = [1,2,3]
def print(self):
with open('test.csv','w',newline='') as outfile:
outfileWrite = csv.writer(outfile)
outfileWrite.writerow('Torque HP RPM Time'.split())
outfileWrite.writerows(zip(self.torque,self.horse_power,self.rpm,self.time))
t = Test()
t.print()
Note writerows (plural). That expects a list of lists. writerow (singular) expects a single list and is used for a header. Output file is:
Torque,HP,RPM,Time
10,100,1000,1
20,200,2000,2
30,300,3000,3
First, calling a definition print in python is not recommended at all. Unless you do want to over-ride python 'print'. 'print_to_csv' for example.
As for the csv, you need to group your data into lists of [torque, horsepower, rpm, time] so your it will look like something like this,
data_lists = [
[torque(0), horsepower(0), rpm(0), time(0)],
[torque(1), horsepower(1), rpm(1), time(1)],
...
[torque(n), horsepower(n), rpm(n), time(n)]
]
then you will loop through this data list and print your rows one by one like so,
for d in data_datalist:
outfileWrite.writerow([d[0],d[1],d[2],d[3])
of course, many ways to structure your data, thats just an example.
Hope this helps.

How to stop htmlpy ui blocking

I was working on a small downloader for Youtube videos using trollius (for async), htmlpy and pafy (and youtube-dl). Now i have a problem where once i click the download button, the UI freezes up while the backend is downloading the video.
I have tried to make the downloader class its own thread and run that alongside the UI but that doesn't seem to work. I also tried to uses coroutine to have the video download asynchronously while the UI continues. Neither seemed to work.
Here is some code
class Downloader(htmlPy.Object,threading.Thread):
dd = os.path.join(os.getenv('USERPROFILE'), 'Downloads') # dd = download director
dd = dd + "/vindownload/"
def __init__(self, app):
threading.Thread.__init__(self)
super(Downloader, self).__init__()
# Initialize the class here, if required.
self.app = app
return
#htmlPy.Slot(str)
def download_single(self, json_data):
form_data = json.loads(json_data)
print json_data
url = form_data["name"]
dt = form_data["dt"] # Download type is audio or video
if url.__contains__("https://www.youtube.com/watch?v="):
if dt == 'audio':
print "hello1"
loop = trollius.get_event_loop()
loop.run_until_complete(self._downloadVid(url, vid=False))
loop.stop()
else:
print "hello1"
loop = trollius.get_event_loop()
loop.run_until_complete(self._downloadVid(url, vid=True))
loop.stop()
self.app.evaluate_javascript("document.getElementById('form').reset()")
else:
print "Incorrect url"
print form_data
#trollius.coroutine
def _downloadVid(self, url, vid=False, order_reverse=False, vinName=None):
print "hello123"
video = pafy.new(url)
print video
name = u''.join(video.title).encode('utf8')
name = re.sub("[<>:\"/\\|?*]", "", name)
if not vid:
file = video.getbestaudio()
else:
file = video.getbest()
if (order_reverse):
file.download(self.dd + vinName + name + ".mp4", quiet=False,callback=self.mycb)
else:
file.download(self.dd + name + ".mp4", quiet=False,callback=self.mycb)
def mycb(self,total, recvd, ratio, rate, eta):
print(recvd, ratio, eta)
and my initialize.py
BASE_DIR = os.path.abspath(os.path.dirname("initilize.py"))
app = htmlPy.AppGUI(title=u"Vin download", width=700, height=400, resizable=False)
app.static_path = os.path.join(BASE_DIR, "static/")
app.template_path = os.path.join(BASE_DIR, "templates/")
app.web_app.setMaximumWidth(830)
app.web_app.setMaximumHeight(600)
download = Downloader(app)
download.start()
# Register back-end functionalities
app.bind(download)
app.template = ("./index.html", {"template_variable_name": "value"})
# Instructions for running application
if __name__ == "__main__":
# The driver file will have to be imported everywhere in back-end.
# So, always keep app.start() in if __name__ == "__main__" conditional
app.start()
Now my question is. Is there a way where i can free up my UI while downloading so it doesn't look like the application crashed.
I am using: Python 2.7, Trollius, Pafy, Youtube-dl, HTMLPY.
Thank you for your time.
Alright i found the answer to my question, here is what i did. i changed my download_single method to the following:
#htmlPy.Slot(str)
def download_single(self, json_data):
form_data = json.loads(json_data)
print json_data
url = form_data["name"]
dt = form_data["dt"] # Download type is audio or video
videoDown = videoDownload(url, dt, self.app, self.dd)
videoDown.start()
print form_data
And the code i had in it earlier is now transferred to a new class called videoDownload taking all those attributes stated above.
videoDownload.py
class videoDownload(threading.Thread):
def __init__(self, url, dt, app, dd):
threading.Thread.__init__(self)
self.url = url
self.dt = dt
self.app = app
self.dd = dd
def run(self):
threads.append(self)
if self.url.__contains__("https://www.youtube.com/watch?v="):
if self.dt == 'audio':
print "hello1"
self._downloadVid(self.url, vid=False)
else:
print "hello1"
self._downloadVid(self.url, vid=True)
else:
print "Incorrect url"
def _downloadVid(self, url, vid=False, order_reverse=False, vinName=None):
print "hello123"
video = pafy.new(url)
print video
name = u''.join(video.title).encode('utf8')
name = re.sub("[<>:\"/\\|?*]", "", name)
if not vid:
file = video.getbestaudio()
else:
file = video.getbest()
if (order_reverse):
file.download(self.dd + vinName + name + ".mp4", quiet=False, callback=self.mycb)
else:
file.download(self.dd + name + ".mp4", quiet=False, callback=self.mycb)
threads.remove(self)
def mycb(self, total, recvd, ratio, rate, eta):
pass
This solved the issues i had with ui being blocked. The thread will end itself once leaving the run method and it will be removed from a threads array that is defined above the class.
Have a great day all
~Ellisan

Refresh QTextEdit in PyQt

Im writing a PyQt app that takes some input in one widget, and then processes some text files.
What ive got at the moment is when the user clicks the "process" button a seperate window with a QTextEdit in it pops up, and ouputs some logging messages.
On Mac OS X this window is refreshed automatically and you cna see the process.
On Windows, the window reports (Not Responding) and then once all the proccessing is done, the log output is shown. Im assuming I need to refresh the window after each write into the log, and ive had a look around at using a timer. etc, but havnt had much luck in getting it working.
Below is the source code. It has two files, GUI.py which does all the GUI stuff and MOVtoMXF that does all the processing.
GUI.py
import os
import sys
import MOVtoMXF
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class Form(QDialog):
def process(self):
path = str(self.pathBox.displayText())
if(path == ''):
QMessageBox.warning(self, "Empty Path", "You didnt fill something out.")
return
xmlFile = str(self.xmlFileBox.displayText())
if(xmlFile == ''):
QMessageBox.warning(self, "No XML file", "You didnt fill something.")
return
outFileName = str(self.outfileNameBox.displayText())
if(outFileName == ''):
QMessageBox.warning(self, "No Output File", "You didnt do something")
return
print path + " " + xmlFile + " " + outFileName
mov1 = MOVtoMXF.MOVtoMXF(path, xmlFile, outFileName, self.log)
self.log.show()
rc = mov1.ScanFile()
if( rc < 0):
print "something happened"
#self.done(0)
def __init__(self, parent=None):
super(Form, self).__init__(parent)
self.log = Log()
self.pathLabel = QLabel("P2 Path:")
self.pathBox = QLineEdit("")
self.pathBrowseB = QPushButton("Browse")
self.pathLayout = QHBoxLayout()
self.pathLayout.addStretch()
self.pathLayout.addWidget(self.pathLabel)
self.pathLayout.addWidget(self.pathBox)
self.pathLayout.addWidget(self.pathBrowseB)
self.xmlLabel = QLabel("FCP XML File:")
self.xmlFileBox = QLineEdit("")
self.xmlFileBrowseB = QPushButton("Browse")
self.xmlLayout = QHBoxLayout()
self.xmlLayout.addStretch()
self.xmlLayout.addWidget(self.xmlLabel)
self.xmlLayout.addWidget(self.xmlFileBox)
self.xmlLayout.addWidget(self.xmlFileBrowseB)
self.outFileLabel = QLabel("Save to:")
self.outfileNameBox = QLineEdit("")
self.outputFileBrowseB = QPushButton("Browse")
self.outputLayout = QHBoxLayout()
self.outputLayout.addStretch()
self.outputLayout.addWidget(self.outFileLabel)
self.outputLayout.addWidget(self.outfileNameBox)
self.outputLayout.addWidget(self.outputFileBrowseB)
self.exitButton = QPushButton("Exit")
self.processButton = QPushButton("Process")
self.buttonLayout = QHBoxLayout()
#self.buttonLayout.addStretch()
self.buttonLayout.addWidget(self.exitButton)
self.buttonLayout.addWidget(self.processButton)
self.layout = QVBoxLayout()
self.layout.addLayout(self.pathLayout)
self.layout.addLayout(self.xmlLayout)
self.layout.addLayout(self.outputLayout)
self.layout.addLayout(self.buttonLayout)
self.setLayout(self.layout)
self.pathBox.setFocus()
self.setWindowTitle("MOVtoMXF")
self.connect(self.processButton, SIGNAL("clicked()"), self.process)
self.connect(self.exitButton, SIGNAL("clicked()"), self, SLOT("reject()"))
self.ConnectButtons()
class Log(QTextEdit):
def __init__(self, parent=None):
super(Log, self).__init__(parent)
self.timer = QTimer()
self.connect(self.timer, SIGNAL("timeout()"), self.updateText())
self.timer.start(2000)
def updateText(self):
print "update Called"
AND MOVtoMXF.py
import os
import sys
import time
import string
import FileUtils
import shutil
import re
class MOVtoMXF:
#Class to do the MOVtoMXF stuff.
def __init__(self, path, xmlFile, outputFile, edit):
self.MXFdict = {}
self.MOVDict = {}
self.path = path
self.xmlFile = xmlFile
self.outputFile = outputFile
self.outputDirectory = outputFile.rsplit('/',1)
self.outputDirectory = self.outputDirectory[0]
sys.stdout = OutLog( edit, sys.stdout)
class OutLog():
def __init__(self, edit, out=None, color=None):
"""(edit, out=None, color=None) -> can write stdout, stderr to a
QTextEdit.
edit = QTextEdit
out = alternate stream ( can be the original sys.stdout )
color = alternate color (i.e. color stderr a different color)
"""
self.edit = edit
self.out = None
self.color = color
def write(self, m):
if self.color:
tc = self.edit.textColor()
self.edit.setTextColor(self.color)
#self.edit.moveCursor(QtGui.QTextCursor.End)
self.edit.insertPlainText( m )
if self.color:
self.edit.setTextColor(tc)
if self.out:
self.out.write(m)
self.edit.show()
If any other code is needed (i think this is all that is needed) then just let me know.
Any Help would be great.
Mark
It looks like your are running an external program, capturing its output into a QTextEdit. I didn't see the code of Form.process, but I am guessing on windows your function waits for the external program to finish, then quickly dumps everything to the QTextEdit.
If your interface really is waiting for the other process to finish, then it will hang in the manner you describe. You'll need to look at subprocess or perhaps even popen to get the program's output in a "non-blocking" manner.
The key to avoiding "(Not Responding)" is to call QApplication.processEvents a few times every few seconds. The QTimer is not going to help in this case, because if Qt cannot process its events, it cannot call any signal handlers.

Categories

Resources