pyautogui works from terminal but not tkinter button - python

Good evening,
I'm trying to learn some Python coding so I've written a short script that searches the screen for a button and then clicks the button a specified number of times. I have the code under 'RunScript' also saved as it's own file. When I run that script from terminal it works fine, but when I try to execute it by double clicking the icon, or from a button on a tkinter box using the below code it asks me for a number of loops and then does nothing. I'm working in a Lubuntu virtual machine.
Please can you tell me what I'm missing?
Thank you
#!/usr/bin/python3
from tkinter import *
import pyautogui
import easygui
PauseStatus = False
def RunScript():
LoopCount = easygui.enterbox('How Many Loops?')
for i in range (int(LoopCount)):
if PauseStatus:
easygui.msgbox(str(i) + ' loops completed\n' + str(int(LoopCount)-i) + 'loops remaining')
PauseStatus = False
while True:
ButtonPos = pyautogui.locateOnScreen('MyButton.png')
if ButtonPos is not None:
break
pyautogui.click(ButtonPos[0],ButtonPos[1],duration=0.25)
while True:
ButtonPos = pyautogui.locateOnScreen('MyButton.png')
if ButtonPos is not None:
break
easygui.msgbox(str(i+1) + ' loops completed')
root = Tk()
ControlPanel = Frame(root)
ControlPanel.pack()
startbutton = Button(ControlPanel, text="Start",command = RunScript)
startbutton.pack(side = LEFT)
stopbutton=Button(ControlPanel,text="Stop")
stopbutton.pack(side = LEFT)
root.mainloop()

You have error message similar to this
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python2.7/lib-tk/Tkinter.py", line 1539, in __call__
return self.func(*args)
File "<pyshell#3>", line 11, in RunScript
if PauseStatus:
UnboundLocalError: local variable 'PauseStatus' referenced before assignment
You have to use global in function RunScript
def RunScript():
global PauseStatus
or you have to declare variable inside function as local variable
def RunScript():
PauseStatus = False

Related

Getting "TypeError: insertstop() takes 0 positional arguments but 1 was given" when there are no arguments in my function calls

I'm very new to Python and I'm trying to put my first application together that takes in trip information and inserts it into a text box for export out to a document. It's gone pretty good until today when I tried to implement multiple ways of inserting text from an entrybox into a text block with tkinter.
I have an entry widget that inserts text into a text widget when a button is pressed. That's simple enough but I wanted to make it to where you could simply hit the enter key to do the same thing.
When I implement this function I get the error:
"Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Program Files\Spyder\pkgs\tkinter_init_.py", line 1892, in __ call __
return self.func(*args)
TypeError: insertstop() takes 0 positional arguments but 1 was given"
I've looked the error up and it seems like it would pop up if I put in arguments in my function call but I don't have any arguments in any of my function calls. Also it seems like maybe this error is related to a class or something? I haven't learned about classes yet and only have a basic idea of what they are. Do I need a class to do this?
Coincidentally I also added the argument(self) in my function and that made pressing enter work but it made my insert stop button quit working.
I'm sure I've missed something very basic but I just can't figure out what.
Thanks for any help!
import time
import os
import sys
from tkinter import *
# Creates the Tkinter form named "screen"
screen = Tk()
screen.geometry("550x645")
screen.title("Test")
# Initialize frames
menuframe = Frame(screen,
height=60,width=600,bg="gray",pady=5)
inputframe = Frame(screen,
height=300,width=600,pady=5)
outputframe = Frame(screen,
height=290,width=600,pady=5)
# Packs the frames so they will display
menuframe.pack()
inputframe.pack()
outputframe.pack()
#==STOPBOX==#
stopbox=Text(inputframe,yscrollcommand=1,height= 10,width=20,
padx=3,pady=3,relief=GROOVE,bg="gray79")
stopbox.place(x=345, y=90)
def insertstop():
global stop_vanconv
stop_vanconv=(stop_entry.get())
stopbox.insert(END, stop_vanconv + "\n")
stop_entry.delete("0","end")
stoplist_label = Label(inputframe,
text="Type stop locations and press" + '\n' +
"the Add Stop button to insert a new stop.")
stoplist_label.place(x=100, y=150)
stop_entry = Entry(inputframe,
textvariable = " ")
stop_entry.place(x=150, y=190)
addstopbutton = Button(inputframe,text="Add Stop",padx=20,pady=0,
activebackground="darkslategray4",command=insertstop)
addstopbutton.place(x=160, y=220)
stop_entry.bind('<Return>',insertstop)
screen.mainloop()

