TKINTER - How to keep the main loop from waiting a validate command? - python

I have an username entry field that validates it's contents by checking if it exists within the domain, the only problem is that this call takes about 1 ~ 2 seconds to return, is there a way to use threading to keep the mainloop from waiting the validate command?
Example code:
import tkinter as tk
import subprocess
from typing import NoReturn
class GUI(tk.Tk):
def __init__(self) -> None:
super().__init__()
self.geometry('300x300')
self.title('test app')
self.__CreateWidgets()
def Start(self) -> None:
self.mainloop()
def __CreateWidgets(self) -> None:
self.__errorlabel = tk.Label(
self,
text = '',
foreground = 'red'
)
self.__errorlabel.grid(column = 0, row = 0)
self.__userIDentry = tk.Entry(
self,
validate = 'focusout',
validatecommand = (self.register(self.__UserIDValidator), '%P'), #This is what I wan't to change.
invalidcommand = lambda: self.__errorlabel.config(
text = 'Invalid user ID'
)
)
self.__userIDentry.grid(column = 0, row = 1)
self.__userIDentry.bind('<FocusIn>', lambda _: self.__errorlabel.config(
text = ''
)
)
tk.Entry( #This is just a blank entry to click on to test the previous entry validation.
self,
).grid(column = 0, row = 2)
def __UserIDValidator(self, string:str) -> bool:
#This function takes about 1 ~ 2 seconds to return:
flag = False
if string:
p = subprocess.Popen(
f'net user /domain {string}',
stdout = subprocess.PIPE,
stderr = subprocess.PIPE
)
error = p.stderr.read()
if not error:
flag = True
return flag
def main() -> NoReturn:
app = GUI()
app.Start()
if __name__ == '__main__':
main()
Running App
You should be able to copy and run the code above if you're on a domain, it basically sends a net user /domain command and checks if there was any error on the request, the program freezes until the validation is complete, so is there a way to run the validation and keep the mainloop from getting stuck?

I had a similar problem, I fixed it with threading:
import threading
def my_function():
something_somewhat_intensive()
def my_function_thr():
thr = threading.Thread(target=my_functioon)
thr.start()
Then you call my_function_thr() to begin that process on a thread. I don't know how this interacts with the import 'subprocess' at all, but this fixed a lot of problems that I had.
It should also be mentioned that if your process is resource intensive, and a bit more than like saving a file or something, use Multiprocessing. For a lot of processes, especially with just wanting the Tkinter window to not freeze, I do recommend threading.

Related

Design pattern for non-blocking nested function calls in main thread of GUI?

