issue with python Tkinter drop down menu - python

The following code is a program to append buttons onto an existing program so selection can occur on a more friendly interface rather than inside the code. I am trying to use drop down menu's but the setEthAnt1 function seems to have an error: TypeError: setEthAnt1() takes no arguments (1 given). I do not know what arg i am failing to pass in. Does anyone have any ideas?
from Tkinter import *
import ThreegroupsGraphics as three
def run():
three.main()
def setEthAnt1():
name = var.get()
print name
three.OneTo2Ant = name
print three.OneTo2Ant
root = Tk()
var = StringVar()
var.set("Group 1 Ethnic Antagonism")
OptionMenu(root, var, "1","2","3","4","5","6","7","8","9","10", command = setEthAnt1).pack()
butn = Button(root, text = 'run', command = run)
butn.pack()
root.mainloop()

When you specify a command for an OptionMenu, the value of the selected item will be sent into the command, which essentially makes your var.get() unneeded. See below:
from Tkinter import *
import ThreegroupsGraphics as three
def run():
three.main()
def setEthAnt1(name):
print name
three.OneTo2Ant = name
print three.OneTo2Ant
root = Tk()
var = StringVar()
var.set("Group 1 Ethnic Antagonism")
OptionMenu(root, var, "1","2","3","4","5","6","7","8","9","10", command = setEthAnt1).pack()
butn = Button(root, text = 'run', command = run)
butn.pack()
root.mainloop()
If you don't want setEthAnt1 to have any parameters and still use var.get(), you can make the command for the OptionMenu a lamda function like so:
OptionMenu(root, var, "1","2","3","4","5","6","7","8","9","10", command = lambda _: setEthAnt1).pack()

Related

Collecting variables from a GUI

I have a simple GUI where the user selects a file, which becomes a variable for my main code. Here, my variable output should be the database path (gui_db_path) which the user inputs. When I run this code, called gui_test.py, the variable is printable, and prints to the console.
class GUI:
def __init__(self, window):
# 'StringVar()' is used to get the instance of input field
self.input_db_text = StringVar()
window.title("HyPep 1.0")
window.geometry("700x700")
ttk.Label(window, text='Database sequences .csv:').grid(row=1,column=0)
ttk.Button(window, text = "Browse", command = lambda: self.set_path_database_field()).grid(row = 1,column=2, ipadx=5, ipady=0)
ttk.Entry(window, textvariable = self.input_db_text, width = 70).grid( row = 1, column = 1, ipadx=1, ipady=1)
ttk.Button(window, text = "Analyze").grid(row = 10,column=1, ipadx=5, ipady=15)
def set_path_database_field(self):
self.path_db = askopenfilename()
self.input_db_text.set(self.path_db)
def get_database_path(self):
""" Function provides the database full file path."""
return self.path_db
if __name__ == '__main__':
window = tkinter.Tk()
gui = GUI(window)
window.mainloop()
print(gui.path_db, '\n', gui.path_qu)
gui_db_path = gui.path_db
print(gui_db_path)
My issue is that I need to retrieve this variable for use in another file, user_input.py, but is no longer callable. My code for user_input.py is:
from gui_test import gui_db_path
print(gui_db_path)
Instead of printing to the console in this instance, I get:
ImportError: cannot import name 'gui_db_path' from 'gui_test'
I'm sure there is a simple solution that I am missing, can anyone shed some light?
...
Update: much closer, need to expand the solution:
How would I go about expanding this to retrieve multiple paths? I have been trying this:
gui_test.py:
...
def get_db_path():
window = tkinter.Tk()
gui = GUI(window)
window.mainloop()
return gui.get_database_path()
def get_qu_path():
window = tkinter.Tk()
gui = GUI(window)
window.mainloop()
return gui.get_query_path()
user_input.py:
from gui_test import get_db_path
from gui_test import get_qu_path
gui_db_path = get_db_path()
gui_qu_path = get_qu_path()
Note that the code inside if __name__ == '__main__' block will not be executed when the file is imported. You need to put those code inside a function instead and returns the path at the end of the function:
gui_test.py
...
def get_db_path():
window = tkinter.Tk()
gui = GUI(window)
window.mainloop()
return gui.get_database_path()
Then import this function inside user_input.py:
from gui_test import get_db_path
gui_db_path = get_db_path()
print(gui_db_path)

Trying to make the program run while waiting for input

This is the error: NameError: name 'data' is not defined
I need the 'data' variable to remain undefined while waiting for user input without the program crashing.
from tkinter import *
import datetime as Dt
root = Tk()
user_input = Entry(root)
user_input.pack()
def get_input():
global assign
data = user_input.get
Dt.time(data)
myButton = Button(root, text="Enter data",command=get_input)
myButton.pack()
root.mainloop()
Since your question is how to use data after it is defined, here is the easiest way how:
def get_input():
global assign
data = user_input.get() # also you need to call this
Dt.time(data)

Extra tk window showing in odd situation