how to take values from user 2nd time on tkinter entry widget

Here I am writing a code to give a different "mode" option to the user, after pressing the mode button my entry widget pops up and takes two values from the user for further work.
once the user presses the "enter" button my widget will be destroyed.
Here is my code ,it successfully takes values once from the user but when the user gives values 2nd time it shows error.
import tkinter as tk
import time
root=tk.Tk()
root.geometry("600x600")
root.title("User Interface Monitor")
rpm=tk.StringVar()
tim=tk.StringVar()
def enter():
global rpm,tim
root.rpmLabel=tk.Label(root,text="enter rpm value:")
root.rpmLabel.grid(row=0)
root.timeLabel=tk.Label(root,text="enter time in sec")
root.timeLabel.grid(row=1)
root.e1 = tk.Entry(root, textvariable=rpm)
root.e1.grid(row=0, column=1)
root.e1.delete(0,"end")
root.e2 = tk.Entry(root, textvariable=tim)
root.e2.grid(row=1, column=1)
root.e2.delete(0, "end")
#rpm=rpm.get()
#tim=tim.get()
#return rpm,tim
def gett():
global rpm, tim
rpm = rpm.get()
tim = tim.get()
print(rpm)
print(tim)
root.rpmLabel.destroy()
root.e1.destroy()
root.timeLabel.destroy()
root.e2.destroy()
#e1.pack()
#e2.pack()
root.Button1=tk.Button(root,text="MODE1",command=enter)
root.Button1.pack()
root.Button1.place(x=200,y=200)
root.Button2=tk.Button(root,text="Enter",command=gett)#root.Button2.pack()
root.Button2.place(x=260,y=200)
root.mainloop()
Here is my error
C:/Users/RAM/PycharmProjects/timing/rpm.py
23
2
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\RAM\AppData\Local\Programs\Python\Python38\lib\tkinter\__init__.py", line 1883, in __call__
return self.func(*args)
File "C:/Users/RAM/PycharmProjects/timing/rpm.py", line 25, in gett
rpm = rpm.get()
AttributeError: 'str' object has no attribute 'get'
Process finished with exit code 0
I am new to Python, I couldn't find the solution for this error as tried with "delete" and "reset".
The problem is that rpm starts out as a StringVar and then you reset it to be a string in this line of code:
rpm = rpm.get()
Once that line of code runs, rpm is no longer a StringVar. A simple solution is to use a different name when fetching the value:
rpm_value = rpm.get()
Here, after carefully observing the error messages...
I changed my code line as Bryan suggested
rpm = rpm.get()
tim = tim.get()
to
rpm_value = rpm.get()
tim_value = tim.get()
then it works exactly as I want.
here is my output:
C:/Users/RAM/PycharmProjects/timing/rpm.py
rpm is : 740
time is : 12
want to test again?
enter values again
rpm is : 920
time is : 18
want to test again?
enter values again
Process finished with exit code 0

'bool' object has no attribute 'idKey' using while

