PyQt5 threading isn't working display freeze - python

I have a python program that uses mysql.connector to login to a server and execute the query and saving the sql result in excel file. i use pyqt for my gui and when i press the button the gui is freezing. i have created the qthread and worker class but when i import the executor function and pressing the button the program is running and the gui is starting to freeze, what am i doing wrong?
how can i implement the multithreading?
from cmath import inf
from multiprocessing import connection
from operator import index
import os
from sqlite3 import Cursor
from unittest.result import failfast
from datetime import datetime
import mysql.connector
from mysql.connector import errorcode
import pandas as pd
#importing Queries
from Queries import *
#Location Ip's
from locations import locs
from locations import usr,passwd,db
startDate='2022-04-01'
endDate='2022-04-15'
logfailedls = 'logfailed.txt'
logsuccessls = 'logsuccess.txt'
class bcolors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKCYAN = '\033[96m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
def executor(QUERY):
alldf = None
for type,info in locs.items():
if not os.path.isdir('%s/'%(type)):
os.makedirs('%s/'%(type))
ls = os.listdir('{}/'.format(type))
if logfailedls in ls:
os.remove('{}/{}'.format(type,logfailedls))
if logsuccessls in ls:
os.remove('{}/{}'.format(type,logsuccessls))
for ip,locName in info.items():
try:
cnx = mysql.connector.connect(user=usr, password=passwd,host=ip, database=db)
if cnx.is_connected():
print("Connection Succesfull to {}".format(locName))
logsuccess = open('{}/logsuccess.txt'.format(type),'a')
logsuccess.write('{} : {}-{}\n'.format(datetime.now().strftime("%Y-%m-%d %H:%M:%S"),ip,locName))
logsuccess.close()
location = cnx.cursor(buffered=True)
location.execute("SELECT loccod FROM docparameters d limit 1")
loc = location.fetchone()[0]
cursor = cnx.cursor()
cursor.execute(QUERY)
df = pd.DataFrame(cursor.fetchall())
if alldf is not None:
alldf = alldf.append(df)
else:
alldf = df
print(df)
field_names = [ i[0] for i in cursor.description]
print(field_names)
xlswriter = pd.ExcelWriter('{}/{}.xls'.format(type,loc),engine='openpyxl')
df.to_excel(xlswriter)
xlswriter.save()
cnx.close()
except mysql.connector.Error as err:
if err.errno == errorcode.ER_ACCESS_DENIED_ERROR:
print("Something wrong with your username or password")
elif err.errno == errorcode.ER_BAD_DB_ERROR:
print("DATABASE does not exist")
else:
print(err)
print("Connectin Failed to %s"%(loc))
logfailed = open("{}/logfailed.txt".format(type),'a')
logfailed.write('{} : {}-{}\n'.format(datetime.now().strftime("%Y-%m-%d %H:%M:%S"),ip,locName))
logfailed.close()
else:
cnx.close()
return [alldf,field_names]
def saveToExcel(query,filename):
xlswriter = pd.ExcelWriter("%s.xls"%(filename),engine='openpyxl')
queryDatas = executor(query)
export = queryDatas[0]
export.columns = queryDatas[1]
export.to_excel(xlswriter,index=False)
xlswriter.save()
#saveToExcel(union,'UNION 15%')
#saveToExcel(hnb,'HBC 25%')
#saveToExcel(SCB,'SCB')
this is my pyqt gui program
from concurrent.futures import Executor
import traceback
from unittest import result
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import sys
import time
import copy
from connector import *
class WorkerSignals(QObject):
finished = pyqtSignal()
error = pyqtSignal(tuple)
result = pyqtSignal(object)
class Worker(QThread):
def __init__(self,fn,*args,**kwargs):
super(Worker,self).__init__()
self.fn = fn
self.args = args
self.kwargs = kwargs
self.signals = WorkerSignals()
#pyqtSlot()
def run(self):
try:
result = self.fn(*self.args,**self.kwargs)
except:
traceback.print_exc()
exctype, value = sys,sys.exc_info()[:2]
self.signals.error.emit((exctype,value,traceback.format_exc()))
else:
self.signals.result.emit(result)
finally:
self.signals.finished.emit()
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.threadpool = QThreadPool()
print("multithreading with maximum %d threads" % self.threadpool.maxThreadCount())
self.counter = 0
layout = QVBoxLayout()
self.l = QLabel("Start")
b = QPushButton("DANGER!")
b.pressed.connect(self.oh_no)
c = QPushButton("?")
c.pressed.connect(self.change_message)
layout.addWidget(self.l)
layout.addWidget(b)
layout.addWidget(c)
w = QWidget()
w.setLayout(layout)
self.setCentralWidget(w)
self.show()
def change_message(self):
self.message = "OH NO"
def print_output(self,s):
print(s)
def thread_complete(self):
print("THREAD COMPLETE!")
def oh_no(self):
worker = Worker(executor(SCB))
worker.signals.result.connect(self.print_output)
worker.signals.finished.connect(self.thread_complete)
self.threadpool.start(worker)
app = QApplication([])
window = MainWindow()
app.exec_()