This is my first question so be gentle!
Situation:
I have two scripts that each use tkinter to prompt for some info. They are separate because sometimes I'll need one, sometime I'll need both.
I also have a main script that imports the two tkinter scripts and calls them.
When I run each tkinter by itself, or from the main script without the other script imported, it works fine. When I import both scripts, a blank tkinter (title = "tk") window pops up.
Questions:
1. What is causing this?
2. How can I prevent that stupid window from popping up?
3. Is there an automated way to see that extra window and kill it when it does show?
What I've done:
Googled my hiney off
Renamed Tk import so each script has its own instance
Banged my head on the desk
Code:
uidpassform (first script that directly uses tkinter)
from tkinter import Tk as lf2Tk
from tkinter import Label, StringVar, Entry, Button
o_window = lf2Tk()
username = StringVar()
password = StringVar()
def close_dialog():
o_window.destroy()
def uidpass form():
#Return the value of the selected option
o_window.title('Oracle Login Credentials')
#username label and text entry box
Label(o_window, text="User Name").grid(row=2, column=0,padx = 5,pady = 20)
Entry(o_window, textvariable=username).grid(row=2, column=2, padx=20)
#password label and password entry box
Label(o_window,text="Password").grid(row=3, column=0,padx = 5)
Entry(o_window, textvariable=password, show='*').grid(row=3, column=2,padx = 20)
#login button
Button(o_window, text="Connect", command=close_dialog).grid(row=4, column=3,columnspan=2, padx = 20)
Label(o_window, text="").grid(row=5)
o_window.mainloop()
print (username.get())
print (password.get())
return [username.get(), password.get()]
if __name__ == "__main__":
uidpassform()
radiobutton form (second tkinter form)
from tkinter import Tk as rbTK
from tkinter import Radiobutton, Button, Label, IntVar, LEFT, W
rb_window = rbTK()
v = IntVar()
def validate():
#Display the value of the selected option for debugging purposes
value = v.get()
return (value)
def close_dialog():
#Check to see if the Radiobutton has a value and if so, close the form
value = v.get()
if value == 0:
value = v.get()
else:
rb_window.destroy()
def fnradiobutton():
#Return the value of the selected option
rb_window.title("Connection")
Label(rb_window, text="Choose a Data Connection:", justify=LEFT, padx=20).grid(row=0, sticky=W)
Radiobutton(rb_window, text="Production", variable=v, value=1, command=validate).grid(row=1, padx=20, sticky=W)
Radiobutton(rb_window, text="Test", variable=v, value=2, command=validate).grid(row=2, padx=20, sticky=W)
Button(rb_window, text="Done", command=close_dialog).grid(row=3, column=2, padx=10)
Label(rb_window, text="").grid(row=4)
#print(str(V.get()) + " from fnradiobutton")
rb_window.mainloop()
return v.get()
if __name__ == "__main__":
fnradiobutton()
Main script (calls the two tkinter scripts)
import cx_Oracle
import lf2 as lf
import time
import radiobutton as rb
import pyodbc
def oracle_connection():
#Get Oracle UserID and password
uidpass_list = lf.uidpassform()
#Create the connection
try:
oracle_conn = cx_Oracle.connect(uidpass_list[0], uidpass_list[1], 'robanner', encoding='UTF-8')
except:
return oracle_conn
def dbconnect(switch):
#Choose the proper connection, based on the radiobutton form
if switch == 1:
connection = pyodbc.connect('DSN=PCard_Production;Trusted_Connection=yes;')
else:
connection = pyodbc.connect('DSN=PCardTest;Trusted_Connection=yes;')
return connection
def run_script():
start = time.time()
oracle_conn = oracle_connection()
swich = rb.fnradiobutton()
conn = dbconnect(swich)
if __name__ =='__main__':
# This is the summary spot
run_script()
Try putting code for creating Root Window into functions and have them return variables. Then you have to modify your other functions to use the variables.
def initialize():
o_window = lf2Tk()
username = StringVar()
password = StringVar()
return o_window, username, password
def close_dialog(o_window):
o_window.destroy()
...
def initialize():
rb_window = rbTK()
v = IntVar()
return rb_window, v
def validate(v):
#Display the value of the selected option for debugging purposes
value = v.get()
return (value)
...
Then in your main script:
def oracle_connection():
#Get Oracle UserID and password
o_window, username, password = lf.initialize()
uidpass_list = lf.uidpassform(o_window, username, password)
#Create the connection
try:
oracle_conn = cx_Oracle.connect(uidpass_list[0], uidpass_list[1], 'robanner', encoding='UTF-8')
except:
return oracle_conn
...

Allow user to change default text in tkinter entry widget.

