tkinter Radiobutton string selector - python-3.x

Some time ago I wrote a Python3 program to allow me to connect to one of a number of computers.
#! /usr/bin/env python3
from tkinter import *
import os
Computers = [
'RaspberryPi3',
'PiUbuntu',
'Thylacoleo']
def sel():
cmd = "open afp://" + Computers[var.get()] + ".local"
os.system( cmd )
root = Tk() # create tkinter object
root.title("Connect to Computer") # give the window a title...
root.minsize(250, 100)
var = IntVar()
button=0
for cc in Computers:
R1 = Radiobutton(root, text=cc, variable=var, value=button, command=sel)
R1.pack( anchor = W )
button += 1
root.mainloop()
This works, and I though it would be simple to adapt this, using a Dictionary to mount nfs shares.
Unfortunately I can't seem to get it to work.
My previous effort returned an integer from each button. but this would not work with a Dictionary, and I wanted to get a string value returned.
Computers = {
'RaspberryPi3': 'Pi3',
'PiUbuntu': 'PiUbuntu',
'Ubuntu-T': 'Thylaco'
}
def sel():
print("selection", tvar)
selection = "You selected the option " + tvar
root = Tk() # create tkinter object
root.title("Connect to Computer") # give the window a title...
root.minsize(250, 100)
# var = IntVar()
# tvar = StringVar()
tvar = str()
button=0
for cc in list(Computers.keys()):
# R1 = Radiobutton(root, text=cc, variable=var, value=button, command=sel)
R1 = Radiobutton(root, text=cc, variable=tvar, value=cc, command=sel)
# R1 = Radiobutton(root, text=cc, textvariable=tvar, command=sel)
R1.pack( anchor = W )
root.mainloop()
I know I could make a list, and use an integer, but I am trying to understand how to get a string returned. I have read the documentation, and looked at lots of links, but not discovered any relevant examples.
tvar = StringVar() results in an error:-
TypeError: must be str, not StringVar

