This question already has answers here:
How to select only one Radiobutton in tkinter
(3 answers)
Closed 6 months ago.
I am trying to learn the basics of the tkinter module. I made this program where I have some questions and each question has some options. My options are displayed using radio button selection. I want to select one choice at a time for each question independently. Currently when I select the 1st option then the 1st option of every question is selected but I don't want the selection for other than the one I am on.
My second question is once the selection [is made] I want to use the selection results and compare them with the answer keys to see how many answers are correct. How do I store the user's answer for each question?
Output result:
Edit:
Sorry for not posting my code as well.
Here is my python file which I am working on.
from tkinter import *
guessOptions =[]
def display():
global guessOptions
if x.get() == 0:
guessOptions.append("A")
elif x.get() == 1:
guessOptions.append("B")
elif x.get() == 2:
guessOptions.append("C")
else:
guessOptions.append("D")
window = Tk()
answers = ['A', 'B', 'C', 'D']
questions = ["Who invented Bulb? ",
"Which is not passive component? ",
"Which is not related to computer? ",
"Opertor used for and operation? "]
options = [['A. Thomas Edison', 'B. Nikola Tesla', 'C. Albert
Einstien', 'D. Michael Faraday'],
['A. Inductor', 'B. op-amp', 'C. Capacitor', 'D.
Resistor'],
['A. RAM', 'B. SSD', 'C. Heat', 'D. Keyboard'],
['!', '~', '||', '&']]
x = IntVar()
for i in range(len(questions)):
label = Label(window,
text=questions[i],
font=('Arial', 15, 'bold'))
label.pack(anchor=W)
for j in range(len(options)):
checkButton = Radiobutton(window,
text=options[i][j],
variable=x,
value=[j],
padx=10,
font=('Arial', 10),
command=display
)
checkButton.pack(anchor=W)
window.mainloop()
Each group of answers to a question needs its own IntVar and you'll need to add a Button to trigger the answer checking process. I've done most of that in the code below, except that check_answers() function doesn't really do anything meaningful since you haven't specified exactly what would be involved (or even what the correct choices are).
from tkinter import *
guessOptions =[]
def display(x):
global guessOptions
if x.get() == 0:
guessOptions.append("A")
elif x.get() == 1:
guessOptions.append("B")
elif x.get() == 2:
guessOptions.append("C")
else:
guessOptions.append("D")
def check_answers():
print(f'{guessOptions=}')
window = Tk()
answers = ['A', 'B', 'C', 'D']
questions = ["Who invented bulb? ",
"Which is not passive component? ",
"Which is not related to computer? ",
"Operator used for and operation? "]
options = [['A. Thomas Edison', 'B. Nikola Tesla', 'C. Albert Einstein',
'D. Michael Faraday'],
['A. Inductor', 'B. Op-amp', 'C. Capacitor', 'D. Resistor'],
['A. RAM', 'B. SSD', 'C. Heat', 'D. Keyboard'],
['!', '~', '||', '&']]
variables = []
for i in range(len(questions)):
label = Label(window, text=questions[i], font=('Arial', 15, 'bold'))
label.pack(anchor=W)
var = IntVar(value=-1)
variables.append(var) # Save for possible later use - one per question.
def handler(variable=var):
"""Callback for this question and group of answers."""
display(variable)
for j in range(len(options)):
checkButton = Radiobutton(window, text=options[i][j], variable=var,
value=j, padx=10, font=('Arial', 10),
command=handler)
checkButton.pack(anchor=W)
comp_btn = Button(window, text="Check Answers", command=check_answers)
comp_btn.pack()
window.mainloop()
I am currently building a ReportLab PDF Form which I want to make interactive. I want that the options shown on the second choice widget, depend on the selection of the first choice widget. (For example: if the selection of the first choice is 'Italy', show as food options on the second widget 'Pizza' and 'Spaghetti').
Currently I am trying to control such condition with an if, however I have been unable to reference the first widget correctly. (Since I called it name='choice1', I figured this would be the way of calling such widget). I get an error:
if choice1 == 'Italy':
NameError: name 'choice1' is not defined
Is there a correct way to do the desired action? I am looking at the Reportlab documentation, however I have not found an answer.
My current Python code is the following:
from reportlab.pdfgen.canvas import Canvas
from datetime import datetime, timedelta
from reportlab.platypus import Table, TableStyle
from reportlab.lib import colors
from reportlab.pdfbase import pdfform
import win32com.client as win32
import pathlib
file_name = 'Example.pdf'
document_title = 'Example'
title = 'Example File'
instrucciones_1 = 'INSTRUCCIONES: Llenar toda la solicitud con la información que se pide.'
instrucciones_2 = 'Al finalizar, este PDF se enviará automáticamente al encargado de su área para aprobación.'
instrucciones_3 = 'La aprobación queda sujeta al criterio de dicho encargado. '
canvas = Canvas(file_name)
canvas.setTitle(document_title)
canvas.setFont("Helvetica-Bold", 24)
canvas.drawCentredString(385, 795, title)
now = datetime.now()
full_date = f'{now.day}/{now.month}/{now.year}'
canvas.setFont('Helvetica', 16)
canvas.drawCentredString(350, 790-20, 'Fecha solicitud: ')
canvas.setFont('Helvetica-Bold', 16)
canvas.drawCentredString(450, 790-20, full_date)
canvas.line(35, 755, 565, 755)
canvas.setFont("Helvetica", 12)
canvas.drawString(40, 740, instrucciones_1)
canvas.drawString(40, 740-15, instrucciones_2)
canvas.drawString(40, 740-30, instrucciones_3)
canvas.line(35, 740 - 35, 565, 740 - 35)
form = canvas.acroForm
canvas.setFont('Helvetica', 14)
canvas.drawString(70, 675, 'Origin of Food: ')
options = ['Select origin', 'Italy', 'Mexico', 'US']
form.choice(name='choice1', tooltip='Select origin of food',
value='Select origin',
x=165, y=670, width=200, height=25,
borderColor=colors.blue, fillColor=colors.lightblue,
textColor=colors.black, forceBorder=True, options=options)
origin = ''
food_italy = ['Select food', 'Spaghetti', 'Pizza']
food_mexico = ['Select food', 'Chiles en Nogada', 'Tacos]
food_us = ['Select food', 'Burgers', 'Buffalo Wings']
if choice1.value == 'Italy':
sucursal = food_italy
elif choice1.value == 'Mexico':
sucursal = food_mexico
elif choice1.value == 'US':
sucursal = food_us
canvas.drawString(70, 645, 'Food: ')
form.choice(name='choice2', tooltip='Select food',
value='Select food',
x=165, y=670, width=200, height=25,
borderColor=colors.blue, fillColor=colors.lightblue,
textColor=colors.black, forceBorder=True, options=sucursal)
canvas.save()
Any suggestions?
Thanks a lot in advance!
EDIT
If PDF and Reportlab is not the way, is there some way I can do an executable file/form which can perform such tasks? Thanks a lot.
This cannot be done in the way you approach this, i.e. in the Python code. The reason for this is that the selection of e.g. 'Italy' happens only when the user opens the PDF file and selects it. So you would need to create a (deprecated) XFA form for this.
I've been coding for years and I have always been able to find an answer on google, until now. I cannot manage to make this work in any way.
Before this I have several lists of different countries, and a dozen or so functions that just print stuff for the user, it is not relevant here.
I use tkinter to create an input box where a user can type a country (input gets assigned to typedCountry). I then search for the country in each and every list in the mainProgram() function, and every time I find a list that matches I return another function. Everything works marvelously as it should, except I want mainProgram() to return the information to a tkinter GUI box and not the terminal. I've been fighting with it for hours and I cannot find a way to make it work, I am willing to take any advice, even changing the code significantly or using something other than tkinter would work just fine.
def mainProgram():
typedCountry = e.get()
Country = typedCountry.lower()
print 'Your country is: ' + typedCountry + '\n'
if Country in bannedCountries:
banned(typedCountry)
if Country in cpBannedCountries:
cpBanned(typedCountry)
if Country in skrillBannedCountries:
skrillBanned(typedCountry)
if Country in bacsCountries:
Bacs(typedCountry)
if Country in sepaCountries:
sepa(typedCountry)
if Country in eftCountries:
eft(typedCountry)
if Country in ltdCountries:
ltd(typedCountry)
if Country in marketsCountries:
markets(typedCountry)
master = Tk()
e = Entry(master)
e.pack()
e.focus_set()
var = mainProgram()
def textBox():
root = Tk()
label = Message(root, textvariable=var)
label.pack()
root.mainloop()
b = Button(master, text = "Search", command = mainProgram)
b.pack()
mainloop()
And here is the main code if you want it (if you want to run this in your end for example):
from tkinter import *
import tkMessageBox
bannedCountries = ['afghanistan','american samoa','belarus','brazil','burundi',
'central african republic','congo','cook islands','cote d\'ivoire',
'crimea','cuba','guam','iran','japan','liberia','libya','myanmar',
'new zealand','north korea','northern mariana islands','puerto rico',
'russia','singapore','somalia','south korea','sudan','syria','tokelau',
'turkey','ukraine','united states','vanuatu','virgin islands',
'western sahara','zimbabwe']
cpBannedCountries = ['belarus','bosnia and herzegovina','burundi','cote d\'ivoire',
'cuba','iran','iraq','kosovo','lebanon','liberia','macedonia','montenegro','myanmar',
'nigeria','north korea','saint helena','somalia','sudan']
skrillBannedCountries = ['angola','barbados','benin','burkina faso','cape verde',
'comoros','djibouti','faroe islands','gambia','greenland','grenada','guyana','laos',
'liechtenstein','macao','martinique','mongolia','namibia','niger','palau','samoa',
'suriname','tajikistan','togo','trinidad and tobago','turkmenistan']
bacsCountries = ["united kingdom"]
eftCountries = ['australia']
sepaCountries = ['austria','belgium','bulgaria','cyprus','czech republic','check',
'denmark','estonia','finland','france','germany','greece','hungary','iceland',
'ireland','italy','latvia','liechtenstein','lithuania','luxembourg','malta',
'martinique','mayotte','monaco','netherlands','norway','poland','portugal',
'romania','slovakia','slovenia','spain','sweden','switzerland','united kingdom']
ltdCountries = ['austria','belgium','bulgaria','croatia','cyprus','czech republic',
'denmark','estonia','finland','france','germany','greece','hungary','ireland',
'italy','latvia','lithuania','luxembourg','malta','netherlands','poland','portugal',
'romania','slovakia','slovenia','spain','united kingdom']
marketsCountries = ['albania','algeria','andorra','angola','anguilla','armenia',
'aruba','bahamas','bangladesh','barbados','belize','benin','bermuda','bhutan',
'bonaire','bosnia','herzegovina','bosnia and herzegovina','botswana','brunei',
'burkina faso','burma','cambodia','cameroon','cape verde','cayman islands',
'chad','comoros','djibouti','equatorial guinea','eritrea','ethiopia','falkland islands (malvinas)',
'faroe islands','gabon','gambia','ghana','greenland','grenada','guinea','guinea-bissau',
'guyana','haiti','iceland','india','jamaica','jordan','kazakhstan','kenya',
'kiribati','kosovo','kyrgyzstan','laos','lesotho','liechtenstein','macao',
'macedonia','madagascar','malawi','malaysia','maldives','mali','marshall islands',
'mauritania','mauritius','micronesia','mongolia','morocco','mozambique','namibia',
'nauru','nepal','niger','nigeria','norway','pakistan','palau','papua new guinea',
'philippines','rwanda','saint helena','saint kitts and nevis','saint lucia','saint vincent and the grenadines',
'samoa','sao tome and principe','senegal','serbia','seychelles','sierra leone',
'solomon islands','sri lanka','suriname','swaziland','tajikistan','tanzania','togo',
'tonga','trinidad and tobago','tunisia','turkmenistan','turks and caicos islands','tuvalu',
'uganda','uzbekistan','yemen','zambia']
def banned(x):
if 'kingdom' not in x:
return 'Clients from %s are not able to open an account with FXCM' % x
else:
return
def cpBanned(x):
return "FXCM does not accept cards issued in %s" % x
def skrillBanned(x):
return "Clients from %s cannot use Skrill" % x
def Bacs(x):
return """Clients from %s can use BACS if their bank account is located in
%s and both their bank account and their FXCM account is in GBP""" % (x, x)
def sepa(x):
return """Clients from %s can use SEPA if their bank account is located either in
%s or in another European country, and both their bank account and their FXCM account is in EUR""" % (x, x)
def eft(x):
return """Clients from %s can use EFT if their bank account is located in
%s, and both their bank account and their FXCM account is in AUD""" % (x, x)
print "Clients from %s must open with FXCM AU" % x
def ltd(x):
return "Clients from %s must open with FXCM LTD" % x
def markets(x):
return "Clients from %s must open with FXCM Markets" % x
def mainProgram():
typedCountry = e.get() # This is the text you may want to use later
Country = typedCountry.lower()
print 'Your country is: ' + typedCountry + '\n'
if Country in bannedCountries:
banned(typedCountry)
if Country in cpBannedCountries:
cpBanned(typedCountry)
if Country in skrillBannedCountries:
skrillBanned(typedCountry)
if Country in bacsCountries:
Bacs(typedCountry)
if Country in sepaCountries:
sepa(typedCountry)
if Country in eftCountries:
eft(typedCountry)
if Country in ltdCountries:
ltd(typedCountry)
if Country in marketsCountries:
markets(typedCountry)
master = Tk()
e = Entry(master)
e.pack()
e.focus_set()
var = mainProgram()
def textBox():
root = Tk()
label = Message(root, textvariable=var)
label.pack()
root.mainloop()
b = Button(master, text = "Search", command = mainProgram)
b.pack()
mainloop()
Just replace for example:
return "FXCM does not accept cards issued in %s" % x
with:
Label(master, text="FXCM does not accept cards issued in %s" % x).pack()
in each of your functions.
Or better add:
lbl = Label(master)
lbl.pack()
under your e lines and then replace the returns with:
lbl['text'] = x
You don't call the textBox function. For this to work, if I understand the problem correctly, the called function has to update the text box label. Also, you don't send the lower() county to the function. A shortened version of your code
import sys
if sys.version_info[0] < 3:
import Tkinter as tk ## Python 2.x
else:
import tkinter as tk ## Python 3.x
ltdCountries = ['austria','belgium','bulgaria','croatia','cyprus','czech republic']
sepaCountries = ['austria','belgium','bulgaria','cyprus','czech republic','check']
marketsCountries = ['albania','algeria','andorra','angola','anguilla']
def ltd(country):
var.set(var.get() +" *** ltd " + country)
def sepa(country):
var.set(var.get() +" *** sepa " + country)
def markets(country):
var.set(var.get() +" *** markets " + country)
def mainProgram():
typedCountry = e.get()
print('Your country is: ' + typedCountry + '\n')
country_lower=typedCountry.lower()
for country_list, country_function in ((ltdCountries, ltd),
(sepaCountries, sepa),
(marketsCountries, markets)):
if country_lower in country_list:
country_function(country_lower)
master = tk.Tk()
e = tk.Entry(master)
e.pack()
e.focus_set()
var=tk.StringVar()
var.set("")
tk.Label(master, textvariable=var, bg="lightyellow",
width=25).pack()
b = tk.Button(master, text = "Search", command = mainProgram)
b.pack()
tk.Button(master, text="Quit", bg="orange",
command=master.quit).pack()
master.mainloop()
# First create a text box
txt = scrolledtext.ScrolledText(root)
# this line is for deleting it's content
txt.delete(1.0, END)
# this other line is for inserting text in it
txt.insert(1.0, 'Some Text')
I have a problem with the listbox because it does not display names like in the first listbox under 1T, only on one line, I want to display the names one under the other. I have no idea how to do this.
Thank you for every advice and attention to the code below
import random
import tkinter, sys
from tkinter import *
import tkinter.messagebox as messagebox
los = []
list = ['1. Kamil Winnicki', '#2. Wiktor Jasiński', '3. Adam Turowski', '#4. Arek Major', '5. Dominik Piechotka', '#6. Jakub Laskowski', '7. Jakub Materak', '8. Kacper Kołodziejski',
'#9. Kamil Stankiewicz', '10. Konrad Nosek', '11. Krzysiek Wawszczak', '12. Andrzej Oleksiak', '13. Miłosz Tarucin', '14. Paweł Pawłowski', '#15. Mateusz Lebioda']
lines = list
for line in lines:
if line [0] != '#':
los.append(line)
main = tkinter.Tk()
def koniec():
main.destroy()
def losowanie():
messagebox.showinfo(message=random.sample(los ,1))
#nagłowek
te = tkinter.Label(main, text = 'Lista 1T:')
te.pack()
#Wyswietla liste 1T
listbox = Listbox(main, width=21, height=15)
listbox.insert(1, '1. Mateusz Lebioda', '2. Jakub Laskowski', '3. Kamil Winnicki', '4. Wiktor Jasiński', '5. Adam Turowski', '6. Arek Major', '7. Dominik Piechotka', '8. Jakub Materak', '9. Kacper Kołodziejski', '10. Kamil Stankiewicz', '11. Konrad Nosek', '12. Krzysiek Wawszczak', '13. Andrzej Oleksiak', '14. Miłosz Tarucin', '15. Paweł Pawłowski')
listbox.pack()
#Obecne osoby
obecne1 = tkinter.Label(main, text = 'Obecne osoby:')
obecne1.pack()
obecne = Listbox(main)
obecne.insert(1, los)
obecne.pack()
#losuje
y = tkinter.Button(main, text = 'losuj', command = losowanie)
y.pack()
#wyjscie z aplikacji
x = tkinter.Button(main, text = 'Zakoncz', command = koniec)
x.pack()
main.mainloop()
You need to unpack your list when inserting.
Changing insertion line would be enough.
obecne.insert("end", *los)
#^ notice this star here. That one makes the unpacking
or you can just iterate over your list items using for loop.
obecne = Listbox(main)
for item in los:
obecne.insert("end", item)
obecne.pack()
I would like to know how to justify the text in a ttk.Treeview column. Below is an example of what I mean. Notice the dates and how the digits are not properly under each other. I think it has something to do with the spacing, but I could be wrong.
EDIT: It's written in Python 3.
#! coding=utf-8
import pickle
import matplotlib.pyplot as plt
import tkinter as tk
from tkinter import ttk
# Create Example
root = tk.Tk()
root.minsize(200,300)
tree = ttk.Treeview(root,columns=("date"))
tree.heading("#0" , text='Sample', anchor=tk.W)
tree.column("#0", stretch=0)
tree.heading("date", text='Date', anchor=tk.E)
tree.column("date", stretch=0)
ABC = ["A","B","C","D","E"]
dates = ["3.4.2013", "14.10.400", "24.12.1234", "1.10.1", "14.7.123"]
tree.insert("",iid="1", index="end",text="No Format")
for i in range(len(ABC)):
dates2 = dates[i].split(".")
date = "{:<2}.{:<2}.{:<4}".format(dates2[0],dates2[1],dates2[2])
tree.insert("1",iid="1"+str(i), index="end",text=ABC[i], value=[dates[i]])
tree.see("14")
tree.insert("",iid="2", index="end",text="With Format")
for i in range(len(ABC)):
dates2 = dates[i].split(".")
date = "{:>2}.{:>2}.{:>4}".format(dates2[0],dates2[1],dates2[2])
tree.insert("2",iid="2"+str(i), index="end",text=ABC[i], value=[date])
tree.see("24")
tree.pack(expand=True,fill=tk.BOTH)
root.mainloop()
Use monospace font using tkinter.ttk.Treeview.tag_configure:
...
for i in range(len(ABC)):
dates2 = dates[i].split(".")
date = "{:>2}.{:>2}.{:>4}".format(dates2[0],dates2[1],dates2[2])
tree.insert("2",iid="2"+str(i), index="end",text=ABC[i], value=[date],
tag='monospace') # <----
tree.tag_configure('monospace', font='courier') # <----
...
See Tag Options.
You can justify the text in the date column in the same way as you have justified the text in the date heading by using the anchor option.
tree.heading("date", text='Date', anchor=tk.E)
tree.column("date", stretch=0, anchor=tk.E)
More detailed information on anchor and other options for the heading and column methods can be found in Tkinter 8.5 reference: a GUI for Python from New Mexico Tech.