I need some help with identifying a design pattern or a technique to make a PyQt GUI application non-blocking, when it has multiple nested calls which invoke one external subprocess after another. The pseudocode is:
class MainWindow:
def executeInSubprocess(self, theCommand):
subprocess.run(theCommand, check = True)
#program control reaches here only after the command executed by subprocess.run completes execution
def function1(self):
commandToExecute = ['python', '-m', 'someProgram.py', '--CLA_option']
self.executeInSubprocess(commandToExecute)
self.function2()
#some commands to update the GUI widgets
def function2(self):
#Some lines here gather data generated by running function1
self.function3(data)
def function3(self, data):
commandToExecute = ['python', '-m', 'anotherProgram.py', '--CLA_option']
for oneData in data:
newCommand = commandToExecute[:] #copy contents of list
newCommand.append('--someOption')
newCommand.append(oneData)
self.executeInSubprocess(newCommand)
When the user clicks a button on the GUI, the function1 gets invoked. The button remains disabled until the #some commands to update the GUI widgets line, where the button is re-enabled.
The problem:
How to design it in such a way that executeInSubprocess is non-blocking? I'd like to try replacing subprocess.run with QProcess, which would not wait until the external command completes, thereby not freezing the GUI.
executeInSubprocess is called inside a for loop multiple times in function3, and is dependent on the data generated by function1.
These functions are not too large, so it shouldn't be an issue refactoring it. What I need, is knowledge on a good way to design such a scenario. I've considered putting references to function1, function2 and function3 in a list and having a function in a class call them one by one, but then the executeInSubprocess in function3 complicates things.
Update: I've provided an example of how complex and intertwined the code can get.
#!/usr/bin/python
# -*- coding: ascii -*-
from PyQt5.QtWidgets import (QApplication, QMainWindow, QPushButton, QPlainTextEdit, QVBoxLayout, QWidget)
from PyQt5.QtCore import QProcess
from collections import deque
import sys
# Note: The objective was to design a way to execute a function and return control back to the main thread so that the GUI does not freeze.
# But it had to be done in a way that a function could invoke another function, which could invoke another function. Each of these functions
# can have one or more external commands that they need to run. So after invoking each external process, control has to return to the main thread
# and then after running the external process completes, the next command or function needs to run and return control to the main thread and
# so on until all functions and external commands are exhausted. What's given below is a very crude, tangled design that needs to be improved.
class ExternalProcessInvoker:
def __init__(self):
self.externalProcess = None
self.currentFunction = None
self.functionQueue = deque() #a sequence of functions to be executed
self.commandQueue = dict() #{the key is a function reference: the value is a list of commands [['python', 'prog1.py'], ['python', 'prog2.py'], ...]}
self.FIRST_ELEMENT_OF_LIST = 0
self.UTF8 = 'utf8'
def registerTheMessageFunction(self, functionReference):
self.message = functionReference
def startTheProcess(self):
while self.functionQueue:
#print('Elements in queue are: ', self.functionQueue)
theFunctionToExecute = self.functionQueue.popleft()
#---run the function
theFunctionToExecute(theFunctionToExecute) #The function may populate commandQueue when run
self.currentFunction = theFunctionToExecute
self.checkForMoreFunctionPopulatedCommandsToExecute()
def checkForMoreFunctionPopulatedCommandsToExecute(self):
#---check if commandQueue is populated with any external process that needs to be run
if self.currentFunction in self.commandQueue:
if self.commandQueue[self.currentFunction]:#contains some command
command = self.commandQueue[self.currentFunction].popleft()
#command = self.convertToUTF8(command)
if self.externalProcess is None: # No process running.
#---run the command
self.message('Executing ' + str(command)); print('Executing ', command)
self.externalProcess = QProcess()
self.externalProcess.readyReadStandardOutput.connect(self.functionForStdout)
self.externalProcess.readyReadStandardError.connect(self.functionForStderr)
self.externalProcess.stateChanged.connect(self.functionForStateChange)
self.externalProcess.finished.connect(self.processCompleted) # Clean up once complete.
self.externalProcess.start(command[self.FIRST_ELEMENT_OF_LIST], command[self.FIRST_ELEMENT_OF_LIST:]) #the first argument is the first command element (usually 'python'). The second argument is a list of all the remaining elements of the command
print('Process ID: ', self.externalProcess.processId())
else:
self.currentFunction = None
def convertToUTF8(self, command):
return [oneString.encode('utf-8') for oneString in command]
def stopTheProcess(self):
self.message('Attempting to stop the processes')
if self.externalProcess:
self.externalProcess.kill()
self.message('Also cleared ' + len(self.functionQueue) + ' items from execution queue')
self.functionQueue.clear()
def functionForStderr(self):
data = self.externalProcess.readAllStandardError()
stderr = bytes(data).decode(self.UTF8)
self.message(stderr)
def functionForStdout(self):
data = self.externalProcess.readAllStandardOutput()
stdout = bytes(data).decode(self.UTF8)
self.message(stdout)
def functionForStateChange(self, state):
states = {QProcess.NotRunning: 'Not running', QProcess.Starting: 'Starting', QProcess.Running: 'Running'}
state_name = states[state]
self.message(f'State changed: {state_name}')
def processCompleted(self):
self.message('Process finished.')
self.externalProcess = None
self.checkForMoreFunctionPopulatedCommandsToExecute()
def addThisFunctionToProcessingQueue(self, functionReference):
#print('Received request to add this function to processing queue: ', functionReference)
#print('What's already in processing queue: ', self.functionQueue)
self.functionQueue.append(functionReference)
def addThisCommandToProcessingList(self, command, functionReference):
if functionReference not in self.commandQueue:
self.commandQueue[functionReference] = deque()
self.commandQueue[functionReference].append(command)
#print('\nfunc ref: ', functionReference, ' command: ', command)
self.message('Added ' + str(command) + ' for processing')
#print(self.commandQueue)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.proc = ExternalProcessInvoker()
self.proc.registerTheMessageFunction(self.message)
self.executeButton = QPushButton('Execute') #TODO: Disable button until processing completes or processes are killed
self.executeButton.pressed.connect(self.initiateProcessing)
self.killButton = QPushButton('Kill process') #TODO: Disable button until processing is started
self.killButton.pressed.connect(self.killProcessing)
self.textDisplay = QPlainTextEdit()
self.textDisplay.setReadOnly(True)
boxLayout = QVBoxLayout()
boxLayout.addWidget(self.executeButton)
boxLayout.addWidget(self.killButton)
boxLayout.addWidget(self.textDisplay)
theWidget = QWidget()
theWidget.setLayout(boxLayout)
self.setCentralWidget(theWidget)
def message(self, mssg):
self.textDisplay.appendPlainText(mssg)
def initiateProcessing(self):
print('Processing initiated')
#---first populate the functions and commands to execute
self.proc.addThisFunctionToProcessingQueue(self.function1)
self.proc.addThisFunctionToProcessingQueue(self.function2)
self.proc.addThisFunctionToProcessingQueue(self.function3)
self.proc.startTheProcess()
def function1(self, functionReference):
self.message('Executing function1')
command = ['python', 'dummyScript1.py']
self.proc.addThisCommandToProcessingList(command, functionReference)
def function2(self, functionReference):
self.message('Executing function2')
def function3(self, functionReference):
self.message('Executing function3')
maxInvocations = 5
secondsToSleep = 1
for _ in range(maxInvocations):
command = ['python', 'dummyScript2.py', str(secondsToSleep)]
self.proc.addThisCommandToProcessingList(command, functionReference)
secondsToSleep = secondsToSleep + 1
self.message('Processing complete')
print('Completed')
def killProcessing(self):
self.proc.stopTheProcess()
app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec_()
Dummy script 1:
#!/usr/bin/python
# -*- coding: ascii -*-
import time
import datetime
sec = 3
print(datetime.datetime.now(), " Going to sleep for ", sec, " seconds")
time.sleep(sec)
print(datetime.datetime.now(), " Done sleeping dummy script1")
Dummy script 2:
#!/usr/bin/python
# -*- coding: ascii -*-
import time
def gotosleep(sleepTime):
print("Going to sleep for ", sleepTime, " seconds")
time.sleep(sleepTime)
print("Done sleeping for ", sleepTime, " seconds in dummy script2")
if __name__ == "__main__":
FIRST_EXTRA_ARG = 1
sleepTime = sys.argv[FIRST_EXTRA_ARG]
gotosleep(sleepTime)

