I'm writing code for an assignment where I can't change the main. The way I have it written, it prints like in the screenshot below:
Here is my code:
import csv
class Customer:
def __init__(self, cust_id, name, lastName, companyName, address, city, state, cust_zip):
self.cust_id = cust_id
self.first_name = name
self.last_name = lastName
self.company_name = companyName
self.address = address
self.city = city
self.state = state
self.zip = cust_zip
def getFullName(self):
return(self.first_name, self.last_name)
def getFullAddress(self):
return(self.getFullName(), self.company_name, self.address, self.city, self.state, self.zip)
def get_customers():
myList = []
counter = 0
with open("customers.csv", "r") as csv_file:
reader = csv.reader(csv_file, delimiter = ",")
for row in reader:
if counter!=0:
customer1 = Customer(row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7])
myList.append(customer1)
counter+=1
return myList
def find_customer_by_id(customers, cust_id):
for i in range(len(customers)):
if cust_id == customers[i].cust_id:
return customers[i]
return None
def main():
#main is fully implemented with no modification expected
print("Customer Viewer")
print()
customers = get_customers()
while True:
cust_id = input("Enter customer ID: ").strip()
print()
customer = find_customer_by_id(customers, cust_id)
if customer == None:
print("No customer with that ID.")
print()
else:
print(customer.getFullAddress())
print()
again = input("Continue? (y/n): ").lower()
print()
if again != "y":
break
print("Bye!")
if __name__ == "__main__":
main()
Why are there parenthesis and, can you get rid of them?
I tried to different approaches but nothing changed the output in the intended way
def login():
#clean
Ename.delete(0,'end')
Eage.delete(0,'end')
Epswrd.delete(0,'end')
Everpass.delete(0,'end')
root.destroy()
#/clean
stem = Tk()
stem.geometry("810x450")
stem.resizable(0,0)
stem.title("Log in")
approve1 = ""
approve2 = ""
#function
#player 1
def player1():
name1 = Ename1.get()
pswrd1 = Epswrd1.get()
if (name1 == "") or (pswrd1==""):
messagebox.showinfo("Invalid", "Please enter a username or password")
else:
conn = mariadb.connect(
user="root",password="",
host="localhost",
database="chessdatabase")
cur = conn.cursor()
#insert information
try:
cur.execute("SELECT User,Password from players where User=?, and Password = ?",(name1,pswrd1))
row = cur.fetchone()
if row==None:
messagebox.showinfo("Error" , "Invalid User Name And Password")
else:
approve1 = p1login
conn.commit()
#/player 1
#/function
#display
title1 = Label(stem, text="Touch-Move Tkinter Chess", font=("Colonna MT", 35))
title1.place(x=140, y=40)
#player 1 display
name1 = Label(stem, text="Player 1", font=("Georgia", 13))
name1.place(x=50, y=175)
Ename1 = Entry(stem, font=("Georgia", 11), width=17)
Ename1.place(x=150, y=175)
The error occurs at the left side indent of title1 = Label(stem, text="Touch-Move Tkinter Chess", font=("Colonna MT", 35)), Why does it make "unexpected unindent" error?
I've encountered the same problem before but for some reason it was fixed. Sorry I'm new to python so I don't really know much about indents in programming
I have a problem to scrape gmail.
Candidates should extract or pull information relating to financial transactions from Gmail. The information could be invoices, subscription alerts, bills, etc. We want you to connect with a Gmail account and scrape or pull data of invoices, subscriptions, upcoming bills. You can scrape the emails for words like upcoming invoice or subscription or invoice etc and pull the
amount, date, attachment if any all these details.
I have to collect information and also store all the attachments. Is there any specific simple way to do it?
my Code
import imaplib
import os
import email, getpass
import sys
import json
class GmailFinin():
def helloWorld(self):
print("\nHello I'm here to help you")
def initializeVariables(self):
self.usr = ""
self.pwd = ""
self.mail = object
self.mailbox = ""
self.mailCount = 0
self.destFolder = ""
self.data = []
self.ids = []
self.idsList = []
def getLogin(self):
print("\nPlease enter your Gmail login details below.")
self.usr = input("Email: ")
# self.pwd = input("Password: ")
self.pwd = getpass.getpass("Enter your password --> ")
def attemptLogin(self):
self.mail = imaplib.IMAP4_SSL("imap.gmail.com", 993)
if self.mail.login(self.usr, self.pwd):
print("\nLogon SUCCESSFUL")
self.destFolder = input("\nPlease choose a destination folder in the form of /Users/username/dest/ (do not forget trailing slash!): ")
if not self.destFolder.endswith("/"): self.destFolder+="/"
return True
else:
print("\nLogon FAILED")
return False
def checkIfUsersWantsToContinue(self):
print("\nWe have found "+str(self.mailCount)+" emails in the mailbox "+self.mailbox+".")
return True if input("Do you wish to continue extracting all the emails into "+self.destFolder+"? (y/N) ").lower().strip()[:1] == "y" else False
def selectMailbox(self):
# self.mailbox = input("\nPlease type the name of the mailbox you want to extract, e.g. Inbox: ")
self.mailbox = "Inbox"
bin_count = self.mail.select(self.mailbox)[1]
self.mailCount = int(bin_count[0].decode("utf-8"))
return True if self.mailCount > 0 else False
def searchThroughMailbox(self):
type, self.data = self.mail.search(None, "ALL")
self.ids = self.data[0]
self.idsList = self.ids.split()
def parseEmails(self):
jsonOutput = {}
for anEmail in self.data[0].split():
type, self.data = self.mail.fetch(anEmail, '(UID RFC822)')
raw = self.data[0][1]
try:
raw_str = raw.decode("utf-8")
except UnicodeDecodeError:
try:
raw_str = raw.decode("ISO-8859-1") # ANSI support
except UnicodeDecodeError:
try:
raw_str = raw.decode("ascii") # ASCII ?
except UnicodeDecodeError:
pass
msg = email.message_from_string(raw_str)
jsonOutput['subject'] = msg['subject']
jsonOutput['from'] = msg['from']
jsonOutput['date'] = msg['date']
raw = self.data[0][0]
raw_str = raw.decode("utf-8")
uid = raw_str.split()[2]
# Body #
if msg.is_multipart():
for part in msg.walk():
partType = part.get_content_type()
## Get Body ##
if partType == "text/plain" and "attachment" not in part:
jsonOutput['body'] = part.get_payload()
## Get Attachments ##
if part.get('Content-Disposition') is not None:
attchName = part.get_filename()
print(attchName)
if bool(attchName):
attchFilePath = str(self.destFolder)+str(uid)+str("/")+str(attchName)
print(attchFilePath)
os.makedirs(os.path.dirname(attchFilePath), exist_ok=True)
with open(attchFilePath, "wb") as f:
f.write(part.get_payload(decode=True))
else:
# jsonOutput['body'] = msg.get_payload(decode=True).decode("utf-8") # Non-multipart email, perhaps no attachments or just text.
jsonOutput['body'] = msg.get_payload()
outputDump = json.dumps(jsonOutput)
emailInfoFilePath = str(self.destFolder)+str(uid)+str("/")+str(uid)+str(".json")
os.makedirs(os.path.dirname(emailInfoFilePath), exist_ok=True)
print(emailInfoFilePath)
with open(emailInfoFilePath, "w") as f:
f.write(outputDump)
def __init__(self):
self.initializeVariables()
self.helloWorld()
self.getLogin()
if self.attemptLogin():
not self.selectMailbox() and sys.exit()
else:
sys.exit()
not self.checkIfUsersWantsToContinue() and sys.exit()
self.searchThroughMailbox()
self.parseEmails()
if __name__ == "__main__":
run = GmailFinin()
I have tried using below for search, but I don't think i.e optimal because it is searching only in subject and How to add multiple or condition for list of keywords.
type, self.data = self.mail.search(None, '(OR TEXT "bill" SUBJECT "bill")')
I am aware this is a duplicate from a past thread, but when I use that suggestion, it says 'unindent does not match any outer indentation level'. When I run the script at school (this is a school assignment) a blank GUI appears with no buttons, and when I run it at home, it appears with the error message as above- I am using Python 3.3.2 on each computer. The code for the 999 limit is in lines 45-57 and the error message appears on the first line (45). I'm quite new to python and my teacher is awful, so apologies if my question sounds quite silly. Can I have a suggestion as to how to get this to work?
Thanks a lot!
from tkinter import *
class Calculator(Frame):
def frame(this, side):
w = Frame(this)
w.pack(side=side, expand=YES, fill=BOTH)
return w
def button(this, root, side, text, command=None):
w = Button(root, text=text, command=command)
w.pack(side=side, expand=YES, fill=BOTH)
return w
need_clr = False
def digit(self, digit):
if self.need_clr:
self.display.set('')
self.need_clr = False
self.display.set(self.display.get() + digit)
def sign(self):
need_clr = False
cont = self.display.get()
if len(cont) > 0 and cont[0] == '-':
self.display.set(cont[1:])
else:
self.display.set('-' + cont)
def oper(self, op):
self.display.set(self.display.get() + ' ' + op + ' ')
self.need_clr = False
def calc(self):
try:
self.display.set(eval(self.display.get()))
self.need_clr = True
except:
showerror('Operation Error', 'Illegal Operation')
self.display.set('')
self.need_clr = False
def calc(self):
try:
self.display.set(self.validate_result(eval(self.display.get())))
self.need_clr = True
except:
showerror('Operation Error', 'Illegal Operation')
self.display.set('')
self.need_clr = False
def validate_result(self, result):
if result >= 1000:
raise ValueError('result too big!')
else:
return result
def __init__(self):
Frame.__init__(self)
self.option_add('*Font', 'Dotum 15')
self.pack(expand=YES, fill=BOTH)
self.master.title('Simple Calculator')
self.display = StringVar()
e = Entry(self, relief=SUNKEN, textvariable=self.display)
e.pack(side=TOP, expand=YES, fill=BOTH)
for key in ("123", "456", "789"):
keyF = self.frame(TOP)
for char in key:
self.button(keyF, LEFT, char,
lambda c=char: self.digit(c))
keyF = self.frame(TOP)
self.button(keyF, LEFT, '0', lambda ch='0': self.digit(ch))
opsF = self.frame(TOP)
for char in "+-=":
if char == '=':
btn = self.button(opsF, LEFT, char, self.calc)
else:
btn = self.button(opsF, LEFT, char,
lambda w=self, s=char: w.oper(s))
clearF = self.frame(BOTTOM)
self.button(clearF, LEFT, 'Clr', lambda w=self.display: w.set(''))
if __name__ == '__main__':
Calculator().mainloop()
I'm having trouble implementing a thread correctly to keep my application from locking up and experiencing weird behavior. The app is designed to log into a ubuntu based server or ubuntu embedded server and search for log files that may be in the clear. The embedded server works, but the app keeps locking up while the search is occurring. The siteserver will not process. I have yet to code the local file search. I would like to add a progress bar once I figure out how to implement threads. I thought this would be straight forward since I've been learning and working with Python for several months now, but working with a GUI has its challenges. I'm still a neophyte and open to all the criticisms; it only helps me to become a better programmer. Any help is greatly appreciated. Here is the code below:
#!c:\python27
import wx
import os
import re
import paramiko
import string
import fileinput
import os.path
import dircache
import sys
import time
import datetime, time
import wx
from wxGui import *
class MyApp(wx.App):
def OnInit(self):
frame = MyFrame("SecureTool v2.0.0", (50, 60), (458, 332))
frame.Show()
self.SetTopWindow(frame)
return True
class MyFrame(wx.Frame):
def __init__(self, title, pos, size):
wx.Frame.__init__(self, None, -1, title, pos, size)
toolbar = self.CreateToolBar()
toolbar.Realize()
menuFile = wx.Menu()
menuFile.Append(1, "&About...")
menuFile.AppendSeparator()
menuFile.Append(2, "E&xit")
menuBar = wx.MenuBar()
menuBar.Append(menuFile, "&File")
menu2 = wx.Menu()
menu2.Append(wx.NewId(), "&Copy", "Copy in status bar")
menu2.AppendSeparator()
menu2.Append(wx.NewId(), "C&ut", "")
menu2.AppendSeparator()
menu2.Append(wx.NewId(), "Paste", "")
menu2.AppendSeparator()
menu2.Append(wx.NewId(), "&Options...", "Display Options")
menuBar.Append(menu2, "&Edit")
self.SetMenuBar(menuBar)
self.CreateStatusBar()
self.SetStatusText("Welcome to SecureTool!")
self.Bind(wx.EVT_MENU, self.OnAbout, id=1)
self.Bind(wx.EVT_MENU, self.OnQuit, id=2)
panel = wx.Panel(self)
panel.SetBackgroundColour('LIGHT GREY')
#Close button
button = wx.Button(panel, label="EXIT", pos=(229, 160), size=(229, 80))
self.Bind(wx.EVT_BUTTON, self.OnQuit, button)
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
#Embed Server button
button2 = wx.Button(panel, label="Embed Server", pos=(0, 160), size=(229, 80))
self.Bind(wx.EVT_BUTTON, self.OnIP, button2)
#Site Server
button3 = wx.Button(panel, label="SITESERVER", pos=(0, 80), size=(229, 80))
self.Bind(wx.EVT_BUTTON, self.OnUsrPswd, button3)
#Local Search
button4 = wx.Button(panel, label="LOCAL SEARCH", pos=(229, 80), size=(229, 80))
self.Bind(wx.EVT_BUTTON, self.OnOpen, button4)
EVT_RESULT(self, self.OnResult)
self.worker = None
def OnIP(self, event):
ip_address = 0
result = ''
dlg = wx.TextEntryDialog(None, "Enter the IP Address.",
'Embed Server Connect', 'xxx.xxx.xxx.xxx')
if dlg.ShowModal() == wx.ID_OK:
ip_address = dlg.GetValue()
if ip_address:
cmsg = wx.MessageDialog(None, 'Do you want to connect to: ' + ip_address,
'Connect', wx.YES_NO | wx.ICON_QUESTION)
result = cmsg.ShowModal()
if result == wx.ID_YES:
self.DispConnect(ip_address)
cmsg.Destroy()
dlg.Destroy()
return True
def OnUsrPswd(self, event):
passwrd = 0
result = ''
result = wx.TextEntryDialog(None, 'Enter Weekly Password', 'Site Server login','')
if result.ShowModal() == wx.ID_OK:
passwrd = result.GetValue()
if passwrd:
psmsg = wx.MessageDialog(None, 'Do you want to connect to the Siteserver?', 'Connect',
wx.YES_NO | wx.ICON_QUESTION)
result = psmsg.ShowModal()
if result == wx.ID_YES:
self.SiteserverConnect(passwrd)
psmsg.Destroy()
result.Destroy()
return True
def ErrMsg(self):
ermsg = wx.MessageDialog(None, 'Invalid Entry!', 'ConnectionDialog', wx.ICON_ERROR)
ermsg.ShowModal()
ermsg.Destroy()
def GoodConnect(self):
gdcnt = wx.MessageDialog(None, 'You are connected!', 'ConnectionStatus', wx.ICON_INFORMATION)
gdcnt.ShowModal()
#if gdcnt.ShowModal() == wx.ID_OK:
gdcnt.Destroy()
def OnFinish(self):
finish = wx.MessageDialog(None, 'Job is finished!', 'WorkStatus', wx.ICON_INFORMATION)
finish.ShowModal()
finish.Destroy()
def DispConnect(self, address):
pattern = r"\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b"
port = 22
user = 'root'
password ='******'
if re.match(pattern, address):
ssh = paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(address,port,user,password)
Ssh = ssh
self.GoodConnect()
self.OnSearch(Ssh)
else:
self.ErrMsg()
def SiteserverConnect(self, password):
port = 22
user = 'root2'
address = '10.5.48.2'
if password:
ssh = paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(address,port,user,password)
Ssh = ssh
self.GoodConnect()
self.OnSiteSearch(Ssh)
else:
self.ErrMsg()
def startWorker(self,a, b, c):
self.button2.Disable()
self.thread = Thread(target=self.LongRunningSearch)
self.thread.start()
def OnSearch(self, sssh):
self.startWorker(self.OnFinish, self.LongRunningSearch, wargs=[sssh])
self.OnFinish()
def LongRunningSearch(sssh):
ssh = sssh
apath = '/'
apattern = '"*.txt" -o -name "*.log"'
rawcommand = 'find {path} -name "*.txt" -o -name "*.log"'
command1 = rawcommand.format(path=apath, pattern=apattern)
stdin, stdout, stderr = ssh.exec_command(command1)
filelist = stdout.read().splitlines()
ftp = ssh.open_sftp()
for afile in filelist:
(head, filename) = os.path.split(afile)
paths = '/dispenser_result.log'
temp = ftp.file(paths, 'w')
from time import strftime
temp.write("{0:^75}".format("Company -Security Report" ) + strftime(" %Y-%m-%d %H:%M:%S") + "\n\n")
ustring = wx.TextEntryDialog(None, 'Enter a search string below:', 'Search', 'String Name')
if ustring.ShowModal() == wx.ID_OK:
userstring = ustring.GetValue()
if userstring:
userStrHEX = userstring.encode('hex')
userStrASCII = ''.join(str(ord(char)) for char in userstring)
regex = re.compile(r"(%s|%s|%s)" % ( re.escape( userstring ), re.escape( userStrHEX ), re.escape( userStrASCII )))
else:
sys.exit('You Must Enter A String!!!')
count = 0
for afile in filelist:
(head, filename) = os.path.split(afile)
if afile.endswith(".log") or afile.endswith(".txt"):
f=ftp.open(afile, 'r')
for i, line in enumerate(f.readlines()):
result = regex.search(line)
if result:
count += 1
ln = str(i)
pathname = os.path.join(afile)
template = "\n\nLine: {0}\nFile: {1}\nString Type: {2}\n\n"
output = template.format(ln, pathname, result.group())
ftp.get(afile, 'c:\\Extracted\\' + filename)
temp.write(output)
break
else:
#print "No Match in: " + os.path.join(afile)
temp.write("\nNo Match in: " + os.path.join(afile))
f.close()
for fnum in filelist:
#print "\nFiles Searched: ", len(filelist)
#print "Files Matched: ", count
num = len(filelist)
temp.write("\n\nFiles Searched:" + '%s\n' % (num))
temp.write("Files Matched:"+ '%s\n' % (count))
temp.write("Search String:"+ '%s\n' % (userstring))
break
temp.close()
defaultFolder = "DispenserLogResults"
if not defaultFolder.endswith(':') and not os.path.exists('c:\\Extracted\\DispenserLogResults'):
os.mkdir('c:\\Extracted\\DispenserLogResults')
else:
pass
ftp.get(paths, 'c:\\Extracted\\DispenserLogResults\\dispenser_result.log')
ftp.remove(paths)
re.purge()
ftp.close()
ssh.close()
def OnSiteSearch(self, sssh):
ssh = sssh
apath = '/var/log/apache2 /var/opt/smartmerch/log/'
apattern = '"*.log"'
rawcommand = 'find {path} -type f -name "*.log"'
command1 = rawcommand.format(path=apath, pattern=apattern)
stdin, stdout, stderr = ssh.exec_command(command1)
filelist = stdout.read().splitlines()
ftp = ssh.open_sftp()
for afile in filelist:
(head, filename) = os.path.split(afile)
paths = '/var/tmp/siteserver_result.log'
temp = ftp.file(paths, 'w')
from time import strftime
temp.write("{0:^75}".format("Gilbarco - SQA Security Report" ) + strftime(" %Y-%m-%d %H:%M:%S") + "\n\n")
temp.write("\n{0:^75}".format("SiteServer Logs" ))
ustring = wx.TextEntryDialog(None, 'Enter a search string below:', 'Search', 'String Name')
if ustring.ShowModal() == wx.ID_OK:
userstring = ustring.GetValue()
if userstring:
userStrHEX = userstring.encode('hex')
userStrASCII = ''.join(str(ord(char)) for char in userstring)
regex = re.compile(r"(%s|%s|%s)" % ( re.escape( userstring ), re.escape( userStrHEX ), re.escape( userStrASCII )))
else:
sys.exit('You Must Enter A String!!!')
count = 0
for afile in filelist:
(head, filename) = os.path.split(afile)
if afile.endswith(".log") or afile.endswith(".txt"):
f=ftp.open(afile, 'r')
for i, line in enumerate(f.readlines()):
result = regex.search(line)
if result:
count += 1
ln = str(i)
pathname = os.path.join(afile)
template = "\n\nLine: {0}\nFile: {1}\nString Type: {2}\n\n"
output = template.format(ln, pathname, result.group())
ftp.get(afile, 'c:\\Extracted\\' + filename)
temp.write(output)
break
else:
temp.write("\nNo Match in: " + os.path.join(afile))
f.close()
for fnum in filelist:
num = len(filelist)
temp.write("\n\nFiles Searched:" + '%s\n' % (num))
temp.write("Files Matched:"+ '%s\n' % (count))
temp.write("Search String:"+ '%s\n' % (userstring))
break
temp.close()
defaultFolder = "SiteServerLogResults"
if not defaultFolder.endswith(':') and not os.path.exists('c:\\Extracted\\SiteServerLogResults'):
os.mkdir('c:\\Extracted\\SiteServerLogResults')
else:
pass
ftp.get(paths, 'c:\\Extracted\\SiteServerLogResults\\siteserver_result.log')
ftp.remove(paths)
re.purge()
ftp.close()
ssh.close()
self.OnFinish()
def OnOpen(self,e):
self.dirname = ''
dlg = wx.FileDialog(self, "Choose a file", self.dirname, "", "*.*", wx.OPEN)
if dlg.ShowModal() == wx.ID_OK:
self.filename = dlg.GetFilename()
self.dirname = dlg.GetDirectory()
f = open(os.path.join(self.dirname, self.filename), 'r')
self.control.SetValue(f.read())
f.close()
dlg.Destroy()
def OnQuit(self, event):
self.Close(True)
def OnAbout(self, event):
wx.MessageBox("This is sQAST v2.0.0",
"About secureTool", wx.OK | wx.ICON_INFORMATION, self)
def OnCloseWindow(self, event):
self.Destroy()
if __name__ == '__main__':
app = MyApp(False)
app.MainLoop()
Traceback Error after running:
Traceback (most recent call last):
File "C:\SQA_log\wxGui.py", line 87, in OnIP
self.DispConnect(ip_address)
File "C:\SQA_log\wxGui.py", line 143, in DispConnect
self.OnSearch(Ssh)
File "C:\SQA_log\wxGui.py", line 169, in OnSearch
self.startWorker(self.OnFinish, self.LongRunningSearch, wargs=[sssh])
In your particular case I would do something like:
1) Encapsulate the long task and separate it from the GUI reaction, simplify your method:
def OnSearch(self, sssh):
self.LongRunningSearch(sssh) # Move all the blocking code here,
# just NOT the GUI reaction !
# Meaning self.OnFinish()...
self.OnFinish()
2) Verify that it still runs fine. Then modify the method to add the thread:
def OnSearch(self, sssh):
startWorker(self.OnFinish, self.LongRunningSearch, wargs=[sssh])
self.OnSearch will end immediately and self.OnFinish will be called after the thread running self.LongRunningSearch has finished. It may still need some tuning as I am unable to run your code on my computer.
I don't see any threading in your application at all. Whenever you make a call to something that will take a while, that something needs to run in a separate thread or it will block the main loop of your GUI.
You should read the following wiki entry on threading in wxPython: http://wiki.wxpython.org/LongRunningTasks
I have used the information therein to successfully create threaded wxPython applications. There's also a simple threading tutorial here: http://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/
Hope that helps. If you get stuck, you should post to the official wxPython mailing group: https://groups.google.com/forum/#!forum/wxpython-users Those guys will set you straight.
You can also have a look at convenience module for threading implemented in the wx, wx.lib.delayedresult. It is very easy to use and to add when you find it is needed. I am not sure why it is ignored so often. I have written an example which uses it some time ago here.
It basically needs you to create two functions / methods. First, which will be ran in another thread, and second, which will be ran after another thread finishes. Then you just call startWorker(LongTaskDone, LongTask).
Example 1: Using wx.lib.delayedresult. wx.CallAfter is used to show progress in GUI thread using gauge widget. Official Documentation.
from time import sleep
import wx
from wx.lib.delayedresult import startWorker
class MainWindow(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
self.panel = wx.Panel(self)
self.startButton = wx.Button(self.panel, label="Long Task")
self.abortButton = wx.Button(self.panel, label="Abort")
self.abortButton.Disable()
self.gauge = wx.Gauge(self.panel, size=(-1, 20))
self.shouldAbort = False
self.startButton.Bind(wx.EVT_BUTTON, self.OnStartButton)
self.abortButton.Bind(wx.EVT_BUTTON, self.OnAbortButton)
self.windowSizer = wx.BoxSizer()
self.windowSizer.Add(self.panel, 1, wx.ALL | wx.EXPAND)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.startButton)
self.sizer.Add(self.abortButton)
self.sizer.Add((10, 10))
self.sizer.Add(self.gauge)
self.border = wx.BoxSizer()
self.border.Add(self.sizer, 1, wx.ALL | wx.EXPAND, 5)
self.panel.SetSizerAndFit(self.border)
self.SetSizerAndFit(self.windowSizer)
self.Show()
def OnStartButton(self, e):
self.startButton.Disable()
self.abortButton.Enable()
startWorker(self.LongTaskDone, self.LongTask)
def OnAbortButton(self, e):
self.shouldAbort = True
def LongTask(self):
for a in range(101):
sleep(0.05)
wx.CallAfter(self.gauge.SetValue, a)
if self.shouldAbort:
break
return self.shouldAbort
def LongTaskDone(self, result):
r = result.get()
if r:
print("Aborted!")
else:
print("Ended!")
self.startButton.Enable()
self.abortButton.Disable()
self.shouldAbort = False
self.gauge.SetValue(0)
app = wx.App(False)
win = MainWindow(None)
app.MainLoop()
Example 2: Using standard threading module. In some cases this may be more "ugly". I would recommend using wx.lib.delayedresult. Official Documentation.
from time import sleep
from threading import Thread
import wx
class MainWindow(wx.Frame):
def __init__(self, *args, **kwargs):
wx.Frame.__init__(self, *args, **kwargs)
self.panel = wx.Panel(self)
self.startButton = wx.Button(self.panel, label="Long Task")
self.abortButton = wx.Button(self.panel, label="Abort")
self.abortButton.Disable()
self.gauge = wx.Gauge(self.panel, size=(-1, 20))
self.shouldAbort = False
self.thread = None
self.startButton.Bind(wx.EVT_BUTTON, self.OnStartButton)
self.abortButton.Bind(wx.EVT_BUTTON, self.OnAbortButton)
self.windowSizer = wx.BoxSizer()
self.windowSizer.Add(self.panel, 1, wx.ALL | wx.EXPAND)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(self.startButton)
self.sizer.Add(self.abortButton)
self.sizer.Add((10, 10))
self.sizer.Add(self.gauge)
self.border = wx.BoxSizer()
self.border.Add(self.sizer, 1, wx.ALL | wx.EXPAND, 5)
self.panel.SetSizerAndFit(self.border)
self.SetSizerAndFit(self.windowSizer)
self.Show()
def OnStartButton(self, e):
self.startButton.Disable()
self.abortButton.Enable()
self.thread = Thread(target=self.LongTask)
self.thread.start()
def OnAbortButton(self, e):
self.shouldAbort = True
def LongTask(self):
for a in range(101):
sleep(0.05)
wx.CallAfter(self.gauge.SetValue, a)
if self.shouldAbort:
break
wx.CallAfter(self.LongTaskDone, self.shouldAbort)
def LongTaskDone(self, r):
if r:
print("Aborted!")
else:
print("Ended!")
self.startButton.Enable()
self.abortButton.Disable()
self.shouldAbort = False
self.gauge.SetValue(0)
app = wx.App(False)
win = MainWindow(None)
app.MainLoop()
Note: threading.Lock may be needed for thread-safe passing of more complicated variables and data than simple boolean flag.
Edit: Added examples.
Edit: Added ability to abort the thread.
Edit: Simplified the examples. Got rid of timer based on tom10's idea and also deleted threading.Lock as it is not needed here.
In wxPython, all calls to methods of GUI objects and event handlers need to happen in the main thread. Because of this, you need to be careful when using threading with wx, but it's usually easy to make the required modifications.
In your code, for example, you could do the call to wx.TextEntryDialog from the main thread, and then pass this information to the search thread.
If you need to request action of the GUI from the thread, the easiest way is to use wx.CallAfter, though there are other approaches that work as well.