I'm writing a python script that requires the user to enter the name of a folder. For most cases, the default will suffice, but I want an entry box to appear that allows the user to over-ride the default. Here's what I have:
from Tkinter import *
import time
def main():
#some stuff
def getFolderName():
master = Tk()
folderName = Entry(master)
folderName.pack()
folderName.insert(END, 'dat' + time.strftime('%m%d%Y'))
folderName.focus_set()
createDirectoryName = folderName.get()
def callback():
global createDirectoryName
createDirectoryName = folderName.get()
return
b = Button(master, text="OK and Close", width=10, command=callback)
b.pack()
mainloop()
return createDirectoryName
getFolderName()
#other stuff happens....
return
if __name__ == '__main__':
main()
I know next to nothing about tkInter and have 2 questions.
Is over-riding the default entry using global createDirectoryName within the callback function the best way to do this?
How can I make the button close the window when you press it.
I've tried
def callback():
global createDirectoryName
createDirectoryName = folderName.get()
master.destroy
but that simply destroys the window upon running the script.
I don't know how experienced are you in Tkinter, but I suggest you use classes.
try:
from tkinter import * #3.x
except:
from Tkinter import * #2.x
class anynamehere(Tk): #you can make the class inherit from Tk directly,
def __init__(self): #__init__ is a special methoed that gets called anytime the class does
Tk.__init__(self) #it has to be called __init__
#further code here e.g.
self.frame = Frame()
self.frame.pack()
self.makeUI()
self.number = 0 # this will work in the class anywhere so you don't need global all the time
def makeUI(self):
#code to make the UI
self.number = 1 # no need for global
#answer to question No.2
Button(frame, command = self.destroy).pack()
anyname = anynamehere() #remember it alredy has Tk
anyname.mainloop()
Also why do you want to override the deafult Entry behavior ?
The solution would be to make another button and bind a command to it like this
self.enteredtext = StringVar()
self.entry = Entry(frame, textvariable = self.enteredtext)
self.entry.pack()
self.button = Button(frame, text = "Submit", command = self.getfolder, #someother options, check tkitner documentation for full list)
self.button.pack()
def getfolder(self): #make the UI in one method, command in other I suggest
text = self.enteredtext.get()
#text now has whats been entered to the entry, do what you need to with it

Clear text from tkinter entry widget

I am using Tkinter entry widgets to allow users to input text to a GUI. The entry widgets have default text which I would like to clear with a single button press. I have the following code:
from Tkinter import *
def delete_entries(fields):
for field in fields:
field.delete(0,END)
def UserInput(status,name):
optionFrame = Frame(root)
optionLabel = Label(optionFrame)
optionLabel["text"] = name
optionLabel.pack(side=LEFT)
var = StringVar(root)
var.set(status)
w = Entry(optionFrame, textvariable= var)
w.pack(side = LEFT)
optionFrame.pack()
if __name__ == '__main__':
root = Tk()
fields = 'ExperimentNumber', 'OutputFileName', 'npts1', 'block1'
ExperimentNumber = UserInput("1", "Experiment number")
OutputFileName = UserInput("output.txt", "Output file name")
npts1 = UserInput("1000", "Number of points")
block1 = UserInput("8", "Block size")
Delete_button = Button(root, text = 'Clear all', command = delete_entries(fields))
Delete_button.pack()
I have tried creating fields with the list of variables that I want to delete (as above) and iterating over this in the function delete_entries(), however this returns an error because the entries in fields are strings. I have tried replacing fields with fields = ExperimentNumber for example, but this returns an error because ExperimentNumber hasn't yet been defined. Finally I tried putting ExperimentNumber within the delete function i.e.
def delete_entries():
ExperimentNumber.delete(0,End)
but this doesn't work because ExperimentNumber has the attribute NoneType (I don't understand why this is, because the delete_entries() function isn't called until after the ExperimentNumber Entry widget is created via the function UserInput). How can I go about deleting all the text in the Entry widgets? I have about 20 of these in my actual code and would like the user to be able to clear all the fields with one button press.
You are on the right track but you missed two little things. I added those two in your code and tried to explain with comments.
from Tkinter import *
def delete_entries():
for field in fields:
field.delete(0,END)
def UserInput(status,name):
optionFrame = Frame(root)
optionLabel = Label(optionFrame)
optionLabel["text"] = name
optionLabel.pack(side=LEFT)
var = StringVar(root)
var.set(status)
w = Entry(optionFrame, textvariable= var)
w.pack(side = LEFT)
optionFrame.pack()
return w
#this return is crucial because if you don't return your widget's identity,
#you can not use them in another function
if __name__ == '__main__':
root = Tk()
ExperimentNumber = UserInput("1", "Experiment number")
OutputFileName = UserInput("output.txt", "Output file name")
npts1 = UserInput("1000", "Number of points")
block1 = UserInput("8", "Block size")
#you are saying it does not work because of they are strings.
#then don't assign strings to fields. assign variables.
fields = ExperimentNumber, OutputFileName, npts1, block1
#since fields is defined in global scope, you don't need to use it as parameter
Delete_button = Button(root, text = 'Clear all', command = delete_entries)
Delete_button.pack()
root.mainloop()

Categories

Resources