Tkinter freezes while trying to read stdout from subprocess

I started a Tkinter application but I'm with problems with buffering. I searched the solution but didn't find it.
Correlated links:
Calling python script with subprocess popen and flushing the data
Python C program subprocess hangs at "for line in iter"
Python subprocess standard output to a variable
As an exemple, this app has two buttons: Start and Stop.
When I press the button Start, the spammer.py is called as a subprocess and when I press the button Stop the program must be killed.
# spammer.py
import time
counter = 0
while counter < 40: # This process will last 10 second maximum
print("counter = %d" % counter)
counter += 1
time.sleep(0.25) # 4 messages/second
While the PrintNumbers.py is running, I want the spammer's output be storage in a variable inside the Tkinter to be used in realtime. But once I try to read the buffer with myprocess.stdout.readline, it stucks and it doesn't continue until the subprocess finish and as consequence for exemple I cannot click on the Stop button.
I read that the function is waiting for EOF to continue, and I tried to use tokens as shown here, and the function that should continue when it finds a or a \n, but it did not work.
The Tkinter exemple is bellow. After I click at the Start button, I instantly see the message Started reading stdout, and after 10 seconds it shows a lot of messages, while I wanted to show every message over time.
# PrintNumbers.py
import Tkinter as tk
import subprocess
class App:
def __init__(self, root):
self.root = root
self.myprocess = None
self.logmessages = []
self.createButtons()
self.timedUpdate()
def createButtons(self):
self.ButtonsFrame = tk.Frame(self.root, width=600, height=400)
self.ButtonsFrame.pack()
self.startbutton = tk.Button(self.ButtonsFrame, text="Start",
command=self.__ClickOnStarButton)
self.stopbutton = tk.Button(self.ButtonsFrame, text="Stop",
command=self.__ClickOnStopButton)
self.startbutton.pack()
self.stopbutton.pack()
self.startbutton["state"] = "normal"
self.stopbutton["state"] = "disable"
def __ClickOnStarButton(self):
print("Click on Start Button")
self.startbutton["state"] = "disable"
self.stopbutton["state"] = "normal"
self.startProcess()
def __ClickOnStopButton(self):
print("Click on Stop Button")
self.startbutton["state"] = "normal"
self.stopbutton["state"] = "disable"
self.killProcess()
def startProcess(self):
command = "python spammer.py"
self.myprocess = subprocess.Popen(command, stdout=subprocess.PIPE, bufsize=1)
def killProcess(self):
self.myprocess.terminate()
self.myprocess.wait()
self.myprocess = None
def timedUpdate(self):
if self.myprocess is not None: # There's a process running
self.getLogText() # Will get the info from spammer.py
self.treatOutput() # Do whatever we want with the data
root.after(200, self.timedUpdate) # Every 0.2 seconds we will update
def getLogText(self):
if self.myprocess is None: # There's no process running
return
# The problem is here
print("Started reading stdout")
for line in iter(self.myprocess.stdout.readline, ''):
print(" Inside the loop. line = '%s'" % line)
self.logmessages.append(line)
print("Finished reading stdout")
def treatOutput(self):
# Any function that uses the spammer's output
# it's here just to test
while len(self.logmessages):
line = self.logmessage.pop(0)
line = line.replace("counter = ", "")
mynumber = int(line)
if mynumber % 3:
print(mynumber)
if __name__ == "__main__":
root = tk.Tk()
app = App(root)
root.mainloop()
How can I read the output without getting stuck? I'm still using python 2.7, and I don't know if it's the problem either.