Related

How to import my main file and Create database connection?

How to import my database connection file into another file and create a connection in that file? For example, I have a main file in the name **"Database_main.py"**In my main file I have a function like. establish_connection, change _passkey . Now I have to import the main file(Database_main.py) things in my second file(database_connection.py). But I got a error message "TypeError: establish_connection_general() missing 1 required positional argument: 'self'. How to sucessfully import my main file and make a connection.
Database_main.py
from PyQt5.QtWidgets import QWidget,QMessageBox,QApplication
from PyQt5.QtGui import QIcon
import sqleet
import os
import sys
file_path_general = r"d:\project database\assist"
db_name_general = (os.path.join(file_path_general,'database_general.db'))
passkey_general = "1234"
new_passkey_general = "1234"
show_errormsg = "show"
class Database_connection(QWidget):
def __init__(self):
super(). __init__()
self.establish_connection_general()
# self.cahnge_passkey()
def establish_connection_general(self):
try:
connection_general = sqleet.connect(db_name_general,key = passkey_general)
print("open scueffully")
except Exception as e:
if show_errormsg == "show":
self.handle_error(e)
else:
pass
def cahnge_passkey(self):
try:
general_connection = sqleet.connect(db_name_general,key = passkey_general)
general_connection.change_key(new_passkey_general)
print("new pass key sucessfully changed")
general_connection.close()
except Exception as e:
if show_errormsg == "show":
self.handle_error(e)
else:
pass
def handle_error(self,error):
exc_type, exc_value, exc_traceback = sys.exc_info()
filenamewithpath = exc_traceback.tb_frame.f_code.co_filename
head,tail = os.path.split((filenamewithpath))
lineno = exc_traceback.tb_lineno
name = exc_traceback.tb_frame.f_code.co_name
type = exc_type.__name__
message = exc_value
nl = '\n'
kk = f'File Name : {tail[:-3]}{nl}'\
f'Line No. : {lineno}{nl}'\
f'Type : {type}{nl}'\
f'Name : {name}{nl}'
self.msg = QMessageBox()
self.msg.setFixedSize(1600,400)
self.msg.setWindowTitle(" Error/Bugs Information")
self.msg.setWindowIcon(QIcon('icon\close006.png'))
fd = " "
self.msg.setText(f'{type} - {lineno}{fd}')
self.msg.setIcon(QMessageBox.Information)
self.msg.setStandardButtons(QMessageBox.Ok)
self.msg.setDefaultButton(QMessageBox.Ok)
self.msg.setInformativeText("")
self.msg.setDetailedText(kk)
self.msg.show()
def main():
app = QApplication(sys.argv)
ex = Database_connection()
app.setStyle("Fusion")
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Database_Connection file
import sys
import os
from makeeasy_database_connection import Database_connection
db = Database_connection.establish_connection_general()
db()
Result
Traceback (most recent call last):
File "D:/project database/assist/database_connection.py", line 6, in <module>
db = Database_connection.establish_connection_general()
TypeError: establish_connection_general() missing 1 required positional argument: 'self'
How to import properly and use my code ?

Pyqt5- QMessageBox is appearing blank & program getting crashed

