Clearing tkinter canvas containing label - python-2.7

I create such a code:
import Tkinter as tk
from Tkinter import *
def b(canvas):
canvas.delete("all")
canvas.update()
print "works"
def main():
root = Tk()
canvas=Canvas(root)
canvas.config(width=400, height=300)
bb=Button(canvas, text="ssss",command=lambda:b(canvas))
bb.place(x=100,y=200)
root.geometry('400x300')
aa=Label(canvas,text="aaaaa")
aa.place(x=10,y=200)
canvas.pack()
root.mainloop()
if __name__ == '__main__':
main()
And the problem is that after clicking on a button label is not destroyed despite the fact that a function with canvas.destroy("all") runs.

The label is not deleted when canvas.delete("all") is invoked because you have used place to display the label, so it is not an item of the canvas. To make the label a canvas item, you need to replace
aa.place(x=10,y=200)
by
canvas.create_window(10, 200, window=aa)
And then canvas.delete("all") will also delete the label.

Related

Tkinter message box without any buttons

How can I do in tkinter something similar to a messagebox, but that doesn't have any buttons, including the close, minimize and maximize buttons on top?
I want it to be in a different window (like a message box), and to be able to update the text and close it only within the code.
Is there a way to do something like that?
Make your own. For example:
try: #python3 imports
import tkinter as tk
except ImportError: #python3 failed, try python2 imports
import Tkinter as tk
class Popup(tk.Toplevel):
"""modal window requires a master"""
def __init__(self, master, **kwargs):
tk.Toplevel.__init__(self, master, **kwargs)
self.overrideredirect(True)
self.geometry('300x200+500+500') # set the position and size of the popup
lbl = tk.Label(self, text="Please wait for other players to join ... ")
lbl.place(relx=.5, rely=.5, anchor='c')
# The following commands keep the popup on top.
# Remove these if you want a program with 2 responding windows.
# These commands must be at the end of __init__
self.transient(master) # set to be on top of the main window
self.grab_set() # hijack all commands from the master (clicks on the main window are ignored)
### demo usage:
def open_popup():
root.popup = Popup(root)
# close the popup in 2 seconds
root.after(2000, close_popup)
def close_popup():
root.popup.destroy()
root = tk.Tk()
btn = tk.Button(root, text='Open Modal Window', command=open_popup)
btn.pack()
root.mainloop()

Adding notebook tabs in tkinter - how do I do it with a class-based structure? (Python 2)