I'm writing a graphic application that gives a word after I press a key in my electric piano using a database.
I'm using PyGame, Tkinter and Sqlite.
The application is pretty simple and is almost finished,
but I'm stuck with that error between my piano.py and the frontEnd.py.
The thing is that I want a Label that writes what was the last key I pressed and put it on a canvas.
I know the problem is related to the 'while True' and already changed it with 'while idKey < 176' but with this change I receive the "noneType" error.
This is the current code in my file piano.py
piano.py
import pygame
import pygame.midi
from pygame.locals import *
class backPiano():
def funcPiano(self):
self = backPiano
pygame.init()
pygame.fastevent.init()
event_get = pygame.fastevent.get
event_post = pygame.fastevent.post
pygame.midi.init()
input_id = pygame.midi.get_default_input_id()
i = pygame.midi.Input( input_id )
while True:
events = event_get()
if i.poll():
midi_events = i.read(10)
idKey = midi_events[0][0][0]
if idKey == 176:
return False
And the code in my frontEnd (only the function with the problem):
frontEnd.py
from tkinter import *
from tkinter import ttk, font
import multiprocessing
import time
import os
from database import dictionary, path
from piano import backPiano
class frontEnd(Frame):
def __init__(self, parent):
self.backPiano = backPiano()
def capturePiano(self):
backPiano.funcPiano(self)
superPiano = StringVar()
superPiano.set(backPiano.funcPiano(self).idKey)
labelPiano.configure(textvariable=superPiano)
self.parent.update()
canvasWidth = 500
canvasHeight = 500
w = Canvas(parent, width=canvasWidth, height=canvasHeight)
w.place(x=monitorWidth/2,y=monitorHeight/2, anchor=CENTER)
w.create_image(canvasWidth/2, canvasHeight/2, image=img, anchor=CENTER)
labelPiano = Label(parent)
labelPiano.place(x=monitorWidth/2,y=monitorHeight/2)
In the line 'superPiano.set(backPiano.funcPiano(self).idKey)' I tried:
"superPiano.set(backPiano.idKey)"
But because the variable is inside a function it can't be called with that.
The exact error I have is this:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\admin\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "C:\Users\admin\Desktop\python\frontEnd.py", line 202, in <lambda>
command=lambda : capturePiano(self)).place(x=monitorWidth/9,y=monitorHeight/2,anchor=CENTER)
File "C:\Users\admin\Desktop\python\frontEnd.py", line 187, in capturePiano
superPiano.set(backPiano.funcPiano(self).idKey)
AttributeError: 'bool' object has no attribute 'idKey'
I can't upload all the code, but the error is in the While True but removing it destroys all my code because I need the loop.
Thank you very much (and sorry if I made grammar mistakes).
As the error message says: funcPiano is returning a boolean (True) so when you try to take the idKey it fails, because booleans don't have that.

How can the variable be used by other functions in TkfileDialog?