I am trying to run a code to load dataframe into a sql server using PyQT5 and also at the same time showing a "Please wait" pop up while data is being loaded in DB. I am utilizing QThread for the same. If there is some error then QMessageBox shows the error to the user. But my program is crashing with Message Box appearing blank. I am attaching both code and error snippet.Error Snippet
from functools import partial
from PyQt5 import QtCore, QtGui, QtWidgets
import configparser
import pyodbc
def ConfigSection(section,Config):
dict1 = {}
options = Config.options(section)
for option in options:
try:
dict1[option] = Config.get(section,option)
except:
dict1[option] = None
return dict1
class DatabaseWorker(QtCore.QObject):
started = QtCore.pyqtSignal()
finished = QtCore.pyqtSignal()
message = QtCore.pyqtSignal(object)
msg = ""
#QtCore.pyqtSlot()
def writeToDatabase(self, final_pivot):
self.started.emit()
Config = configparser.ConfigParser(interpolation=None)
try:
config_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'config.ini')
Config.read_string(open(config_file).read())
config_values = ConfigSection("Global", Config)
driver = config_values.get('driver')
server = config_values.get('server')
database = config_values.get('database')
username = config_values.get('username')
password = config_values.get('password')
con_str = ("Driver={" + driver + "};"
"Server=" + server + ";"
"Database=" + database + ";"
"UID=" + username + ";"
"PWD=" + password + ";")
cnxn = pyodbc.connect(con_str)
cursor = cnxn.cursor()
for i, row in final_pivot.iterrows():
sql = "INSERT INTO dbo.[FPP_Cleansed_MarketData] (ID,Region,Geography,Category,Company,Year,Adjusted_Sales,Sales_Units,Unit_Type) VALUES (" + "?," * (
len(row) - 1) + "?)"
cursor.execute(sql, tuple(row))
cnxn.commit()
except pyodbc.Error as ex:
sqlstate = ex.args[0]
if sqlstate == '28000':
msg = "Error: Error while logging in. Please check login credentials"
self.message.emit(msg)
credentials")
return -1
elif sqlstate == '23000':
msg = "Error: Trying to insert duplicate ID"
self.message.emit(msg)
return -1
else:
msg = "Error: Error encountered while inserting records into Data Warehouse"
self.message.emit(msg)
return -1
finally:
self.finished.emit()
class Windows_GUI(QtWidgets.QMainWindow):
def __init__(self, df):
QtWidgets.QMainWindow.__init__(self)
self.__threads = []
self.thread = QtCore.QThread(parent=self)
self.__threads.append(self.thread)
self.thread.start()
self.m_database_worker = DatabaseWorker()
self.m_database_worker.moveToThread(self.thread)
self.m_database_worker.started.connect(self.start_animation)
self.m_database_worker.message.connect(self.show_message)
wrapper = partial(self.m_database_worker.writeToDatabase,df)
QtCore.QTimer.singleShot(0, wrapper)
#QtCore.pyqtSlot()
def start_animation(self):
gif_path = "loading.gif"
self.loading_window = QtWidgets.QDialog()
self.loading_window.setWindowFlags(QtCore.Qt.SplashScreen)
self.loading_window.setAttribute(QtCore.Qt.WA_DeleteOnClose)
movie = QtGui.QMovie(gif_path, cacheMode=QtGui.QMovie.CacheAll)
movie_label = QtWidgets.QLabel(alignment=QtCore.Qt.AlignCenter)
movie_label.setFixedSize(100, 75)
movie_label.setMovie(movie)
text_label = QtWidgets.QLabel('Data is getting loaded into Data Warehouse. Please wait...')
text_label.setFont(QtGui.QFont('Arial',11))
vbox = QtWidgets.QHBoxLayout(self.loading_window)
vbox.addWidget(movie_label)
vbox.addWidget(text_label)
self.m_database_worker.finished.connect(self.close_window)
movie.start()
self.setVisible(False)
self.loading_window.show()
def show_message(self,msg):
try:
self.msg_box = QtWidgets.QMessageBox()
self.msg_box.setWindowTitle('Error')
self.msg_box.setIcon(QtWidgets.QMessageBox.Critical)
self.msg_box.information(self, 'Message', msg)
#self.msg_box.setText("Hello Rock the Brahma Bull")
self.msg_box.move(self.frameGeometry().center())
self.msg_box.exec_()
except Exception as e:
print(e)
def close_window(self):
for thread in self.__threads:
thread.quit()
thread.wait()
self.close()
if __name__ == "__main__":
import sys
import pandas as pd
app = QtWidgets.QApplication(sys.argv)
df = pd.read_excel('test.xlsx')
df['ID'] = ['Project_id_' + str(i) for i in range(len(df))]
df = df[['ID', 'Regions', 'Geographies', 'Categories', 'Companies', 'Year', 'Sales', 'Sales_Unit','Currency Conversion']]
w = Windows_GUI(df)
w.show()
sys.exit(app.exec_())

