Hi I am making a tkinter program but have run into this issue.
I am trying to use the grid method to center a load of buttons in the middle of the screen(The amount of buttons will vary dynamically) However I cant keep the buttons to a reasonable size I have followed the advice of someone who had a similar problem however I cant figure out what I am doing differently as it hasn't solved my issue.
Here is my code (it uses a directory pathway so it won't work for the reader but maybe you can spot what I am doing wrong)
ef open_win3():
global third_window
third_window = Toplevel()
third_window.config(height = 1800,width = 1800, bg = "chocolate1")
create_thirdwindow_button()
def create_thirdwindow_button():
bf = Frame(third_window,bg = "blue")
bf.grid(row=0, column=0,sticky="NESW")
bf.rowconfigure(0,weight = 1)
bf.columnconfigure(0,weight =1)
third_window.grid_rowconfigure(0, weight=1)
third_window.grid_columnconfigure(0, weight=1)
count = 0
x = 1
y = 0
mypath = "C:\\Users\\link\\OneDrive\\Desktop\\python stuff\\screenshot example\\Snapshots by catagory"
for g in listdir(mypath):
count += 1
for I in listdir(mypath):
btp = mypath +"\\"+str(I)
print(btp)
screenshot_snap = Button(bf,text = str(I),width = 1,height = 1, bg = "chocolate3",activebackground = "white",padx= 10,pady =10)
screenshot_snap.grid(sticky = "NESW")
screenshot_snap.grid_rowconfigure(0, weight=1)
screenshot_snap.grid_columnconfigure(0, weight=1)
x += 10
if y < count:
y += 1
Thanks a lot for any help!
Related
Hello I am building a tkinter app and need to open photos within a function. Upon research I saw that you need to make the image = to a variable to keep track of it and use global. Despite doing these things my image still wont show up
can anyone help??
Here is my code
#when one of the catagory buttons is pressed this func is called opening a new window with
#a button for all images
def open_catagory(button_name):
fourth_window = Toplevel()
global fourth_pics
global fourthview
global CC
fourth_pics = (
"C:\\Users\\link\\OneDrive\\Desktop\\python stuff\\screenshot example\\Snapshots by catagory\\"+ str(button_name))
CC = [f for f in listdir(fourth_pics)]
print(CC)
fourthview = Image.open(
fourth_pics+"\\" + str(CC[-1]))
fourthveiw = fourthview.resize((800, 800), Image.ANTIALIAS)
fourthveiw = ImageTk.PhotoImage(fourthveiw)
fourth_window.config(height=1800, width=1800, bg="chocolate1")
fourthw_picture_box = Label(fourth_window, height=800, width=800,image = fourthveiw)
fourthw_picture_box.place(x=800, y=100)
count = 0
x = 1
y = 0
catagorypath = "C:\\Users\\link\\OneDrive\\Desktop\\python stuff\\screenshot example\\Snapshots by catagory\\" + str(button_name)
for g in listdir(catagorypath):
count += 1
for I in listdir(catagorypath ):
screenshot_snap = Button(fourth_window,text = str(I), bg = "chocolate3",activebackground = "white",padx= 80,pady =10)
screenshot_snap.grid(column = 4, row = int(x),rowspan = 5,columnspan = 5,padx = 50,pady =10)
x += 10
if y < count:
y += 1
Im making one of my first programs, using python, tkinter and pillow.
This program is supposed to randomly select one of four tile images, create an image and repeat 25 times
Making a 5x5 Board using a grid to position the images in a square.
This is not what happened when i ran my code though
One or two columns and 4 rows are usually generated and not every coordinate is filled with an image.
And only the corner of the images are visible for some reason?
The images center seems to be placed in the top left corner of their grid.
A output might look something like this
X = coordinate filled with an image
O = coordinate filled with bg colour
X X
O X
O X
When i want it to look like this
X X X X X
X X X X X
X X X X X
X X X X X
X X X X X
The code thats supposed to place the images looks like this
while n < 25:
n = n + 1
number = random.randint(1,4)
if number == 1:
TILE_FLOWER.grid(row = x, column = y)
TILE_FLOWER.create_image(16,16, image = TILE_FLOWER_IMG)
elif number == 2:
TILE_GRASS.grid(row = x, column = y)
TILE_GRASS.create_image(16,16, image = TILE_GRASS_IMG)
elif number == 3:
TILE_STONE.grid(row = x, column = y)
TILE_STONE.create_image(16,16, image = TILE_STONE_IMG)
elif number == 4:
TILE_WATER.grid(row = x, column = y,)
TILE_WATER.create_image(16,16, image = TILE_WATER_IMG)
if x == 5:
x = 0
y = y + 1
else:
x = x + 1
win.mainloop()
The code defining my canvases looks like this
They're the same size as the images i want to draw on them.
TILE_FLOWER = Canvas(win, height = 80, width = 80)
TILE_GRASS = Canvas(win, height = 80, width = 80)
TILE_STONE = Canvas(win, height = 80, width = 80)
TILE_WATER = Canvas(win, height = 80, width = 80)
And lastly the code defining the images looks like this
TILE_FLOWER_IMG = PhotoImage(file = 'Path1.png')
TILE_GRASS_IMG = PhotoImage(file = 'Path2.png')
TILE_STONE_IMG = PhotoImage(file = 'Path3.png')
TILE_WATER_IMG = PhotoImage(file = 'Path4.png')
Hope what i've written makes sense!
And i would be super thankful if someone could help me fix this mess :)
You need to create new Label or Canvas in each cell of the 5x5 grid:
import tkinter as tk
import random
root = tk.Tk()
imagelist = [
tk.PhotoImage(file='Path1.png'),
tk.PhotoImage(file='Path2.png'),
tk.PhotoImage(file='Path3.png'),
tk.PhotoImage(file='Path4.png'),
]
for i in range(25):
image = random.choice(imagelist)
tk.Label(root, image=image, width=80, height=80, bg='white').grid(row=i//5, column=i%5)
'''
# or using Canvas
canvas = tk.Canvas(root, width=80, height=80, bg='white')
canvas.create_image(40, 40, image=image)
canvas.grid(row=i//5, column=i%5)
'''
root.mainloop()
Or using single Canvas:
canvas = tk.Canvas(root, width=400, height=400, bg='white')
canvas.pack()
for i in range(25):
image = random.choice(imagelist)
row = i // 5
col = i % 5
canvas.create_image(40+col*80, 40+row*80, image=image)
I am trying to draw a simple mesh with tkinter:
from tkinter import *
root=Tk()
root.title('Mesh simulator')
window_identifiers = {}
frame_identifiers = {}
canvas_identifiers = {}
mesh_identifiers = []
window_identifiers["main_window"] = root
SETTINGS_canvas_total_width = 2048
SETTINGS_canvas_total_height = 1536
SETTINGS_canvas_visible_width = 800
SETTINGS_canvas_visible_height = 600
SETTINGS_canvas_color = "black"
SETTINGS_grid_color = "white"
mesh_density = 50
frame=Frame(window_identifiers["main_window"],width=SETTINGS_canvas_visible_width,height=SETTINGS_canvas_visible_height)
frame_identifiers["body_holder"] = frame
frame.grid(row=0,column=0)
canvas=Canvas(frame,bd=-2, bg=SETTINGS_canvas_color,width=SETTINGS_canvas_visible_width,height=SETTINGS_canvas_visible_height,scrollregion=(0,0,SETTINGS_canvas_total_width,SETTINGS_canvas_total_height), highlightthickness=0)
canvas_identifiers["main_canvas"] = canvas
canvas.grid(row=0, column=0)
i = 0
while(i<=SETTINGS_canvas_total_height):
l = canvas_identifiers["main_canvas"].create_line(0, i, SETTINGS_canvas_total_width, i, width=1, fill=SETTINGS_grid_color)
mesh_identifiers.append(l)
i+=mesh_density
i = 0
while(i<=SETTINGS_canvas_total_width):
l = canvas_identifiers["main_canvas"].create_line(i, 0, i, SETTINGS_canvas_total_height, width=1, fill=SETTINGS_grid_color)
mesh_identifiers.append(l)
i+=mesh_density
root.mainloop()
But on the very end, when I measure up the distance between two lines, it seems it is not 50px, but about 62-64px. I don't have a clue what adds those 12 pixels per square. Can anyone explain me the root cause of this please, based on my upper snippet?
EDIT:
Interesting fact, I've just done the measurement on 2 different monitors (laptop and 22" one), and results are interesting. On 22" monitor, everything seems perfectly fine (image 1) while on laptop monitor, there's an offset (image 2)
And since this is not an HTML and web-design issue, I am even more confused now :)
My title may be kind of confusing, but I essentially want to draw a different set of shapes every four seconds then start over. For example, second one I want to draw triangles, second two I want to draw lines, second three I want to draws rectangles, and second four I want to draw ovals. The for second five I want this process to repeat. My Idea was to use the remainder which works up to second seven. Also is this possible to do without importing any additional modules. Any help would be great and if something was not clear please ask.
Thanks,
Scott
Here is my current code to run if you want:
from tkinter import *
from random import *
#creates a class
class mainWindow():
def __init__(self,theWindow,winName):
#Sets values for variable
self.running = 0
#makes theWindow and instnace var
self.theWindow = theWindow
#creates the main frames
self.mainFrame = Frame(theWindow,width=600,height=200,bg="light gray")
self.secondframe = Frame(theWindow,width=600, height =287, bg = "green")
self.mainFrame.grid()
self.secondframe.grid()
# gives the window a title
theWindow.title(winName)
# do not resize window based on widgets
self.mainFrame.grid_propagate(False)
# window location
theWindow.geometry('+500+300')
#Makes it so the window wont resize
self.theWindow.resizable(0,0)
#
self.theWindow.wm_attributes("-topmost",1)
`enter code here`#Creates the three frames that will be used
#Inerts a blank label to help with formating
self.blank1 = Label(self.mainFrame, bg= "light gray", height =3, width=19)
self.blank1.grid(row=0, column=0, rowspan =1)
#Creates and places the start button
self.startbutton = Label(self.mainFrame,text = "Start", bg= "green", height =1, width=10,relief=RAISED)
self.startbutton.bind("<Button-1>", self.startTimer)
self.startbutton.grid(row=0, column=2, rowspan =1, sticky = E)
#Creates and places the stop button
self.stopbutton = Label(self.mainFrame,text = "Stop", bg= "red", height =1, width=10,relief=RAISED)
self.stopbutton.bind("<Button-1>", self.endTimer)
self.stopbutton.grid(row=0, column=3, rowspan =1, sticky =W)
#Creates and places the timer
self.timerLabel = Label(self.mainFrame,text = "Time: 0", bg= "white", height =2, width=14,relief=SUNKEN)
self.timerLabel.bind("<Button-1>",)
self.timerLabel.grid(row=3, column=2, columnspan =2, pady =25)
#draws the canvas
self.drawCanvas = Canvas(self.secondframe,width=598,height=285, bg= "light green")
self.drawCanvas.grid()
#Function for strting the timer
def startTimer(self,event):
if self.running == 0:
self.running = 1
self.countElapse(0)
#function for ening the timer
def endTimer(self,event):
if self.running == 1:
self.running = 0
self.timecount = 0
self.drawCanvas.delete(ALL)
self.timerLabel.configure(text = "Time: %d" %0)
#function for showing the time
def countElapse(self,localTime = NONE):
#self.timerLabel.configure()
if self.running:
if localTime is not NONE:
self.timecount = localTime
self.timerLabel.configure(text ="Time: "+str(self.timecount+1))
self.timecount = self.timecount+1
self.drawshapes(self.timecount)
self.mainFrame.after(1000,self.countElapse)
#function for drawing the shpaes
def drawshapes(self,timecount):
self.drawCanvas.delete(ALL)
color = ["red","white","purple","green","lime green", "cyan", "black","light blue","blue","pink","brown","gray"]
numshapes = 100
counter = 0
print(self.timecount)
var = self.timecount
#draws ovals
if var % 4 ==0:
while counter != numshapes:
counter += 1
x = randint(10,600)
y = randint(10,600)
x1 = randint(10,600)
y1 = randint(10,600)
#draws the shape
self.drawCanvas.create_oval(x,y,x1,y1,fill=choice(color))
#draws rectangles
elif var % 3 ==0:
while counter != numshapes:
counter += 1
x = randint(10,600)
y = randint(10,600)
x1 = randint(10,600)
y1 = randint(10,600)
self.drawCanvas.create_rectangle(x,y,x1,y1,fill= choice(color))
#draws Lines
elif var % 2 ==0:
while counter != numshapes:
counter += 1
x = randint(10,600)
y = randint(10,600)
x1 = randint(10,600)
y1 = randint(10,600)
self.drawCanvas.create_line(x,y,x1,y1,fill= choice(color))
#draws triangles
elif var % 1 ==0:
while counter != numshapes:
counter += 1
x = randint(10,600)
y = randint(10,600)
x1 = randint(10,600)
y1 = randint(10,600)
x2 = randint(10,600)
y2 = randint(10,600)
self.drawCanvas.create_polygon(x,y,x1,y1,x2,y2,fill= choice(color))
def main():
# create a tkinter object
mainWin = Tk()
# create a mainWindow object
theMainWin = mainWindow(mainWin,"Scott Rodgers")
# keep the window displaying
mainWin.mainloop()
#calls main
main()
What you are looking for is how to use the .after method.
Here is how it works.
Lbl = Label()
Lbl.pack()
Lbl.after([Amount of milliseconds], lamba: [Function])
For more advanced notation,
after(delay_ms, callback=None, *args)
What this does is that it registers an alarm callback that is called after a given time
I am a beginner programmer. I have a task to make a GUI with a linear equation y=mx+b and a set of parameters where I can change the m and b values. I have both matplotlib and numpy. I also have tkinter for the GUI. This is what i have so far i edited my friends code on a coordinate GUI.
def onButtonValChange():
if X1.get() != '':
x[0] = float(X1.get())
if Y1.get() != '':
y[0] = float(Y1.get()
def createGraph(x,y):
graphRoot = Tk.Tk()
graphRoot.wm_title("Your Graph")
graphRoot.resizable(0,0)
f = Figure(figsize=(5, 4), dpi=100)
a = f.add_subplot(111)
a.plot(x, y)
canvas = FigureCanvasTkAgg(f, master=graphRoot)
canvas.show()
canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)
x = [1]
y = [1]
ButtonChangeValues = Tk.Button(root, text="Submit Change", command=onButtonValChange)
ButtonChangeValues.grid(row=11, columnspan=3)
ButtonCreateGraph = Tk.Button(root, text="Create This Graph", command=lambda: createGraph(x, y))
ButtonCreateGraph.grid(row="15", columnspan=3)
Tk.mainloop()
So here is some code that i use its a moving line graph but you could adapt the code to move only when you change the equation. all you would have to do is populate the lists of x0Coords y0Coords and xy0Coords with the right mx+b formula
# Run from IDLE or LXTerminal not IDLE 3
# for import spidev to work, must run as python (v2) not python3
from Tkinter import * #to run on python 2, use Tkinter, for python3 use tkinter
import math
from datetime import datetime, timedelta
import numpy as np
import spidev
#--------------------- variables -------------------------
#---user defined settings
screenWidth = 450
resolution = 5 #number of pixels between data points, for visual purposes only
samplePeriod = 100 #milliseconds, time between data points written to txt file
timeRange = .5 #minutes
#---end user settings
baseTime = int(timeRange*60*1000/screenWidth)
startTime = datetime.now()
nl = "\n"
root = Tk()
root.title("Simple GUI")
root.geometry("500x300") #widthxheight
C = Canvas(root, bg = "gray", height = 250, width = screenWidth)
x0Coords = []
y0Coords = []
xy0Coords = []
coordLength = int(screenWidth/resolution)
#---initiation of lists
for i in range(0,coordLength):
x0Coords.append(i*resolution)
y0Coords.append(125)
xy0Coords.append(0)
xy0Coords.append(0)
#putting X and Y corrdinites in a list
def coordinate():
global x0Coords, y0Coords, xy0Coords
for i in range(0,coordLength*2,2):
xy0Coords[i] = x0Coords[i/2]
xy0Coords[i+1] = y0Coords[i/2]
#print(xy0Coords)
#---End initiation of lists
c0 = C.create_rectangle(0,0,20,50)
cl0 = C.create_line(xy0Coords)
pressure = Label(root, text="test")
pressure.pack()
spi_0 = spidev.SpiDev()
spi_0.open(0, 0)
#--------------------------- End of Variables -------------------------
#--------------------------- Definitions ------------------------------
#shifts y values down in index in array to represent time moved forward
def shiftCoords(nextValue):
global y0Coords, xy0Coords
y0Coords.pop(0)
y0Coords.append(nextValue)
coordinate()
#updates the GUI based on the new time
def move_time():
global c0,cl0,xy0Coords, resolution, baseTime
C.delete(c0)
C.delete(cl0)
c0 = C.create_rectangle(0,0,20,int(float(readadc_0(0))/1023*250))
shiftCoords(125-int(float(readadc_0(0))/1023*125))
cl0 = C.create_line(xy0Coords)
#print(float(readadc_0(0))/1023*250)
root.title("V= " + str(round(3.3*float(readadc_0(0))/1023,2)))
root.after(baseTime*resolution,move_time)
C.pack()
root.after(baseTime,move_time)
root.after(samplePeriod,writeData)
root.mainloop()