Python GUI stays frozen waiting for thread code to finish running

I have a python GUI program that needs to do a same task but with several threads. The problem is that I call the threads but they don't execute parallel but sequentially. First one executes, it ends and then second one, etc. I want them to start independently.
The main components are:
1. Menu (view)
2. ProcesStarter (controller)
3. Process (controller)
The Menu is where you click on the "Start" button which calls a function at ProcesStarter.
The ProcesStarter creates objects of Process and threads, and starts all threads in a for-loop.
Menu:
class VotingFrame(BaseFrame):
def create_widgets(self):
self.start_process = tk.Button(root, text="Start Process", command=lambda: self.start_process())
self.start_process.grid(row=3,column=0, sticky=tk.W)
def start_process(self):
procesor = XProcesStarter()
procesor_thread = Thread(target=procesor.start_process())
procesor_thread.start()
ProcesStarter:
class XProcesStarter:
def start_process(self):
print "starting new process..."
# thread count
thread_count = self.get_thread_count()
# initialize Process objects with data, and start threads
for i in range(thread_count):
vote_process = XProcess(self.get_proxy_list(), self.get_url())
t = Thread(target=vote_process.start_process())
t.start()
Process:
class XProcess():
def __init__(self, proxy_list, url, browser_show=False):
# init code
def start_process(self):
# code for process
When I press the GUI button for "Start Process" the gui is locked until both threads finish execution.
The idea is that threads should work in the background and work in parallel.
you call procesor.start_process() immediately when specifying it as the target of the Thread:
#use this
procesor_thread = Thread(target=procesor.start_process)
#not this
procesor_thread = Thread(target=procesor.start_process())
# this is called right away ^
If you call it right away it returns None which is a valid target for Thread (it just does nothing) which is why it happens sequentially, the threads are not doing anything.
One way to use a class as the target of a thread is to use the class as the target, and the arguments to the constructor as args.
from threading import Thread
from time import sleep
from random import randint
class XProcesStarter:
def __init__(self, thread_count):
print ("starting new process...")
self._i = 0
for i in range(thread_count):
t = Thread(
target=XProcess,
args=(self.get_proxy_list(), self.get_url())
)
t.start()
def get_proxy_list(self):
self._i += 1
return "Proxy list #%s" % self._i
def get_url(self):
self._i += 1
return "URL #%d" % self._i
class XProcess():
def __init__(self, proxy_list, url, browser_show=False):
r = 0.001 * randint( 1, 5000)
sleep(r)
print (proxy_list)
print (url)
def main():
t = Thread( target=XProcesStarter, args=(4, ) )
t.start()
if __name__ == '__main__':
main()
This code runs in python2 and python3.
The reason is that the target of a Thread object must be a callable (search for "callable" and "__call__" in python documentation for a complete explanation).
Edit The other way has been explained in other people's answers (see Tadhg McDonald-Jensen).
I think your issue is that in both places you're starting threads, you're actually calling the method you want to pass as the target to the thread. That runs its code in the main thread (and tries to start the new thread on the return value, if any, once its done).
Try:
procesor_thread = Thread(target=procesor.start_process) # no () after start_process
And:
t = Thread(target=vote_process.start_process) # no () here either