How do I use multiple threads with PySide and Twython?

I'm trying to write a small python app, using PySide for the GUI and Twython as a Twitter API library, to catch a stream from Twitter.
The problem that I am having is that when I click "Start Monitoring Twitter" button, the UI freezes until the stream is complete, at which point the code continues to execute and disables the Start button and enables the Stop button. Here's the UI:
Everything else seems to work -- if I leave it, then the CSV file is created as I suspect -- the Twython components seem to be working as expected.
Line 151 is where the streaming from Twitter is engaged when I click start:
self.stream.statuses.filter(track=self.search_term)
How can I move the streaming to a separate thread and then use the Stop button on the UI to tell Twython to complete capturing the stream and exit?
I need to be able to send the MyStreamer instance to another thread and then send it the .disconnect() signal to have it terminate capturing the stream.
Here's the full code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import platform
import PySide
from PySide.QtGui import QApplication, QMainWindow, QPushButton, QCheckBox, QTextEdit
from time import sleep
from ui_tweetstream import Ui_MainWindow
from twython import Twython
from twython import TwythonStreamer
import csv
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
# Set up Variables
self.tweet_fav_count = True
self.tweet_geocoordinates = True
self.tweet_id = True
self.tweet_language = True
self.tweet_orig_tweet_id = True
self.tweet_orig_username = True
self.tweet_retweeted = True
self.tweet_sensitive = True
self.tweet_source_app = True
self.tweet_timestamp = True
self.tweet_user_name = True
self.search_term = "#bigdata"
self.tweets_to_get = 1000
# Bind the interface
self.check_tweet_fav_count.clicked.connect(self.setTweetFavCount)
self.check_tweet_geocoordinates.clicked.connect(self.setTweetGeocoordinates)
self.check_tweet_id.clicked.connect(self.setTweetID)
self.check_tweet_language.clicked.connect(self.setTweetLanguage)
self.check_tweet_orig_tweet_id.clicked.connect(self.setTweetOrigTweetID)
self.check_tweet_orig_username.clicked.connect(self.setTweetOrigUsername)
self.check_tweet_retweeted.clicked.connect(self.setTweetRetweeted)
self.check_tweet_sensitive.clicked.connect(self.setTweetSensitive)
self.check_tweet_source_app.clicked.connect(self.setTweetSourceApp)
self.check_tweet_timestamp.clicked.connect(self.setTweetTimestamp)
self.check_tweet_user_name.clicked.connect(self.setTweetUsername)
self.button_start.clicked.connect(self.streamStart)
self.button_stop.clicked.connect(self.streamStop)
# Set the initial states
self.button_stop.setEnabled(False)
APP_KEY = ''
APP_SECRET = ''
OAUTH_TOKEN = ''
OAUTH_TOKEN_SECRET = ''
self.t = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET)
self.stream = MyStreamer(APP_KEY,APP_SECRET,OAUTH_TOKEN,OAUTH_TOKEN_SECRET)
self.stream.init_mainWindow(self)
def streamStop(self):
print "Stopping stream"
# Enable other controls here
self.button_stop.setEnabled(False)
self.button_start.setEnabled(True)
self.setControlStates(True)
self.stream.stopStream()
def setControlStates(self, state):
self.check_tweet_fav_count.setEnabled(state)
self.check_tweet_geocoordinates.setEnabled(state)
self.check_tweet_id.setEnabled(state)
self.check_tweet_language.setEnabled(state)
self.check_tweet_orig_tweet_id.setEnabled(state)
self.check_tweet_orig_username.setEnabled(state)
self.check_tweet_retweeted.setEnabled(state)
self.check_tweet_sensitive.setEnabled(state)
self.check_tweet_source_app.setEnabled(state)
self.check_tweet_timestamp.setEnabled(state)
self.check_tweet_user_name.setEnabled(state)
self.search_box.setEnabled(state)
self.num_tweets_box.setEnabled(state)
# Functions for determining what to track
def setTweetFavCount(self):
self.tweet_fav_count = not self.tweet_fav_count
print "tweet_fav_count:", self.tweet_fav_count
def setTweetGeocoordinates(self):
self.tweet_geocoordinates = not self.tweet_geocoordinates
print "tweet_geocoordinates:", self.tweet_geocoordinates
def setTweetID(self):
self.tweet_id = not self.tweet_id
print "tweet_id:", self.tweet_id
def setTweetLanguage(self):
self.tweet_language = not self.tweet_language
print "tweet_language:", self.tweet_language
def setTweetOrigTweetID(self):
self.tweet_orig_tweet_id = not self.tweet_orig_tweet_id
print "tweet_orig_tweet_id:", self.tweet_orig_tweet_id
def setTweetOrigUsername(self):
self.tweet_orig_username = not self.tweet_orig_tweet_id
print "tweet_orig_username:", self. tweet_orig_username
def setTweetRetweeted(self):
self.tweet_retweeted = not self.tweet_retweeted
print "tweet_retweeted:", self.tweet_retweeted
def setTweetSensitive(self):
self.tweet_sensitive = not self.tweet_sensitive
print "tweet_sensitive:", self.tweet_sensitive
def setTweetSourceApp(self):
self.tweet_source_app = not self.tweet_source_app
print "tweet_source_app:", self.tweet_source_app
def setTweetTimestamp(self):
self.tweet_timestamp = not self.tweet_timestamp
print "tweet_timestamp:", self.tweet_timestamp
def setTweetUsername(self):
self.tweet_user_name = not self.tweet_user_name
print "tweet_user_name:", self.tweet_user_name
# Functions for starting and stopping the stream
def streamStart(self):
print "Starting stream"
self.setControlStates(False)
# Disable other controls here
self.button_start.setEnabled(False)
self.button_stop.setEnabled(True)
# Hack to try to disable the UI
# sleep(0.25)
# Get the active search term
self.search_term = self.search_box.text()
# Get the number of tweets
self.tweets_to_get = int(self.num_tweets_box.text())
# Set the streamer
self.stream.set_start_criteria(self.tweets_to_get)
self.stream.statuses.filter(track=self.search_term)
class MyStreamer(TwythonStreamer):
def init_mainWindow(self, the_main_window):
self.main_window = the_main_window
self.stop = False
self.header_done = False
def set_start_criteria(self, numTweets):
self.maxTweets = numTweets
self.tweetCount = 0
print "Number of tweets to get:", self.maxTweets
def stopStream(self):
self.stop = True
def on_success(self, data):
if 'text' in data:
self.tweetCount += 1
print "tweetCount:", self.tweetCount
#tweet = data['text'].encode('utf-8')
theTweet = data
writer = TweetMonkey()
writer.assignMainWindow(self.main_window, self.header_done)
self.header_done = True
writer.process(theTweet)
# Want to disconnect after the first result?
if self.stop is True or self.tweetCount >= self.maxTweets:
self.disconnect()
def on_error(self, status_code, data):
print status_code, data
class TweetMonkey:
def assignMainWindow(self,the_main_window, is_header_done):
self.main_window = the_main_window
self.header_done = is_header_done
def clean(self,text):
text = text.replace("\n","; ")
text = text.replace('"', "'")
text = text.replace(','," ")
return text
def create_header(self):
header = []
tweets = open("tweets.csv", 'ab+')
wr = csv.writer(tweets, dialect='excel')
if self.main_window.tweet_id is True:
header.append("id")
if self.main_window.tweet_language is True:
header.append("lang")
if self.main_window.tweet_user_name is True:
header.append("user_name")
header.append("tweet")
if self.main_window.tweet_retweeted is True:
header.append("retweeted")
if self.main_window.tweet_fav_count is True:
header.append("favorite_count")
if self.main_window.tweet_source_app is True:
header.append("source")
if self.main_window.tweet_orig_tweet_id is True:
header.append("in_reply_to_status_id")
if self.main_window.tweet_orig_username is True:
header.append("in_reply_to_screen_name")
# header.append("in_reply_to_user_id")
if self.main_window.tweet_sensitive is True:
header.append("possibly_sensitive")
if self.main_window.tweet_geocoordinates is True:
header.append("geo")
if self.main_window.tweet_timestamp is True:
header.append("created_at")
wr.writerow(header)
tweets.close()
def process(self, tweet):
if not self.header_done:
self.create_header()
self.header_done = True
# Create the file or append to the existing
theOutput = []
tweets = open("tweets.csv", 'ab+')
wr = csv.writer(tweets, dialect='excel')
if self.main_window.tweet_id is True:
theOutput.append(tweet['id'])
if self.main_window.tweet_language is True:
theOutput.append(tweet['lang'].encode('utf-8'))
if self.main_window.tweet_user_name is True:
theOutput.append(tweet['user']['name'].encode('utf-8', 'replace'))
theOutput.append(self.clean(tweet['text']).encode('utf-8', 'replace'))
if self.main_window.tweet_retweeted is True:
theOutput.append(tweet['retweeted'])
if self.main_window.tweet_fav_count is True:
theOutput.append(tweet['favorite_count'])
if self.main_window.tweet_source_app is True:
theOutput.append(self.clean(tweet['source']).encode('utf-8', 'replace'))
if self.main_window.tweet_orig_tweet_id is True:
theOutput.append(tweet['in_reply_to_status_id'])
if self.main_window.tweet_orig_username is True:
theOutput.append(tweet['in_reply_to_screen_name'])
#theOutput.append(tweet['in_reply_to_user_id'])
if self.main_window.tweet_sensitive is True:
if tweet.get('possibly_sensitive'):
theOutput.append(tweet['possibly_sensitive'])
else:
theOutput.append("False")
if self.main_window.tweet_geocoordinates is True:
if tweet['geo'] is not None:
if tweet['geo']['type'] == 'Point':
lat = str(tweet['geo']['coordinates'][0]) + " "
lon = str(tweet['geo']['coordinates'][1])
theOutput.append(lat + lon)
else:
theOutput.append(tweet['geo'])
else:
theOutput.append(tweet['geo'])
if self.main_window.tweet_timestamp is True:
theOutput.append(tweet['created_at'])
wr.writerow(theOutput)
tweets.close()
if __name__ == '__main__':
app = QApplication(sys.argv)
frame = MainWindow()
frame.show()
app.exec_()
I know this is an old post but I ran into a similar problem in a simple app I recently wrote, my solution was to use threading.
I used the worker from:
https://pymotw.com/2/threading/
and the method described in:
http://aadrake.com/using-twitter-as-a-stream-processing-source.html
Basically running the Twython stream as a separate thread feeding text to a queue then I run the rest of the program in a separate loop reading from the queue.

