I have made "sticky notes" in python but how do I make the same open in another window when I press the new File (+ on the title bar) button? I thought of creating an object within the class but I don't think that's possible. Should I import and run similar file? Please suggest a method to do so. Suggestions to improve the code are welcomed.
Here's the code
from tkinter import *
import tkinter.scrolledtext as tkst
from tkinter import messagebox
from tkinter import font
class StickyNotes:
xclick = 0
yclick = 0
def __init__(self,master):
def get_pos(event):
self.xclick = event.x
self.yclick = event.y
def move_window(event):
master.geometry('+{0}+{1}'.format(event.x_root-self.xclick, event.y_root-self.yclick))
def another_window(event):
pass
def quit_window(event):
self.closebutton.config(relief = 'flat', bd = 0)
if(messagebox.askyesno('Delete Note?','Are you sure you want to delete this note?')):
master.destroy()
return
self.closebutton.config(relief = 'flat', bd = 0, bg = '#F8F7B6')
# master (root) window
master.overrideredirect(True)
master.geometry('250x250')
master.config(bg = '#838383')
master.resizable(True,True)
# titlebar
self.titlebar = Frame(root, bg = '#F8F796', relief = 'flat', bd = 2)
self.titlebar.bind('<Button-1>', get_pos)
self.titlebar.bind('<B1-Motion>', move_window)
self.titlebar.pack(fill = X, expand = 1, side = TOP)
self.closebutton = Label(self.titlebar, text = 'X', bg = '#F8F7B6', relief = 'flat')
self.closebutton.bind('<Button-1>', quit_window)
self.closebutton.pack(side = RIGHT)
self.newbutton = Label(self.titlebar, text = '+', bg = '#F8F7B6', relief = 'flat')
self.newbutton.pack(side = LEFT)
self.newbutton.bind('<Button-1>', another_window)
# main text area
self.mainarea = tkst.ScrolledText(master, bg = '#FDFDCA', font=('Comic Sans MS', 14, 'italic'), relief = 'flat', padx = 5, pady = 10)
self.mainarea.pack(fill = BOTH, expand = 1)
# frames to introduce shadows
self.shadow = Frame(root).pack(side=BOTTOM)
self.shadow = Frame(root).pack(side=RIGHT)
root = Tk()
root.attributes('-topmost', 'true')
sticky = StickyNotes(root)
root.mainloop()
You are using classes all wrong. One of the biggest advantages to using classes is the ability to steal code from Tkinter (or whatever GUI or framework you are trying to use). The Tkinter window class is called Toplevel, so you want to subclass that and use the class itself (named "self") for all your operations. I rewrote it for you:
from tkinter import *
import tkinter.scrolledtext as tkst
from tkinter import messagebox
from tkinter import font
class StickyNotes(Toplevel):
def __init__(self, master, **kwargs):
super().__init__(master, **kwargs)
self.xclick = 0
self.yclick = 0
# master (root) window
self.overrideredirect(True)
self.geometry('250x250+500+500')
self.config(bg = '#838383')
self.attributes('-topmost', 'true')
self.resizable(True,True)
# titlebar
self.titlebar = Frame(self, bg = '#F8F796', relief = 'flat', bd = 2)
self.titlebar.bind('<Button-1>', self.get_pos)
self.titlebar.bind('<B1-Motion>', self.move_window)
self.titlebar.pack(fill = X, expand = 1, side = TOP)
self.closebutton = Label(self.titlebar, text = 'X', bg = '#F8F7B6', relief = 'flat')
self.closebutton.bind('<Button-1>', self.quit_window)
self.closebutton.pack(side = RIGHT)
self.newbutton = Label(self.titlebar, text = '+', bg = '#F8F7B6', relief = 'flat')
self.newbutton.pack(side = LEFT)
self.newbutton.bind('<Button-1>', self.another_window)
# main text area
self.mainarea = tkst.ScrolledText(self, bg = '#FDFDCA', font=('Comic Sans MS', 14, 'italic'), relief = 'flat', padx = 5, pady = 10)
self.mainarea.pack(fill = BOTH, expand = 1)
# frames to introduce shadows
self.shadow = Frame(self).pack(side=BOTTOM)
self.shadow = Frame(self).pack(side=RIGHT)
def get_pos(self, event):
self.xclick = event.x
self.yclick = event.y
def move_window(self, event):
self.geometry('+{0}+{1}'.format(event.x_root-self.xclick, event.y_root-self.yclick))
def another_window(self, event):
sticky = StickyNotes(root)
def quit_window(self, event):
self.closebutton.config(relief = 'flat', bd = 0)
if(messagebox.askyesno('Delete Note?','Are you sure you want to delete this note?')):
self.destroy()
return
self.closebutton.config(relief = 'flat', bd = 0, bg = '#F8F7B6')
root = Tk()
root.withdraw()
sticky = StickyNotes(root) # make the first note.
root.mainloop()
Related
I have several larger tkinter / python program which I would like to incorporate into one program which would clear a frame when another program is called; each program currently being inside a function (I probably should use classes eventually when I understand them) and each of these function being displayed on a form being cleared of widgets from the previous if any do exist.
The code below is just a small trial for me to understand how to do this, but it's not working.
When I invoke the widget.destroy() function, it removes the frame (DisplayFrame) and does not clear the widgets inside it and hence not displaying the new widgets.
here is the current trial code:
#!/usr/bin/env python3
import tkinter as tk
from tkinter import *
from tkinter import ttk
#import pandas as pd
import MultiTempsP3
import datetime, time
from tkinter import messagebox
import sqlite3
from tkinter import colorchooser
from configparser import ConfigParser
import os
import csv
if os.environ.get('DISPLAY','') == "":
print('no display found.Using :0.0')
os.environ.__setitem__('DISPLAY',':0.0')
root = tk.Tk()
root.title("Kombucha Program")
root.geometry("1400x800")
root.minsize(width=900, height=600)
#root.maxsize(width=1400, height = 900)
root.grid_rowconfigure(3, weight=1)
root.grid_columnconfigure(2, weight=1)
root.configure( bg = '#000080' )
DisplayFrame = tk.Frame(root, width=1200, height = 630, bg = 'yellow') #0059b3')
DisplayFrame.grid(column=0,row=1, sticky = N, in_ = root)
rightFrame = tk.Frame(root, width = 120, height = 390, bg = 'white') # #000080
rightFrame.grid(column = 1, row = 0, pady = 10, padx = 10)
lblFrame = tk.Frame(root, height = 70, width = 670, bg = 'black')
lblFrame.grid(column = 0, row = 0, sticky =N, in_ = root)
##'W' stands for West = WrightFrmae (west fframe on the right of screen
#WrightFrame = tk.Frame(rightFrame, width = 70, height = 300, bg = 'green') # #000080
#WrightFrame.grid(column = 0, row = 1)
WidgetFrame = tk.Frame(root, height = 300, width = 120, bg = 'red') # #000080
WidgetFrame.grid(column=0,row=2, pady = 30)
fromTemp = MultiTempsP3.temps("65cd6bd")
lblTemp = Label(rightFrame, text=fromTemp).grid(row=1,column=0,pady=0 )
#lblTemp.pack()
def clearDisplayFrame():
for widgets in DisplayFrame.winfo_children():
widgets.destroy()
###***### - This section is in the right top little frame = rightFrame
state = "yes" ## delete this row and use below state=GPIO when on an RPi
#state = GPIO.input(17)
if state:
state_17="GPIO_17 (HeatPad) is On "
else:
state_17="GPIO_17 (HeatPad) is Off "
lblHeatPad = Label(rightFrame, text=state).grid(row=3,column=0,pady=0 ) #shows as text in the window
#lblHeatPad.pack() #organizes widgets in blocks before placing them in the parent.
###***### End of rightFrame widgets
def func_quit():
root.destroy()
def openData():
clearDisplayFrame()
print("I am inside openData()")
lbltrial=tk.Label(DisplayFrame,text="trial").grid(row=3, column=2)
def func_Temps():
clearDisplayFrame()
print("I am inside func_Temps()")
#DisplayFrame = tk.Frame(root, width=1200, height = 630, bg = 'yellow') #0059b3')
#DisplayFrame.grid(column=0,row=1, sticky = N, in_ = root)
lblSomething = tk.Label(DisplayFrame, text = "Open Temps").grid(row=2,column=2)
###***### This section is top of left = lblFrame
exitButton = tk.Button(lblFrame, text="Quit the Program", width = 12, command=root.destroy, bg= "magenta")
exitButton.grid(row = 0, column = 0, columnspan = 1, pady = 5, padx = 5)
dataButton = Button(lblFrame, text="Open Dates Window", command=openData).grid(row=0, column=1) ## the open refers to the above function
tempsButton= Button(lblFrame, text="Open Temps Info", command=func_Temps).grid(row=0, column=2)
###***### End of top left widget in lblFrame
mainloop()
As an answer, here is an approach that uses 2 frame and switches between them in the click of the switch. This is the way usually switching between frame is implemented in procedural programming, AFAIK:
from tkinter import *
root = Tk()
def change(frame):
frame.tkraise() # Raising the passed frame
window1 = Frame(root)
window2 = Frame(root)
window1.grid(row=0,column=0) # Grid in the same location so one will cover/hide the other
window2.grid(row=0,column=0)
# Contents inside your frame...
Label(window1,text='This is page 1',font=(0,21)).pack()
Label(window2,text='This is page 2',font=(0,21)).pack()
# Buttons to switch between frame by passing the frame as an argument
Button(root,text='Page 1',command=lambda: change(window1)).grid(row=1,column=0,stick='w')
Button(root,text='Page 2',command=lambda: change(window2)).grid(row=1,column=0,stick='e')
root.mainloop()
So instead of destroying all the items inside your frame, you should just raise the other frame, as destroyed widgets cannot be brought back.
I am trying to do a message box to warns the user in my UI that they will be moved to the homepage after 10 seconds, codes are as following:
from tkinter import *
import warnings
import random
import time
import sqlite3
from tkinter import simpledialog
from tkinter import messagebox
from tkcalendar import *
from tkinter import ttk
import math
from PIL import Image, ImageTk
import winsound
##-------------Frames setup--------------------------
class VendingApp(Tk):
def __init__(self):
Tk.__init__(self)
self._frame = None
self.switch_frame(Home)
def switch_frame(self, frame_class):
#Destroys current frame and replaces it with a new one.
new_frame = frame_class(self)
if self._frame is not None:
self._frame.destroy()
self._frame = new_frame
self._frame.pack()
####-----------------------Home page---------------------------
class Home(Frame):
def __init__(self, master):
Frame.__init__(self, master)
##-----------------------fuctions-----------------------------------
def clicked(a):
if (a.x <=1920) and (a.y<=1080):
master.switch_frame(Store)
print ("1")
else:
None
None
##----------------setup------------------------------------------
self._images = list()
img_banner = Image.open("pic/banner.jpg")
img_banner = img_banner.resize((400,100), Image.ANTIALIAS)
banner = ImageTk.PhotoImage(img_banner)
self._images.append(banner)
##---------------------Top frame Home------------------------------------
topFrame = Frame(self,width = 1920, height = 1080)
topFrame.pack()
canvasM = Canvas(topFrame,height=1080, width=1920)
canvasM['highlightthickness'] = 0
canvasM.pack()
body = canvasM.create_rectangle(0, 0,1920,1080, fill = 'gray95')
mylabel = canvasM.create_text((960, 390),font=("Purisa", 40), text="Touch anywhere to continue")
canvasM.tag_bind(body,"<Button>",clicked)
canvasM.tag_bind(mylabel,"<Button>",clicked)
#-------------------------Store page--------------------------------------------------------------
class Store(Frame):
def __init__(self, master):
Frame.__init__(self, master)
def timeset():
global time
time = 15
def active(event):
global time
time = 15
print (time)
def timeout():
global time
if time >= 10:
time -= 1
master.after(1000, timeout)
elif time <= 10 and time > 0:
askuser()
time -= 1
master.after(1000, timeout)
elif time <= 0:
master.switch_frame(Home)
print(time)
def askuser():
ask = messagebox.showinfo('Are you there?','Returning to home page in ' + (str(time)) + ' seconds. \n please touch the screen to continue using the app')
self._images = list()
img_banner = Image.open("pic/banner.jpg")
img_banner = img_banner.resize((400, 100), Image.ANTIALIAS)
banner = ImageTk.PhotoImage(img_banner)
self._images.append(banner)
##---------------------pictures and filters Store------------------------------------
PicFrame = Frame(self, width=400, height=100)
PicFrame.grid(row = 0, column = 0)
PicFrame.grid_propagate(False)
canvas_for_banner = Canvas(PicFrame, height=100, width=400 ) # banner image
canvas_for_banner.pack(anchor = N)
canvas_for_banner['highlightthickness'] = 0
canvas_for_banner.grid_propagate(False)
canvas_for_banner.create_image(0, 0, anchor=NW, image=banner)
##---------------------------------Midd store-------------------
FilterFrame =Frame(self, width=400, height=930, relief = RAISED, bd =1)
FilterFrame.grid(row = 1, column = 0)
FilterFrame.pack_propagate(0)
Ava_title = Label(FilterFrame, text = "Availability", font = ('Helvetica', 20, 'bold'))
Ava_title.pack(pady = (100,0))
self.stock_yes = IntVar()
self.stock_no = IntVar()
check_ava = Checkbutton(FilterFrame, text = 'Avaliable', variable = self.stock_yes, font = 20, command = None)
check_ava.pack( anchor = 'w', padx = 30, pady =10)
check_unava = Checkbutton(FilterFrame, text = 'Unavaliable', font = 20, variable = self.stock_no, command = None)
check_unava.pack(anchor = 'w', padx = 30, pady = 10)
gend_title = Label(FilterFrame, text = "Gender", font = ('Helvetica', 20, 'bold'))
gend_title.pack(pady = (30,0))
self.boi = IntVar()
self.girl = IntVar()
check_boi = Checkbutton(FilterFrame, text = 'Male', font = 20, variable = self.boi)
check_boi.pack( anchor = 'w', padx = 30, pady = 10)
cehck_girl = Checkbutton(FilterFrame, text = 'Female', font = 20, variable = self.girl)
cehck_girl.pack(anchor = 'w', padx = 30, pady =10)
Class_title = Label(FilterFrame, text = "Uniform class", font = ('Helvetica', 20, 'bold'))
Class_title.pack(pady = (30,0))
self.formal = IntVar()
self.sport = IntVar()
check_formal = Checkbutton(FilterFrame, text = 'Formal', font = 20, variable = self.formal)
check_formal.pack( anchor = 'w', padx = 30, pady =10)
check_sport = Checkbutton(FilterFrame, text = 'Sport', font = 20, variable = self.sport)
check_sport.pack(anchor = 'w', padx = 30, pady =10)
type_title = Label(FilterFrame, text = "Type", font = ('Helvetica', 20, 'bold'))
type_title.pack(pady = (30,0))
self.shirts = IntVar()
self.pants = IntVar()
self.misc = IntVar()
check_shirts = Checkbutton(FilterFrame, text = 'Shirts', font = 20, variable = self.shirts)
check_shirts.pack( anchor = 'w', padx = 30, pady =10)
check_pants = Checkbutton(FilterFrame, text = 'Pants', font = 20, variable = self.pants)
check_pants.pack(anchor = 'w', padx = 30, pady =10)
check_misc = Checkbutton(FilterFrame, text = 'Misc', font = 20, variable = self.misc)
check_misc.pack(anchor = 'w', padx = 30, pady =10)
##------------------------\\\\\\\\\\\\\\\\\\\\\\---------------------------------------------
MidFrame = Frame(self,width = 1520, height = 1030, relief = SUNKEN, bd = 2)
MidFrame.grid(row = 0, column = 1, rowspan = 2)
MidFrame.grid_propagate(False)
store_canvas = Canvas(MidFrame, width = 1520, height = 1030)
store_canvas.pack()
store_canvas.pack_propagate(0)
frames = []
frame_order = []
num = 1
for x in range(4):
frames.append([])
for y in range(4):
frames[x].append(0)
for x in range(4):
for y in range(4):
frames[x][y] = Frame(store_canvas, width=1520 / 4, height=1030 / 4, bd = 2, relief = SOLID)
frames[x][y].grid(row=y, column=x)
frames[x][y].pack_propagate(False)
frame_order.append(frames[x][y])
for frame in frame_order:
Label(frame, text=num, anchor='nw').pack( side = 'left')
num += 1
##------------------------\\\\\\\\\\\\\\\\\\\\\\---------------------------------------------
BottomFrame = Frame(self,width = 1920, height = 50, bd = 2, relief = RAISED)
BottomFrame.grid(row = 2, column =0, columnspan = 2)
BottomFrame.pack_propagate(False)
help_btn = Button(BottomFrame, width = 5, height = 3, text = '?', image = None)
help_btn.pack(side = 'right')
master.bind("<Button>",active)
timeset()
timeout()
#----------------------------------------------------------------------------------------
if __name__ == "__main__":
root = VendingApp()
#Renames the TITLE of the window
root.title("Vending machine")
root.geometry("1920x1080")
root.attributes('-fullscreen', True)
root.resizable(False, False)
root.mainloop()
The problem is that the whole program 'freezes' every time the msg box pop up and unless the user confirms 'ok' then the function will pick up where it left off. Is there any way to keep the function going, hence the number in the msg box will update according to the time remaining? Am I approaching this problem the wrong way? Is there another module for this all along and I am just using the wrong module for the task? Please go easy on me, I am still learning. All responses all much appreciated.
messagebox will pause the further execution until it receives an input. To prevent this you can try the following
Use threading
from tkinter import *
from tkinter import messagebox
from threading import Thread
def msgbox():
def _display():
messagebox.showinfo('Info','Self distruction after 2 seconds')
Thread(target=_display).start()
root.after(2000,root.destroy)
root=Tk()
button=Button(root,text='Run',command=msgbox)
button.pack()
root.mainloop()
Create your own info box using Toplevel (the below example will create a replica (sort of) of standard windows info box)
from tkinter import *
import tkinter.ttk as ttk
class InfoBox(Toplevel):
def __init__(self,title,message,parent=None):
Toplevel.__init__(self,parent)
self.bell()
self.transient(self.master)
self.title(title)
self.config(bg='white')
top_frame=Frame(self,bd=0,bg=self['bg'])
top_frame.pack(side='top',fill='x',pady=20)
bottom_frame=Frame(self,bd=0)
bottom_frame.pack(side='bottom',fill='x')
self.info_icon=Canvas(top_frame,width=36,height=36
,bg=self['bg'],bd=0,highlightthickness=0)
self.info_icon.create_oval(0,0,30,30,fill='#0077be',outline='#0077be')
self.info_icon.create_text(15,16,text='i',font=('',18),fill='white')
self.info_icon.pack(side='left',padx=(20,0),anchor='center')
self.label=Label(top_frame,text=message,bg=self['bg'])
self.label.pack(padx=(1,20),pady=5,anchor='center')
self.ok_button=ttk.Button(bottom_frame,text='OK',
state='active',command=self.destroy)
self.ok_button.pack(anchor='e',padx=15,pady=10)
self.update()
center_x=self.winfo_screenwidth()//2-self.winfo_width()//2
center_y=self.winfo_screenheight()//2-self.winfo_height()//2
self.geometry(f'+{center_x}+{center_y}')
def msgbox():
InfoBox('Info','Self distruction after 2 seconds')
root.after(2000,root.destroy)
root=Tk()
button=Button(root,text='Run',command=msgbox)
button.pack()
root.mainloop()
UPDATE
Stacking is automatically prevented
from tkinter import *
import tkinter.ttk as ttk
class InfoBox(Toplevel):
def __init__(self):
self.exists=False
def call(self,title,message,parent=None):
if self.exists:
self._destroy()
Toplevel.__init__(self,parent)
self.bell()
self.transient(self.master)
self.title(title)
self.config(bg='white')
top_frame=Frame(self,bd=0,bg=self['bg'])
top_frame.pack(side='top',fill='x',pady=20)
bottom_frame=Frame(self,bd=0)
bottom_frame.pack(side='bottom',fill='x')
self.info_icon=Canvas(top_frame,width=36,height=36
,bg=self['bg'],bd=0,highlightthickness=0)
self.info_icon.create_oval(0,0,30,30,fill='#0077be',outline='#0077be')
self.info_icon.create_text(15,16,text='i',font=('',18),fill='white')
self.info_icon.pack(side='left',padx=(20,0),anchor='center')
self.label=Label(top_frame,text=message,bg=self['bg'])
self.label.pack(padx=(1,20),pady=5,anchor='center')
self.ok_button=ttk.Button(bottom_frame,text='OK',
state='active',command=self._destroy)
self.ok_button.pack(anchor='e',padx=15,pady=10)
self.update()
center_x=self.winfo_screenwidth()//2-self.winfo_width()//2
center_y=self.winfo_screenheight()//2-self.winfo_height()//2
self.geometry(f'+{center_x}+{center_y}')
self.protocol('WM_DELETE_WINDOW',self._destroy)
self.exists=True
def _destroy(self):
self.destroy()
self.exists=False
root=Tk()
infobox=InfoBox()
button=Button(root,text='Hello',command=lambda:infobox.call('Info','Hello'))
button.pack()
button1=Button(root,text='World',command=lambda:infobox.call('Info','World'))
button1.pack()
root.mainloop()
I have this reproducible code, and I cannot understand why when I set the width value to 100 in the self.display_tcm_18 variable, it still does not increase its width. This self.display_tcm_18 lies within the self.xf Frame, which I set to a width value of 300 (wide enough to host a Label widget of 100). I don't know what I am missing in the Logic of building this GUI with tkinter. Does anyone could give me some hint?
import Tkinter
from Tkinter import *
import tkFileDialog
from tkFileDialog import askopenfilename
from tkFileDialog import askdirectory
class Window(Frame):
def __init__(self, master = None):
self.master = master
path = "logo.gif"
self.image = Tkinter.PhotoImage(file=path)
self.f = Frame(master, width=300, height =70)
self.sf = Frame(master, width=300, height=70)
self.xf = Frame(self.f,width = 300, relief=GROOVE, borderwidth = 2)
self.file_name_18 = ''
self.var = IntVar()
def browse_button():
filename = askopenfilename(filetypes = (("GEOTIFF Files", "*.tif"),))
self.file_name = filename
self.display.config(text = filename)
print(self.file_name)
self.Logo = Label(self.master, image = self.image).pack(side=TOP, padx=5)
self.open_tcm_button = Button(self.xf, text = "Open..", command = browse_button).pack(side=LEFT, padx = 5, pady = 10)
self.display_tcm_18 = Label(self.xf, width = 100, bg = "white", textvariable = self.file_name_18, relief = SUNKEN, anchor = W)
self.display_tcm_18.pack(side=LEFT)
self.tcm18_label = Label(self.f, text = "Tree Cover Mask 2018 ").place(relx=0.06, rely=0.125,anchor=W)
self.xf.place(relx=0.01, rely=0.125, anchor=NW)
self.f.pack(side=TOP)
root = Tk()
root.geometry("600x400")
app = Window(root)
root.mainloop()
I'm working on a GUI software with Tkinter which basically print a general plane of the product after pushing the "Crear" button, as you can see at the following images:
GUI Interface
After pushing "Crear" Button
As you may have appreciated, once you give the full information at the entries and push the "Crear" button, a dynamic table (made with labels and entries in a for cycle) appear with the dimensions of the modules seen at the "Esquema" frame. The problem I have is that, when I edit the information at the dynamic table, I have an immediate change on the graph (which is possible thanks to the trace method) without letting me finish the number I'm already writing; I mean: I can't write the full number at the entries on the dynamic table before it make the changes on the graph. So, my question is: which function or command can I apply to make the program stop and reactivate after I finish writing the full number at the entries on the table?
Any help will be highly appreciated,
PS: I have already tried the "time.stop" and "after" functions. The first one crashed the program, which is unacceptable, and the second one increased the waiting time before I could continue writing numbers at the table. The full code of the program is really extensive, but here I share a runnable code:
Code
from tkinter import *
from tkinter import filedialog as fd
from tkinter import messagebox as ms
from tkinter import ttk
from io import open
import tkinter as tk
from pathlib import Path
import PIL
from PIL import Image, ImageTk
import glob
import sys
import numpy as np
import os
import os, os.path
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import time
#Made by:
#Juan David Argüello Plata
#----------------------------------------------CLASSES AND FUNCTIONS-----------------------------------------------------
class Interface():
def __init__(self, inter, w=860,h=700, titulo = "Example", titulo_principal = "EXAMPLE"):
inter.title(titulo)
inter.resizable(False, False)
#Dimensions of the screen
ws = inter.winfo_screenwidth()
hs = inter.winfo_screenheight()
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
#Position of the interface
inter.geometry('%dx%d+%d+%d' % (w, h, x, y))
titulo = Label(inter, text = titulo_principal, font=(fuente,24, "bold italic"))
titulo.pack()
self.inter = inter
#---Frames, labels and general data---
self.Principal_frames()
self.subframes()
self.Data()
#---Actions to execute---
Action(self)
def Principal_frames(self):
self.Frame_Table = Frame(self.inter)
self.Frame_Table.config(width = "400", height = "600", bd = 2, relief = "groove")
self.Frame_Table.place(x=10, y=50)
titulo = Label(self.Frame_Table, text = "Data", font=(fuente,20, "bold italic"))
titulo.place(x=180, y=5)
self.Frame_graph = Frame(self.inter)
self.Frame_graph.config(width = "400", height = "600", bd = 2, relief = "groove")
self.Frame_graph.place(x=450, y=50)
titulo = Label(self.Frame_graph, text = "Graph", font=(fuente,20, "bold italic"))
titulo.place(x=150, y=5)
def subframes(self):
self.subframe_Data = Frame(self.Frame_Table)
self.subframe_Data.config(width = "300", height = "200", bd = 2, relief = "groove")
self.subframe_Data.place(x=80, y=50)
self.subframe_graph = Frame(self.Frame_graph)
self.subframe_graph.config(width = "395", height = "400", bd = 2, relief = "flat")
self.subframe_graph.place(x=0, y=50)
def Data(self):
Length = Label(self.subframe_Data, text = "Length", font = Font)
Length.grid(row=0, column = 0, sticky=W, padx=3)
self.Length=Entry(self.subframe_Data, width=8)
self.Length.grid(row=0,column=1, sticky=W, padx=3)
self.Sub_Length=Entry(self.subframe_Data, width=8)
self.Sub_Length.grid(row=0,column=2, sticky=W, padx=3)
Width = Label(self.subframe_Data, text = "Width", font = Font)
Width.grid(row=1, column = 0, sticky=W, padx=3)
self.Width=Entry(self.subframe_Data, width=8)
self.Width.grid(row=1,column=1, sticky=W, padx=3)
self.Sub_Width=Entry(self.subframe_Data, width=8)
self.Sub_Width.grid(row=1,column=2, sticky=W, padx=3)
class Action(Interface):
def __init__(self, inter):
self.Interface = inter
self.modification = 0
Create = Button(self.Interface.subframe_Data, text="Create", font = Font, command = self.Table)
Create.grid(row=1,column=3)
def Table(self):
self.Table = Frame(self.Interface.Frame_Table)
self.Table.config(width = "150", height = "400", bd=2, relief="groove")
self.Table.place(x=80, y=150)
#Dimensions of the labels and entries of the table
Length = 176
Width = 200
#Reading of Data
self.Data = np.zeros(4)
self.Data[0] = float(self.Interface.Length.get())
self.Data[1] = float(self.Interface.Sub_Length.get())
self.Data[2] = float(self.Interface.Width.get())
self.Data[3] = float(self.Interface.Sub_Width.get())
#---Dynamic table ---
if self.Data[1] > self.Data[3]:
self.Max = self.Data[1]
else:
self.Max = self.Data[3]
#-Variables-
label = "label"
Entry_length = "length"
Entry_width = "width"
Numbers_label = [""]*(int(self.Max)+1)
self.width_data = [""]*(int(self.Max)+1)
self.length_data=[""]*(int(self.Max)+1)
self.First_Time = 0 #Counter that depends of the size of the table (help the program to recognize if it's the first time the "Create" button is pressed)
self.Modules = np.zeros((int(self.Max),2)) #Matrix which contains the table info
#--Scorllbar--
self.canvas_table = Canvas(self.Table)
self.canvas_table.pack(side="left", fill="both", expand = True)
self.canvas_table.config(width=str(Width), height=str(Length))
self.Frame_table = Frame(self.canvas_table)
self.Frame_table.config(width=str(Width), height=str(Length), relief="flat")
self.canvas_table.create_window(0,0,window= self.Frame_table, anchor = 'nw')
self.yscroll = Scrollbar(self.Table, orient = "vertical", command = self.canvas_table.yview)
self.yscroll.pack(side='right', fill='y')
self.canvas_table['yscrollcommand'] = self.yscroll.set
self.Frame_table.bind("<Configure>", self.AuxscrollFunction)
self.yscroll.grid_forget()
Number = Label(self.Frame_table, text="", width=4, font = Font, bd = 2, relief="groove")
Number.grid(row=0,column=0,sticky=W)
L = Label(self.Frame_table, text="L", width=8, font = Font, bd = 2, relief="groove")
L.grid(row=0,column=1,sticky=W)
Wid = Label(self.Frame_table, text="W", width=8, font = Font, bd = 2, relief="groove")
Wid.grid(row=0,column=2,sticky=W)
#Subdivisions (defect values)
Wth = self.Data[2]/self.Data[3]
l = self.Data[0]/self.Data[1]
self.var_length = []
self.var_width = []
for i in range(int(self.Max)+1):
if i != 0:
Numbers_label[i] = label + str(i)
Numbers_label[i] = Label(self.Frame_table, text=str(i), width=4, font = Font, bd = 2, relief="groove")
Numbers_label[i].grid(row=i,column=0,sticky=W)
if i <= self.Data[1]:
text = str(l)
else:
text = "0.0"
var_length = StringVar()
self.var_length.append(var_length)
self.length_data[i] = Entry_length + str(i)
self.length_data[i] = Entry(self.Frame_table, width=9, font = Font, bd = 2, relief="groove", textvariable = self.var_length[i-1])
self.var1 = self.length_data[i]
self.var_length[i-1].trace("w", lambda name, index, mode, envio=self: Action.callback(envio))
self.length_data[i].grid(row=i,column=1,sticky=W)
self.length_data[i].insert(0, text)
if i <= self.Data[3]:
text = str(Wth)
else:
text = "0.0"
var_width = StringVar()
self.var_width.append(var_width)
self.width_data[i] = Entry_width + str(i)
self.width_data[i] = Entry(self.Frame_table, width=9, font = Font, bd = 2, relief="groove", textvariable = self.var_width[i-1])
self.var1 = self.width_data[i]
self.var_width[i-1].trace("w", lambda name, index, mode, envio=self: Action.callback(envio))
self.width_data[i].grid(row=i,column=2,sticky=W)
self.width_data[i].insert(0, text)
self.yscroll.pack(side='right', fill = 'y')
def AuxscrollFunction(self,event):
self.canvas_table.configure(scrollregion=self.canvas_table.bbox("all"))
def callback(self, *args):
self.First_Time = self.First_Time+1
if self.First_Time >= 2*int(self.Max) and self.modification == 0:
try:
for i in range(int(self.Max)+1):
if i != 0:
self.Modules[i-1][0] = float(self.length_data[i].get())
self.Modules[i-1][1] = float(self.width_data[i].get())
self.Data[0] = 0
self.Data[2] = 0
for i in range(int(self.Max)):
self.Data[0] = self.Data[0]+self.Modules[i][0]
self.Data[2] = self.Data[2]+self.Modules[i][1]
self.Interface.Length.delete(0, 'end')
self.Interface.Width.delete(0, 'end')
self.Interface.Length.insert(0, str(self.Data[0]))
self.Interface.Width.insert(0, str(self.Data[2]))
#self.var1.focus()
self.Graph()
except ValueError:
pass
def Graph(self):
#---Area---
f=Figure(figsize=(3,3), dpi=100)
a=f.add_subplot(111)
type_line = 'r--' #Línea de borde de área
a.plot([0,self.Data[2]], [0,0], type_line)
a.plot([0,self.Data[2]], [self.Data[0],self.Data[0]], type_line)
a.plot([0,0], [0,self.Data[0]], type_line)
a.plot([self.Data[2],self.Data[2]], [0,self.Data[0]], type_line)
canvas = FigureCanvasTkAgg(f, self.Interface.subframe_graph)
canvas.draw()
canvas.get_tk_widget().place(x=0,y=0)
#--------------------------------------------------------INTERFACE-----------------------------------------------
#---Beginning of the interface---
root = Tk()
#Font
fuente = "TkFixedFont"
Font = (fuente, 10)
Interface(root)
root.mainloop()
I am making a maze where the user enters the dimensions and can then click on a button to change the colour of that button to black. What i eventually want is to be making an ai which will try to navigate the maze the user created with the black rectangle the ai not being allowed to go on.
The problem is i dont know how to change the properties of the button clicked as due to a nested loop being used for creation they all have the same name.
from tkinter import *
import tkinter as tk
from tkinter.ttk import Combobox,Treeview,Scrollbar
class MainMenu(Frame):
def __init__(self, master):
""" Initialize the frame. """
super(MainMenu, self).__init__(master)
self.grid()
self.frame1 = tk.LabelFrame(self, text="entering diemsions", width=300, height=130, bd=5)
self.frame1.grid(row=0, column=0, columnspan=3, padx=8)
self.frame2 = tk.LabelFrame(self, text="creating maze", width=300, height=130, bd=5)
self.frame2.grid(row=1, column=0, columnspan=3, padx=8)
self.create_GUI()
def create_GUI(self):
self.width_lbl = Label(self.frame1, text = "width:")
self.width_lbl.grid(row = 1 , column = 1)
self.width_txt = Entry(self.frame1)
self.width_txt.grid(row = 1, column = 2)
self.getdimensions_btn = Button(self.frame1, text = "enter dimensions",command = lambda:self.createmaze())
self.getdimensions_btn.grid(row = 1 , column = 3)
self.height_lbl = Label(self.frame1, text = "height:")
self.height_lbl.grid(row = 1 , column = 4)
self.height_txt = Entry(self.frame1)
self.height_txt.grid(row = 1, column = 5)
def createmaze(self):
width = int(self.width_txt.get())
height = int(self.height_txt.get())
for widthcount in range (width):
for heightcount in range(height):
self.maze_btn = Button(self.frame2, text = "",width = 4, height = 2)
self.maze_btn.grid(row = heightcount , column = widthcount)
self.maze_btn.bind("<Button-1>", self.disablebtn)
def disablebtn(self,event):
grid_info = event.widget.grid_info()
col = grid_info["column"]
col = int(col)
row = grid_info["row"]
row = int(row)
root = Tk()
root.title("hi")
root.geometry("500x500")
root.configure(bg="white")
app = MainMenu(root)
root.mainloop()