Background Process Locking up GUI Python

I have a background Process (using Process from multiprocessing) that is pushing objects to my GUI, however this background process keeps locking up the GUI and the changes being pushed are never being displayed. The objects are being put in to my queue, however the update method in my GUI isn't being called regularly. What can I do make the GUI update more regularly? My GUI is written in Tkinter.
My background process has a infinite loop within it because I always need to keep reading the USB port for more data, so basically my code looks like this:
TracerAccess.py
import usb
from types import *
import sys
from multiprocessing import Process, Queue
import time
__idVendor__ = 0xFFFF
__idProduct__ = 0xFFFF
END_POINT = 0x82
def __printHEXList__(list):
print ' '.join('%02x' % b for b in list)
def checkDeviceConnected():
dev = usb.core.find(idVendor=__idVendor__, idProduct=__idProduct__)
if dev is None:
return False
else:
return True
class LowLevelAccess():
def __init__(self):
self.rawIn = []
self.tracer = usb.core.find(idVendor=__idVendor__, idProduct=__idProduct__)
if self.tracer is None:
raise ValueError("Device not connected")
self.tracer.set_configuration()
def readUSB(self):
"""
This method reads the USB data from the simtracer.
"""
try:
tmp = self.tracer.read(END_POINT, 10000,None, 100000).tolist()
while(self.checkForEmptyData(tmp)):
tmp = self.tracer.read(END_POINT, 10000,None, 100000).tolist()
self.rawIn = tmp
except:
time.sleep(1)
self.readUSB()
def checkForEmptyData(self, raw):
if(len(raw) == 10 or raw[10] is 0x60 or len(raw) == 11):
return True
else:
return False
class DataAbstraction:
def __init__(self, queue):
self.queue = queue
self.lowLevel = LowLevelAccess()
def readInput(self):
while True:
self.lowLevel.readUSB()
raw = self.lowLevel.rawIn
self.queue.put(raw)
ui.py
from Tkinter import *
import time
import TracerAccess as io
from multiprocessing import Process, Queue
from Queue import Empty
from math import ceil
def findNumberOfLines(message):
lines = message.split("\n")
return len(lines)
class Application(Frame):
def addTextToRaw(self, text, changeColour=False, numberOfLines=0):
self.rawText.config(state=NORMAL)
if changeColour is True:
self.rawText.insert(END,text, 'oddLine')
else:
self.rawText.insert(END,text)
self.rawText.config(state=DISABLED)
def updateRaw(self, text):
if(self.numberOfData() % 2 is not 0):
self.addTextToRaw(text, True)
else:
self.addTextToRaw(text)
def startTrace(self):
self.dataAbstraction = io.DataAbstraction(self.queue)
self.splitProc = Process(target=self.dataAbstraction.readInput())
self.stopButton.config(state="normal")
self.startButton.config(state="disabled")
self.splitProc.start()
def pollQueue(self):
try:
data = self.queue.get(0)
self.dataReturned.append(data)
self.updateRaw(str(data).upper())
self.rawText.tag_config("oddLine", background="#F3F6FA")
except Empty:
pass
finally:
try:
if(self.splitProc.is_alive() is False):
self.stopButton.config(state="disabled")
self.startButton.config(state="normal")
except AttributeError:
pass
self.master.after(10, self.pollQueue)
def stopTrace(self):
self.splitProc.join()
self.stopButton.config(state="disabled")
self.startButton.config(state="normal")
def createWidgets(self):
self.startButton = Button(self)
self.startButton["text"] = "Start"
self.startButton["command"] = self.startTrace
self.startButton.grid(row = 0, column=0)
self.stopButton = Button(self)
self.stopButton["text"] = "Stop"
self.stopButton["command"] = self.stopTrace
self.stopButton.config(state="disabled")
self.stopButton.grid(row = 0, column=1)
self.rawText = Text(self, state=DISABLED, width=82)
self.rawText.grid(row=1, columnspan=4)
def __init__(self, master):
Frame.__init__(self, master)
self.queue = Queue()
self.master.after(10, self.pollQueue)
self.pack()
self.dataReturned = []
self.createWidgets()
def numberOfData(self):
return len(self.dataReturned)
Main.py
import ui as ui
if __name__ == "__main__":
root = Tk()
root.columnconfigure(0,weight=1)
app = ui.Application(root)
app.mainloop()
So the background thread never finishes, however when I end the process the UI starts to be displayed before closing. The problem could have appeared because of my design for the TracerAccess.py module as I developed this after moving straight form java and little to no design experience for python.
What multiprocess.Process does, internally, is really a fork(), which effectively duplicated your process. You can perhaps visualize it as:
/ ["background" process] -------------\
[main process] --+ +-- [main process]
\ [main process continued] -----------/
p.join() attempts to "join" the two processes back to one. This effectively means: waiting until the background process is finished. Here's the actual (full) code from the .join() function:
def join(self, timeout=None):
'''
Wait until child process terminates
'''
assert self._parent_pid == os.getpid(), 'can only join a child process'
assert self._popen is not None, 'can only join a started process'
res = self._popen.wait(timeout)
if res is not None:
_current_process._children.discard(self)
Note how self._popen.wait is called.
This is obviously not what you want.
What you probably want, in the context of TKinter, is use the tk event loop, for example like this (Python 3, but the concept also works on Python 2)
from multiprocessing import Process, Queue
import time, tkinter, queue, random, sys
class Test:
def __init__(self, root):
self.root = root
txt = tkinter.Text(root)
txt.pack()
self.q = Queue()
p = Process(target=self.bg)
p.start()
self.checkqueue()
print('__init__ done', end=' ')
def bg(self):
print('Starting bg loop', end=' ')
n = 42
while True:
# Burn some CPU cycles
(int(random.random() * 199999)) ** (int(random.random() * 1999999))
n += 1
self.q.put(n)
print('bg task finished', end=' ')
def checkqueue(self):
try:
print(self.q.get_nowait(), end=' ')
except queue.Empty:
print('Queue empty', end=' ')
sys.stdout.flush()
# Run myself again after 1 second
self.root.after(1000, self.checkqueue)
root = tkinter.Tk()
Test(root)
root.mainloop()
You don't call the .join(), and instead use the .after() method, which schedules a function to run after n microseconds (if you've ever used Javascript, then think setTimeout()) to read the queue.
Depending on the actual content of your bg() function, you may not event need multiprocesing at all, just scheduling a function with .after() may be enough.
Also see:
http://tkinter.unpythonic.net/wiki/UsingTheEventLoop