I want each tab to come from it's own class (classes are in their own files - I am just testing the first one for now).
Here is what I tried:
tab1.py
from Tkinter import *
import Tkinter as tk
class Tab(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
fr = Frame(self).pack()
Label(fr, text="one", bg='red', bd=2).pack()
Label(fr, text="two", bg='yellow', bd=2).pack()
if __name__ == '__main__':
root = Tk()
frame = Frame(root).pack()
Tab(frame)
Button(frame, text='only if class', command=root.destroy).pack()
mainloop()
noteBook.py
from Tkinter import *
from ttk import *
from tab1 import Tab
root = Tk()
note = Notebook(root)
main_frame = Frame(note)
button1 = Button(main_frame, text='test').pack()
#tab1 = Tab(note)
tab1 = Frame(note)
tab2 = Frame(note)
tab3 = Frame(note)
Tab(tab1)
Button(tab1, text='Exit', command=root.destroy).pack()
note.add(tab1, text = "Tab One", compound=TOP)
note.add(tab2, text = "Tab Two")
note.add(tab3, text = "Tab Three")
note.pack()
root.mainloop()
exit()
run with:
python2.7 noteBook.py
The problem is that the content of tab1.py does not appear within the first tab, it instead appears within the frame that contains the whole noteBook.
Also when running tab1.py directly with python2.7 noteBook.py I need it to behave properly meaning from what it has now it should show just the tab with an extra button from the if __name___... part.
I have come accros multiple examples but only found one that was what I want but it had no working solution and it was for python3 - I would like python2. python3 question with no working answer Thanks.
The problem is this line of code:
fr = Frame(self).pack()
When you do the above, fr is None because .pack() returns None (because x().y() returns the value of y()). Later, you do this:
Label(fr, text="one", bg='red', bd=2).pack()
Since fr is None, the label is created in the root window.
Unrelated to the problem, here's some advice: you are creating too many frames. You don't need fr inside of Tab, and you don't need tab1, tab2, or tab3
Here's all you need for Tab:
class Tab(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master, background="pink")
Label(self, text="one", bg='red', bd=2).pack()
Label(self, text="two", bg='yellow', bd=2).pack()
To add it to the notebook, you just need two lines:
tab1 = Tab(note)
note.add(tab1, text = "Tab One", compound=TOP)
This works perfectly and just for fun I've illustrated the populating of tabs 2 and 3 althought I just reused the same class for simplicity here. The goal was to be able to run the tabs directly to view them alone during developpement without having to run the whole thing every time.
noteBook.py
from Tkinter import *
from ttk import *
from tab1 import Tab
root = Tk()
note = Notebook(root)
main_frame = Frame(note)
button1 = Button(main_frame, text='test').pack()
tab1 = Frame(note)
tab2 = Frame(note)
tab3 = Frame(note)
Tab(tab1)
Tab(tab2)
Tab(tab3)
Button(tab1, text='Exit', command=root.destroy).pack()
note.add(tab1, text = "Tab One", compound=TOP)
note.add(tab2, text = "Tab Two")
note.add(tab3, text = "Tab Three")
note.pack()
root.mainloop()
exit()
tab1.py
import Tkinter as tk
class Tab(tk.Frame):
def __init__(self, parent_widget):
tk.Frame.__init__(self, parent_widget)
self.fr = tk.Frame(parent_widget, width=200, height=200, bg='pink', bd=2)
tk.Label(self.fr, text="one", bg='red', bd=2).pack()
tk.Label(self.fr, text="two", bg='yellow', bd=2).pack()
self.fr.pack() # this packing must be done after 2 above packings
if __name__ == '__main__':
root = tk.Tk() # the app window
main_frame = tk.Frame(root, height=200, width=200, bg='blue', bd=2) # main frame
Tab(main_frame) # instatiate Tab(), sending main_frame as the parent_widget
tk.Button(main_frame, text='only if class', command=root.destroy).pack()
main_frame.pack() # display main frame on window
tk.mainloop()

tk button changes appearance

So I was doing this program and noticed that both my buttons look initially like this
And after I run my program for some time the second button changes it appearance to this
When does this happen?
Here's my code :/ in case I am doing something that should not be done. I am doing this in python 2.7.8 in IDLE.
import time
import Tkinter as tk
from Tkinter import StringVar
import threading
global root
root = tk.Tk()
x = tk.StringVar()
x.set('false')
def xval(*args):
try:
for i in range(0,9):
global x
print x.get()
if x.get()== 'false' :
print "x=false %d time"%i
time.sleep(1)
else:
print "waiting"
root.update()
except:
pass
def stop(event):
resume_btn.configure(state="normal")
global x
x.set('true')
print "execution stopped:%s"%x
def start(event):
global x
x.set('false')
print "execution started:%s"%x
xval()
root.title("GUI-Data Retrieval")
th = threading.Event()
t = threading.Thread(target=xval,args=(th,))
t.deamon=True
t.start()
x_btn = tk.Button(root, text="Stop", background="Snow", width=20, relief="raised")
x_btn.grid(row=0, column=4, sticky="W", padx=20, pady=5)
x_btn.bind('<Button-1>',stop)
resume_btn = tk.Button(root, text="Start", background="Snow", width=20, relief="raised")
resume_btn.configure(state="disabled")
resume_btn.grid(row=0, column=6, sticky="W", padx=20, pady=5)
resume_btn.bind('<Button-1>',start)
root.mainloop()
The problem is that your binding is handled before the default bindings. It is the default bindings that change the appearance of the button when it is clicked on. You are disabling the button on a click, preventing the default behavior from resetting the appearance of the button when you release the mouse button.
Unless there's a specific reason to do otherwise, you should use the command attribute of the button widget rather than try to create your own bindings.

tkinter progressbar with text inside it

import Tkinter
import ttk
def main():
root = Tkinter.Tk()
root.geometry("500x200")
ft = ttk.Frame()
ft.pack(expand=True, fill=Tkinter.BOTH, side=Tkinter.TOP)
pb_hd = ttk.Progressbar(ft, orient='horizontal', mode='indeterminate')
pb_hd.pack(expand=False, fill=Tkinter.BOTH, side=Tkinter.TOP)
pb_hd.start(50)
root.mainloop()
if __name__ == '__main__':
main()
I want to add text inside the progress bar but not getting any idea how to do it?
The ttk progressbar does not support a text option. You can create a label and pack it immediately above or below the widget.

TreeView in a ScrollView in Kivy - No Scroll

I'm working on a kivy app that pulls data from an sqlite3 database and populates a TreeView with it. The TreeView becomes too large to fit on my screen when I expand a few of the groups so I want to put it inside a ScrollView so I can still scroll down and see the items that have gone off the bottom of my screen. I can get a basic ScrollView to work, but when I put my TreeView inside it there is no scrolling and the top part of my TreeView is off the top of my screen.
I have trimmed down the code into this working example of the problem that runs without a .kv file:
from kivy.uix.scrollview import ScrollView
from kivy.uix.gridlayout import GridLayout
from kivy.core.window import Window
from kivy.uix.widget import Widget
from kivy.uix.treeview import TreeView, TreeViewNode
from kivy.uix.treeview import TreeViewLabel
from kivy.app import App
from kivy.properties import ObjectProperty, StringProperty
from kivy.uix.button import Button
class TreeViewButton(Button, TreeViewNode):
pass
modGroups = [u'Fruit', u'Fruit', u'Meat', u'Dairy', u'Dairy', u'Fruit']
modItems = [u'Apple', u'Pear', u'Spam', u'Egg', u'Milk', u'Banana']
modDict = dict()
modDictUnique = dict()
def populate_tree_view(tv):
modDict = zip(modGroups, modItems)
print modGroups
print modItems
for k, v in modDict:
if k not in modDictUnique:
modDictUnique[k] = [v]
else:
modDictUnique[k].append(v)
sortedGroups = modDictUnique.keys()
sortedGroups.sort()
#print modItems
#print modDictUnique
n = tv.add_node(TreeViewLabel(text='Food', is_open=True))
for group in sortedGroups:
g = tv.add_node(TreeViewLabel(text='%s' % group), n)
for item in modDictUnique[group]:
tv.add_node(TreeViewButton(text='%s' % item), g)
class POSFMApp(App):
def build(self):
layout = GridLayout(cols=1, spacing=50, size_hint_y=None,width=800)
layout.bind(minimum_height=layout.setter('height'))
#for i in range(30):
# btn = Button(text=str(i), size=(480, 40),
# size_hint=(None, None))
# layout.add_widget(btn)
tv = TreeView(root_options=dict(text='Tree One'), hide_root=True, indent_level=4, minimum_height=5000)
populate_tree_view(tv)
layout.add_widget(tv)
root = ScrollView(size_hint=(None, None), size=(800, 700))
root.center = Window.center
root.add_widget(layout)
return root
if __name__ == '__main__':
POSFMApp().run()
In my actual app, modGroups and modItems are populated from an sqlite3 database, but this example presents the problem without having to mess around with sqlite3. I put in the (commented out) lines:
#for i in range(30):
# btn = Button(text=str(i), size=(480, 40),
# size_hint=(None, None))
# layout.add_widget(btn)
from this kivy ScrollView example to show that if I uncomment these lines and comment out the three lines about my TreeView
tv = TreeView(root_options=dict(text='Tree One'), hide_root=True, indent_level=4, minimum_height=5000)
populate_tree_view(tv)
layout.add_widget(tv)
Then I can get a working ScrollView with a scroll bar on the right as expected when I use my mouse's scroll wheel.
My best guess is that the TreeView doesn't tell the ScrollView how long it is vertically so the ScrollView doesn't realize it needs to scroll on the y-axis. That's just a guess, though.
How can I get a TreeView to work inside a ScrollView so I can scroll (especially on the y-axis) through my TreeView?
a) Using a GridLayout just for one child, pease don't. I'll asume that it's a left over from when/if you add more children to it.
b) Documentation of TreeView states that it has minimun_height property which indicates the minimum width/height needed to hold all it's children. The Treeview does not change it's height on it's own depending on the no of children. You should update (in this case) TreeViews height to it's minimum_height... tv.bind(minimum_height=tv.setter('height'))
c) taking into account the information provided in the points above, you can just do::
tv = TreeView(root_options=dict(text='Tree One'), hide_root=True, indent_level=4)
tv.size_hint = 1, None
tv.bind(minimum_height = tv.setter('height'))
populate_tree_view(tv)
root = ScrollView(pos = (0, 0))
root.add_widget(tv)
Here is the entire code including these changes so one can just copy and paste the code to a .py file and run it.
from kivy.uix.scrollview import ScrollView
from kivy.uix.gridlayout import GridLayout
from kivy.core.window import Window
from kivy.uix.widget import Widget
from kivy.uix.treeview import TreeView, TreeViewNode
from kivy.uix.treeview import TreeViewLabel
from kivy.app import App
from kivy.properties import ObjectProperty, StringProperty
from kivy.uix.button import Button
class TreeViewButton(Button, TreeViewNode):
pass
modGroups = [u'Fruit', u'Fruit', u'Meat', u'Dairy', u'Dairy', u'Fruit']
modItems = [u'Apple', u'Pear', u'Spam', u'Egg', u'Milk', u'Banana']
modDict = dict()
modDictUnique = dict()
def populate_tree_view(tv):
modDict = zip(modGroups, modItems)
print modGroups
print modItems
for k, v in modDict:
if k not in modDictUnique:
modDictUnique[k] = [v]
else:
modDictUnique[k].append(v)
sortedGroups = modDictUnique.keys()
sortedGroups.sort()
#print modItems
#print modDictUnique
n = tv.add_node(TreeViewLabel(text='Food', is_open=True))
for group in sortedGroups:
g = tv.add_node(TreeViewLabel(text='%s' % group), n)
for item in modDictUnique[group]:
tv.add_node(TreeViewButton(text='%s' % item), g)
class POSFMApp(App):
def build(self):
#for i in range(30):
# btn = Button(text=str(i), size=(480, 40),
# size_hint=(None, None))
# layout.add_widget(btn)
tv = TreeView(root_options=dict(text='Tree One'), hide_root=True, indent_level=4)
tv.size_hint = 1, None
tv.bind(minimum_height = tv.setter('height'))
populate_tree_view(tv)
root = ScrollView(pos = (0, 0))
root.add_widget(tv)
return root
if __name__ == '__main__':
POSFMApp().run()
Add hight to TreeView then it will scroll. Like this.
ScrollView:
id: kr_scroll
do_scroll_x: False
TreeView:
id: trvMenu
root_options: { 'text': 'Home', 'font_size': 15}
hide_root: False
indent_level: 4
size_hint_y: None
height: self.parent.height*2