Set attribute on a python thread from traits

I am new to python and I am implementing a simple serial adquisition in a thread.
I can adquire the data using a class by
class CaptureAngles(threading.Thread, port)
def __init__(self):
threading.Thread.__init__(self)
self.port_name = port
...
def run():
self.connect(self.port_name)
...
However, to better integrate with a graphical interface using the traits library I wrote the code as the following, which is no longer working. I am not able to define the attribute of a thread that is started from traits, what am I doing wrong?
This is the error reported
AttributeError: 'CaptureAngles' object has no attribute 'port_name'
And this the full code:
from threading import Thread
from time import sleep
from enthought.traits.api import *
from enthought.traits.ui.api import View, Item, ButtonEditor
from Queue import Queue
class TextDisplay(HasTraits):
string = String()
view= View( Item('string',show_label=False, springy=True, style='custom' ))
class CaptureAngles(Thread):
self.port_name = String('COM5')
def connect(self, port_name):
self.port = serial.Serial(
port = port_name,
baudrate = 9600,
)
self.display.string='Opening Serial Port...' + self.display.string
self.port.close()
self.port.open()
def run(self):
self.connect(self.port_name)
self.display.string = 'Arduino started\n' + self.display.string
self.port.flushInput()
self.port.flushOutput()
self.port.readline() # Discard first package (can be corrupt)
while not self.wants_abort:
rcv = self.port.readline() # Read the data and split into words
angle = int(rcv)
self.display.string = '%d angle captured\n' % n_img \
+ self.display.string
self.close()
def close(self):
self.port.close()
self.display.string='...Serial Port Closed!' + self.display.string
class Arduino(HasTraits):
start_stop_capture = Button()
display = Instance(TextDisplay)
capture_angles = Instance(CaptureAngles)
capture_angles.port_name = 'COM5'
view = View(Item('start_stop_capture', show_label=False ))
def _start_stop_capture_fired(self):
if self.capture_angles and self.capture_angles.isAlive():
self.capture_angles.wants_abort = True
else:
self.capture_angles = CaptureAngles()
self.capture_angles.wants_abort = False
self.capture_angles.display = self.display
self.capture_angles.start()
class MainWindow(HasTraits):
display = Instance(TextDisplay, ())
arduino = Instance(Arduino)
def _arduino_default(self):
return Arduino(display=self.display)
view = View('arduino','display', style="custom", resizable=True)
if __name__ == '__main__':
MainWindow().configure_traits()
Ok, I got it: I was adding the attribute port_name before creating the instance.
class Arduino(HasTraits):
start_stop_capture = Button()
display = Instance(TextDisplay)
capture_angles = Instance(CaptureAngles)
capture_angles.port_name = 'COM5' # <-- wrong: the object is not created yet
...
instead of:
def _start_stop_capture_fired(self):
if self.capture_angles and self.capture_angles.isAlive():
self.capture_angles.wants_abort = True
else:
self.capture_angles = CaptureAngles()
self.capture_angles.port_name = 'COM5' # <-- correct
...