I susspect you have problem in line (you didn't show full Traceback)
selection = "You selected the option " + tvar
You have to use tvar.get() to get value/string from tvar
selection = "You selected the option " + tvar.get()

Related

Missing Argument / issues opening GUI program on macOS Big Sur

This is my first GUI program and I am having some major issues. I really need some help. First, I cannot get the program to open on my computer (mac). When running in Idle IDE I get this error message: import Tkinter
ModuleNotFoundError: No module named 'Tkinter'.
I have 3.9 installed which I thought had a GUI interface.
When debugging in VS Code i get this error message # line 44:
Exception has occurred: TypeError
init() takes at least 4 arguments (3 given)
I think I have 4
I'm not sure where to begin with these issues. From my research it appears that there is an issue running GUI programs on macs updated higher then 11.1.
Code is below
# Create a Tkinter GUI program that converts Celsius Temp to Fahrenheit
# F == Fahrenheit
# C == Celsius
# Tkinter imported
import Tkinter
# Global variable used
temp_val = 'Celsius'
#Set value for drop down menu
def store_temp (set_temp):
global temp_val
temp_Val = set_temp
class TemperatureConverter:
def __init__(self):
# create main window
self.main_window = Tkinter.Tk()
# create a title for window
self.main_window.title('Temperature Converter')
# create three frames
self.top_frame = Tkinter.Frame()
self.option_frame = Tkinter.Frame()
self.mid_frame = Tkinter.Frame()
self.bottom_frame = Tkinter.Frame()
#create widget for top frame
self.prompt_label = Tkinter.Label(self.top_frame, text= 'Enter a temperature in Celsius: ')
#pack top frame
self.prompt_label.pack(side='left')
# create str variable obj to hold empty string variable
self.inputNumber = Tkinter.StringVar()
self.var = Tkinter.StringVar()
# create widget for option drop down menu
self.entry = Tkinter.Entry(self.option_frame, textvariable=self.inputNumber )
self.dropDownList = ['Celsius','Fahrenheit']
self.drop_down = Tkinter.OptionMenu(self.option_frame, value=self.var , values=self.dropDownList, command=store_temp)
self.var.set(dropDownList[0])
# option widgets packed
self.entry.pack(side='right')
self.dropDownList.pack(side='left')
#create widget for middle frame
self.result_label = Tkinter.Label(self.mid_frame)
# create widgets for bottom frame
self.call_convert = (call_convert , result_label, inputNumber)
self.convert_button = Tkinter.Button(self.bottom_frame, text='Convert', command=self.call_convert)
self.quit_button= Tkinter.Button(self.bottom_frame, text= 'Quit', command= self.main_window.destroy)
#pack the buttons
self.convert_button.pack(side='left')
self.quit_button.pack(side='left')
#pack the frames
self.top_frame.pack()
self.option_frame.pack()
self.mid_frame.pack()
self.bottom_frame.pack()
#Enter the tkinter main loop
Tkinter.mainloop()
# convert method is callback fucntion for convert button
def call_convert(self):
if temp_Val == 'Celsius':
f = float((float(temp)* 9/5)+32)
self.result_label.config(text='The temperature in Fahrenhiet is:')
if temp_Val == 'Fahrenheit':
c = float((float(temp)-32) * 5 / 9)
self.result_label.config(text='The temperature in Celsius is:')
if __name__ == '__main__':
temp_converter = TemperatureConverter()
There were a lot of bugs in your code. I fixed all of them (I think). I had to guess where you wanted to put the label with the results. I also had to fix all of the indentations. This is the working code:
# Create a tkinter GUI program that converts Celsius Temp to Fahrenheit
# F == Fahrenheit
# C == Celsius
# tkinter imported
import tkinter
class TemperatureConverter:
def __init__(self):
# create main window
self.main_window = tkinter.Tk()
# create a title for window
self.main_window.title("Temperature Converter")
# create three frames
self.top_frame = tkinter.Frame(self.main_window)
self.option_frame = tkinter.Frame(self.main_window)
self.mid_frame = tkinter.Frame(self.main_window)
self.bottom_frame = tkinter.Frame(self.main_window)
# create widget for top frame
self.prompt_label = tkinter.Label(self.top_frame, text="Enter a temperature in Celsius:")
# pack top frame
self.prompt_label.pack(side="left")
# create str variable obj to hold empty string variable
self.inputNumber = tkinter.StringVar(self.main_window)
self.var = tkinter.StringVar()
# create widget for option drop down menu
self.entry = tkinter.Entry(self.option_frame, textvariable=self.inputNumber)
self.dropDownList = ["Celsius", "Fahrenheit"]
self.drop_down = tkinter.OptionMenu(self.option_frame, self.var, *self.dropDownList)
self.var.set(self.dropDownList[0])
# option widgets packed
self.entry.pack(side="right")
self.drop_down.pack(side="left")
# create widget for middle frame
self.result_label = tkinter.Label(self.mid_frame)
# create widgets for bottom frame
self.convert_button = tkinter.Button(self.bottom_frame, text="Convert", command=self.call_convert)
self.quit_button= tkinter.Button(self.bottom_frame, text= "Quit", command=self.main_window.destroy)
# pack the buttons
self.convert_button.pack(side="left")
self.quit_button.pack(side="left")
# pack the frames
self.top_frame.pack()
self.option_frame.pack()
self.mid_frame.pack()
self.bottom_frame.pack()
# It is better to call `<tkinter.Tk>.mainloop()`
self.main_window.mainloop()
# convert method is callback fucntion for convert button
def call_convert(self):
if self.var.get() == "Celsius":
f = float((float(self.entry.get())* 9/5)+32)
self.result_label.config(text="The temperature in Fahrenhiet is: "+str(f))
if self.var.get() == "Fahrenheit":
c = float((float(self.entry.get())-32) * 5 / 9)
self.result_label.config(text="The temperature in Celsius is: "+str(c))
self.result_label.pack(side="bottom")
if __name__ == "__main__":
temp_converter = TemperatureConverter()
Look at what I did for the OptionMenu and look at how I fixed you call_convert function. If you have any specific questions, tell me and I will try to answer them.
By the way I don't think any of the errors you were getting were caoused by your OS. Also I suggest that next time you use import tkinter as tk as it will make it way easier to write code.

How do I get the value from an option in tkinter after it has passed through a function?

I'm using tkinter to create an option menu for a user to interact with, when the selection has been made it will pass through a function to return an integer based on the input. I want to be able to return the integer back to a variable outside of the function so it can be received by another file. My problem is that python will keep returning the button as the command has not yet been processed.
from tkinter import *
Final = [] ##List containing options
master = Tk()
variable = StringVar(master)
variable.set(Final[0]) # default value
w = OptionMenu(master, variable, *Final)
w.pack()
def ok():
global choice
choice = variable.get()
global x
x = 0
for i in Final:
if str(i) == str(choice):
break
x += 1
button = Button(master, text="Choose", command=ok)
button.pack()
values = x

Creating tkinter gui.How to display information when ID number provided

I am working on creating a gui and could use some help. There are three programs that build off of each other. MY imput will be two CSV files, Examples below:
items4.csv
12345,Italy,100
13579,China,50
ETC.
transactions4.csv
12345,15
13579,10
12345,20
13579,-10
What I want it to do is upon running the gui will open and the window will ask for the "Item ID" Upon entering an id, say 12345, it will open up a new window that displays the following: getID, getName, getAvailableStart, and getAvailableEnd, all of these definitions are were created by the travelclass program (found below) when the program travelToolbox reads the two CSV files.
Note: Both the travelClass and travelToolbox programs are working fine. IT is only travelSystem that needs changing at this point
What I've done:
At this point I have managed to get the travelSystems presents the initial GUI however it doesn't matter what I enter in the entry box because when I hit the open button the next gui opens up but it only shows the information found in the first line of items4.csv. I think my main issue is line 34 or may be line 16. Let me know if any other information is needed.
I could really appreciate some help. Thank you in advance.
travelsystem
from travelToolbox import readItems, readTransactions
from tkinter import *
from tkinter import font
import tkinter as tk
class myApp :
def __init__(self, top, itemRecords) :
self.root = top
# Create a container Frame at the bottom
self.bframe = Frame(self.root)
self.bframe.pack(side=BOTTOM) # Create Label
self.xlabel = Label(self.root, text="Item ID")
self.xlabel.pack(side=LEFT)
self.xentry = Entry(self.root, bd=5) # Create Entry box
self.xentry.pack(side=LEFT)
self.xentry.focus_set() # Set focus in Entry box
self.xopen = Button(self.root, text="Open", command=self.showStockItem) # Create open Button
self.xopen.pack(side=LEFT)
self.xquit = Button(self.bframe, text="Quit", command=self.quitit ) # Create quit Button
#self.root instead of bframe
self.xquit.pack(side=BOTTOM)
def showStockItem(self):
tbl = Toplevel() # Create Toplevel window
hdr = font.Font(underline=1, weight="bold") # Create header font
tid = Label(tbl, text="ID", font=hdr) # Create 4 column headers in grid
tid.grid(row=0, column=0)
tlast = Label(tbl, text="Name", font=hdr)
tlast.grid(row=1, column=0)
tfirst = Label(tbl, text="Start", font=hdr)
tfirst.grid(row=2, column=0)
tlabel = Label(tbl, text="End", font=hdr)
tlabel.grid(row=3, column=0)
for rec in itemRecords.values() :
tid = Label(tbl, text= rec.getID()) # Create 4 column headers in grid
tid.grid(row=0, column=1)
tlast = Label(tbl, text= rec.getName())
tlast.grid(row=1, column=1)
tfirst = Label(tbl, text= rec.getAvailableStart())
tfirst.grid(row=2, column=1)
tlabel = Label(tbl, text= rec.getAvailableEnd())
tlabel.grid(row=3, column=1)
#self.xquit.pack(side=BOTTOM) #May not need this.
return
def quitit(self):
self.root.destroy()
return
itemsFileName = "items4.csv"
transactionsFileName = "transactions4.csv"
# itemRecords is a dictionary of stockItem records indexed by item ID
itemRecords = {}
# Read the items from itemsFileName into itemRecords
readItems(itemsFileName, itemRecords)
# Read the transactions from transactionsFileName into itemRecords
readTransactions(transactionsFileName, itemRecords)
top = tk.Tk()
#top = Travel()
app = myApp(top, itemRecords)
top.mainloop()
Other files:
travelToolbox
import csv
from travelClass import travelItem
def readItems(itemsFileName, itemRecords) :
# readItems reads items from itemsFileName into the itemRecords dictionary
# Open itemsFileName and create a CSV file reader
itemsFile = open(itemsFileName, 'r')
itemsReader = csv.reader(itemsFile)
# Process each row of the items file
for row in itemsReader :
# Get the values for the record
(iid, iname, icount) = row
iid = str(iid)
iname = str(iname)
icount = int(icount)
# Check if this ID is not yet in itemRecords
if (not(iid in itemRecords)) :
# Create a travelItem object and add it to itemRecords
itemRecord = travelItem(iid, iname, icount)
itemRecords[iid] = itemRecord
def readTransactions(transactionsFileName, itemRecords) :
# readTransactions reads transactions from transactionsFileName into the itemRecords dictionary
transactionFile = open(transactionsFileName, 'r')
transactionReader = csv.reader(transactionFile)
for row in transactionReader :
# Get the values for the record
(iid, itransaction) = row
iid = str(iid)
itransaction = int(itransaction)
itemRecords[iid].appendTransaction(itransaction)
#for key, value in itemRecords.items() :
transactionFile.close()
travelClass
class travelItem :
Class travelItem :
def __init__(self, itemID, itemName, itemCount) :
# Constructor to create inventoryItem CORRECT
self.id = itemID
self.name = itemName
self.AvailableStart = itemCount
self.transactions = []
def getID(self) :
# getID returns the tour ID CORRECT
return(self.id)
def getName(self) :
# getName returns the tour name CORRECT
return (self.name)
def setName(self, newName) :
# setName sets the tour name
self.name = newName
def getAvailableStart(self) :
# returns the starting availability
return (self.AvailableStart)
def appendTransaction(self, num) :
# appendTransaction appends a transaction to the transactions list
self.transactions.append(num)
def getTransactions(self) :
# getTransactions returns the list of transactions
return (self.transactions)
def getReservations(self) :
# returns the total of reservation transactions
total = 0
for num in self.transactions :
if ((num) > 0):
total += (num)
self.Reservations = total
return(self.Reservations)
def getCancellations(self) :
# returns the total of cancellation transactions
total = 0
for num in self.transactions :
if (num <= 0):
total += (num)
return(total)
def getAvailableEnd(self) :
# returns the ending availability, which is availableStart minus transactions
self.AvailableEnd = ((self.AvailableStart) - (self.Reservations) - (self.getCancellations()))
return(self.AvailableEnd)

Python Variable in tkinter window

I am building a device that counts how many parts are made off a machine and then turns the machine off at a specific number. I am using an Arduino for all the I/O work and then importing the serial data into Python as variable partCount. I would like to create a simple GUI in tkinter to show the number of parts that have been made and the total number needed. The problem is that I keep getting an error on the label lines that include a variable instead of just a text. I've done a lot of research on it, but I just can't get it for some reason. Any advice would be appreciated.
import serial
import csv
import datetime
import tkinter
#Part Variables
partNumber = "A-33693" #Part Number
stockupTotal = 10
arduinoSerialData = serial.Serial('com3',9600) #Serial Variable
now = datetime.datetime.now()
#GUI
window = tkinter.Tk()
window.title("Troy Screw Products")
titleLabel = tkinter.Label(window, text="Davenport Machine Control")
partNumberLabel = tkinter.Label(window, text="Part #:")
stockUpTotalLabel = tkinter.Label(window, text="Stockup Total:")
partCountLabel = tkinter.Label(window, text="Current Part Count:")
partNumberInfo = tkinter.Label(window, partNumber)
stockUpTotalInfo = tkinter.Label(window, stockupTotal)
partCountInfo = tkinter.Label(window, partCount)
titleLabel.pack()
partNumberLabel.pack()
partNumberInfo.pack()
stockUpTotalLabel.pack()
stockUpTotalInfo.pack()
partCountLabel.pack()
partCountInfo.pack()
window.mainloop()
#Write to CSV File
def writeCsv():
with open("machineRunData.csv", "a") as machineData:
machineDataWriter = csv.writer(machineData)
machineDataWriter.writerow([partNumber, "Stockup Complete",now.strftime("%Y-%m-%d %H:%M")])
machineData.close()
#Serial Import
while (1==1):
if (arduinoSerialData.inWaiting()>0):
partCount = arduinoSerialData.readline()
partCount = int(partCount)
if partCount == 999999:
writeCsv()
print(partCount)
There are several options you can give to a Label widget, as you can see here. You should specify all parameters after the first by name:
partNumberInfo = tkinter.Label(window, text=PartNumber)
To use Python variables in Tkinter you need to special Tk objects, of which there are four: BooleanVar, DoubleVar, IntVar, and StringVar. See this answer for a good example.
So after a ton of research over the last week, I found a solution. The problem was that the program would run the GUI, but not run the code for the serial import until the GUI window was closed. I needed a way to get both the GUI running and updated and get the serial data importing at the same time. I resolved this by creating a thread for both operations. There's probably an easier way to do this, but this what I came up with. The code is below for anyone having a similar problem.
import serial
import time
import threading
from tkinter import *
#Part Variables
partNumber = "A-33693" #Part Number
stockupTotal = 10
partCount = 0
def countingModule():
global partCount
while (1==1):
time.sleep(2)
partCount += 1
print(partCount)
def gui():
global partCount
root = Tk()
pc = IntVar()
pc.set(partCount)
titleLabel = Label(root, text="Machine Control")
partNumberLabel = Label(root, text="Part #:")
stockUpTotalLabel = Label(root, text="Stockup Total:")
partCountLabel = Label(root, text="Current Part Count:")
partNumberInfo = Label(root, text=partNumber)
stockUpTotalInfo = Label(root, text=stockupTotal)
partCountInfo = Label(root, textvariable=pc)
titleLabel.pack()
partNumberLabel.pack()
partNumberInfo.pack()
stockUpTotalLabel.pack()
stockUpTotalInfo.pack()
partCountLabel.pack()
partCountInfo.pack()
def updateCount():
pc.set(partCount)
root.after(1, updateCount)
root.after(1, updateCount)
root.mainloop()
op1 = threading.Thread(target = countingModule)
op2 = threading.Thread(target = gui)
op1.start()
op2.start()

tkinter need to click in shell to get gui fields to update

I have a tkinter gui with Python 3.4.2 in which there are various buttons, a user entry field and a text field. Everything works except that I appear to have to click in the Python shell (IDLE) and out of the gui to get fields to update in response to button presses. The updates are immediate when I click on the shell. I have copied this tkintergui from http://ubuntuforums.org/showthread.php?t=1156637 which gives the same problem on my Mac. Immediate update if IDLE shell clicked or very slow update in the GUI
#!/usr/bin/python
from tkinter import *
from tkinter.filedialog import *
class SimpleEdApp:
def __init__(self, parent=Tk()):
self.mainWindow = (parent)
self.mainWindow.title("Simple Editor")
self.mainWindow.resizable(0, 0)
self.make_mnu()
self.make_txt()
def make_txt(self):
self.text = Text(self.mainWindow, width = 80, height = 40, background = 'white')
self.scrollY = Scrollbar(self.mainWindow, orient = VERTICAL, command = self.text.yview, troughcolor = 'white')
self.text["yscrollcommand"] = self.scrollY.set
self.scrollY.pack(side = RIGHT, fill = Y)
self.text.pack(expand = TRUE, fill = BOTH)
def make_mnu(self):
self.menubar = Menu(self.mainWindow)
self.filemenu = Menu(self.menubar, tearoff = 0)
self.filemenu.add_command(label = "Open", command = self.file_open)
self.filemenu.add_command(label = "Save as...", command = self.file_save)
self.filemenu.add_separator()
self.filemenu.add_command(label = "Exit", command = self.mainWindow.destroy)
self.menubar.add_cascade(label = "File", menu = self.filemenu)
self.mainWindow.config(menu = self.menubar)
def file_open(self):
filename =askopenfilename(filetypes=[("pythonfiles","*.py"),("tclfiles","*.tcl"),("allfiles","*")])
f = open(filename, 'r')
data = f.read()
f.close()
self.text.delete(1.0, END)
self.text.insert(1.0, data)
def file_save(self):
filename =asksaveasfilename(filetypes=[("pythonfiles","*.py"),("tclfiles","*.tcl"),("allfiles","*")])
f = open(filename, 'w')
data = self.text.get(1.0, END)
f.write(data)
f.close()
app = SimpleEdApp()
app.mainWindow.mainloop()
Grateful for correct implementation
There is nothing wrong with your code. This looks to be a bug in IDLE.
In the comments you asked how to run the program outside of IDLE. To do that, open up a prompt and type the command python myfile.py, where myfile.py is the name of your python file (assuming "python" is in your PATH).
*note: depending on what is installed in your system, you may need to use python3 rather than python.

Resources