I intended to write a GUI to import URLs data then process these data,
so I had 2 buttons. Below is my code.
from Tkinter import *
root=Tk()
root.title('Videos Episodes')
root.geometry('500x300')
def OpenFile(): # import URLs data from local machine
paths=tkFileDialog.askopenfilename()
return paths
def read_files(paths): #read data from the directory from OpenFile
with open(paths) as myfile:
return data
Button(root,text='Input',command=OpenFile).pack()
Button(root,text='Process',command=read_files).pack()
root.mainloop()
My problem is that when 'Process' button clicked, error happened:
Exception in Tkinter callback Traceback (most recent call last):
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1532, in __call__
return self.func(*args) TypeError: read_files() takes exactly 1 argument (0 given)
How can I fix the bug?
If you want to pass an argument (you didn't specify what), use a lambda:
Button(root,text='Process',command=lambda: read_files('whatever')).pack()
Perhaps, this is what you wanted to do (?):
Button(root,text='Process',command=lambda: read_files(OpenFile())).pack()
or alternatively, you meant to store the result of OpenFile (from clicking the other button) in a global variable, and pass that as argument of read_files...?

Python/Tkinter: Loop iterations not completing

In the following case, I am trying to print all output of temp2 script (which is run through subprocess) on to a textbox widget in realtime basis.
The problem I am facing is this, in temp2, for i <= 468, the script is working fine and to me it appears to be real time.
However, if i put i = 469 or above, the execution halts after many iterations without finishing.
So for example, for i = 469, the log file has entries for i = 469 to i = 3. There after the whole process halts.
Please note: the value i = 469 may not be the same for your machine. If i = 469 works fine for you, try some higher value.
Temp1.py is the main script.
#temp1.py
from Tkinter import *
import Tkinter as tk
import os
import ttk
os.system('echo OS ready')
os.system('chmod 755 *')
import subprocess
import sys
#Creating new Window to display output
t = Tk()
t.title('output Run Display')
t.geometry('800x1000-5+40')
t.state('normal')
little = Label(t, text="NRUNTEST OUTPUT LOG").grid(column = 0, row = 0)
log = Text(t, state='disabled', width=115, height=150, wrap='none')
log.grid(row = 1, column = 0)
test=subprocess.Popen('temp2',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
#stdout
while True:
line_out = test.stdout.readline()
line_er = test.stderr.readline()
if line_out == "" and line_er == "":
break
else:
log['state'] = 'normal'
log.insert('end', line_out)
log.insert('end', line_er)
log['state'] = 'disabled'
print line_out
print line_er
t.update()
t.mainloop()
And below is the script i am running through the subprocess.
#temp2 #csh script
set i = 469
while ($i > 0)
echo i is $i | tee -a log
set i = `expr "$i" - 1`
end
Your problem is that the call to test.stdout.readline is blocking - which means processing will stop there and only resume when there is a new line of data avalilable which is returned.
The same is true for test.stderr.readline of course.
I think the simplest way of dealing with what you want is having your subprocess write to a file on the filesystem, you open that file on your main process, and try to read from it inside a tkinter callback function called regularly with the .after tkinter method.
(witha file on filesystem you can use seek and tell methods to check if you are at the end of file)
Note that in the code you placed as example, your call to Tkinter.mainloop is only reached after the subprocess is exausted already.
A better yet solution would be to read the logs you want entirely in Python without relying to a shell script.
Tkinter.after is similar to javascript's settimeout - it is a method on a widget (say, your "t" object), and you pass it the number of miliseconds to wait, and the name of the function to be called -
like in
def verify_output():
# read subprocess output file and update the window if needed
...
# call self after 1 second
t.after(1000, verify_output)
# callreader callback for the first time:
t.after(10, verify_output)
Tkinter.mainloop()
import os
import ConfigParser
from Tkinter import *
import Tkinter as tk
import os
import ttk
os.system('echo OS ready')
os.system('chmod 755 *')
import subprocess
from subprocess import call
import sys
os.system('rm stdout')
#Creating new Window to display output
t = Tk()
t.title('output Run Display')
t.geometry('100x100')
t.state('normal')
little = Label(t, text="NRUNTEST OUTPUT LOG").grid(column = 0, row = 0)
log = Text(t, state='disabled', width=50, height=50, wrap='none')
log.grid(row = 1, column = 0,sticky=(N,W,E,S))
s = ttk.Scrollbar(t,orient=VERTICAL,command=log.yview)
s.grid(column=1,row=1,sticky=(N,S))
log.configure(yscrollcommand=s.set)
ttk.Sizegrip().grid(column=1, row=1, sticky=(S,E))
with open("stdout","wb") as out:
with open("stderr","wb") as err:
test=subprocess.Popen('tem',shell=True,stdout=out,stderr=err)
fout = open('stdout','r')
ferr = open('stderr','r')
def verify():
data_out = fout.readlines()
data_out = ''.join(data_out)
log['state'] = 'normal'
log.insert('end',data_out)
log['state'] = 'disabled'
#print data_out
t.after(1000,verify)
fout.close()
verify()
t.mainloop()
As jsbueno answer, you problem come from blocking call to readline. You may instead use a file event source to get notified when data are available (through createfilehandler tkinter method). See this previous answer for details.

Categories

Resources