class calculate:
def __init__(self):
self.window = tk.Tk()
self.numbers = tk.Frame(master = self.window)
self.signs = tk.Frame(master = self.window)
self.lst, self.lst2 = (1,2,3,4,5,6,7,8,9,0,".","="),("C","+","-","*","/")
def buttons(self):
val = 0
for i in range(4):
for j in range(3):
self.numbutton = tk.Button(master = self.numbers,text = self.lst[val])
self.numbutton.grid(row = i,column = j)
val += 1
for i in range(5):
self.signbutton = tk.Button(master = self.signs,text = self.lst2[i])
self.signbutton.grid(row = i)
def packing(self):
self.numbers.grid(column= 0,row = 0,rowspan = 4)
self.signs.grid(column = 1,row = 0,rowspan = 4)
self.window.mainloop()
calculator = calculate()
calculator.buttons()
calculator.packing()
I am trying to put some buttons by using gird in python tkinter.
and I want that numbers and signs have same height.
but the signs is of larger height.
please help.
Thanks for help in advance.
You can force the size of a frame by giving the frame an height:
self.numbers = tk.Frame(master = self.window, height=200)
self.signs = tk.Frame(master = self.window, height=200)
Both frames will have a height of 200 but you can change it to whatever you want
for i in range(4):
for j in range(3):
self.numbutton = tk.Button(master = self.numbers,text = self.lst[val],width=5,height=5)
self.numbutton.grid(row = i,column = j)
val += 1
for i in range(5):
self.signbutton = tk.Button(master = self.signs,text = self.lst2[i],width=5, height=4)
self.signbutton.grid(row = i)
Add a padding in y of some 0.1 or 0.2 to make it look good.
You can add sticky="nsew" to all .grid(...) and add self.numbers.rowconfigure("all", weight=1) to make the number buttons to use all the available space inside self.numbers frame.
Below is modified code:
import tkinter as tk
class calculate:
def __init__(self):
self.window = tk.Tk()
self.numbers = tk.Frame(master=self.window)
self.signs = tk.Frame(master=self.window)
self.lst, self.lst2 = (1,2,3,4,5,6,7,8,9,0,".","="), ("C","+","-","*","/")
def buttons(self):
val = 0
for i in range(4):
for j in range(3):
self.numbutton = tk.Button(master=self.numbers, text=self.lst[val])
self.numbutton.grid(row=i, column=j, sticky="nsew") # added sticky
val += 1
for i in range(5):
self.signbutton = tk.Button(master=self.signs, text=self.lst2[i])
self.signbutton.grid(row=i, sticky="nsew") # added sticky
def packing(self):
self.numbers.grid(column=0, row=0, sticky="nsew") # added sticky
self.signs.grid(column=1, row=0, sticky="nsew") # added sticky
self.numbers.rowconfigure("all", weight=1) # use all available vertical space
self.window.mainloop()
calculator = calculate()
calculator.buttons()
calculator.packing()
Related
I want to display live data in a GUI, in tkinter. The data I am getting contains a list of two integers [current, voltage]. I am getting new data every second.
I managed to create a GUI, now I want to know how to display data in GUI Label widgets (python tkinter) and update labels dynamically. Any suggestions please
Here is my code so far:
#data getting is a list eg. [10, 12]
from tkinter import *
import tkinter.font
#main Window using Tk
win = Tk()
win.title("v1.0")
win.geometry('800x480')
win.configure(background='#CD5C5C')
#Labels
voltage = Label(win, text = "voltage")
voltage.place(x=15, y=100)
current = Label(win, text = "current")
current.place(x=15, y=200)
#display measured values
#how to display here !!!
currentValues = Label(win, text = "want to display somewhere like this")
currentValues.place(x=200, y=100)
voltageValues = Label(win, text = "want to display somewhere like this")
voltageValues.place(x=200, y=200)
mainloop()
If you want to graph your live data and want to avoid using other libraries to do that for you, you might find the following to be an enlightening starting point for creating your own graphs. The sample draws a full circle of values when evaluating the math.sin function that comes in the standard library. The code takes into account automatic sampling, resizing, and updating as needed and should be fairly responsive.
#! /usr/bin/env python3
import math
import threading
import time
import tkinter.ttk
import uuid
from tkinter.constants import EW, NSEW, SE
class Application(tkinter.ttk.Frame):
FPS = 10 # frames per second used to update the graph
MARGINS = 10, 10, 10, 10 # internal spacing around the graph
#classmethod
def main(cls):
tkinter.NoDefaultRoot()
root = tkinter.Tk()
root.title('Tkinter Graphing')
# noinspection SpellCheckingInspection
root.minsize(640, 480) # VGA (NTSC)
cls(root).grid(sticky=NSEW)
root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)
root.mainloop()
def __init__(self, master=None, **kw):
super().__init__(master, **kw)
self.display = tkinter.Canvas(self, background='white')
self.display.bind('<Configure>', self.draw)
self.start = StatefulButton(self, 'Start Graphing', self.start_graph)
self.grip = tkinter.ttk.Sizegrip(self)
self.grid_widgets(padx=5, pady=5)
self.data_source = DataSource()
self.after_idle(self.update_graph, round(1000 / self.FPS))
self.run_graph = None
def grid_widgets(self, **kw):
self.display.grid(row=0, column=0, columnspan=2, sticky=NSEW, **kw)
self.start.grid(row=1, column=0, sticky=EW, **kw)
self.grip.grid(row=1, column=1, sticky=SE)
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
def start_graph(self):
self.run_graph = True
threading.Thread(target=self.__simulate, daemon=True).start()
return 'Stop Graphing', self.stop_graph
def stop_graph(self):
self.run_graph = False
return 'Clear Graph', self.clear_graph
def clear_graph(self):
self.data_source.clear()
self.reset_display()
return 'Start Graphing', self.start_graph
# def __simulate(self):
# # simulate changing populations
# for population in itertools.count():
# if not self.run_graph:
# break
# self.data_source.append(population, get_max_age(population, 200))
# def __simulate(self):
# # simulate changing ages
# for age in itertools.count(1):
# if not self.run_graph:
# break
# self.data_source.append(age, get_max_age(250_000_000, age))
def __simulate(self):
# draw a sine curve
for x in range(800):
time.sleep(0.01)
if not self.run_graph:
break
self.data_source.append(x, math.sin(x * math.pi / 400))
def update_graph(self, rate, previous_version=None):
if previous_version is None:
self.reset_display()
current_version = self.data_source.version
if current_version != previous_version:
data_source = self.data_source.copy()
self.draw(data_source)
self.after(rate, self.update_graph, rate, current_version)
def reset_display(self):
self.display.delete('data')
self.display.create_line((0, 0, 0, 0), tag='data', fill='black')
def draw(self, data_source):
if not isinstance(data_source, DataSource):
data_source = self.data_source.copy()
if data_source:
self.display.coords('data', *data_source.frame(
self.MARGINS,
self.display.winfo_width(),
self.display.winfo_height(),
True
))
class StatefulButton(tkinter.ttk.Button):
def __init__(self, master, text, command, **kw):
kw.update(text=text, command=self.__do_command)
super().__init__(master, **kw)
self.__command = command
def __do_command(self):
self['text'], self.__command = self.__command()
def new(obj):
kind = type(obj)
return kind.__new__(kind)
def interpolate(x, y, z):
return x * (1 - z) + y * z
def interpolate_array(array, z):
if z <= 0:
return array[0]
if z >= 1:
return array[-1]
share = 1 / (len(array) - 1)
index = int(z / share)
x, y = array[index:index + 2]
return interpolate(x, y, z % share / share)
def sample(array, count):
scale = count - 1
return tuple(interpolate_array(array, z / scale) for z in range(count))
class DataSource:
EMPTY = uuid.uuid4()
def __init__(self):
self.__x = []
self.__y = []
self.__version = self.EMPTY
self.__mutex = threading.Lock()
#property
def version(self):
return self.__version
def copy(self):
instance = new(self)
with self.__mutex:
instance.__x = self.__x.copy()
instance.__y = self.__y.copy()
instance.__version = self.__version
instance.__mutex = threading.Lock()
return instance
def __bool__(self):
return bool(self.__x or self.__y)
def frame(self, margins, width, height, auto_sample=False, timing=False):
if timing:
start = time.perf_counter()
x1, y1, x2, y2 = margins
drawing_width = width - x1 - x2
drawing_height = height - y1 - y2
with self.__mutex:
x_tuple = tuple(self.__x)
y_tuple = tuple(self.__y)
if auto_sample and len(x_tuple) > drawing_width:
x_tuple = sample(x_tuple, drawing_width)
y_tuple = sample(y_tuple, drawing_width)
max_y = max(y_tuple)
x_scaling_factor = max(x_tuple) - min(x_tuple)
y_scaling_factor = max_y - min(y_tuple)
coords = tuple(
coord
for x, y in zip(x_tuple, y_tuple)
for coord in (
round(x1 + drawing_width * x / x_scaling_factor),
round(y1 + drawing_height * (max_y - y) / y_scaling_factor)))
if timing:
# noinspection PyUnboundLocalVariable
print(f'len = {len(coords) >> 1}; '
f'sec = {time.perf_counter() - start:.6f}')
return coords
def append(self, x, y):
with self.__mutex:
self.__x.append(x)
self.__y.append(y)
self.__version = uuid.uuid4()
def clear(self):
with self.__mutex:
self.__x.clear()
self.__y.clear()
self.__version = self.EMPTY
def extend(self, iterable):
with self.__mutex:
for x, y in iterable:
self.__x.append(x)
self.__y.append(y)
self.__version = uuid.uuid4()
if __name__ == '__main__':
Application.main()
You can change label text dynamically:
This is a way using textvariable option with StringVar and .set() method
str_var = tk.StringVar(value="Default")
currentValues= Label(win, textvariable=my_string_var)
currentValues.place(x=200, y=100)
str_var.set("New value")
Another way using simply .configure() method
currentValues = Label(win, text = "default")
currentValues.configure(text="New value")
Finally, to make the UI update without waiting the rest of the loop do an update
win.update()
I figured out a liveplot inspired by a demo, where I used this to plot the realtime current-voltage scan in Keithley2410.
The whole script is below:
import matplotlib.pyplot as plt
import numpy as np
import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
from tkinter import ttk
x_data, y_data = [], []
class Win(tk.Tk):
def __init__(self):
super().__init__()
self.title('I-V liveplot')
self.geometry('500x450')
# Frame that holds wigets on the left side
left_frame = ttk.Frame(self)
left_frame.pack(side= "left", padx =10, pady = 10) #, fill="y", expand=True
self.fig = plt.figure(figsize=(4, 3.5), dpi=100)
self.ax = self.fig.add_subplot(1,1,1)
self.line, = self.ax.plot([0], [0])
self.ax.set_xlabel('Voltage / V', fontsize = 12)
self.ax.set_ylabel('Current / A', fontsize = 12)
self.fig.tight_layout()
self.canvas = FigureCanvasTkAgg(self.fig, master=self)
self.toolbar = NavigationToolbar2Tk(self.canvas, self)
self.canvas.get_tk_widget().pack(side= tk.BOTTOM)
voltage_range_label = tk.Label(left_frame, text = "Voltage range")
voltage_range_label.pack(side = "top", padx =10, pady =2)
self.voltage_range = tk.IntVar()
self.voltage_range.set(10)
voltage_range_spinbox = ttk.Spinbox(left_frame, from_=-3e2, to = 5e2, textvariable = self.voltage_range, width=8)
voltage_range_spinbox.pack(side="top", padx =10, pady =5)
voltage_step_label = tk.Label(left_frame, text = "Step")
voltage_step_label.pack(side = "top", padx =10, pady =2)
self.step = tk.IntVar()
self.step.set(1)
step_spinbox = ttk.Spinbox(left_frame, from_=-3e2, to = 5e2, textvariable = self.step, width =9)
step_spinbox.pack(side="top", padx =10, pady =5)
self.start = tk.BooleanVar(value = False)
start_butt = ttk.Button(left_frame, text="Start", command= lambda: self.start.set(True))
start_butt.pack(side='top', padx =10, pady =10)
stop_butt = ttk.Button(left_frame, text="Resume", command=lambda: self.is_paused.set(False))
stop_butt.pack(side="top", padx =10, pady =10)
self.is_paused = tk.BooleanVar() # variable to hold the pause/resume state
restart_butt = ttk.Button(left_frame, text="Pause", command=lambda: self.is_paused.set(True))
restart_butt.pack(side="top", padx =10, pady =10)
def update(self, k=1):
if self.start.get() and not self.is_paused.get():
# quasi For Loop
idx = [i for i in range(0, k, self.step.get())][-1]
x_data.append(idx)
y_data.append(np.sin(idx/5))
self.line.set_data(x_data, y_data)
self.fig.gca().relim()
self.fig.gca().autoscale_view()
self.canvas.draw()
#self.canvas.flush_events()
k += self.step.get()[![enter image description here][2]][2]
if k <= self.voltage_range.get():
self.after(1000, self.update, k)
if __name__ == "__main__":
app = Win()
app.after(1000, app.update)
app.mainloop()
This code works properly and results in an output shown in Graph. I hope it would be helpful.
.
I want to display some live data in a GUI.
I think what you want to do is use the .after() method. The .after() method queues tkinter to run some code after a set time.
For example:
currentValues = Label(win, text = "want to display somewhere like this")
currentValues.place(x=200, y=100)
voltageValues = Label(win, text = "want to display somewhere like this")
voltageValues.place(x=200, y=200)
def live_update():
currentValues['text'] = updated_value
voltageValues['text'] = updated_value
win.after(1000, live_update) # 1000 is equivalent to 1 second (closest you'll get)
live_update() # to start the update loop
1000 units in the after method is the closest you'll get to 1 second exactly.
I was really curious why I cannot get my add_button to work,
as the window fails to come up when creating it.
from tkinter import *
class Calculator:
#-------------------------------------------------
def __init__(self, master):
self.master = master
master.title("Calculator")
self.close_button = Button(master, text = "Close", command = master.destroy)
Label(master, text = "First Digit").grid(row = 0)
Label(master, text = "Second Digit").grid(row = 1)
self.input1 = 0
self.input2 = 0
input1 = Entry(master)
input2 = Entry(master)
input1.grid(row = 0, column = 1)
input2.grid(row = 1, column = 1)
self.close_button.grid(row = 2, column = 0)
self.add_buton = Button(master, text = "Add", command = self.add())
self.add_button.grid(row = 2, column = 1)
master.configure(background = 'grey')
return
#-------------------------------------------------
def add(self):
return self.input1.get() + self.input2.get()
#-------------------------------------------------
#-------------------------------------------------
root = Tk()
calc = Calculator(root)
root.mainloop()
#-------------------------------------------------
Welcome to Stack!
I've looked through you code I've been able to do what you are asking. There were a few errors within your code:
a) you had self.add_buton and self.add_button which caused an error.
b) self.input1 = 0 and self.input2 = 0 are not required.
c) You were calling self.add() as the command and you should be calling self.add. When calling it as a command you do not need ()
d)input1 = Entry(master) should be self.input1 = tk.Entry(master)
e) You should convert your input values into int or float as otherwise it will just one value onto the end of the other. (Eg, 1 + 5 = 15 whereas int(1) + int(5) = 6
Here is your code with the entry boxes working as they should. I have import tkinter as tk hence why it is tk.Entry
from tkinter import *
import tkinter as tk
class Calculator:
#-------------------------------------------------
def __init__(self, master):
self.master = master
master.title("Calculator")
self.close_button = Button(master, text = "Close", command = master.destroy)
Label(master, text = "First Digit").grid(row = 0)
Label(master, text = "Second Digit").grid(row = 1)
self.input1 = tk.Entry(bd=5, width=35, background='gray35', foreground='snow')
self.input2 = tk.Entry(bd=5, width=35, background='gray35', foreground='snow')
self.input1.grid(row = 0, column = 1)
self.input2.grid(row = 1, column = 1)
self.close_button.grid(row = 2, column = 0)
self.add_button = tk.Button(master, text = "Add", command = self.add)
self.add_button.grid(row = 2, column = 1)
master.configure(background = 'grey')
return
#-------------------------------------------------
def add(self):
val = self.input1.get()
print(val)
#-------------------------------------------------
#-------------------------------------------------
root = Tk()
calc = Calculator(root)
root.mainloop()
This should now work how you wanted it too. The variables within the entry can be changed to suit. You were correct in calling the value of the entry with self.input1.get().
Hope this has helped.
I think there's something fundamental I don't understand about tkinter but having read loads of tutorials and other answers, I still don't get it. I'm trying to organise a simple GUI. It should have a left hand pane with a game board (the game is othello) which has active buttons (I've left out the action function as that works ok), then a right hand pane which has 3 panes, top to bottom: one with radio buttons to toggle between 1 or 2 player, one with the current score, and one with a game evaluation. For now these latter 2 are just lines of text.
I thought I could set up a grid structure in a parent frame, then have 4 frames inside that grid, and then widgets inside them. Here's the code (you can ignore Board class unless you want to run it: the bit I'm struggling with is in Master)
from tkinter import *
from collections import defaultdict
from PIL import Image as PIL_Image, ImageTk
class Master:
def __init__(self):
self.board = Board()
self.display = Tk()
self.f = Frame(self.display, width=1050, height=700)
self.f.grid(row=0, column=0, rowspan=8, columnspan=8)
self.frame2 = Frame(self.f)
self.frame2.grid(row=0, column=8, rowspan=4, columnspan=4)
self.frame3 = Frame(self.f)
self.frame3.grid(row=4, column=8, rowspan=2, columnspan=4)
self.frame4 = Frame(self.f)
self.frame4.grid(row=6, column=8, rowspan=2, columnspan=4)
self.text1 = Text(self.frame3)
self.text1.pack()
self.text2 = Text(self.frame4)
self.text2.pack()
self.square = defaultdict(Button)
self.images = [ImageTk.PhotoImage(PIL_Image.open(f)) for f in ['white.png', 'empty.png', 'black.png']]
modes = [('{} vs {}'.format(i,j), (i, j)) for i in ['human','computer']
for j in ['human', 'computer']]
v = StringVar()
v.set(modes[0][1])
for text, mode in modes:
b = Radiobutton(self.frame2, text=text, variable=v, value=mode, command=lambda mode=mode: self.cp_set(mode))
b.pack(anchor=W)
self.text1.insert(END, 'score')
self.text2.insert(END, 'evaluation')
self.draw_board()
self.display.mainloop()
def draw_board(self):
for i, j in [(x,y) for x in range(8) for y in range(8)]:
self.square[i,j] = Button(self.f, command=lambda i=i, j=j: self.press(i,j), image=self.images[1 + self.board.square[i,j]])
self.square[i,j].image = 1 + self.board.square[i,j]
self.square[i,j].grid(column=i, row=j)
def cp_set(self, m):
self.pb, self.pw = m
return
def press(self, a, b):
# make it do something
return
class Board:
def __init__(self, parent=None):
self.parent = parent
if parent:
self.square = parent.square.copy()
self.black_next = not parent.black_next
self.game_over = parent.game_over
else:
self.square = defaultdict(int)
for square in [(x,y) for x in range(8) for y in range(8)]:
self.square[square] = 0
for square in [(3,3), (4,4)]:
self.square[square] = 1
for square in [(3,4), (4,3)]:
self.square[square] = -1
self.black_next = True
self.game_over = False
This gives a picture in which the top 4 rows of the game board line up with the radiobuttons but the bottom 4 rows get split up, with both text lines sitting in rows of their own, not opposite a row of the game board.
Seeing that this didn't work, I read something about the problem being grid not preserving column and rows between parent and child frames, so I tried a different approach in which the parent frame splits into 2 columns, and then the child frame sits underneath that with its own row/column definitions. But that didn't work either:
self.board = Board()
self.display = Tk()
self.f = Frame(self.display, width=1050, height=700)
self.f.grid(row=0, column=0, rowspan=1, columnspan=2)
self.frame1 = Frame(self.f, width=700, height=700)
self.frame1.grid(row=0, column=0, rowspan=8, columnspan=8)
self.f2 = Frame(self.f)
self.f2.grid(row=0, column=1, rowspan=2, columnspan=1)
self.frame2 = Frame(self.f2, width=350, height=350)
self.frame2.grid(row=0, column=0)
self.frame3 = Frame(self.f2, width=350, height=350)
self.frame3.grid(row=1, column=0)
self.text1 = Text(self.frame2)
self.text1.pack()
self.text2 = Text(self.frame3)
self.text2.pack()
# in this version, Radiobuttons are children of self.frame2,
# and Buttons in draw_board() are children of self.frame1
I really liked this second version until I saw the results in which the board has disappeared altogether. Any pointers would be much appreciated.
You might want to try something like this:
from tkinter import *
from collections import defaultdict
from PIL import Image as PIL_Image, ImageTk
class Master:
def __init__(self):
self.board = Board()
self.display = Tk()
self.left = Frame(self.display)
self.left.grid(row=0, column=0, sticky="new")
self.right = Frame(self.display)
self.right.grid(row=0, column=1)
self.right_top = Frame(self.right)
self.right_top.grid(row=0, column=0, sticky="nsw")
self.right_mid = Frame(self.right)
self.right_mid.grid(row=1, column=0)
self.right_bottom = Frame(self.right)
self.right_bottom.grid(row=2, column=0)
self.text1 = Text(self.right_mid)
self.text1.pack()
self.text2 = Text(self.right_bottom)
self.text2.pack()
self.square = defaultdict(Button)
self.images = [ImageTk.PhotoImage(PIL_Image.open(f)) for f in ['white.png', 'empty.png', 'black.png']]
modes = [('{} vs {}'.format(i,j), (i, j)) for i in ['human','computer'] for j in ['human', 'computer']]
v = StringVar()
v.set(modes[0][1])
for text, mode in modes:
b = Radiobutton(self.right_top, text=text, variable=v, value=mode, command=lambda mode=mode: self.cp_set(mode))
b.pack(anchor=W)
self.text1.insert(END, 'score')
self.text2.insert(END, 'evaluation')
self.draw_board()
self.display.mainloop()
def draw_board(self):
for i, j in [(x,y) for x in range(8) for y in range(8)]:
self.square[i,j] = Button(self.left, command=lambda i=i, j=j: self.press(i,j), image=self.images[1 + self.board.square[i,j]])
self.square[i,j].image = 1 + self.board.square[i,j]
self.square[i,j].grid(column=i, row=j)
The layout of the frames will be like this:
I'm just beginning to program in python and I'm using it to make a little program with an GUI (using tkinter) that can take data from an excel file (using openpyxl). Let the user change things when necesarry and then use a button to write the data from the entries to a data file (.dat) (preferable by updating the values in the defaultdict arrays and then write the .dat file) and use a modelling language (pyomo) to create a model with the provided data and solve it with the cbc solver.
I'm now sofar that I made the model, the graphical interface (which is filled with data from the excel file). However I can't get the data in the entries fields back (to write update the defaultdicts arrays). I understand the simple examples on stackoverflow (with entry.get()), but it didn't worked on my example (probably because I use notbook tabs, panels and frames or I messed something up).
I use notebook tabs instead of one page, because I will have more (around 5) other categories of data in the complete program. At last I want to make the programm is such a way that it can adapt to the input (so it does not know if there are going to be 3, 8 or 10 facilities). I use python version 3.5.1. Here is the link to the excel file: https://drive.google.com/file/d/0B5vmtJnltudJWW4xakZlYnQ3RTg/view?usp=sharing
import sys
from tkinter import ttk
import tkinter as tk
import openpyxl
import numpy as np
import os
from collections import defaultdict
from facility_panel import *
class App(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.getdata()
self.tabes()
button_box = tk.Frame(self)
tk.Button(button_box, text='Create Planning', command=self.on_ok_clicked).grid(pady=15)
button_box.pack()
self.create_menu()
self.set_keybindings()
#staticmethod
def center_on_screen(toplevel):
toplevel.update_idletasks()
w = toplevel.winfo_screenwidth()
h = toplevel.winfo_screenheight()
size = tuple(int(_) for _ in toplevel.geometry().split('+')[0].split('x'))
x = w/2 - size[0]/2
y = h/2 - size[1]/2
toplevel.geometry('%dx%d+%d+%d' % (size + (x, y)))
def set_keybindings(self):
self.bind_all('<Control-o>', lambda event: self.open_file())
self.bind_all('<Control-s>', lambda event: self.save_file())
self.bind_all('<Control-q>', self.quit_app)
self.bind_all('<Control-h>', lambda event: self.show_help())
self.bind_all('<Return>', lambda event: self.on_ok_clicked())
def on_ok_clicked(self):
print ('Entry text: %s' % self.entry.get())
print ('Scale value: %.1f' % self.scale.get())
print ('Checkbutton value: %i' % self.checkbox_val.get())
print ('Spinbox value: %i' % int(self.spinbox.get()))
print ('OptionMenu value: %s' % self.enum_val.get())
def create_menu(self):
menubar = tk.Menu(self)
fileMenu = tk.Menu(menubar, tearoff=False)
menubar.add_cascade(label="File", underline=0, menu=fileMenu)
fileMenu.add_command(label="Open", underline=1, command=self.open_file, accelerator="Ctrl+O")
fileMenu.add_command(label="Save", underline=1, command=self.save_file, accelerator="Ctrl+S")
fileMenu.add_command(label="Quit", underline=1, command=self.quit_app, accelerator="Ctrl+Q")
helpMenu = tk.Menu(menubar, tearoff=False)
menubar.add_cascade(label="Help", underline=0, menu=helpMenu)
helpMenu.add_command(label="Help", underline=1, command=self.show_help, accelerator="Ctrl+H")
helpMenu.add_command(label="About", underline=1, command=self.about_app)
self.config(menu=menubar)
def open_file(self):
"""Options are explained here: http://tkinter.unpythonic.net/wiki/tkFileDialog"""
filename = askopenfilename(title='Open a file')
if filename:
print ('Open and do something with %s' % filename)
def save_file(self):
"""Options are explained here: http://tkinter.unpythonic.net/wiki/tkFileDialog"""
filename = asksaveasfilename()
if filename:
print ('Save something to %s' % filename)
def quit_app(self):
app.destroy()
def show_help(self):
# FIXME: pressing return correctly closes dialog, but also incorrectly fires the main window's 'on_click' method
about_text = """
Contact: \n
example#hotmail.com"""
about_dialog = tk.Toplevel(self)
about_dialog.title('About App')
about_dialog.bind('<Escape>', lambda event: about_dialog.destroy())
about_dialog.bind('<Return>', lambda event: about_dialog.destroy())
App.center_on_screen(about_dialog)
tk.Message(about_dialog, text=about_text).pack()
button = tk.Button(about_dialog, text='Close', command=about_dialog.destroy).pack()
def about_app(self):
# FIXME: pressing return correctly closes dialog, but also incorrectly fires the main window's 'on_click' method
about_text = """
This application is made by Jan Jansen\n
version 0.7"""
about_dialog = tk.Toplevel(self)
about_dialog.title('About App')
about_dialog.bind('<Escape>', lambda event: about_dialog.destroy())
about_dialog.bind('<Return>', lambda event: about_dialog.destroy())
App.center_on_screen(about_dialog)
tk.Message(about_dialog, text=about_text).pack()
button = tk.Button(about_dialog, text='Close', command=about_dialog.destroy).pack()
def tabes(self):
nb = ttk.Notebook()
nb.pack(expand=1, fill="both")
# Frame to hold contentx
frame = tk.Frame(nb)
vscroll = tk.Scrollbar(frame, orient="vertical")
#panel['yscroll'] = vscroll.set
vscroll.pack(side="right", fill="y")
for facilityname in Facilities:
panel = FacilityPanel(frame, facilityname, capfacility[facilityname], safetystock[facilityname], maxpressure[facilityname], str(compulsorystarttime[facilityname]), str(compulsoryendtime[facilityname]), demandmatrix[facilityname][1], demandmatrix[facilityname][2], demandmatrix[facilityname][3], demandmatrix[facilityname][4], demandmatrix[facilityname][5], demandmatrix[facilityname][6], demandmatrix[facilityname][7])
panel.pack(fill="both")
# add to notebook (underline = index for short-cut character)
nb.add(frame, text='Facilities', underline=0, padding=2)
#--------------------------------------------------------------------------------------------------------
def getdata(self):
wb = openpyxl.load_workbook("data.xlsx")
ws = wb["Facilities"]
global Facilities
Facilities = ([])
row_count = ws.max_row
column_count = ws.max_column
global initlevel
initlevel = defaultdict(dict)
global capfacility
capfacility = defaultdict(dict)
global safetystock
safetystock = defaultdict(dict)
global maxpressure
maxpressure = defaultdict(dict)
global pressureincrease
pressureincrease = defaultdict(dict)
global compulsorystarttime
compulsorystarttime = defaultdict(dict)
global compulsoryendtime
compulsoryendtime = defaultdict(dict)
global demandmatrix
demandmatrix = defaultdict(dict)
for i in range(3, row_count+1, 1):
Facilities.append(ws.cell(row = i, column = 1).value)
initlevel[ws.cell(row = i, column = 1).value] = ws.cell(row = i, column = 2).value
capfacility[ws.cell(row = i, column = 1).value] = ws.cell(row = i, column = 3).value
safetystock[ws.cell(row = i, column = 1).value] = ws.cell(row = i, column = 4).value
maxpressure[ws.cell(row = i, column = 1).value] = ws.cell(row = i, column = 5).value
pressureincrease[ws.cell(row = i, column = 1).value] = ws.cell(row = i, column = 6).value
compulsorystarttime[ws.cell(row = i, column = 1).value] = ws.cell(row = i, column = 7).value
compulsoryendtime[ws.cell(row = i, column = 1).value] = ws.cell(row = i, column = 8).value
for j in range (9, column_count+1, 1):
demandmatrix[ws.cell(row = i, column = 1).value][ws.cell(row = 2, column = j).value] = ws.cell(row = i, column = j).value
if __name__ == "__main__":
app = App()
app.title("Planning")
toplevel = app.winfo_toplevel()
toplevel.wm_state('zoomed')
app.mainloop()
And this is the class I made:
from tkinter import *
class FacilityPanel(Frame):
def __init__(self, app, facility_name, capacity, safetystock, maxpressure, compulsorystarttime, compulsoryendtime, demandma, demanddi, demandwo, demanddo, demandvr, demandza, demandzo):
Frame.__init__(self, app)
group = LabelFrame(self, text=facility_name)
group.pack(side =LEFT)
group.enable_facility = IntVar()
enable_button = Checkbutton(group, variable = group.enable_facility,
command = print("toggle"))
enable_button.pack(side = LEFT)
enable_button.select()
group.init_level = IntVar()
init_label = Label(group, text="Current Level: 5,06 m\u00B3")
init_label.pack(side = LEFT)
group.capacity = DoubleVar()
capacity_label = Label(group, text="Capacity:")
capacity_label.pack(side = LEFT)
capacity_entry = Entry(group, width=8)
capacity_entry.pack(side = LEFT)
capacity_entry.insert(0, capacity)
capacity_label_unit = Label(group, text="kg ")
capacity_label_unit.pack(side = LEFT)
group.safetystock = DoubleVar()
safetystock_label = Label(group, text="Safetystock:")
safetystock_label.pack(side = LEFT)
safetystock_entry = Entry(group, width=8)
safetystock_entry.pack(side = LEFT)
safetystock_entry.insert(0, safetystock)
safetystock_label_unit = Label(group, text="kg ")
safetystock_label_unit.pack(side = LEFT)
group.maxpressure = DoubleVar()
maxpressure_label = Label(group, text="Maxpressure:")
maxpressure_label.pack(side = LEFT)
maxpressure_entry = Entry(group, width=8)
maxpressure_entry.pack(side = LEFT)
maxpressure_entry.insert(0, maxpressure)
maxpressure_label_unit = Label(group, text="bar ")
maxpressure_label_unit.pack(side = LEFT)
group.comp_start_time = DoubleVar()
comp_time1_label = Label(group, text="Unload time window:")
comp_time1_label.pack(side = LEFT)
comp_start_time_entry = Entry(group, width=8)
comp_start_time_entry.pack(side = LEFT)
comp_start_time_entry.insert(0, compulsorystarttime)
comp_time2_label = Label(group, text="-")
comp_time2_label.pack(side = LEFT)
comp_end_time_entry = Entry(group, width=8)
comp_end_time_entry.pack(side = LEFT)
comp_end_time_entry.insert(0, compulsoryendtime)
comp_time3_label = Label(group, text="hours ")
comp_time3_label.pack(side = LEFT)
group.demandmaandag = DoubleVar()
demandmaandag_label = Label(group, text="Maandag:")
demandmaandag_label.pack(side = LEFT)
demandmaandag_entry = Entry(group, width=8)
demandmaandag_entry.pack(side = LEFT)
demandmaandag_entry.insert(0, demandma)
demandmaandag_label_unit = Label(group, text="kg ")
demandmaandag_label_unit.pack(side = LEFT)
group.demanddinsdag = DoubleVar()
demanddinsdag_label = Label(group, text="Dinsdag:")
demanddinsdag_label.pack(side = LEFT)
demanddinsdag_entry = Entry(group, width=8)
demanddinsdag_entry.pack(side = LEFT)
demanddinsdag_entry.insert(0, demanddi)
demanddinsdag_label_unit = Label(group, text="kg ")
demanddinsdag_label_unit.pack(side = LEFT)
group.demandwoensdag = DoubleVar()
demandwoensdag_label = Label(group, text="Woensdag:")
demandwoensdag_label.pack(side = LEFT)
demandwoensdag_entry = Entry(group, width=8)
demandwoensdag_entry.pack(side = LEFT)
demandwoensdag_entry.insert(0, demandwo)
demandwoensdag_label_unit = Label(group, text="kg ")
demandwoensdag_label_unit.pack(side = LEFT)
group.demanddonderdag = DoubleVar()
demanddonderdag_label = Label(group, text="Donderdag:")
demanddonderdag_label.pack(side = LEFT)
demanddonderdag_entry = Entry(group, width=8)
demanddonderdag_entry.pack(side = LEFT)
demanddonderdag_entry.insert(0, demanddo)
demanddonderdag_label_unit = Label(group, text="kg ")
demanddonderdag_label_unit.pack(side = LEFT)
group.demandvrijdag = DoubleVar()
demandvrijdag_label = Label(group, text="Vrijdag:")
demandvrijdag_label.pack(side = LEFT)
demandvrijdag_entry = Entry(group, width=8)
demandvrijdag_entry.pack(side = LEFT)
demandvrijdag_entry.insert(0, demandvr)
demandvrijdag_label_unit = Label(group, text="kg ")
demandvrijdag_label_unit.pack(side = LEFT)
group.demandzaterdag = DoubleVar()
demandzaterdag_label = Label(group, text="Zaterdag:")
demandzaterdag_label.pack(side = LEFT)
demandzaterdag_entry = Entry(group, width=8)
demandzaterdag_entry.pack(side = LEFT)
demandzaterdag_entry.insert(0, demandza)
demandzaterdag_label_unit = Label(group, text="kg ")
demandzaterdag_label_unit.pack(side = LEFT)
group.demandzaterdag = DoubleVar()
demandzondag_label = Label(group, text="Zondag:")
demandzondag_label.pack(side = LEFT)
demandzondag_entry = Entry(group, width=8)
demandzondag_entry.pack(side = LEFT)
demandzondag_entry.insert(0, demandzo)
demandzondag_label_unit = Label(group, text="kg ")
demandzondag_label_unit.pack(side = LEFT)
I found something that worked on this question:
tkinter create labels and entrys dynamically
I made a global entry for every entryfield
I want to make a grid of entry boxes that I can edit and save to a text file somewhere else, but every time I run my code, If I call the variable "e", I can only edit the last box that was made.
from Tkinter import *
class Application(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.grid()
self.create_widgets()
def create_widgets(self):
self.TXTlist = open('txtlist.txt', 'r+')
self.row = self.TXTlist.readline()
self.row = self.row.rstrip('\n')
self.row = self.row.replace('characters = ', "") #should end up being "6"
self.columns = self.TXTlist.readline()
self.columns = self.columns.rstrip('\n')
self.columns = self.columns.replace('columns = ', "") #should end up being "9"
i = 0
x = 0
for i in range (int(self.row)):
for x in range (int(self.columns)):
sroot = str('row' + str(i) + 'column' + str(x))
e = Entry(self, width=15)
e.grid(row = i, column = x, padx = 5, pady = 5, sticky = W)
e.delete(0, END)
e.insert(0, (sroot))
x = x + 1
x = 0
i = i + 1
root = Tk()
root.title("Longevity")
root.geometry("450x250")
app = Application(root)
root.mainloop()
I would store the entries in some sort of data structure to have easy access to them later. a list of lists would work nicely for this:
self.entries = []
for i in range (int(self.row)):
self.entries.append([])
for x in range (int(self.columns)):
...
e = Entry(self, width=15)
self.entries[-1].append(e)
...
Now you have a reference to the entry box:
self.entries[row_idx][col_idx]
And you can modify it however you want.