I created one window and split it into 3 different windows. I want to add a clock to each screen, that does not depend on the other clocks.
my code opens 2 window- one is the timer and the second one is the window that i split to 3 windows.
from tkinter import *
import Tkinter as tk
class split_screen(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.label = tk.Label(self, text="", width=10,fg="black", bg ="red", font="david 18 bold underline")
self.label.pack()
self.remaining = 0
self.countdown(1000)
self.configure(background="black")
def screen(self):
root = Tk()
root.geometry("650x700")
root.configure(bg='black')
root.title("test")
left = Frame(root, borderwidth=200, relief="solid")
right = Frame(root, borderwidth=20, relief="solid")
box3 = Frame(right, borderwidth=2, relief="solid")
box1 = Frame(left, borderwidth=2, relief="solid")
box2 = Frame(left, borderwidth=2, relief="solid")
label1 = Label(box3, text="winner's" + "\n\n\n" + "Player 1",fg= "black", bg = "red", font = "david 18 bold underline")
label2 = Label(box1, text="Computer 1",fg = "black", bg = "red", font= "david 18 bold underline")
label3 = Label(box2, text="Computer 2",fg = "black", bg = "red", font= "david 18 bold underline")
left.pack(side="left", expand=True, fill="both")
right.pack(side="right", expand=True, fill="both")
box3.pack(expand=True, fill="both", padx=10, pady=10)
box1.pack(expand=True, fill="both", padx=10, pady=10)
box2.pack(expand=True, fill="both", padx=10, pady=10)
label1.pack()
label2.pack()
label3.pack()
def countdown(self, remaining = None):
if remaining is not None:
self.remaining = remaining
if self.remaining <= 0:
self.label.configure(text="time's up!")
else:
self.label.configure(text="%d" % self.remaining)
self.remaining = self.remaining - 1
self.after(1000, self.countdown)
if __name__ == "__main__":
app = split_screen()
app.screen()
app.mainloop()
I did multiple changes :
As Bryan Oakley said, don't create multiple instances of Tk(). You also don't need to import tkinter twice.
import tkinter as tk
class split_screen(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.geometry("650x700")
self.configure(bg='black')
self.title("test")
left = tk.Frame(self, borderwidth=200, relief="solid")
right = tk.Frame(self, borderwidth=20, relief="solid")
box1 = tk.Frame(left, borderwidth=2, relief="solid")
box2 = tk.Frame(left, borderwidth=2, relief="solid")
box3 = tk.Frame(right, borderwidth=2, relief="solid")
label1 = tk.Label(box3, text="winner's" + "\n\n\n" + "Player 1",fg= "black", bg = "red", font = "david 18 bold underline")
label2 = tk.Label(box1, text="Computer 1",fg = "black", bg = "red", font= "david 18 bold underline")
label3 = tk.Label(box2, text="Computer 2",fg = "black", bg = "red", font= "david 18 bold underline")
clock1 = Clock(box1, 1000)
clock2 = Clock(box2, 2000)
clock3 = Clock(box3, 1300)
left.pack(side="left", expand=True, fill="both")
right.pack(side="right", expand=True, fill="both")
box3.pack(expand=True, fill="both", padx=10, pady=10)
box1.pack(expand=True, fill="both", padx=10, pady=10)
box2.pack(expand=True, fill="both", padx=10, pady=10)
label1.pack()
label2.pack()
label3.pack()
class Clock():
def __init__(self, frame, count):
self.frame = frame
self.label = tk.Label(frame, text="", width=10,fg="black", bg ="red", font="david 18 bold underline")
self.label.pack()
self.remaining = 0
self.countdown(count)
frame.configure(background="black")
def countdown(self, remaining = None):
if remaining is not None:
self.remaining = remaining
if self.remaining <= 0:
self.label.configure(text="time's up!")
else:
self.label.configure(text="%d" % self.remaining)
self.remaining = self.remaining - 1
self.frame.after(1000, self.countdown)
if __name__ == "__main__":
app = split_screen()
app.mainloop()
The simplest solution -- and arguably the best -- is to create a class that represents a single timer. You can then make as many instances as you want. This is precisely the sort of thing that classes are for: to encapsulate some behavior inside an object.
Since you're using a label to display the time, you can either have the timer class inherit from Label, or you can pass the label in when creating the timer.
Here's an example which inherits from tk.Label:
import tkinter as tk
class TimerLabel(tk.Label):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.after_id = None
self.remaining = None
def countdown(self, seconds):
if seconds <= 0:
self.configure(text="Time's up!")
else:
self.configure(text=f"{seconds}")
self.after_id = self.after(1000, self.countdown, seconds-1)
def stop(self):
if self.after_id:
self.configure(text="cancelled")
self.after_cancel(self.after_id)
Using the above class definition, you can create as many timer widgets as you want. Here's an example that creates three:
root = tk.Tk()
timer1 = TimerLabel(root, width=10)
timer2 = TimerLabel(root, width=10)
timer3 = TimerLabel(root, width=10)
timer1.pack(side="top", padx=20)
timer2.pack(side="top", padx=20)
timer3.pack(side="top", padx=20)
timer1.countdown(30)
timer2.countdown(20)
timer3.countdown(10)
root.mainloop()
Related
I've made a simple GUI for placing objects in RoboDK via a Python script using Tkinter.
Essentailly, the user selects an object using the btnSelect button, which then updates the entry widgets with its coordinates (x, y, z, then Euler rotation). The user can then edit the entry widgets then select the "Move object" button (or btnMove in the code) to move the object to the new position. However, when selecting an object for the second time, the entry fields cannot be edited without selecting a new object.
from tkinter.constants import DISABLED, NORMAL, CENTER, END
from typing import *
import tkinter as tk
import threading
from robolink import * # RoboDK API
from robodk import * # Robot toolbox
X_MAX = 500
X_MIN = 0
Y_MAX = 300
Y_MIN = -360
ROTZ_MAX = 180
ROTZ_MIN = -180
# Keep track of selected item
obj = None
def main():
rdk = Robolink()
window = buildGUI(rdk)
window.mainloop()
def buildGUI(rdk: Robolink) -> tk.Tk:
window = tk.Tk()
canvas = tk.Canvas(window, width=200)
canvas.grid(columnspan=3, rowspan=14)
# Set the window title (must be unique for the docking to work, try to be creative)
window_title = 'Move object window'
window.title(window_title)
title = tk.Label(window, text="Move Object", font="none 14 bold")
title.grid(columnspan=3, column=0, row=0)
# Delete the window when we close it
window.protocol("WM_DELETE_WINDOW", lambda: onClose(window))
deadspace1 = tk.Label(text="")
deadspace1.grid(columnspan=3, column=0, row=1)
selectText = tk.StringVar()
btnSelect = tk.Button(window, textvariable=selectText, height=2, width=0,
bg="#bbbbbb", fg='white', justify=CENTER)
selectText.set("Select object")
btnSelect.grid(column=1, row=2)
deadspace2 = tk.Label("")
deadspace2.grid(columnspan=3, column=0, row=3)
objName = tk.StringVar()
objLabel = tk.Label(window, textvariable=objName, font="none 12 bold")
objName.set("None Selected")
objLabel.grid(columnspan=3, column=0, row=4)
deadspace2 = tk.Label("")
deadspace2.grid(columnspan=3, column=0, row=5)
# Position options
xLabel = tk.Label(window, text="x: ", font='none 12')
xLabel.grid(column=0, row=6)
xEntry = tk.Entry(window, width=10)
xEntry.grid(columnspan=2, column=1, row=6)
yLabel = tk.Label(window, text="y: ", font='none 12')
yLabel.grid(column=0, row=7)
yEntry = tk.Entry(window, width=10)
yEntry.grid(columnspan=2, column=1, row=7)
zLabel = tk.Label(window, text="z: ", font='none 12')
zLabel.grid(column=0, row=8)
zEntry = tk.Entry(window, width=10)
zEntry.grid(columnspan=2, column=1, row=8)
# Rotation options
rxLabel = tk.Label(window, text="rx: ", font='none 12')
rxLabel.grid(column=0, row=9)
rxEntry = tk.Entry(window, width=10)
rxEntry.grid(columnspan=2, column=1, row=9)
ryLabel = tk.Label(window, text="ry: ", font='none 12')
ryLabel.grid(column=0, row=10)
ryEntry = tk.Entry(window, width=10)
ryEntry.grid(columnspan=2, column=1, row=10)
rzLabel = tk.Label(window, text="rz: ", font='none 12')
rzLabel.grid(column=0, row=11)
rzEntry = tk.Entry(window, width=10)
rzEntry.grid(columnspan=2, column=1, row=11)
entries = [xEntry, yEntry, zEntry, rzEntry, ryEntry, rxEntry]
deadspace3 = tk.Label(text="")
deadspace3.grid(columnspan=3, column=0, row=12)
btnMove = tk.Button(window, text="Move object", height=2, width=0,
bg="#bbbbbb", fg='white', justify=CENTER,
command=lambda: moveObject(entries))
btnMove.grid(column=1, row=13)
selectCallback = lambda: select_item(rdk, selectText, objName, entries)
btnSelect['command'] = selectCallback
EmbedWindow(window_title)
return window
# Close the window
def onClose(window: tk.Tk):
window.destroy()
quit(0)
def select_item(rdk: Robolink, selectText: tk.StringVar, objName: tk.Label,
entries: List[tk.Entry]):
def thread_btnSelect():
selectText.set("Waiting...")
item = rdk.ItemUserPick('Select an item', ITEM_TYPE_OBJECT)
if item.Valid():
global obj
obj = item
objName.set(item.Name())
updateObjectPosition(item, entries)
selectText.set("Select object")
# Prevent RoboDK from freezing
threading.Thread(target=thread_btnSelect).start()
def updateObjectPosition(item: Item, entries: List[tk.Entry]):
pose = item.Pose()
coords = Pose_2_KUKA(pose)
for entry, coord in zip(entries, coords):
entry.delete(0, END)
entry.insert(0, str(coord))
def moveObject(entries: tk.Entry):
global obj
if obj is None:
ShowMessage("No object selected")
return
try:
coords = getCoords(entries)
obj.setPose(KUKA_2_Pose(coords))
except Exception as err:
ShowMessage(str(err))
def getCoords(entries: List[tk.Entry]) -> list:
coords = [0] * 6
for i, entry in enumerate(entries):
coords[i] = float(entry.get())
return coords
if __name__ == "__main__":
main()
Using a tkinter.Variable such as tkinter.DoubleVar with your entries should fix this issue. You can also use tkinter.DoubleSpin for convenience.
x, y, z, rx, ry, rz = Pose_2_TxyzRxyz(item.Pose())
xVar = tk.DoubleVar(value=x)
xEntry = tk.Spinbox(window, textvariable=xVar, format="%.2f", from_=-9999999, to=9999999)
xVal = xVal.get()
This is a part of code from my school project.
from tkinter import *
from tkinter.font import Font
class student_window():
def __init__(self, master):
self.student_win = master
#window = Toplevel(self.master)
self.student_win.geometry("1280x720")
self.header1Font = Font(family='Helvetica', size=20)
self.optionFont = Font(family='Sans Serrif', size=20)
self.student_win.focus()
self.show_window()
def show_window(self):
print("ookk")
self.student_win.title("Student Window")
self.option_frame = Frame(self.student_win, width=200, height=720)
lbl_header = Label(self.option_frame,text="EXAMINATION", font=self.header1Font, fg='white', bg='#172D44').grid(row=0,column=0, sticky=NSEW)
lbl_welcome = Label(self.option_frame, text="Welcome,", fg='#E9F1F7', bg='#2A3F54').grid(row=1,column=0)
lbl_username = Label(self.option_frame, text="Username", fg='white', bg='#2A3F54').grid(row=2,column=0)
lbl_header2 = Label(self.option_frame, text="STUDENT CORNER", fg='white', bg='#2A3F54').grid(row=3, column=0)
self.btn_tests = Button(self.option_frame, text="Attempt Exam", fg='#E9F1F7', bg='#35495D', relief=FLAT)
self.btn_tests.grid(row=4,column=0, sticky=NSEW)
self.btn_attempts = Button(self.option_frame, text="Attempts", fg='#E9F1F7', bg='#2A3F54', relief=FLAT)
self.btn_attempts.grid(row=5, column=0, sticky=NSEW)
self.btn_result = Button(self.option_frame, text="Result", fg='#E9F1F7', bg='#2A3F54', relief=FLAT)
self.btn_result.grid(row=6, column=0, sticky=NSEW)
self.btn_goBack = Button(self.option_frame, text="Go Back", fg='#E9F1F7', bg='#2A3F54', relief=FLAT)
self.btn_goBack.grid(row=7, column=0, sticky=NSEW)
self.option_frame.configure(bg='#2A3F54')
self.option_frame.grid(row=0, column=0)
self.option_frame.grid_propagate(0)
self.main_frame = Frame(self.student_win, width=880, height=720)
self.main_result_frame = Frame(self.main_frame)
self.main_result_frame.grid(row=0,column=0)
self.attempts_frame = Frame(self.main_frame)
self.attempts_frame.grid(row=0, column=0)
self.test_frame = Frame(self.main_frame)
lbl_test = Label(self.test_frame, text="In test frame").pack()
self.test_frame.grid(row=0,column=0)
self.main_frame.grid(row=0,column=1)
self.main_frame.grid_propagate(0)
self.info_frame = Frame(self.student_win, width=200, height=720)
self.btn_username = Button(self.info_frame, text="Username", relief=FLAT)
self.btn_username.grid(row=0,column=0)
self.userInfo_frame = Frame(self.info_frame)
self.info_frame.grid(row=0, column=2)
self.info_frame.grid_propagate(0)
root = Tk()
student_window(root)
root.mainloop()
And it looks something like this.
The Student Panel for my project
The whole window is divided into three frames and want to expand each label and button of the left frame(self.option_frame) to fill it horizontally. I tried doing sticky=EW and sticky=NSEW but still some space is left. How do I fix that?
You need to call self.option_frame.columnconfigure(0, weight=1) to make column 0 to use all the available horizontal space.
I was just trying some things and what I have found to be working is to make the label width bigger than than the frame then anchoring the text to the left.
I'm trying to make a mini timer programme, but I have a question: each frame uses the same function called setTimer, so what frame should I reference in the setTimer function? Here is my code:
def createFrames(self):
self.timer1_frame = Frame(root, width=300, height=300, background="red")
self.timer1_frame.grid_propagate(0)
self.timer1_frame.grid(row=0, column=0)
self.timer2_frame = Frame(root, width=300, height=300, background="blue")
self.timer2_frame.grid_propagate(0)
self.timer2_frame.grid(row=0, column=1)
self.timer3_frame = Frame(root, width=300, height=300, background="orange")
self.timer3_frame.grid_propagate(0)
self.timer3_frame.grid(row=1, column=0)
self.timer4_frame = Frame(root, width=300, height=300, background="yellow")
self.timer4_frame.grid_propagate(0)
self.timer4_frame.grid(row=1, column=1)
def createWidgets(self):
self.setTimer1_button = Button(self.timer1_frame, text="SET TIMER", command=self.setTimer)
self.setTimer1_button.grid(row=0, column=0, padx=30, pady=20)
self.setTimer2_button = Button(self.timer2_frame, text="SET TIMER", command=self.setTimer)
self.setTimer2_button.grid(row=0, column=1, padx=30, pady=20)
self.setTimer3_button = Button(self.timer3_frame, text="SET TIMER", command=self.setTimer)
self.setTimer3_button.grid(row=1, column=0, padx=30, pady=20)
self.setTimer4_button = Button(self.timer4_frame, text="SET TIMER", command=self.setTimer)
self.setTimer4_button.grid(row=1, column=1, padx=30, pady=20)
def setTimer(self):
self.hoursLabel = Label(root, text="Hours: ")
self.minutesLabel = Label(root, text="Minutes: ")
self.secondsLabel = Label(root, text="Seconds: ")
As you can see, I'm referencing root in my setTimer function but I don't think it's correct, what would I put there instead so it knows which frame I'm referring to, rather than having to write 4 lots of the same code (is this possible?)
You could create method with argument frame which is used in Label
def setTimer(self, frame):
self.hoursLabel = Label(frame, text="Hours: ")
# ... rest ...
and then you can use lambda in command= to assign function with argument
self.setTimer1_button = tk.Button..., command=lambda:self.setTimer(self.timer1_frame))
And it works.
But it has one problem: in all frames it assigns labels to the same variables self.hoursLabel, etc. so you can't access labels to change text (ie. to update time). You would have to use separated variables but it would need to keep them on list or dictionary and use frame as key.
import tkinter as tk
class Window():
def __init__(self):
# dictionary for labels
self.labels = {}
self.createFrames()
self.createWidgets()
def createFrames(self):
self.timer1_frame = tk.Frame(root, width=300, height=300, background="red")
self.timer1_frame.grid_propagate(0)
self.timer1_frame.grid(row=0, column=0)
self.timer2_frame = tk.Frame(root, width=300, height=300, background="blue")
self.timer2_frame.grid_propagate(0)
self.timer2_frame.grid(row=0, column=1)
self.timer3_frame = tk.Frame(root, width=300, height=300, background="orange")
self.timer3_frame.grid_propagate(0)
self.timer3_frame.grid(row=1, column=0)
self.timer4_frame = tk.Frame(root, width=300, height=300, background="yellow")
self.timer4_frame.grid_propagate(0)
self.timer4_frame.grid(row=1, column=1)
def createWidgets(self):
self.setTimer1_button = tk.Button(self.timer1_frame, text="SET TIMER", command=lambda:self.setTimer(self.timer1_frame))
self.setTimer1_button.grid(row=0, column=0, padx=30, pady=20)
self.setTimer2_button = tk.Button(self.timer2_frame, text="SET TIMER", command=lambda:self.setTimer(self.timer2_frame))
self.setTimer2_button.grid(row=0, column=0, padx=30, pady=20)
self.setTimer3_button = tk.Button(self.timer3_frame, text="SET TIMER", command=lambda:self.setTimer(self.timer3_frame))
self.setTimer3_button.grid(row=0, column=0, padx=30, pady=20)
self.setTimer4_button = tk.Button(self.timer4_frame, text="SET TIMER", command=lambda:self.setTimer(self.timer4_frame))
self.setTimer4_button.grid(row=0, column=0, padx=30, pady=20)
def setTimer(self, frame):
self.hoursLabel = tk.Label(frame, text="Hours: ")
self.minutesLabel = tk.Label(frame, text="Minutes: ")
self.secondsLabel = tk.Label(frame, text="Seconds: ")
self.hoursLabel.grid(row=1)
self.minutesLabel.grid(row=2)
self.secondsLabel.grid(row=3)
# remember labels in dictionary
self.labels[frame] = [self.hoursLabel, self.minutesLabel, self.secondsLabel]
# start update time
self.updateTimer(frame, 0)
def updateTimer(self, frame, seconds):
secondsLabel = self.labels[frame][2]
secondsLabel['text'] = "Seconds: {}".format(seconds)
seconds += 1
root.after(1000, self.updateTimer, frame, seconds)
root = tk.Tk()
Window()
root.mainloop()
EDIT:
It can be simpler to use Frame to create own widget with one Frame, one Button, all Labels and variables needed in timer. And later use this widget 4 times in main window.
import tkinter as tk
class MyTimer(tk.Frame):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.hours = 0
self.minutes = 0
self.seconds = 0
self.button = tk.Button(self, text="SET TIMER", command=self.set_timer)
self.button.grid(row=0, column=0, padx=30, pady=20)
self.hours_label = None
self.minutes_label = None
self.seconds_label = None
def set_timer(self):
if self.hours_label is None:
self.hours_label = tk.Label(self, text="Hours: ")
self.minutes_label = tk.Label(self, text="Minutes: ")
self.seconds_label = tk.Label(self, text="Seconds: ")
self.hours_label.grid(row=1)
self.minutes_label.grid(row=2)
self.seconds_label.grid(row=3)
# reset time
self.hours = 0
self.minutes = 0
self.seconds = 0
# start updating time
self.update_timer()
def update_timer(self):
self.hours_label['text'] = "Hours: {}".format(self.hours)
self.minutes_label['text'] = "Minutes: {}".format(self.minutes)
self.seconds_label['text'] = "Seconds: {}".format(self.seconds)
self.seconds += 1
if self.seconds == 60:
self.seconds = 0
self.minutes += 1
if self.minutes == 60:
self.minutes = 0
self.hours += 1
# update again after 1000ms (1s)
root.after(1000, self.update_timer)
class Window():
def __init__(self):
self.createFrames()
def createFrames(self):
self.timer1_frame = MyTimer(root, width=300, height=300, background="red")
self.timer1_frame.grid_propagate(0)
self.timer1_frame.grid(row=0, column=0)
self.timer2_frame = MyTimer(root, width=300, height=300, background="blue")
self.timer2_frame.grid_propagate(0)
self.timer2_frame.grid(row=0, column=1)
self.timer3_frame = MyTimer(root, width=300, height=300, background="orange")
self.timer3_frame.grid_propagate(0)
self.timer3_frame.grid(row=1, column=0)
self.timer4_frame = MyTimer(root, width=300, height=300, background="yellow")
self.timer4_frame.grid_propagate(0)
self.timer4_frame.grid(row=1, column=1)
root = tk.Tk()
Window()
root.mainloop()
I am working on a program where there is a scrollable frame that will be containing a large quantity of items. But with my app it does not render all of them. Can someone possibly tell me why? And how I can fix it?
Code:
#700x650
from Tkinter import *
import ttk
class itemLoad:
def __init__(self):
pass
def item(self):
items = "Video File,Image File,None,King King"
return items
class App(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.pack(fill=BOTH)
self.loadItem = itemLoad()
self.one = None
self.create_widgets()
self.loadItems()
def create_widgets(self):
self.mainFrame = Frame(self, width=700, height=650)
self.mainFrame.pack_propagate(False)
self.mainFrame.pack()
self.menu = Frame(self.mainFrame, width=150, height=650, bg="Gray92")
self.menu.pack_propagate(False)
self.menu.pack(side=LEFT)
self.itemMenu = Frame(self.mainFrame, width=550, height=650)
self.itemMenu.pack_propagate(False)
self.itemMenu.pack(side=LEFT)
self.vScroller = ttk.Scrollbar(self.itemMenu, orient=VERTICAL)
self.vScroller.pack(side=RIGHT, fill=Y)
self.canvas = Canvas(self.itemMenu, bd=0, width=534, highlightthickness=0, yscrollcommand=self.vScroller.set)
self.canvas.pack_propagate(False)
self.canvas.pack(side=LEFT, fill=BOTH)
self.vScroller.config(command=self.canvas.yview)
self.innerFrame = Frame(self.canvas, width=550, height=650, bg="Pink")
self.canvas.create_window(0, 0, window=self.innerFrame, anchor=NW)
def update(event):
self.canvas.config(scrollregion=self.canvas.bbox("all"))
self.innerFrame.bind("<Configure>", update)
self.spacer = Frame(self.mainFrame, bg="Gray")
self.spacer.pack(side=LEFT, fill=Y)
frame = Frame(self.menu, bg="Gray92")
frame.pack(side=TOP, fill=X)
high = Frame(frame, bg="Gray92", width=10)
high.pack(side=LEFT, fill=Y)
self.bu1 = Label(frame, font=("Calibri", 14), text=" Main Folder", width=12, anchor=W, bg="Gray92")
self.bu1.pack(side=LEFT, fill=X, ipadx=10, ipady=10)
frame2 = Frame(self.menu, bg="Gray92")
frame2.pack(side=TOP, fill=X)
high2 = Frame(frame2, bg="Gray92", width=10)
high2.pack(side=LEFT, fill=Y)
self.bu2 = Label(frame2, font=("Calibri", 14), text=" Favorited", width=12, anchor=W, bg="Gray92")
self.bu2.pack(side=LEFT, fill=X, ipadx=10, ipady=10)
frame3 = Frame(self.menu, bg="Gray92")
frame3.pack(side=TOP, fill=X)
high3 = Frame(frame3, bg="Gray92", width=10)
high3.pack(side=LEFT, fill=Y)
self.bu3 = Label(frame3, font=("Calibri", 14), text=" Trash Can", width=12, anchor=W, bg="Gray92")
self.bu3.pack(side=LEFT, fill=X, ipadx=10, ipady=10)
frame4 = Frame(self.menu, bg="Gray92")
frame4.pack(side=BOTTOM, fill=X)
high4 = Frame(frame4, bg="Gray92", width=10)
high4.pack(side=LEFT, fill=Y)
self.bu4 = Label(frame4, font=("Calibri", 14), text=" Log Out", width=12, anchor=W, bg="Gray92")
self.bu4.pack(side=LEFT, fill=X, ipadx=10, ipady=10)
def hover(event):
widg = event.widget
items = widg.winfo_children()
if items[1].cget("text") == self.one:
pass
else:
items[0].config(bg="Gray85")
items[1].config(bg="Gray85")
def unHover(event):
widg = event.widget
text = None
items = widg.winfo_children()
if items[1].cget("text") == self.one:
pass
else:
items[0].config(bg="Gray92")
items[1].config(bg="Gray92")
def clicked(event):
widg = event.widget
par = widg.winfo_parent()
par = self.menu._nametowidget(par)
for item in self.menu.winfo_children():
items = item.winfo_children()
items[0].config(bg="Gray92")
for item in par.winfo_children():
try:
self.one = item.cget("text")
except:
item.config(bg="lightBlue")
frame.bind("<Enter>", hover)
frame2.bind("<Enter>", hover)
frame3.bind("<Enter>", hover)
frame4.bind("<Enter>", hover)
frame.bind("<Leave>", unHover)
frame2.bind("<Leave>", unHover)
frame3.bind("<Leave>", unHover)
frame4.bind("<Leave>", unHover)
high.bind("<Button-1>", clicked)
self.bu1.bind("<Button-1>", clicked)
high2.bind("<Button-1>", clicked)
self.bu2.bind("<Button-1>", clicked)
high3.bind("<Button-1>", clicked)
self.bu3.bind("<Button-1>", clicked)
high4.bind("<Button-1>", clicked)
self.bu4.bind("<Button-1>", clicked)
def loadItems(self):
theItems = self.loadItem.item()
for i in range(0, 500):
none = Frame(self.innerFrame, width=200, height=500, bg="red")
none.pack_propagate(False)
none.pack(side=TOP, padx=10, pady=10)
let = Label(none, text=i)
let.pack(side=TOP)
root = Tk()
root.geometry("700x650")
root.resizable(0,0)
app = App(root)
root.mainloop()
I think you're exceeding the limits of the tkinter canvas. The frame you're trying to scroll is 250,000 pixels tall. I doubt the canvas can handle that.
When I make all of your inner widgets considerably smaller your code works fine.
I've a simple GUI thats shows the users some options, after putting the number of the initial options to be shown. In this case, 4:
By clicking on Add row you can add a row to the GUI. The thing is that if the user wants 100 options, the GUI becomes extra big and all the options are not shown.
So I would like to have a scrollbar only on the options space, not the rest parts. Sorry for the bad Photoshop, but I would like to have something like this:
The options space is the FrameTwo, so I would like to have the entire FrameTwo inside of scrollbar like the image above.
# -*- coding: utf-8 -*-
from Tkinter import *
import Image
import ImageTk
import tkFileDialog
import datetime
class Planificador(Frame):
def __init__(self,master):
Frame.__init__(self, master)
self.master = master
self.initUI()
def initUI(self):
self.master.title("Plan")
self.frameOne = Frame(self.master)
self.frameOne.grid(row=0,column=0)
self.frameTwo = Frame(self.master)
self.frameTwo.grid(row=1, column=0)
self.frameThree = Frame(self.master)
self.frameThree.grid(row=2, column=0)
# Borrar esto?
self.txt = Text(self)
self.txt.pack(fill=BOTH, expand=1)
self.piezastext = Label(self.frameOne, text = " Amount of pieces ", justify="center")
self.piezastext.grid(row=1, column=0)
self.entrypiezas = Entry(self.frameOne,width=3)
self.entrypiezas.grid(row=2, column=0, pady=(5,5))
self.aceptarnumpiezas = Button(self.frameOne,text="Click me", command=self.aceptar_piezas,width=8)
self.aceptarnumpiezas.grid(row=6, column=0, pady=(5,5))
def aceptar_piezas(self):
try:
val = int(self.entrypiezas.get())
self.aceptar_piezas_ok()
except ValueError:
showerror('Error', "Introduce un numero")
def aceptar_piezas_ok(self):
self.num_piezas = self.entrypiezas.get()
self.piezastext.grid_remove()
self.entrypiezas.grid_remove()
self.aceptarnumpiezas.grid_remove()
self.optionmenus_piezas = list()
self.numpiezas = []
self.numerolotes = []
self.optionmenus_prioridad = list()
self.lotes = list()
self.mispiezas = ['One', 'Two', 'Three', 'Four', 'Five']
self.n = 1
while self.n <= int(self.num_piezas):
self.textopieza = Label(self.frameTwo, text = "Pieza: ", justify="left")
self.textopieza.grid(row=self.n, column=0)
var = StringVar()
menu = OptionMenu(self.frameTwo, var, *self.mispiezas)
menu.config(width=10)
menu.grid(row=self.n, column=1)
var.set("One")
self.optionmenus_piezas.append((menu, var))
self.numpiezastext = Label(self.frameTwo, text = "Numero de piezas: ", justify="center")
self.numpiezastext.grid(row=self.n, column=2, padx=(10,0))
self.entrynumpiezas = Entry(self.frameTwo,width=6)
self.entrynumpiezas.grid(row=self.n, column=3, padx=(0,10))
self.entrynumpiezas.insert(0, "0")
self.textoprioridad = Label(self.frameTwo, text = "Prioridad: ", justify="center")
self.textoprioridad.grid(row=self.n, column=4)
var2 = StringVar()
menu2 = OptionMenu(self.frameTwo, var2, "Normal", "Baja", "Primera pieza", "Esta semana")
menu2.config(width=10)
menu2.grid(row=self.n, column=5)
var2.set("Normal")
self.optionmenus_prioridad.append((menu2, var2))
self.lotestext = Label(self.frameTwo, text = "Por lotes?", justify="center")
self.lotestext.grid(row=self.n, column=6, padx=(10,0))
self.var1 = IntVar()
self.entrynumlotes = Checkbutton(self.frameTwo, variable=self.var1)
self.entrynumlotes.grid(row=self.n, column=7, padx=(5,10))
self.lotes.append(self.var1)
self.numpiezas.append(self.entrynumpiezas)
self.n += 1
self.anadirpiezas = Button(self.frameThree, text="Add row", command=self.addpieza, width=10)
self.anadirpiezas.grid(row=0, column=2, pady=(10,10))
self.calculotext = Label(self.frameThree, text = "Other stuff ")
self.calculotext.grid(row=1, column=2, padx=(10,0), pady=(10,10))
self.graspbutton = Button(self.frameThree, text="OPT 1", width=10)
self.graspbutton.grid(row=2, column=1)
self.parettobutton = Button(self.frameThree, text="OPT 2",width=10)
self.parettobutton.grid(row=2, column=2, pady=(10,10), padx=(10,0))
self.parettoEvolbutton = Button(self.frameThree, text="OPT 2", width=10)
self.parettoEvolbutton.grid(row=2, column=3, pady=(10,10), padx=(10,0))
def addpieza(self):
self.textopiezanuevo = Label(self.frameTwo, text = "Pieza: ", justify="left")
self.textopiezanuevo.grid(row=int(self.num_piezas)+1, column=0)
var = StringVar()
menu = OptionMenu(self.frameTwo, var, *self.mispiezas)
menu.grid(row=self.n, column=1)
menu.config(width=10)
menu.grid(row=int(self.num_piezas)+1, column=1)
var.set("One")
self.optionmenus_piezas.append((menu, var))
self.numpiezastext = Label(self.frameTwo, text = "Numero de piezas: ", justify="center")
self.numpiezastext.grid(row=int(self.num_piezas)+1, column=2, padx=(10,0))
self.entrynumpiezas = Entry(self.frameTwo,width=6)
self.entrynumpiezas.grid(row=int(self.num_piezas)+1, column=3, padx=(0,10))
self.entrynumpiezas.insert(0, "0")
self.textoprioridad = Label(self.frameTwo, text = "Prioridad: ", justify="center")
self.textoprioridad.grid(row=int(self.num_piezas)+1, column=4)
var2 = StringVar()
menu2 = OptionMenu(self.frameTwo, var2, "Normal", "Baja", "Primera pieza", "Esta semana")
menu2.config(width=10)
menu2.grid(row=int(self.num_piezas)+1, column=5)
var2.set("Normal")
self.optionmenus_prioridad.append((menu2, var2))
self.lotestext = Label(self.frameTwo, text = "Por lotes?", justify="center")
self.lotestext.grid(row=int(self.num_piezas)+1, column=6, padx=(10,0))
self.var1 = IntVar()
self.entrynumlotes = Checkbutton(self.frameTwo, variable=self.var1)
self.entrynumlotes.grid(row=int(self.num_piezas)+1, column=7, padx=(5,10))
self.lotes.append(self.var1)
self.numpiezas.append(self.entrynumpiezas)
self.num_piezas = int(self.num_piezas)+1
if __name__ == "__main__":
root = Tk()
aplicacion = Planificador(root)
root.mainloop()
FrameOne is used to put an image I removed to make this example more simple. And FrameThree are the buttons you can see at the bottom of the GUI.
So it would be very helpful if someone could give me a hand and tell me how to put the entire FrameTwo inside of a scrollbar as you can see on the third image.
Thanks in advance.
One of your problems, is that "frameTwo" has no limits to it's size. If you don't limit it's size, any scrollbar you add, never will act. But limiting the size of you frame have the inconvenient of limit the number of lines you can grid, making the scrollbar useless again.
A solution is creating a frame inside the "frameTwo", to receive the pieces you create. This way, by one hand, allow you to limit the size of "frameTwo" and attach the scrollbar to it, and by other hand, allow you to grid the pieces you add to the frame located inside "frameTwo", named, let's say, "ListFrame". when "ListFrame" size becomes bigger than "frameTwo" size, you can now make the scrollbar work.
I change your code with the changes mentioned above. Check it out.
The changes are commented in the code.
Sorry for the short explanation, but i'm a bit hurry. I may edit this answer when I have more time.
PS: Sorry if my english is not the best
# -*- coding: utf-8 -*-
from Tkinter import *
import Image
import ImageTk
import tkFileDialog
import datetime
class Planificador(Frame):
def __init__(self,master):
Frame.__init__(self, master)
self.master = master
self.initUI()
def initUI(self):
self.master.title("Plan")
self.frameOne = Frame(self.master)
self.frameOne.grid(row=0,column=0)
self.frameTwo = Frame(self.master)
self.frameTwo.grid(row=1, column=0)
#Creating of a new frame, inside of "frameTwo" to the objects to be inserted
#Creating a scrollbar
#The reason for this, is to attach the scrollbar to "FrameTwo", and when the size of frame "ListFrame" exceed the size of frameTwo, the scrollbar acts
self.canvas=Canvas(self.frameTwo)
self.listFrame=Frame(self.canvas)
self.scrollb=Scrollbar(self.master, orient="vertical",command=self.canvas.yview)
self.scrollb.grid(row=1, column=1, sticky='nsew') #grid scrollbar in master, but
self.canvas['yscrollcommand'] = self.scrollb.set #attach scrollbar to frameTwo
self.canvas.create_window((0,0),window=self.listFrame,anchor='nw')
self.listFrame.bind("<Configure>", self.AuxscrollFunction)
self.scrollb.grid_forget() #Forget scrollbar because the number of pieces remains undefined by the user. But this not destroy it. It will be "remembered" later.
self.canvas.pack(side="left")
self.frameThree = Frame(self.master)
self.frameThree.grid(row=2, column=0)
# Borrar esto?
self.txt = Text(self)
self.txt.pack(fill=BOTH, expand=1)
self.piezastext = Label(self.frameOne, text = " Amount of pieces ", justify="center")
self.piezastext.grid(row=1, column=0)
self.entrypiezas = Entry(self.frameOne,width=3)
self.entrypiezas.grid(row=2, column=0, pady=(5,5))
self.aceptarnumpiezas = Button(self.frameOne,text="Click me", command=self.aceptar_piezas,width=8)
self.aceptarnumpiezas.grid(row=6, column=0, pady=(5,5))
def AuxscrollFunction(self,event):
#You need to set a max size for frameTwo. Otherwise, it will grow as needed, and scrollbar do not act
self.canvas.configure(scrollregion=self.canvas.bbox("all"),width=600,height=500)
def aceptar_piezas(self):
#IMPORTANT!!! All the objects are now created in "ListFrame" and not in "frameTwo"
#I perform the alterations. Check it out
try:
val = int(self.entrypiezas.get())
self.aceptar_piezas_ok()
self.scrollb.grid(row=1, column=1, sticky='nsew') #grid scrollbar in master, because user had defined the numer of pieces
except ValueError:
showerror('Error', "Introduce un numero")
def aceptar_piezas_ok(self):
self.num_piezas = self.entrypiezas.get()
self.piezastext.grid_remove()
self.entrypiezas.grid_remove()
self.aceptarnumpiezas.grid_remove()
self.optionmenus_piezas = list()
self.numpiezas = []
self.numerolotes = []
self.optionmenus_prioridad = list()
self.lotes = list()
self.mispiezas = ['One', 'Two', 'Three', 'Four', 'Five']
self.n = 1
while self.n <= int(self.num_piezas):
self.textopieza = Label(self.listFrame, text = "Pieza: ", justify="left")
self.textopieza.grid(row=self.n, column=0)
var = StringVar()
menu = OptionMenu(self.listFrame, var, *self.mispiezas)
menu.config(width=10)
menu.grid(row=self.n, column=1)
var.set("One")
self.optionmenus_piezas.append((menu, var))
self.numpiezastext = Label(self.listFrame, text = "Numero de piezas: ", justify="center")
self.numpiezastext.grid(row=self.n, column=2, padx=(10,0))
self.entrynumpiezas = Entry(self.listFrame,width=6)
self.entrynumpiezas.grid(row=self.n, column=3, padx=(0,10))
self.entrynumpiezas.insert(0, "0")
self.textoprioridad = Label(self.listFrame, text = "Prioridad: ", justify="center")
self.textoprioridad.grid(row=self.n, column=4)
var2 = StringVar()
menu2 = OptionMenu(self.listFrame, var2, "Normal", "Baja", "Primera pieza", "Esta semana")
menu2.config(width=10)
menu2.grid(row=self.n, column=5)
var2.set("Normal")
self.optionmenus_prioridad.append((menu2, var2))
self.lotestext = Label(self.listFrame, text = "Por lotes?", justify="center")
self.lotestext.grid(row=self.n, column=6, padx=(10,0))
self.var1 = IntVar()
self.entrynumlotes = Checkbutton(self.listFrame, variable=self.var1)
self.entrynumlotes.grid(row=self.n, column=7, padx=(5,10))
self.lotes.append(self.var1)
self.numpiezas.append(self.entrynumpiezas)
self.n += 1
self.anadirpiezas = Button(self.frameThree, text="Add row", command=self.addpieza, width=10)
self.anadirpiezas.grid(row=0, column=2, pady=(10,10))
self.calculotext = Label(self.frameThree, text = "Other stuff ")
self.calculotext.grid(row=1, column=2, padx=(10,0), pady=(10,10))
self.graspbutton = Button(self.frameThree, text="OPT 1", width=10)
self.graspbutton.grid(row=2, column=1)
self.parettobutton = Button(self.frameThree, text="OPT 2",width=10)
self.parettobutton.grid(row=2, column=2, pady=(10,10), padx=(10,0))
self.parettoEvolbutton = Button(self.frameThree, text="OPT 2", width=10)
self.parettoEvolbutton.grid(row=2, column=3, pady=(10,10), padx=(10,0))
def addpieza(self):
self.textopiezanuevo = Label(self.listFrame, text = "Pieza: ", justify="left")
self.textopiezanuevo.grid(row=int(self.num_piezas)+1, column=0)
var = StringVar()
menu = OptionMenu(self.listFrame, var, *self.mispiezas)
menu.grid(row=self.n, column=1)
menu.config(width=10)
menu.grid(row=int(self.num_piezas)+1, column=1)
var.set("One")
self.optionmenus_piezas.append((menu, var))
self.numpiezastext = Label(self.listFrame, text = "Numero de piezas: ", justify="center")
self.numpiezastext.grid(row=int(self.num_piezas)+1, column=2, padx=(10,0))
self.entrynumpiezas = Entry(self.listFrame,width=6)
self.entrynumpiezas.grid(row=int(self.num_piezas)+1, column=3, padx=(0,10))
self.entrynumpiezas.insert(0, "0")
self.textoprioridad = Label(self.listFrame, text = "Prioridad: ", justify="center")
self.textoprioridad.grid(row=int(self.num_piezas)+1, column=4)
var2 = StringVar()
menu2 = OptionMenu(self.listFrame, var2, "Normal", "Baja", "Primera pieza", "Esta semana")
menu2.config(width=10)
menu2.grid(row=int(self.num_piezas)+1, column=5)
var2.set("Normal")
self.optionmenus_prioridad.append((menu2, var2))
self.lotestext = Label(self.listFrame, text = "Por lotes?", justify="center")
self.lotestext.grid(row=int(self.num_piezas)+1, column=6, padx=(10,0))
self.var1 = IntVar()
self.entrynumlotes = Checkbutton(self.listFrame, variable=self.var1)
self.entrynumlotes.grid(row=int(self.num_piezas)+1, column=7, padx=(5,10))
self.lotes.append(self.var1)
self.numpiezas.append(self.entrynumpiezas)
self.num_piezas = int(self.num_piezas)+1
if __name__ == "__main__":
root = Tk()
aplicacion = Planificador(root)
root.mainloop()
You have option menus, labels, entry boxes, and checkbuttons in FrameTwo. How would you expect a scrollbar for the entire frame would work? Would it scroll all widgets at the same time? Tkinter scrollbars are generally attached to listboxes, canvases, entry widgets, and text fields. http://effbot.org/zone/tkinter-scrollbar-patterns.htm Come up with a simple example that illustrates the problem for further help.