I am trying to achieve grabbing par02_1 using .get(). I have success writing the rest of the .txt file but my program is not grabbing my gui entry lines. I'm guessing this has something to do with the association self, and the scrollable section, etc. but I can't track this one down. Any help is appreciated.
from tkinter import *
from tkinter import ttk
import tkinter.messagebox
import time
root = Tk()
# GUI Window
root.title("Outfile Automation")
# Gui Future Menu Logic
def future01():
print("Future Command 01")
# GUI Main Menu
menu = Menu(root)
root.config(menu=menu)
subMenu = Menu(menu)
menu.add_cascade(label="File", menu=subMenu)
subMenu.add_command(label="New Script...", command=future01)
subMenu.add_separator()
subMenu.add_command(label="Exit Program", command=future01)
helpMenu = Menu(menu)
menu.add_cascade(label="Help", menu=helpMenu, command=future01)
helpMenu.add_command(label="Instruction Manual", command=future01)
helpMenu.add_command(label="Software Version: A0.003")
##Scrollbar
class VerticalScrolledFrame(Frame):
def __init__(self, parent, *args, **kw):
Frame.__init__(self, parent, *args, **kw)
# create a canvas object and a vertical scrollbar for scrolling it
vscrollbar = Scrollbar(self, orient=VERTICAL)
vscrollbar.pack(fill=Y, side=RIGHT, expand=FALSE)
canvas = Canvas(self, bd=0, highlightthickness=0,
yscrollcommand=vscrollbar.set)
canvas.pack(side=LEFT, fill=BOTH, expand=TRUE)
vscrollbar.config(command=canvas.yview)
# reset the view
canvas.xview_moveto(0)
canvas.yview_moveto(0)
# create a frame inside the canvas which will be scrolled with it
self.interior = interior = Frame(canvas)
interior_id = canvas.create_window(0, 0, window=interior,
anchor=NW)
# track changes to the canvas and frame width and sync them,
# also updating the scrollbar
def _configure_interior(event):
# update the scrollbars to match the size of the inner frame
size = (interior.winfo_reqwidth(), interior.winfo_reqheight())
canvas.config(scrollregion="0 0 %s %s" % size)
if interior.winfo_reqwidth() != canvas.winfo_width():
# update the canvas's width to fit the inner frame
canvas.config(width=interior.winfo_reqwidth())
interior.bind('<Configure>', _configure_interior)
def _configure_canvas(event):
if interior.winfo_reqwidth() != canvas.winfo_width():
# update the inner frame's width to fill the canvas
canvas.itemconfigure(interior_id, width=canvas.winfo_width())
canvas.bind('<Configure>', _configure_canvas)
if __name__ == "__main__":
class AutoApp(Tk):
def __init__(self, *args, **kwargs):
root = Tk.__init__(self, *args, **kwargs)
self.frame = VerticalScrolledFrame(root)
self.frame.pack()
self.label = Label(text="")
self.label.pack()
self.par02_1 = StringVar()
title_1 = Label(self.frame.interior, text="Device IP (DHCP)", fg="blue", font="Verdana 10 underline")
title_1.pack()
label_1 = Label(self.frame.interior, text="Device 01")
label_1.pack()
entry_1 = Entry(self.frame.interior, textvariable=self.par02_1)
entry_1.pack()
outFile = open('CSC.txt', 'wt')
outFile.write("[Script Header]\nDebugStrings=on\nAbortOnError=on\nConcurrentSectionLimit=230\n"
"//23 Devices if necessary""\n\n[Variables]""\n"
+ (self.par02_1.get()) + "\n\n"
"[Device01]\nConnect=tcp |proc01|\nRunAsSingleTransaction=on\nEthernetDHCPHost "
+ (self.par02_1.get()) + "EthernetCurrentConnectionInfo\n")
outFile.close()
def muser():
feedback_1 = Label(root, text="Creating Script...").pack()
feedback_2 = Label(root, text="Script Complete!").pack()
time.sleep(2)
return
# GUI Buttons
mbutton = Button(root, text="Create Script", command=muser, fg="black", bg='green')
mbutton.pack()
app = AutoApp()
app.mainloop()
Hello thank you both for your guidance as I learn proper syntax. I have a long way to go but you both helped point me in the right direction so I can get my program online. I stripped this down to the basics and will implement a variation of the following architecture in my actual code.
from tkinter import *
from tkinter import ttk
import tkinter.messagebox
import time
root = Tk()
# GUI Window
root.title("Outfile Automation")
# Gui Future Menu Logic
def future01():
print("Future Command 01")
# GUI Main Menu
menu = Menu(root)
root.config(menu=menu)
subMenu = Menu(menu)
menu.add_cascade(label="File", menu=subMenu)
subMenu.add_command(label="New Script...", command=future01)
subMenu.add_separator()
subMenu.add_command(label="Exit Program", command=future01)
helpMenu = Menu(menu)
menu.add_cascade(label="Help", menu=helpMenu, command=future01)
helpMenu.add_command(label="Instruction Manual", command=future01)
helpMenu.add_command(label="Software Version: A0.003")
par02_1 = StringVar()
title_1 = Label(root, text="Device IP (DHCP)", fg="blue", font="Verdana 10 underline")
title_1.pack()
label_1 = Label(root, text="Device 01")
label_1.pack()
entry_1 = Entry(root, textvariable=par02_1)
entry_1.pack()
root.mainloop()
template = """[Script Header]\nDebugStrings=on\nAbortOnError=on\nConcurrentSectionLimit=230\n//23 Devices if necessary
\n\n[Variables]\n{}\n\n[Device01]\nConnect=tcp |proc01|\nRunAsSingleTransaction=on\nEthernetDHCPHost\nEthernetCurrentConnectionInfo\n"""
outFile = open('CSC.txt', 'wt')
outFile.write(template.format(par02_1.get()).rstrip())
outFile.close()
root.mainloop()
Related
Hi guys i'm having trouble with a scrollbar, in the photo you can see the grey box that is a simple listbox, how to put the scrollbar in that red specific position, and not in the right or bottom end of the screen just like te normal scollbar? Thanks!
adding code:
from tkinter import *
from ctypes import windll
def inserisci_spesa():
global lista_spese
global testo_nuova_spesa
if testo_nuova_spesa.get() != "":
lista_spese.insert(0,testo_nuova_spesa.get())
def invio_aggiungi_spesa(e):
window.bind("<Return>",illumina_aggiungi_spesa)
def illumina_aggiungi_spesa(e):
bottone_inserisci_spesa.config(bg="#052b4d")
window.after(200,illumina_aggiungi_spesa2)
def illumina_aggiungi_spesa2():
bottone_inserisci_spesa.config(bg="#1e476b")
window.after(0,inserisci_spesa)
def invio_descrivi_spesa(e):
window.bind("<Return>",illumina_descrivi_spesa)
def illumina_descrivi_spesa(e):
global bottone_inserisci_descrizione
bottone_inserisci_descrizione.config(bg="#052b4d")
window.after(200,illumina_descrivi_spesa2)
def illumina_descrivi_spesa2():
global bottone_inserisci_descrizione
bottone_inserisci_descrizione.config(bg="#1e476b")
windll.shcore.SetProcessDpiAwareness(1)
window = Tk()
frame = Frame (window)
frame.pack(padx=150, pady=150)
window.geometry("1500x770")
window.title ("Gestione spese")
window.call('wm', 'iconphoto', window._w, PhotoImage(file="trasparente.png"))
sfondo = PhotoImage(file="soldi.png")
etichetta_sfondo = Label(window,image=sfondo)
etichetta_sfondo.place(x=0,y=0)
testo_nuova_spesa = Entry(window,borderwidth=5,font=("Ink Free",20),width=9,bg="#f2f2f2")
testo_nuova_spesa.place(x=36,y=80)
testo_nuova_spesa.bind("<FocusIn>",invio_aggiungi_spesa)
descrizione_testo_nuova_spesa = Label(window,text="Nuova spesa",bg="#64d981",font=("Ink Free",19),relief="solid",borderwidth=1)
descrizione_testo_nuova_spesa.place(x=40,y=28)
testo_descrivi_spesa = Entry(window,borderwidth=5,font=("Ink Free",20),width=22,bg="#f2f2f2")
testo_descrivi_spesa.place(x=300,y=80)
testo_descrivi_spesa.bind("<FocusIn>",invio_descrivi_spesa)
descrizione_testo_descrivi_spesa = Label(window,text="Descrizione",bg="#64d981",font=("Ink Free",19),relief="solid",borderwidth=1)
descrizione_testo_descrivi_spesa.place(x=304.5,y=28)
bottone_inserisci_spesa = Button(window,text="Inserisci",font=("Ink Free",15),bg="#1e476b",fg="white",activebackground="#052b4d",activeforeground="white",command=inserisci_spesa)
bottone_inserisci_spesa.place(x=36,y=140)
bottone_inserisci_descrizione = Button(window,text="Inserisci",font=("Ink Free",15),bg="#1e476b",fg="white",activebackground="#052b4d",activeforeground="white")
bottone_inserisci_descrizione.place(x=300,y=140)
lista_spese = Listbox(frame)
lista_spese.pack(side=LEFT)
lista_spese.configure(font=('Courier 20 '), width=21, height=9, bg="#4a4a4a", fg="#dedede",relief="solid",borderwidth=4)
etichetta_lista_spese = Label(window,text="Lista delle spese",bg="#64d981",font=("Ink Free",19),relief="solid",borderwidth=1)
etichetta_lista_spese.place(x=720,y=270)
scrollbar = Scrollbar(frame,command=lista_spese.yview)
scrollbar.pack(side=RIGHT,fill=Y)
lista_spese.config(yscrollcommand=scrollbar.set)
window.mainloop()
Simply put both (Listbox and Scrollbar) in the same Frame to group them.
Minimal working code
import tkinter as tk
root = tk.Tk()
root['bg'] = '#ff8080'
# - create -
frame = tk.Frame(root)
frame.pack(padx=150, pady=150)
listbox = tk.Listbox(frame)
listbox.pack(side='left', fill='both', expand=True)
scrollbar = tk.Scrollbar(frame, orient='vertical', command=listbox.yview)
scrollbar.pack(side='right', fill='y')
#scrollbar.pack(side='left', fill='y') # `left` also works
listbox.config(yscrollcommand=scrollbar.set)
# - add some values to listbox for scrolling -
for i in range(50):
listbox.insert('end', str(i))
# - start -
root.mainloop()
Result:
EDIT:
You may also use Frame to create own widget ScrolledListbox and then you can reuse it many times.
import tkinter as tk
class ScrolledListbox(tk.Frame):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.listbox = tk.Listbox(self)
self.listbox.pack(side='left', fill='both', expand=True)
self.scrollbar = tk.Scrollbar(self, orient='vertical', command=self.listbox.yview)
self.scrollbar.pack(side='right', fill='y')
#self.scrollbar.pack(side='left', fill='y') # `left` also works
self.listbox.config(yscrollcommand=self.scrollbar.set)
# - main -
root = tk.Tk()
root['bg'] = '#ff8080'
# - create -
lb1 = ScrolledListbox(root)
lb1.pack(side='left', fill='both', expand=True, padx=25, pady=25)
lb2 = ScrolledListbox(root)
lb2.pack(side='left', fill='both', expand=True, padx=25, pady=25)
lb3 = ScrolledListbox(root)
lb3.pack(side='left', fill='both', expand=True, padx=25, pady=25)
# - add some values to listbox for scrolling -
for i in range(50):
lb1.listbox.insert('end', str(i))
lb2.listbox.insert('end', str(i+100))
lb3.listbox.insert('end', str(i+200))
# - start -
root.mainloop()
This is to be a desktop application for opening multiple small databases and running queries on them. So far I've written some code for opening forms as necessary. Is this a good way to do it? Also - the code shown opens two copies of each form - what am I doing wrong? It's my first attempt at Python and I'm a rudimentary programmer so simple answers would be of most help please. TIA (Python 3.9.6)
link_1.py
from tkinter import Tk
import link_2
root = Tk()
class ClassLink_1:
#if another function in the class is called, the __init__ function is run at start up
def __init__(self):
print("in link_1 __init__ instruction")
#the call_function function can be called at start up, or not, and will act accordingly
def call_function(self):
print("in call_function")
#the line below is run at start up whether or not another function in the class is called
print("in link_1")
root.withdraw() #hides the blank form at start up
#if __name__ == "__main__":
#the line below shows the link_2 form, whether or not the if __name__==__main__ condition is used as its condition
link_2.ClassLink_2(root).__init__(root)
#link_3.ClassLink_3(root).__init__(root)
#the line below runs call_function on start up to print text
ClassLink_1().call_function()
root.mainloop()
link_2.py
from tkinter import Tk, Button
from tkinter import * #for Toplevel
import link_3
root = Tk()
class ClassLink_2:
def __init__(self, master):
self.openNewWindow()
def openNewWindow(self):
newWindow = Toplevel(root) #creates a top level widget with the parent root (first parameter)
newWindow.title("Title opened from link_1")
newWindow.geometry("500x500")
label = Label(newWindow, text ="Opened from link_1").grid(row=1, column=1)
self.add_button = Button(newWindow, text="in ClassLink_2", command= self.do_add)
self.add_button.grid(row=3, column=1)
def do_add(self):
print("button pressed")
link_3.ClassLink_3(root).__init__(root)
root.withdraw() #hides the blank form at start up
link_3.py
from tkinter import Tk, Button
from tkinter import * #for Toplevel
root = Tk()
class ClassLink_3:
def __init__(self, master):
self.openNewWindow()
def openNewWindow(self):
newWindow = Toplevel(root) #creates a top level widget with the parent root (first parameter)
newWindow.title("Title opened from link_2")
newWindow.geometry("500x500")
label = Label(newWindow, text ="Opened from link_2").grid(row=1, column=1)
self.add_button = Button(newWindow, text="in ClassLink_3", command= self.do_add)
self.add_button.grid(row=3, column=1)
def do_add(self):
print("button pressed")
# link_4.ClassLink_4(root).__init__(root) this file has not yet been made
root.withdraw() #hides the blank form at start up
This is a proposed solution, can be expanded as needed. Constructive suggestions for improvement of the structure or code would be appreciated. TIA. I've left in the details in case they are of use to anyone.
link_1
from tkinter import Tk
import link_2
root = Tk()
class ClassLink_1:
def __init__(self):
print("in link_1 __init__ instruction")
root.withdraw() #hides the blank form at start up
link_2.ClassLink_2(root).openNewWindow(0)
root.mainloop()
link_2
from tkinter import Tk, Button
from tkinter import *
import link_3
root = Tk()
class ClassLink_2:
root.withdraw() #hides the blank form at start up
class_var_1 = 0
inst_var_1 = 0
def __init__(self, incoming_inst_var_1):
pass
def openNewWindow(self, inst_var_1_to_open):
newWindow = Toplevel(root)
newWindow.title("Title opened from link_1")
newWindow.geometry("500x500")
label = Label(newWindow, text ="Opened from link_1").grid(row=1, column=1)
self.add_button = Button(newWindow, text="in ClassLink_2", command= self.do_add)
self.add_button.grid(row=3, column=1)
self.add_button = Button(newWindow, text="increment class_var_1", command= self.inc_class_var_1)
self.add_button.grid(row=5, column=1)
self.inst_var_1 = inst_var_1_to_open
def do_add(self):
print("button pressed")
link_3.ClassLink_3(root).openNewWindow(0)
def inc_class_var_1(self):
ClassLink_2.class_var_1 += 2
self.inst_var_1 += 1
print("self.class_var_1 = " + (str)(self.class_var_1))
print("self.inst_var_1 = " + (str)(self.inst_var_1))
link_3
from tkinter import Tk, Button
from tkinter import *
from tkinter.ttk import Combobox
import tkinter.scrolledtext as tkscrolled
# import link_4 <filename of next form>
root = Tk()
class ClassLink_3:
class_var_1 = 0
inst_var_1 = 0
# ------------------------------- START CLASS CONTROLS -----------------------------
root.withdraw()
def __init__(self, incoming_inst_var_1):
pass
def openNewWindow(self, inst_var_1_to_open):
new_window = Toplevel(root)
self.widget_factory(new_window)
self.inst_var_1 = inst_var_1_to_open
def do_add(self):
print("button pressed")
# link_4.ClassLink_4(root).openNewWindow(0) # <filename of next form>
# ---------------------------------- END CLASS CONTROLS -----------------------------
# -------------------------------------- START CALCS --------------------------------------
def inc_class_var_1(self):
ClassLink_3.class_var_1 += 2
self.inst_var_1 += 1
print("self.class_var_1 = " + (str)(self.class_var_1))
print("self.inst_var_1 = " + (str)(self.inst_var_1))
# ---------------------------------------- END CALCS --------------------------------------
# ---------------------------------------- START FACTORY SHOPS-----------------------------------------
def widget_factory(self, new_window):
self.shop_window(new_window)
self.shop_labels(new_window)
self.shop_buttons(new_window)
self.shop_menu(new_window)
self.shop_listbox(new_window)
self.shop_combobox(new_window)
self.shop_radiobuttons(new_window)
self.shop_checkbuttons(new_window)
self.shop_entries(new_window)
self.shop_canvas(new_window)
self.shop_scale(new_window)
self.shop_scrollbars(new_window)
self.shop_textbox(new_window)
self.shop_menu(new_window)
pass
# ------------------------
def shop_window(self, new_window):
new_window.title("Title opened from link_2")
new_window.geometry("800x900")
def shop_labels(self, new_window):
self.label_1 = Label(new_window, text ="Opened from link_2").grid(row=1, column=1)
def shop_buttons(self, new_window):
self.button_1 = Button(new_window, text="in ClassLink_3", command= self.do_add)
self.button_1.grid(row=3, column=1)
self.button_2 = Button(new_window, text="increment class_var_1", command= self.inc_class_var_1)
self.button_2.grid(row=5, column=1)
def shop_listbox(self, new_window):
data=("one", "two", "three", "four")
self.listbox_1 = Listbox(new_window, height=5, selectmode='multiple')
for num in data:
self.listbox_1.insert(END,num)
self.listbox_1.grid(row=7, column=1)
def shop_combobox(self, new_window):
data=("one", "two", "three", "four")
self.combobox_1 = Combobox(new_window, values=data)
self.combobox_1.grid(row=8, column=3)
def shop_radiobuttons(self, new_window):
var_1 = IntVar()
var_1.set(1)
self.rad_btn_1 = Radiobutton(new_window, text="male", variable=var_1, value=1)
self.rad_btn_2 = Radiobutton(new_window, text="female", variable=var_1, value=2)
self.rad_btn_1.grid(row=9, column=1)
self.rad_btn_2.grid(row=9, column=2)
def shop_checkbuttons(self, new_window):
var_1 = IntVar()
var_2 = IntVar()
self.checkbtn_1 = Checkbutton(new_window, text = "Cricket", variable = var_1)
self.checkbtn_2 = Checkbutton(new_window, text = "Tennis", variable = var_2)
self.checkbtn_1.grid(row=10, column=1)
self.checkbtn_2.grid(row=10, column=2)
def shop_entries(self, new_window):
self.entry_1 = Entry(new_window, width = 20)
self.entry_1.insert(0,'Username')
self.entry_1.grid(row= 11, column=2)
self.entry_2 = Entry(new_window, width = 15)
self.entry_2.insert(0,'password')
self.entry_2.grid(row= 12, column=2)
#might want to place on a frame, see example https://coderslegacy.com/python/list-of-tkinter-widgets/
def shop_canvas(self, new_window):
canvas = Canvas(new_window, bg= 'white', width = 260,height = 260) #this is the background for the figure
# left and top of figure is from [x from left, y from top] of canvas right and bottom of figure from [x from left, y from top] of canvas
coordinates = 20, 50, 210, 230
arc = canvas.create_arc(coordinates, start=0, extent=250, fill="blue") #start is from E, extent is in degrees CCW
arc = canvas.create_arc(coordinates, start=250, extent=50, fill="red")
arc = canvas.create_arc(coordinates, start=300, extent=60, fill="yellow")
canvas.grid(row=2, column=1)
def shop_scale(self, new_window):
self.scale_1 = Scale(new_window, from_=0, to=10, orient=VERTICAL)
self.scale_1.grid(row=15, column=2)
self.scale_2 = Scale(new_window, from_=0, to=10, orient = HORIZONTAL)
self.scale_2.grid(row=15, column=3)
def shop_scrollbars(self, new_window):
self.scroll_vert = Scrollbar(new_window)
self.scroll_vert.grid(row=19, column=3)
self.listbox_3 = Listbox(new_window, yscrollcommand = self.scroll_vert.set )
for line in range(1, 100):
self.listbox_3.insert(END, "Number " + str(line))
self.listbox_3.grid(row=19 , column=2)
self.scroll_vert.config(command = self.listbox_3.yview)
def shop_textbox(self, new_window):
#make a frame with parent new_window
self.frame_textbox_1 = Frame(new_window)
self.frame_textbox_1.grid(row=1, column=5)
#make the textbox with parent frame
self.textbox_1 = Text(self.frame_textbox_1)
self.textbox_1.config(wrap=NONE, width=15, height=8) #width, height are characters x rows permitted wrap values should be WORD CHAR, or NONE
#make the X scrollbar with parent frame
self.scroll_text_horiz = Scrollbar(self.frame_textbox_1, orient="horizontal")
self.scroll_text_horiz.config(command = self.textbox_1.xview)
#make the Y scrollbar with parent frame
self.scroll_text_vert = Scrollbar(self.frame_textbox_1, orient="vertical")
self.scroll_text_vert.config(command = self.textbox_1.yview)
#pack the scrollbars before the texbox to allow them to fill the frame width and height
self.scroll_text_horiz.pack(side=BOTTOM, fill=X)
self.scroll_text_vert.pack(side=RIGHT, fill=Y)
self.textbox_1.pack(fill="y")
#connect the scrollbars to the textbox
self.textbox_1["xscrollcommand"] = self.scroll_text_horiz.set
self.textbox_1["yscrollcommand"] = self.scroll_text_vert.set
message = "the quick brown fox"
self.textbox_1.insert(1.1, message)
# ----------------------------------------------
def shop_menu(self, new_window):
print("in shop menu1")
menubar = Menu(new_window)
print("in shop_menu2")
file = Menu(menubar, tearoff=0)
file.add_command(label="New")
file.add_command(label="Open")
file.add_command(label="Save")
file.add_command(label="Save as...")
file.add_command(label="Close")
file.add_separator()
file.add_command(label="Exit", command=new_window.quit)
menubar.add_cascade(label="File", menu=file)
edit = Menu(menubar, tearoff=0)
edit.add_command(label="Undo")
edit.add_separator()
edit.add_command(label="Cut")
edit.add_command(label="Copy")
edit.add_command(label="Paste")
edit.add_command(label="Delete")
edit.add_command(label="Select All")
menubar.add_cascade(label="Edit", menu=edit)
help = Menu(menubar, tearoff=0)
help.add_command(label="About")
menubar.add_cascade(label="Help", menu=help)
new_window.config(menu=menubar)
print("in shop menu3")
# --------------------------------------- END FACTORY SHOPS---------------------------------------
I'm trying to make a sub window for configuration settings. But the text in the sub window is invisible. I am reading correctly but I cannot see the text. Below is my sample code with the problem:
import tkinter as tk
from tkinter import ttk
from tkinter import Menu
class Frames:
def __init__(self):
self.port_com = None
def main_frame(self, win):
# Main Frame
main = ttk.LabelFrame(win, text="")
main.grid(column=0, row=0, sticky="WENS", padx=10, pady=10)
return main
def dut_configuration_frame(self, win):
# Configuration Frame
dut_config_frame = ttk.LabelFrame(win, text="Config")
dut_config_frame.grid(column=0, row=0, sticky='NWS')
# Port COM
ttk.Label(dut_config_frame, text="Port COM").grid(column=0, row=0)
self.port_com = tk.StringVar()
ttk.Entry(dut_config_frame, width=12, textvariable=self.port_com).grid(column=0, row=1, sticky=tk.EW)
self.port_com.set(value="COM7")
print(self.port_com.get())
class ConfigFrames:
def __init__(self):
self.port_com = None
def main_frame(self, win):
# Main Frame
main = ttk.LabelFrame(win, text="")
main.grid(column=0, row=0, sticky="WENS", padx=10, pady=10)
return main
def configuration_frame(self, win):
# Configuration Frame
dut_config_frame = ttk.LabelFrame(win, text="Config")
dut_config_frame.grid(column=0, row=0, sticky='NWS')
# Port COM
ttk.Label(dut_config_frame, text="Port COM").grid(column=0, row=0)
self.port_com = tk.StringVar()
ttk.Entry(dut_config_frame, width=12, textvariable=self.port_com).grid(column=0, row=1, sticky=tk.EW)
self.port_com.set(value="COM5")
print(self.port_com.get())
def menu_bar(win):
def _config():
config_frame = ConfigFrames()
config_window = tk.Tk()
config_window.title("Sub window")
config_window.geometry("200x200")
config_window.resizable(0, 0)
main = config_frame.main_frame(config_window)
config_frame.configuration_frame(main)
config_window.mainloop()
# Menu
menuBar = Menu(win)
win.config(menu=menuBar)
settingsMenu = Menu(menuBar, tearoff=0)
settingsMenu.add_command(label="Config", command=_config)
menuBar.add_cascade(label="Settings", menu=settingsMenu)
frames = Frames()
win = tk.Tk()
win.title("Main window")
win.geometry("200x200")
win.resizable(0, 0)
menu_bar(win)
main = frames.main_frame(win)
frames.dut_configuration_frame(win)
win.mainloop()
As you can see in main window it is visible, but in sub window it is invisible.
And printing in console is correct:
I want to make a lot of notebook tabs, and I want to put them in canvas and to add a horizontal scrollbar so that I can scroll trough them.
I set the canvas size, but canvas size keep changing when I add new tab. Also, scrollbar does not work, can you tell me what am I doing wrong?
The program does not show me any error. This is the code:
from tkinter import *
from tkinter import ttk
myApp = Tk()
myApp.title(" Program ")
myApp.geometry("900x500")
CanvasTabs = Canvas(myApp, width=50, height=50)
CanvasTabs.grid(row=0,column=0)
tabs = ttk.Notebook(CanvasTabs, width=100, height=100)
tab1 = ttk.Frame(tabs)
tabs.add(tab1,text=" Tab 1 ")
tab2 = ttk.Frame(tabs)
tabs.add(tab2,text=" Tab 2 ")
tab3 = ttk.Frame(tabs)
tabs.add(tab3,text=" Tab 3 ")
tab4 = ttk.Frame(tabs)
tabs.add(tab4,text=" Tab 4 ")
hbar=Scrollbar(CanvasTabs,orient=HORIZONTAL)
hbar.pack(side=TOP,fill=X)
hbar.config(command=CanvasTabs.xview)
CanvasTabs.config(xscrollcommand=hbar.set)
tabs.pack(expand=1, fill="both")
myApp.mainloop()
I code a widget to fix the problem. Here is a real solution:
https://github.com/muhammeteminturgut/ttkScrollableNotebook
# -*- coding: utf-8 -*-
# Copyright (c) Muhammet Emin TURGUT 2020
# For license see LICENSE
from tkinter import *
from tkinter import ttk
class ScrollableNotebook(ttk.Frame):
def __init__(self,parent,*args,**kwargs):
ttk.Frame.__init__(self, parent, *args)
self.xLocation = 0
self.notebookContent = ttk.Notebook(self,**kwargs)
self.notebookContent.pack(fill="both", expand=True)
self.notebookTab = ttk.Notebook(self,**kwargs)
self.notebookTab.bind("<<NotebookTabChanged>>",self._tabChanger)
slideFrame = ttk.Frame(self)
slideFrame.place(relx=1.0, x=0, y=1, anchor=NE)
leftArrow = ttk.Label(slideFrame, text="\u25c0")
leftArrow.bind("<1>",self._leftSlide)
leftArrow.pack(side=LEFT)
rightArrow = ttk.Label(slideFrame, text=" \u25b6")
rightArrow.bind("<1>",self._rightSlide)
rightArrow.pack(side=RIGHT)
self.notebookContent.bind( "<Configure>", self._resetSlide)
def _tabChanger(self,event):
self.notebookContent.select(self.notebookTab.index("current"))
def _rightSlide(self,event):
if self.notebookTab.winfo_width()>self.notebookContent.winfo_width()-30:
if (self.notebookContent.winfo_width()-(self.notebookTab.winfo_width()+self.notebookTab.winfo_x()))<=35:
self.xLocation-=20
self.notebookTab.place(x=self.xLocation,y=0)
def _leftSlide(self,event):
if not self.notebookTab.winfo_x()== 0:
self.xLocation+=20
self.notebookTab.place(x=self.xLocation,y=0)
def _resetSlide(self,event):
self.notebookTab.place(x=0,y=0)
self.xLocation = 0
def add(self,frame,**kwargs):
if len(self.notebookTab.winfo_children())!=0:
self.notebookContent.add(frame, text="",state="hidden")
else:
self.notebookContent.add(frame, text="")
self.notebookTab.add(ttk.Frame(self.notebookTab),**kwargs)
def forget(self,tab_id):
self.notebookContent.forget(tab_id)
self.notebookTab.forget(tab_id)
def hide(self,tab_id):
self.notebookContent.hide(tab_id)
self.notebookTab.hide(tab_id)
def identify(self,x, y):
return self.notebookTab.identify(x,y)
def index(self,tab_id):
return self.notebookTab.index(tab_id)
def insert(self,pos,frame, **kwargs):
self.notebookContent.insert(pos,frame, **kwargs)
self.notebookTab.insert(pos,frame,**kwargs)
def select(self,tab_id):
self.notebookContent.select(tab_id)
self.notebookTab.select(tab_id)
def tab(self,tab_id, option=None, **kwargs):
return self.notebookTab.tab(tab_id, option=None, **kwargs)
def tabs(self):
return self.notebookContent.tabs()
def enable_traversal(self):
self.notebookContent.enable_traversal()
self.notebookTab.enable_traversal()
Taking Bryan's example on this post and modifying it to include your Notebook code we get a functioning scrollbar that will allow you to scroll over your Notebook widget if it exceeds the limit of the window.
Bryan's example uses the pack() geometry manager however I personally find grid() easier to visualize so I replace pack with grid() in my example.
UPDATE:
import tkinter as tk
import tkinter.ttk as ttk
class Example(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.canvas = tk.Canvas(self, borderwidth=0)
self.frame = tk.Frame(self.canvas)
self.vsb = tk.Scrollbar(self, orient="horizontal", command=self.canvas.xview)
self.vsb.grid(row=1, column=0, sticky="nsew")
self.canvas.configure(xscrollcommand=self.vsb.set)
self.canvas.grid(row=0, column=0, sticky="nsew")
self.canvas.create_window((3,2), window=self.frame, anchor="nw", tags="self.frame")
self.frame.bind("<Configure>", self.frame_configure)
self.populate()
def populate(self):
tabs = ttk.Notebook(self.frame, width=100, height=100)
for tab in range(50):
tabs.add(ttk.Frame(tabs), text=" Tab {} ".format(tab))
tabs.grid(row=0, column=0, sticky="ew")
def frame_configure(self, event):
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
if __name__ == "__main__":
app = Example()
app.mainloop()
Updated results:
Per your request in the comments here is a Non-OOP example:
import tkinter as tk
import tkinter.ttk as ttk
root = tk.Tk()
canvas = tk.Canvas(root, borderwidth=0)
frame = tk.Frame(canvas)
vsb = tk.Scrollbar(root, orient="horizontal", command=canvas.xview)
vsb.grid(row=1, column=0, sticky="nsew")
canvas.configure(xscrollcommand=vsb.set)
canvas.grid(row=0, column=0, sticky="nsew")
canvas.create_window((3,2), window=frame, anchor="nw", tags="frame")
tabs = ttk.Notebook(frame, width=100, height=100)
for tab in range(50):
tabs.add(ttk.Frame(tabs), text=" Tab {} ".format(tab))
tabs.grid(row=0, column=0, sticky="ew")
def frame_configure(event):
global canvas
canvas.configure(scrollregion=canvas.bbox("all"))
frame.bind("<Configure>", frame_configure)
root.mainloop()
I'm learning how to use Anaconda because I want the statistics functions. However, I would like to do all of the work and data entry on the canvas with tkinter. Eventually, draw normal distributions. I am unsure how to draw a grid on the canvas and then prompt the user to enter data into four cells and then process the data all on the canvas. I would like this to eventually be a stand alone program.
import tkinter as tk
import numpy
import math
def fishers():
cell_a = input("Enter Cell A value: ")
cell_b = input("Enter Cell B value: ")
cell_c = input("Enter Cell C value: ")
cell_d = input("Enter Cell D value: ")
cell_a = float(cell_a)
cell_b = float(cell_b)
cell_c = float(cell_c)
cell_d = float(cell_d)
fenum = math.factorial(cell_a+cell_b)*math.factorial(cell_c+cell_d)*
math.factorial(cell_a+cell_c)*math.factorial(cell_b+cell_d)
feden =
math.factorial(cell_a)*math.factorial(cell_b)*math.factorial(cell_c)*
math.factorial(cell_d)*math.factorial(cell_a+cell_b+cell_c+cell_d)
fe = fenum/feden
print ("Fishers Exact: =\t {:>8.4f}\n".format(fe))
#This is test code to see if I can write into the canvas
self.fishers.canvas.create_text(100,10,fill="darkblue",font="Times 20
italic bold", text="We will enter the data here.")
class Window(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.master = master
self.main_window()
self.widgets()
# All main window parameters go here
def main_window(self):
self.master.title("Quick-Statistics Calculator")
self.master.geometry("1000x800")
self.pack()
def widgets(self):
main_menu = tk.Menu(self.master, tearoff=0)
self.master.config(menu=main_menu)
# Create File Menu and Drop Down
file = tk.Menu(main_menu, tearoff=0)
file.add_command(label="Save")
file.add_separator()
file.add_command(label="Exit", command=exit)
main_menu.add_cascade(label="File", menu=file)
# Create Edit Menu and Drop Down
edit = tk.Menu(main_menu, tearoff=0)
edit.add_command(label="Undo")
main_menu.add_cascade(label="Edit", menu=edit)
#Create Means Analysis Menu and Drop Down
means = tk.Menu(main_menu,tearoff=0)
means.add_command(label="Group t")
means.add_command(label="Paired t")
means.add_separator()
means.add_command(label="ANOVA")
means.add_separator()
means.add_command(label="Mann-Whitney U")
means.add_command(label="Wilcoxon rank sum")
main_menu.add_cascade(label="Means", menu=means)
#Create Chi-square Analysis Menus and Drop Down
chi = tk.Menu(main_menu, tearoff=0)
chi.add_command(label="Chi-Square 2x2 table")
chi.add_command(label="Chi-Square for larger table")
chi.add_separator()
chi.add_command(label="McNemar's Test")
chi.add_command(label="Fisher's Exact", command=fishers)
main_menu.add_cascade(label="Tables", menu=chi)
#Create Help Menu
help = tk.Menu(main_menu, tearoff=0)
help.add_command(label="Means Analysis")
help.add_command(label="Chi-Square Analysis")
main_menu.add_cascade(label="Help",menu=help)
main = tk.Tk()
comm_prog = Window(master=main)
main.mainloop()
You can use Toplevel() to create window with Entry() and Button() to get values.
When you click button OK then it uses your code to calculate something and to put text on canvas.
import tkinter as tk
import numpy
import math
class Window(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
# self.master = master #super/Frame will do it
self.main_window()
self.widgets()
# All main window parameters go here
def main_window(self):
self.master.title("Quick-Statistics Calculator")
self.master.geometry("500x400")
self.pack()
def widgets(self):
main_menu = tk.Menu(self.master, tearoff=0)
self.master.config(menu=main_menu)
# Create File Menu and Drop Down
file = tk.Menu(main_menu, tearoff=0)
file.add_command(label="Save")
file.add_separator()
file.add_command(label="Exit", command=exit)
main_menu.add_cascade(label="File", menu=file)
# Create Edit Menu and Drop Down
edit = tk.Menu(main_menu, tearoff=0)
edit.add_command(label="Undo")
main_menu.add_cascade(label="Edit", menu=edit)
#Create Means Analysis Menu and Drop Down
means = tk.Menu(main_menu,tearoff=0)
means.add_command(label="Group t")
means.add_command(label="Paired t")
means.add_separator()
means.add_command(label="ANOVA")
means.add_separator()
means.add_command(label="Mann-Whitney U")
means.add_command(label="Wilcoxon rank sum")
main_menu.add_cascade(label="Means", menu=means)
#Create Chi-square Analysis Menus and Drop Down
chi = tk.Menu(main_menu, tearoff=0)
chi.add_command(label="Chi-Square 2x2 table")
chi.add_command(label="Chi-Square for larger table")
chi.add_separator()
chi.add_command(label="McNemar's Test")
chi.add_command(label="Fisher's Exact", command=self.window_fishers)
main_menu.add_cascade(label="Tables", menu=chi)
#Create Help Menu
help = tk.Menu(main_menu, tearoff=0)
help.add_command(label="Means Analysis")
help.add_command(label="Chi-Square Analysis")
main_menu.add_cascade(label="Help",menu=help)
self.canvas = tk.Canvas(self, width=500, height=400)
self.canvas.pack(fill='both', expand=True)
def window_fishers(self):
self.win = tk.Toplevel(self)
tk.Label(self.win, text="Enter Cell A value: ").grid(row=0, column=0)
tk.Label(self.win, text="Enter Cell B value: ").grid(row=1, column=0)
tk.Label(self.win, text="Enter Cell C value: ").grid(row=2, column=0)
tk.Label(self.win, text="Enter Cell D value: ").grid(row=3, column=0)
self.entry_a = tk.Entry(self.win)
self.entry_a.grid(row=0, column=1)
self.entry_b = tk.Entry(self.win)
self.entry_b.grid(row=1, column=1)
self.entry_c = tk.Entry(self.win)
self.entry_c.grid(row=2, column=1)
self.entry_d = tk.Entry(self.win)
self.entry_d.grid(row=3, column=1)
tk.Button(self.win, text='Cancel', command=self.win.destroy).grid(row=4, column=0)
tk.Button(self.win, text='OK', command=self.get_fishers).grid(row=4, column=1)
def get_fishers(self):
cell_a = float(self.entry_a.get())
cell_b = float(self.entry_b.get())
cell_c = float(self.entry_c.get())
cell_d = float(self.entry_d.get())
fenum = math.factorial(cell_a+cell_b)*math.factorial(cell_c+cell_d)*math.factorial(cell_a+cell_c)*math.factorial(cell_b+cell_d)
feden = math.factorial(cell_a)*math.factorial(cell_b)*math.factorial(cell_c)*math.factorial(cell_d)*math.factorial(cell_a+cell_b+cell_c+cell_d)
fe = fenum/feden
text = "Fishers Exact: =\t {:>8.4f}\n".format(fe)
#This is test code to see if I can write into the canvas
self.canvas.create_text(250, 100, fill="darkblue", font="Times 20 italic bold", text=text)
# close after entry.get()
self.win.destroy()
main = tk.Tk()
app = Window(main)
main.mainloop()