system call in python

i want to make a system call in my python code but the problem is that it breaks the sequence of my original code..
for ex.
def call_host(self):
self.builder.get_object("windowMain").show()
os.system('python Adder.py')
self.builder.get_object("window1").show()
in above pygtk code once Adder.py is called next line wont execute i want system to execute adder.py and come back to my original code...
thnx in advance
Here is my code for Adder.py
import sys
try:
import pygtk
pygtk.require("2.0")
except:
pass
try:
import gtk
except:
print("GTK Not Availible")
sys.exit(1)
class adder:
result = 0
def __init__( self, number1, number2 ):
return None
def giveResult( self,number1,number2 ):
self.result = int( number1 ) + int( number2 )
return str(self.result)
class adderGui:
def __init__( self ):
self.builder = gtk.Builder()
self.builder.add_from_file("Adder.glade")
dic = {
"on_buttonQuit_clicked" : self.quit,
"on_buttonAdd_clicked" : self.add,
"on_windowMain_destroy" : self.quit,
}
self.builder.connect_signals( dic )
def add(self, widget):
entry1 = self.builder.get_object ("entry1")
entry2 = self.builder.get_object ("entry2")
try:
thistime = adder( entry1.get_text(), entry2.get_text() )
except ValueError:
self.builder.get_object("hboxWarning").show()
self.builder.get_object("entryResult").set_text("ERROR")
return 0
self.builder.get_object("hboxWarning").show()
#self.builder.get_object("image1").hide()
self.builder.get_object("entryResult").set_text(
thistime.giveResult(entry1.get_text(), entry2.get_text())
)
def quit(self, widget):
sys.exit(0)
adderGui = adderGui()
gtk.main()
If you use subprocess.Popen, your main program will continue running without "blocking" until the subprocess terminates.
os.system will run a command in a subprocess and wait for it to finish before running. If you want to run it in parallel with the parent process, then you should look at the subprocess module -- in particular, you'll want to create a subprocess.Popen object.

Categories