How do you append a large text file in a textBrowser in PyQt without freezing the GUI?

I want to display a log file in a dialogue with three buttons.I can append each line to the textBrowser with the following code, but when I try to append the whole text the GUI freezes.
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import os
import sys
import time
import UI_logs
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
_fromUtf8 = lambda s: s
class WorkThread(QtCore.QThread):
def __init__(self):
QtCore.QThread.__init__(self)
def __del__(self):
self.wait()
def run(self):
#Reading and appending the whole text
# logs = open('logs.txt', 'r').read()
# self.emit(QtCore.SIGNAL('update(QString)'), str(logs))
#Reading and appending line by line
logs = open('logs.txt', 'r').readlines()
for line in logs:
self.emit(QtCore.SIGNAL('update(QString)'), str(line))
time.sleep(0.1)
self.terminate()
class Logs(QtGui.QDialog):
def __init__(self, parent=None):
super(Logs, self).__init__(parent)
self.ui = UI_logs.Ui_Dialog()
self.ui.setupUi(self)
self.load_logs()
QtCore.QObject.connect(self.ui.pushButton_3, QtCore.SIGNAL(_fromUtf8("clicked()")), self.clear_logs)
QtCore.QObject.connect(self.ui.pushButton_4, QtCore.SIGNAL(_fromUtf8("clicked()")), self.load_logs)
QtCore.QObject.connect(self.ui.pushButton, QtCore.SIGNAL(_fromUtf8("clicked()")), self.export)
def display_logs(self, text):
self.ui.textBrowser.append(text)
self.ui.textBrowser.update()
self.ui.textBrowser.moveCursor(QtGui.QTextCursor.End)
def load_logs(self):
self.workThread = WorkThread()
QtCore.QObject.connect(self.workThread, QtCore.SIGNAL("update(QString)"), self.display_logs)
self.workThread.start()
def clear_logs(self):
try:
os.remove('logs.txt')
self.ui.textBrowser.clear()
info_msg = "Your logs file has been deleted."
info_reply = QtGui.QMessageBox.warning(None, 'Logs Notification', info_msg, QtGui.QMessageBox.Ok)
except:
info_msg = "Your logs file can not be deleted."
info_reply = QtGui.QMessageBox.warning(None, 'Logs Notification', info_msg, QtGui.QMessageBox.Ok)
def export(self):
log_text = self.ui.textBrowser.toPlainText()
if log_text:
filename = QtGui.QFileDialog.getSaveFileName(None, 'Export logs as',
'.', 'Text Documents (*.txt)')
if filename:
fname = open(filename, 'w')
fname.write(log_text)
fname.close()
info_msg = "Your logs file has been exported successfully."
info_reply = QtGui.QMessageBox.warning(None, 'Logs Notification', info_msg, QtGui.QMessageBox.Ok)
else:
warning_title = 'Export Warning'
warning_text = 'There is nothing in the logs to export.'
QtGui.QMessageBox.warning(None, warning_title,
warning_text, QtGui.QMessageBox.Ok)
app = QApplication(sys.argv)
app.setApplicationName('MyWindow')
window = Logs()
window.show()
sys.exit(app.exec_())
Try with one of those 3 commented lines:
logs = open('logs.txt', 'r').read()
#logs = logs.encode('utf-8')
#logs = QString(logs)
#logs = unicode(QString(logs))
self.emit(QtCore.SIGNAL('update(QString)'), str(logs))
also, try them without converting logs to string:
self.emit(QtCore.SIGNAL('update(QString)'), logs)
I don't have import UI_logs so I can't test it, but one of those should work...

Categories

Resources