I am new to Python and am using Tkinter to create a basic GUI for a game.
I have got some buttons an image and numerous labels to work, but I am wondering..
What is the best way to get a large, initially blank text box on the GUI, and how would I go about having the text box update on the press of a "next" button.
I need it to scroll through text with each press, showing the next relevant line.
The text that is shown will depend on the choice(s) that are made, so variables like current location etc are necessary.
The aim is to make a simple game that allows you to read through the text with the Next button, then make choices etc, a mostly text-based adventure game.
I'll post what I have already below. Yes I know it's terrible, this is my first try so don't judge too harshly on my mistakes.
Any tips, advice or methods are much appreciated.
Some things to note:
My quit button isn't working yet, not too sure why.
I would love to figure out how to store variables based on what the user inputs, via an input box that can be prompted when an input is required from the user.
Also, happy to start from scratch if it's easier.
# Widgets:
import sys #Imports the system commands which makes it possible to terminate the program
import time #Imports the time module to allow delays in script
import os #Imports os to make it possible to play music/sound
import random #Imports random variable to allow for random number generation
import pickle #allows the game state to be saved.
from tkinter import * # imports tkinter
import tkinter as tk
from tkinter import *
from tkinter import messagebox
from textwrap import wrap # imports text wrap
#base variables for testing
character_Gold = 1
character_Health = 100
character_base_Health = 100
character_Strength = 10
character_Dexterity = 10
character_Constitution = 10
character_Intelligence = 10
character_Wisdom = 10
character_Charisma = 10
character_base_Perception = 10
#Text Boxes
#Base Geometry and image
window = Tk()
TitleScreen = PhotoImage( file = 'test.gif' )
window.geometry("1100x600")
#defines
def close():
#win.destroy()
window.quit()
imgLbl = Label( window, image = TitleScreen )
label1 = Label( window, relief = 'groove', width = 4)
label2 = Label( window, relief = 'groove', width = 4)
label3 = Label( window, relief = 'groove', width = 4)
label4 = Label( window, relief = 'groove', width = 4)
label5 = Label( window, relief = 'groove', width = 4)
label6 = Label( window, relief = 'groove', width = 4)
label7 = Label( window, relief = 'groove', width = 4)
label8 = Label( window, relief = 'groove', width = 4)
label9 = Label( window, relief = 'groove' , width = 3)
label10 = Label( window, relief = 'groove' , width = 3)
label11 = Label( window, relief = 'groove' , width = 3)
label12 = Label( window, relief = 'groove' , width = 3)
label13 = Label( window, relief = 'groove' , width = 3)
label14 = Label( window, relief = 'groove' , width = 3)
label15 = Label( window, relief = 'groove' , width = 3)
label16 = Label( window, relief = 'groove' , width = 3)
TextLabel = Label( window, relief = 'groove', width = 50)
LocationLabel = Label( window, relief = 'groove', width = 18)
LocationBase = Label( window, relief = 'groove', width = 13)
NextBtn = Button( window )
MainText = Label( window, relief = 'groove', width = 40, height = 8)
QuitButton = Button(window, text="Quit",command=close)
# Geometry:
imgLbl.grid( row = 1, column = 1 , rowspan = 24 ) # Change Rowspan here to increase number of Rows and shrink gaps
label1.grid( row = 1, column = 2, padx = 10 )
label2.grid( row = 1, column = 4, padx = 10 )
label3.grid( row = 1, column = 5, padx = 10 )
label4.grid( row = 1, column = 6, padx = 10 )
label5.grid( row = 1, column = 7, padx = 10 )
label6.grid( row = 1, column = 8, padx = 10)
label7.grid( row = 1, column = 9, padx = 10)
label8.grid( row = 1, column = 10, padx = 5)
label9.grid( row = 2, column = 2, padx = (1, 10)) #Health
label10.grid(row = 2, column = 4, padx = 10) #STR
label11.grid(row = 2, column = 5, padx = 10) # DEX
label12.grid(row = 2, column = 6, padx = 10) # CON
label13.grid(row = 2, column = 7, padx = 10) #INT
label14.grid(row = 2, column = 8, padx = 10) #WIS
label15.grid(row = 2, column = 9, padx = 10) # CHA
label16.grid(row = 2, column = 10, padx= 10) # gold
TextLabel.grid( row = 26, column = 1, padx = 10) # instruction label
LocationLabel.grid( row = 2, column = 11, padx = 10) # dynamic location label, changes
LocationBase.grid( row = 1, column = 11, padx = 10) # location text only not dynamic
MainText.grid( row = 30, column = 1, padx = 10) # main text box
QuitButton.grid(row = 34, column = 14 , padx = 10) #Quit Button
NextBtn.grid( row = 26, column = 2, columnspan = 4 )
# Static Properties
window.title( ' The Adventure ')
NextBtn.configure( text = 'Next')
Current_Location = "Title Screen"
#DynamicProperties. BD is button facelift level, bg is colour.
label1.configure( text = 'HP:', bg = 'Red' )
label1.configure( bd = 8, relief=RAISED)
label2.configure( text = 'STR:', bg = 'Orange')
label2.configure( bd = 8, relief=RAISED)
label3.configure( text = 'DEX:', bg = 'Purple')
label3.configure( bd = 8, relief=RAISED)
label4.configure( text = 'CON:', bg = 'Green')
label4.configure( bd = 8, relief=RAISED)
label5.configure( text = 'INT:', bg = 'light green')
label5.configure( bd = 8, relief=RAISED)
label6.configure( text = 'WIS:', bg = 'white')
label6.configure( bd = 8, relief=RAISED)
label7.configure( text = 'CHA:', bg = 'light blue')
label7.configure( bd = 8, relief=RAISED)
label8.configure( text = 'GP:', bg = 'yellow')
label8.configure( bd = 8, relief=RAISED)
label9.configure( text = character_Health)
label9.configure( bd = 6, relief=RAISED)
label10.configure( text = character_Strength)
label10.configure( bd = 6, relief=RAISED)
label11.configure( text = character_Dexterity)
label11.configure( bd = 6, relief=RAISED)
label12.configure( text = character_Constitution)
label12.configure( bd = 6, relief=RAISED)
label13.configure( text = character_Intelligence)
label13.configure( bd = 6, relief=RAISED)
label14.configure( text = character_Wisdom)
label14.configure( bd = 6, relief=RAISED)
label15.configure( text = character_Charisma)
label15.configure( bd = 6, relief=RAISED)
label16.configure( text = character_Gold)
LocationLabel.configure( text = Current_Location, fg = 'White', bg = 'Black')
LocationLabel.configure( bd = 8, relief=RAISED) # raises the button up to look 3d
LocationBase.configure( text = "Your Location:", fg = "black", bg = "White") #"location" text above tab that changes actual location
LocationBase.configure( bd = 8, relief=RAISED)
TextLabel.configure( text = "Welcome To The Adventure. Click 'Next' to begin!") # instruction label
TextLabel.configure( bd = 2, relief=RAISED)
MainText.configure( text = '''This is the large box where \n the main game text should go.''', fg = "Black", bg = "White") # use \n for a NEWLINE
MainText.configure( bd = 10, relief=RAISED)
NextBtn.configure( bd = 8, relief=RAISED) # raises next button
QuitButton.configure( bd = 2, relief=RAISED, text="Quit",command=close)
#Sustain Window:
window.mainloop()
Related
I have written the following code to get the user input. But I am not able to add a scrollbar to it. I want to place a vertical scrollbar because I am not able to view all the input labels on my screen.
I first tried:
v = Scrollbar(root, orient='vertical')
v.config(command=root.yview)
It gave me the following error:
File "/Users/aaditya/Desktop/Blender_software/Blender_algo_exp/testing.py", line 235, in <module>
label1.grid(row = 1, column = 0, padx = 10, pady = 10)
File "/opt/anaconda3/envs/blender_env/lib/python3.9/tkinter/__init__.py", line 2486, in grid_configure
self.tk.call(
_tkinter.TclError: cannot use geometry manager grid inside . which already has slaves managed by pack
After that I tried the following:
myscroll = Scrollbar(root)
myscroll.pack(side = RIGHT, fill = Y)
Which resulted in the following error:
AttributeError: '_tkinter.tkapp' object has no attribute 'yview'
How can I fix this?
This is my entire code:
# Driver code
if __name__ == "__main__" :
root = Tk()
# v = Scrollbar(root, orient='vertical')
# v.config(command=root.yview)
# myscroll = Scrollbar(root)
# myscroll.pack(side = RIGHT, fill = Y)
root.configure(background = 'light gray')
root.geometry("700x700")
root.title("Blender Software")
label1 = Label(root, text = "Total Quantity: ",
fg = 'black', bg = 'white')
label2 = Label(root, text = "Percentage of Solid Scrap : ",
fg = 'black', bg = 'white')
label3 = Label(root, text = "Cr min : ",
fg = 'black', bg = 'white')
label4 = Label(root, text = "Cr max : ",
fg = 'black', bg = 'white')
label1.grid(row = 1, column = 0, padx = 10, pady = 10)
label2.grid(row = 2, column = 0, padx = 10, pady = 10)
label3.grid(row = 3, column = 0, padx = 10, pady = 10)
label4.grid(row = 4, column = 0, padx = 10, pady = 10)
# Create a entry box
# for filling or typing the information.
total_quantity = Entry(root)
per_solid_scrap = Entry(root)
Cr_min_input = Entry(root)
Cr_max_input = Entry(root)
# grid method is used for placing
# the widgets at respective positions
# in table like structure .
total_quantity.grid(row = 1, column = 1, padx = 10, pady = 10)
per_solid_scrap.grid(row = 2, column = 1, padx = 10, pady = 10)
Cr_min_input.grid(row = 3, column = 1, padx = 10, pady = 10)
Cr_max_input.grid(row = 4, column = 1, padx = 10, pady = 10)
button1 = Button(root, text = "Submit", bg = "red",
fg = "black", command = calculate_op)
button1.grid(row = 21, column = 1, pady = 10)
# Start the GUI
root.mainloop()
Pack and grid cannot be used at the same time. So since you called the pack for the scrollbar, you cannot manage the following widgets by grid anymore. An easy fix is to place the scrollbar with grid function instead. Apart from that, try using a function or class to make your code less lengthy because now it seems hard to read and purposeless.
the following is working first pass around. Select file/s, activate the view button and def, view files. all good.
When trying to select another file/s, during the selection process, the GUI closes abruptly.
I tried to figure out of the variable needs to be reset, but that did not change.
after all the imports:
root = tk.Tk()
root.title("Motion GUI")
root.minsize(width=1000, height=700)
root.maxsize(width=1400, height = 900)
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N,W,E,S))
root.columnconfigure(0, weight=1)
root.rowconfigure(0,weight=1)
WidgetFrame = ttk.Frame(mainframe, borderwidth=2,relief='ridge',height = 60)
WidgetFrame.grid(column=0,row=0, sticky="E,W")
def CreateWidgets():
link_Label = Label(WidgetFrame, text ="Select File(s): ", bg = "#E8D579")
link_Label.grid(row = 1, column = 0, pady = 5, padx = 5)
WidgetFrame.sourceText = Entry(WidgetFrame, width = 50, textvariable = sourceLocation)
WidgetFrame.sourceText.grid(row = 1, column = 1, pady = 5, padx = 5, columnspan = 2)
source_browseButton = Button(WidgetFrame, text ="Browse", command = SourceBrowse, width = 15)
source_browseButton.grid(row = 1, column = 3, pady = 5, padx = 5)
viewButton = Button(WidgetFrame, text ="View File(s)", command = ViewFile, width = 15)
viewButton.grid(row = 3, column = 0, pady = 5, padx = 5)
def SourceBrowse():
WidgetFrame.files_list = list(filedialog.askopenfilenames(initialdir ="/mnt/data/Motion_Data/Motion_Clips",title="Press shift key plus Left mouse click to select multiple files"))
def ViewFile():
# plays all selected files one by one, keeps speed selected in 1st clip unless changed..
files_list = WidgetFrame.files_list
for f in files_list:
player.playlist_append(f)
player.playlist_pos = 0
player.wait_for_playback
sourceLocation = StringVar()
destinationLocation = StringVar()
file_list = StringVar()
CreateWidgets()
root.mainloop()
What am I missing?
here is the full code with all the buttons and functions. BTW, all the other Buttons and Functions do work without problems (that is: Copy/Move/Delete):
#!/usr/bin/python3
import os
import shutil
import tkinter as tk
from tkinter import *
from tkinter import filedialog, messagebox
from tkinter import ttk
import webbrowser
if os.environ.get('DISPLAY','') == "":
print('no display found.Using :0.0')
os.environ.__setitem__('DISPLAY',':0.0')
##### MPV.py HAS TO BE copied into the directory which imports mpv ######
import mpv
player = mpv.MPV(ytdl=True,input_default_bindings=True,input_vo_keyboard=True,osc=True)
media = open('mPlaylist.u3e', 'r').read().splitlines()
# Creating object of tk class
root = tk.Tk()
root.title("Motion GUI")
root.minsize(width=1000, height=700)
root.maxsize(width=1400, height = 900)
mainframe = ttk.Frame(root, padding="3 3 12 12")
mainframe.grid(column=0, row=0, sticky=(N,W,E,S))
root.columnconfigure(0, weight=1)
root.rowconfigure(0,weight=1)
WidgetFrame = ttk.Frame(mainframe, borderwidth=2,relief='ridge',height = 60)
WidgetFrame.grid(column=0,row=0, sticky="E,W")
# Setting the title and background color disabling the resizing property
root.geometry("830x420")
root.title("View/Copy/Move/Delete mkv's")
root.config(background = "gray")
def CreateWidgets():
WidgetFrame.link_Label = Label(WidgetFrame, text ="Select File(s): ", bg = "#E8D579")
WidgetFrame.link_Label.grid(row = 1, column = 0, pady = 5, padx = 5)
WidgetFrame.sourceText = Entry(WidgetFrame, width = 50, textvariable = sourceLocation)
WidgetFrame.sourceText.grid(row = 1, column = 1, pady = 5, padx = 5, columnspan = 2)
WidgetFrame.source_browseButton = Button(WidgetFrame, text ="Browse", command = SourceBrowse, width = 15)
WidgetFrame.source_browseButton.grid(row = 1, column = 3, pady = 5, padx = 5)
WidgetFrame.destinationLabel = Label(WidgetFrame, text ="Select The Destination : ", bg ="#E8D579")
WidgetFrame.destinationLabel.grid(row = 2, column = 0, pady = 5, padx = 5)
WidgetFrame.destinationText = Entry(WidgetFrame, width = 50, textvariable = destinationLocation)
WidgetFrame.destinationText.grid(row = 2, column = 1, pady = 5, padx = 5, columnspan = 2)
WidgetFrame.dest_browseButton = Button(WidgetFrame, text ="Browse", command = DestinationBrowse, width = 15)
WidgetFrame.dest_browseButton.grid(row = 2, column = 3, pady = 5, padx = 5)
WidgetFrame.viewButton = Button(WidgetFrame, text ="View File(s)", command = ViewFile, width = 15)
WidgetFrame.viewButton.grid(row = 3, column = 0, pady = 5, padx = 5)
WidgetFrame.copyButton = Button(WidgetFrame, text ="Copy File", command = CopyFile, width = 15)
WidgetFrame.copyButton.grid(row = 3, column = 1, pady = 5, padx = 5)
WidgetFrame.moveButton = Button(WidgetFrame, text ="Move File", command = MoveFile, width = 15)
WidgetFrame.moveButton.grid(row = 3, column = 2, pady = 5, padx = 5)
WidgetFrame.moveButton = Button(WidgetFrame, text ="Delete File(s)", command = DeleteFile, width = 15)
WidgetFrame.moveButton.grid(row = 3, column = 3, pady = 5, padx = 5)
WidgetFrame.MotionButton = Button(WidgetFrame, text="IP Streams",command=MotionHTTP, font="LUCIDA 12")
WidgetFrame.MotionButton.grid(row=3,column=5,pady=5,padx=5)
WidgetFrame.exitButton = Button(WidgetFrame, text="Quit", command=root.destroy, font="LUCIDA 12 bold")
WidgetFrame.exitButton.grid(row = 3, column = 6,pady = 5, padx = 5)
def MotionHTTP():
webbrowser.open("http://192.168.0.26:8080")
def SourceBrowse():
WidgetFrame.files_list = list(filedialog.askopenfilenames(initialdir ="/home/rainer/Videos",title="Press shift key plus Left mouse click to select multiple files"))
files_list = []
WidgetFrame.sourceText.insert('1', WidgetFrame.files_list)
def DestinationBrowse():
destinationdirectory = filedialog.askdirectory(initialdir ="/mnt/data/Motion_Data/Motion_Clips")
WidgetFrame.destinationText.insert('1', destinationdirectory)
def ViewFile():
# plays all selected files one by one, keeps speed selected in 1st clip unless changed..
files_list = WidgetFrame.files_list
for f in files_list:
print(f)
player.playlist_append(f)
player.playlist(files_list)
#player.playlist_pos = 0
player.wait_for_playback
playlist.close()
def CopyFile():
files_list = WidgetFrame.files_list
destination_location = destinationLocation.get()
# Looping through the files present in the list
shutil.copy(f, destination_location)
def MoveFile():
files_list = WidgetFrame.files_list
destination_location = destinationLocation.get()
for f in files_list:
shutil.move(f, destination_location)
def DeleteFile():
files_list = WidgetFrame.files_list
for f in files_list:
os.remove(f)
# Creating tkinter variable
sourceLocation = StringVar()
destinationLocation = StringVar()
files_list = StringVar()
#destinationLocation = StringVar(value='/home/rainer/Music')
#file_list = StringVar()
# Calling the CreateWidgets() function
CreateWidgets()
# Defining infinite loop
root.mainloop()
I am attempting to create a relatively simple survey like form in Tkinter, and I'm relatively new to the GUI framework. I'm having real issues trying to figure out why there are so many inconsistencies, especially when working with grid placement+frames+multiple widgets in same row. Especially this specific example. I'm tying together all my questions into a single frame, and it seems to work out... sort of half. Though the rows seem to cooperate nicely, the columns are where the whole thing gets erupted.
qframe1 = Frame(question, bg='black')
qframe1.grid(row=1, padx = 20, sticky = W)
q1l = Label(qframe1, text = 'Question 1: How often do you eat at Mcdonalds?', font = ('Calibri', 14), bg = 'azure')
q1l.grid(columnspan = 4, pady = 5, sticky = W)
q1 = StringVar()
q1.set('None')
q1r1 = Radiobutton(qframe1, text = 'Everyday!', font = ('Calibri', 12), bg = 'azure', variable = q1, value = 'Always')
q1r1.grid(row=1, column = 0, pady = 5, sticky = W)
q1r2 = Radiobutton(qframe1, text = 'Sometimes', font = ('Calibri', 12), bg = 'azure', variable = q1, value = 'Sometimes')
q1r2.grid(row=1, column = 1, pady = 5, sticky = W)
q1r3 = Radiobutton(qframe1, text = 'Not Frequently', font = ('Calibri', 12), bg = 'azure', variable = q1, value = 'Infrequent')
q1r3.grid(row=1, column = 2, pady = 5, sticky = W)
q1r4 = Radiobutton(qframe1, text = 'Never', font = ('Calibri', 12), bg = 'azure', variable = q1, value = 'Never')
q1r4.grid(row=1, column = 3, pady = 5, sticky = W)
This is the bare code for the section that's messing up.
Also, I have made sure that it's not the length of each radio button that is causing the issue. When I change the text of the radio buttons, they still get placed in the same irregular positions.
Here's the code for another section of the trivia.
q2l = Label(qframe1, text = 'Question 2: What meal do you normally order?', font = ('Calibri', 14), bg = 'azure')
q2l.grid(row=2, columnspan = 4, pady = 5, sticky = W)
q2 = StringVar()
q2.set('None')
q2r1 = Radiobutton(qframe1, text = 'Fries', font = ('Calibri', 12), bg = 'azure', variable = q2, value = 'Fries')
q2r1.grid(row=3, column = 0, pady = 5, sticky = W)
q2r2 = Radiobutton(qframe1, text = 'Hamburgers', font = ('Calibri', 12), bg = 'azure', variable = q2, value = 'Hamburgers')
q2r2.grid(row=3, column = 1, pady = 5, sticky = W)
q2r3 = Radiobutton(qframe1, text = 'Chicken Nuggets', font = ('Calibri', 12), bg = 'azure', variable = q2, value = 'Chicken Nuggets')
q2r3.grid(row=3, column = 2, pady = 5, sticky = W)
q2r4 = Radiobutton(qframe1, text = 'Coffee', font = ('Calibri', 12), bg = 'azure', variable = q2, value = 'Coffee')
q2r4.grid(row=3, column = 3, pady = 5, sticky = W)
This again causes an irregular spacing. But this time, the spacing is completely different from the radio buttons in question 1. And rinse and repeat with every new question set of radio buttons.
There are no issues with the buttons on the right side. Perhaps it's because they're aligned in rows and not columns which are causing the spacing issue.
bframe = Frame(question, bg='black')
bframe.grid(row=1, padx = 20, sticky = E)
audioq1 = Button(bframe, text = ' Listen to Audio', font = ('Calibri', 14), bg = 'brown1', fg = 'azure', image = sound, relief = SUNKEN, compound = LEFT, command = q1audio)
audioq1.grid(ipadx = 5, pady = 20)
audioq2 = Button(bframe, text = ' Listen to Audio', font = ('Calibri', 14), bg = 'brown1', fg = 'azure', image = sound, relief = SUNKEN, compound = LEFT, command = q2audio)
audioq2.grid(row = 1, ipadx = 5, pady = 20)
audioq3 = Button(bframe, text = ' Listen to Audio', font = ('Calibri', 14), bg = 'brown1', fg = 'azure', image = sound, relief = SUNKEN, compound = LEFT, command = q3audio)
audioq3.grid(row = 2, ipadx = 5, pady = 20)
audioq4 = Button(bframe, text = ' Listen to Audio', font = ('Calibri', 14), bg = 'brown1', fg = 'azure', image = sound, relief = SUNKEN, compound = LEFT, command = q4audio)
audioq4.grid(row = 3, ipadx = 5, pady = 20)
audioq5 = Button(bframe, text = ' Listen to Audio', font = ('Calibri', 14), bg = 'brown1', fg = 'azure', image = sound, relief = SUNKEN, compound = LEFT, command = q5audio)
audioq5.grid(row = 4, ipadx = 5, pady = 20)
Any help would be greatly appreciated!
If, as mentioned in the comments, "weight isn't necessarily the problem", the placement of the radiobuttons can be realized using pack instead of grid.
This gives something like this (on a mac):
If you want a more evenly placed buttons to fill the available width, you can achieve this with grid:
I also rewrote a portion of the code to make it easier to add questions to the form. Each question is now in its own frame, allowing for more flexibility.
import tkinter as tk
class QFrame(tk.Frame):
id = 1
def __init__(self, master, question):
self.master = master
super().__init__(self.master)
self.id = QFrame.id
QFrame.id += 1
self.q = tk.StringVar()
self.q.set('None')
self.question, self.choices = question
self.q_label = tk.Label(self, text=f'Question {self.id}: {self.question}')
self.q_label.pack(expand=True, anchor=tk.W)
self.choose = []
for idx, choice in enumerate(self.choices):
txt, value = choice
qr = tk.Radiobutton(self, text=txt, variable=self.q, value=value)
self.choose.append(qr)
qr.pack(side=tk.LEFT)
class App(tk.Tk):
def __init__(self, questions):
self.questions = questions
super().__init__()
for question in questions:
self.qframe = QFrame(self, question)
self.qframe.pack(fill=tk.X)
q1 = ['How often do you eat at Mcdonalds?',
(('Everyday!', 'Always'),
('Sometimes', 'Sometimes'),
('Not Frequently', 'Infrequent'),
('Never', 'Never'))]
q2 = ['What meal do you normally order?',
(('Fries!', 'Fries'),
('Hamburgers', 'Hamburgers'),
('Chicken Nuggets', 'Chicken Nuggets'),
('Coffee', 'Coffee'))]
q3 = ['how large is your usual party?',
(('alone!', 'alone'),
('two', 'two'),
('less than 5', 'less than 5'),
('5 or more', '5 or more'))]
questions = [q1, q2, q3]
app = App(questions)
app.mainloop()
The code for grid geometry manager:
class QFrame(tk.Frame):
id = 1
def __init__(self, master, question):
self.master = master
super().__init__(self.master)
self.id = QFrame.id
QFrame.id += 1
self.q = tk.StringVar()
self.q.set('None')
self.question, self.choices = question
self.grid_rowconfigure(0, weight=1)
for idx in range(4):
self.grid_columnconfigure(idx, weight=1)
self.q_label = tk.Label(self, text=f'Question {self.id}: {self.question}')
self.q_label.grid(row=0, column=0, columnspan=4, sticky="w")
self.choose = []
for idx, choice in enumerate(self.choices):
txt, value = choice
qr = tk.Radiobutton(self, text=txt, variable=self.q, value=value)
self.choose.append(qr)
qr.grid(row=1, column=idx, columnspan=1, sticky="ew")
I created a loop to search a CSV file and return a row with a specified keyword. When the else function is hastagged out, the loop works fine.
import csv
from tkinter import *
import tkinter.messagebox as box
master = Tk()
label1 = Label(master, text = 'User_ID', relief = 'groove', width = 40)
label2 = Label(master, text = 'User_Info', relief = 'groove', width = 40, height = 5)
e1 = Entry(master, relief = 'groove', width = 40)
e2 = Text(master, relief = 'groove', width = 40, height = 5, borderwidth = 2)
def enter():
csvfile = open('stack_example.csv', 'r')
read = csv.reader(csvfile)
for row in read:
if str(e1.get()) in row:
e2.insert("1.0", row, 'r')
#break
#else:
#box.showinfo('Search Result','Not Found')
#master.mainloop()
button3 = Button(master, text = 'Retrieve File', relief = 'groove', width = 25, command=enter)
label1.grid( row = 1, column = 1, padx = 10 )
label2.grid( row = 2, column = 1, padx = 10 )
e1.grid( row = 1, column = 2, padx = 10 )
e2.grid( row = 2, column = 2, padx = 10 )
button3.grid( row = 3, column = 1, columnspan = 2)
However, when the else function is part of the code, the loop skips right to the else command and ignores the if command. The output produced above is an insertion of the row with the keyword from the csv file to a text widget. But, the output below is a display box. (with the same entry keyword, that is in the csv file)
import csv
from tkinter import *
import tkinter.messagebox as box
master = Tk()
label1 = Label(master, text = 'User_ID', relief = 'groove', width = 40)
label2 = Label(master, text = 'User_Info', relief = 'groove', width = 40, height = 5)
e1 = Entry(master, relief = 'groove', width = 40)
e2 = Text(master, relief = 'groove', width = 40, height = 5, borderwidth = 2)
def enter():
csvfile = open('stack_example.csv', 'r')
read = csv.reader(csvfile)
for row in read:
if str(e1.get()) in row:
e2.insert("1.0", row, 'r')
#break
else:
box.showinfo('Search Result','Not Found')
master.mainloop()
button3 = Button(master, text = 'Retrieve File', relief = 'groove', width = 25, command=enter)
label1.grid( row = 1, column = 1, padx = 10 )
label2.grid( row = 2, column = 1, padx = 10 )
e1.grid( row = 1, column = 2, padx = 10 )
e2.grid( row = 2, column = 2, padx = 10 )
button3.grid( row = 3, column = 1, columnspan = 2)
My understanding is that only if an if statement is false does the else command execute. However, the else statement seems to be overriding the if statement with this code. I am unsure of how to write a loop that will function so that:
if the keyword is in the csvfile
then the row with the keyword is inserted to a blank widget
if the keyword is not in the csvfile
then a box with text 'Not Found' is displayed
When your else condition is observed at least once in the for loop, the text will change. So, your if statement code is likely still being evaluated, but you are also observing the else behavior in the same loop. Try this:
import csv
from tkinter import *
import tkinter.messagebox as box
master = Tk()
label1 = Label(master, text = 'User_ID', relief = 'groove', width = 40)
label2 = Label(master, text = 'User_Info', relief = 'groove', width = 40, height = 5)
e1 = Entry(master, relief = 'groove', width = 40)
e2 = Text(master, relief = 'groove', width = 40, height = 5, borderwidth = 2)
def enter():
csvfile = open('stack_example.csv', 'r')
read = csv.reader(csvfile)
contains_keyword = False
for row in read:
if str(e1.get()) in row:
contains_keyword = True
break
if contains_keyword:
e2.insert("1.0", row, 'r')
else:
box.showinfo('Search Result','Not Found')
master.mainloop()
button3 = Button(master, text = 'Retrieve File', relief = 'groove', width = 25, command=enter)
label1.grid( row = 1, column = 1, padx = 10 )
label2.grid( row = 2, column = 1, padx = 10 )
e1.grid( row = 1, column = 2, padx = 10 )
e2.grid( row = 2, column = 2, padx = 10 )
button3.grid( row = 3, column = 1, columnspan = 2)
Thank you for reading. I am new to coding and have googled this problem and consulted text resources without success. I do not have access to a teacher. I did my best to create a version of the problem in as simple a way as I could. I greatly appreciate your time and effort in helping me to solve this problem.
I am working in Python using IDLE and tkinter.
I am trying to link two interfaces using tkinter. I designed the first interface to ask for two entries, (defined as factor1 and factor2). I also put a button on the first interface. I am trying to create a command for the button to open the second interface.
Once, the second interface is open, the second interface is designed to use the user inputs into the two entries from the first interface (defined as factor1 and factor2) as labels.
#First Interface
from tkinter import *
from tkinter.messagebox import *
master = Tk()
master.title('Getting Started')
label1 = Label(master, text = 'what is factor 1:', relief = 'groove', width = 19)
label2 = Label(master, text = 'what is factor 2:', relief = 'groove', width = 19)
factor1 = Entry(master, relief = 'groove', width = 12)
factor2 = Entry(master, relief = 'groove', width = 12)
button2 = Button(master, text = 'Go', relief = 'groove', width = 25)
label1.grid( row = 1, column = 1, padx = 10 )
label2.grid( row = 2, column = 1, padx = 10 )
factor1.grid( row = 1, column = 2, padx = 10 )
factor2.grid( row = 2, column = 2, padx = 10 )
button2.grid( row = 3, column = 1, columnspan = 2)
#Second Interface
from tkinter import *
from tkinter.messagebox import *
mydict = {'good':0.75, 'outstanding': 1}
master = Tk()
label1 = Label(master, text = 'proposal', relief = 'groove', width = 19)
label2 = Label(master, text = factor1, relief = 'groove', width = 19)
label3 = Label(master, text = factor2, relief = 'groove', width = 19)
label4 = Label(master, text = 'Proposal Score', relief = 'groove', width = 19)
label5 = Label(master, text = '1', relief = 'groove', width = 12)
entry1 = Entry(master, relief = 'groove', width = 12)
entry2 = Entry(master, relief = 'groove', width = 12)
blank1 = Entry(master, relief = 'groove', width = 12)
def show_answer():
c = float( mydict[entry1.get()]) *float( mydict[entry2.get()])
blank1.insert(0, c)
button1 = Button(master, text = 'Calculate Proposal Scores', relief = 'groove', width = 25, command = show_answer)
label1.grid( row = 1, column = 1, padx = 10 )
label2.grid( row = 1, column = 2, padx = 10 )
label3.grid( row = 1, column = 3, padx = 10 )
label4.grid( row = 1, column = 4, padx = 10 )
label5.grid( row = 2, column = 1, padx = 10 )
entry1.grid( row = 2, column = 2, padx = 10 )
entry2.grid( row = 2, column = 3, padx = 10 )
blank1.grid( row = 2, column = 4, padx = 10 )
button1.grid( row = 3, column = 2, columnspan = 2)
Right now, both interfaces are in one IDLE document. However, I am unsure whether they should be kept in separate files.
My questions are:
Should I use one IDLE file or two?
If one, how do I make two separate interfaces in one idle file?
If two, how do I link the information, so that the second interface can use the inputs entered in the first interface?
How do I create a command so that the button is able to signal to close interface one and open interface two?
I understand this question may be complicated. If you have any additional books or resources to recommend I would greatly appreciate it. Additionally, if you have any suggestions on how I could make this question better, I would greatly appreciate it. Thank you!
Whether you use one file or two is completely up to you. If the code was very long, I'd recommend splitting into two files, but it's short enough that there's nothing wrong with keeping it all in the same file.
What you should do, however, is to separate the code into two functions. One function will open the first window and ask the user to input the two factors. Then when the button is pressed, it will take the two factors and use them as arguments for the second function (which opens the 2nd window). The code looks like this:
from tkinter import *
from tkinter.messagebox import *
def first_interface():
master = Tk()
master.title('Getting Started')
label1 = Label(master, text = 'what is factor 1:', relief = 'groove', width = 19)
label2 = Label(master, text = 'what is factor 2:', relief = 'groove', width = 19)
factor1 = Entry(master, relief = 'groove', width = 12)
factor2 = Entry(master, relief = 'groove', width = 12)
def start_second_interface():
f1 = float(factor1.get())
f2 = float(factor2.get())
second_interface(f1, f2)
button2 = Button(master, text = 'Go', relief = 'groove', width = 25, command=start_second_interface)
label1.grid( row = 1, column = 1, padx = 10 )
label2.grid( row = 2, column = 1, padx = 10 )
factor1.grid( row = 1, column = 2, padx = 10 )
factor2.grid( row = 2, column = 2, padx = 10 )
button2.grid( row = 3, column = 1, columnspan = 2)
def second_interface(factor1, factor2):
mydict = {'good':0.75, 'outstanding': 1}
master = Toplevel()
label1 = Label(master, text = 'proposal', relief = 'groove', width = 19)
label2 = Label(master, text = factor1, relief = 'groove', width = 19)
label3 = Label(master, text = factor2, relief = 'groove', width = 19)
label4 = Label(master, text = 'Proposal Score', relief = 'groove', width = 19)
label5 = Label(master, text = '1', relief = 'groove', width = 12)
entry1 = Entry(master, relief = 'groove', width = 12)
entry2 = Entry(master, relief = 'groove', width = 12)
blank1 = Entry(master, relief = 'groove', width = 12)
def show_answer():
c = float( mydict[entry1.get()]) *float( mydict[entry2.get()])
blank1.insert(0, c)
button1 = Button(master, text = 'Calculate Proposal Scores', relief = 'groove', width = 25, command = show_answer)
label1.grid( row = 1, column = 1, padx = 10 )
label2.grid( row = 1, column = 2, padx = 10 )
label3.grid( row = 1, column = 3, padx = 10 )
label4.grid( row = 1, column = 4, padx = 10 )
label5.grid( row = 2, column = 1, padx = 10 )
entry1.grid( row = 2, column = 2, padx = 10 )
entry2.grid( row = 2, column = 3, padx = 10 )
blank1.grid( row = 2, column = 4, padx = 10 )
button1.grid( row = 3, column = 2, columnspan = 2)
first_interface()
This has solved all your problems in a single simple step: The code is neatly organized, and you can easily pass the two factors to the second window.
(P.S. I've used a tk.TopLevel instead of a tk.Tk for the second window. There should be exactly one tk.Tk instance in each program. If you use more than one, you're going to run into problems.)