From ingoogni at gmail.com Tue Jan 19 09:56:00 2016 From: ingoogni at gmail.com (ingo) Date: Tue, 19 Jan 2016 15:56:00 +0100 Subject: [Tkinter-discuss] Lost images on tabs ttk.notebook Message-ID: I'm trying to create a simple tabbed editor and merged two examples found on the web. One of those is the one with the closing images on the tabs. In the proces of understanding I somehowe lost the images on the tabs but not the fuctionality of clicking on the right position of the tabs. What is going wrong? TIA, Ingo import os from tkinter import * from tkinter import ttk class OPMLnotebook(Frame): def __init__(self): Frame.__init__(self) self.master.title('OPML Notebook') self._create_panel() def _tabbtn_press(self, event): x, y, widget = event.x, event.y, event.widget elem = widget.identify(x, y) index = widget.index("@%d,%d" % (x, y)) if "close" in elem: widget.state(['pressed']) widget.pressed_index = index def _tabbtn_release(self, event): x, y, widget = event.x, event.y, event.widget if not widget.instate(['pressed']): return elem = widget.identify(x, y) index = widget.index("@%d,%d" % (x, y)) if "close" in elem and widget.pressed_index == index: widget.forget(index) widget.event_generate("<>") widget.state(["!pressed"]) widget.pressed_index = None def _create_panel(self): imgdir = os.path.join(os.path.dirname(__file__), 'img') i1 = PhotoImage("img_close", file=os.path.join(imgdir, 'close.gif')) i2 = PhotoImage("img_closeactive", file=os.path.join(imgdir, 'close_active.gif')) i3 = PhotoImage("img_closepressed", file=os.path.join(imgdir, 'close_pressed.gif')) style = ttk.Style() style.element_create("close", "image", "img_close", ("active", "pressed", "!disabled", "img_closepressed"), ("active", "!disabled", "img_closeactive"), border=10, sticky='') style.layout("ButtonNotebook", [("ButtonNotebook.client", {"sticky": "nswe"})]) style.layout("ButtonNotebook.Tab", [ ("ButtonNotebook.tab", {"sticky": "nswe", "children": [("ButtonNotebook.padding", {"side": "top", "sticky": "nswe", "children": [("ButtonNotebook.label", {"side": "left", "sticky": ''}), ("ButtonNotebook.close", {"side": "left", "sticky": ''})] })] })] ) self.bind_class("TNotebook", "", self._tabbtn_press, True) self.bind_class("TNotebook", "", self._tabbtn_release) nb = ttk.Notebook(width=400, height=400, style="ButtonNotebook") nb.pressed_index = None nb.enable_traversal() nb.pack(fill='both', expand=1) self._create_text_tab(nb) self._create_text_tab(nb) def _create_text_tab(self, nb): frame = Frame(nb) txt = Text(frame, wrap=WORD, width=40, height=10) vscroll = Scrollbar(frame, orient=VERTICAL, command=txt.yview) txt['yscroll'] = vscroll.set vscroll.pack(side=RIGHT, fill=Y) txt.pack(fill='both', expand=Y) nb.add(frame, text='Text Editor', underline=0) if __name__ == '__main__': OPMLnotebook().mainloop() From klappnase at web.de Tue Jan 19 11:42:50 2016 From: klappnase at web.de (Michael Lange) Date: Tue, 19 Jan 2016 17:42:50 +0100 Subject: [Tkinter-discuss] Lost images on tabs ttk.notebook In-Reply-To: References: Message-ID: <20160119174250.c4f1c88cfcae803bac473c7f@web.de> Hi, On Tue, 19 Jan 2016 15:56:00 +0100 ingo wrote: > I'm trying to create a simple tabbed editor and merged two examples > found on the web. One of those is the one with the closing images on > the tabs. In the proces of understanding I somehowe lost the images on > the tabs but not the fuctionality of clicking on the right position of > the tabs. > > What is going wrong? Looks like your image data is being garbage-collected. This is a very common pitfall in Tkinter. This is the problematic part of your example code: > > def _create_panel(self): > > imgdir = os.path.join(os.path.dirname(__file__), 'img') > i1 = PhotoImage("img_close", file=os.path.join(imgdir, > 'close.gif')) > i2 = PhotoImage("img_closeactive", file=os.path.join(imgdir, > 'close_active.gif')) > i3 = PhotoImage("img_closepressed", file=os.path.join(imgdir, > 'close_pressed.gif')) Here you fail to keep references to the PhotoImage objects, so immediately after the _create_panel() function is done, the image data will be garbage-collected. To avoid this you can change your code like this: def _create_panel(self): imgdir = os.path.join(os.path.dirname(__file__), 'img') self.i1 = PhotoImage("img_close",\ file=os.path.join(imgdir, 'close.gif')) self.i2 = PhotoImage("img_closeactive",\ file=os.path.join(imgdir, 'close_active.gif')) self.i3 = PhotoImage("img_closepressed",\ file=os.path.join(imgdir, 'close_pressed.gif')) (...) You may look here for a brief explanation on this topic: http://effbot.org/pyfaq/why-do-my-tkinter-images-not-appear.htm Best regards Michael .-.. .. ...- . .-.. --- -. --. .- -. -.. .--. .-. --- ... .--. . .-. If I can have honesty, it's easier to overlook mistakes. -- Kirk, "Space Seed", stardate 3141.9 From ingoogni at gmail.com Tue Jan 19 12:12:18 2016 From: ingoogni at gmail.com (ingo) Date: Tue, 19 Jan 2016 18:12:18 +0100 Subject: [Tkinter-discuss] Lost images on tabs ttk.notebook In-Reply-To: <20160119174250.c4f1c88cfcae803bac473c7f@web.de> References: <20160119174250.c4f1c88cfcae803bac473c7f@web.de> Message-ID: Op 2016-01-19 om 17:42 schreef Michael Lange: > You may look here for a brief explanation on this topic: > http://effbot.org/pyfaq/why-do-my-tkinter-images-not-appear.htm > Thank you, that solved it, Ingo From ingoogni at gmail.com Sat Jan 23 04:05:21 2016 From: ingoogni at gmail.com (ingo) Date: Sat, 23 Jan 2016 10:05:21 +0100 Subject: [Tkinter-discuss] 'connect' widget classes in an application Message-ID: In the code below I get the error below. I'm trying to create a class for several widgets and make the "interact" within a main Frame. Can't figure it out (lack of programming experience) and couldn't find an eye opening example. I understand that the toolbar has no way to access the txt in the editor, how do I make it so? TIA, Ingo ERROR: Exception in Tkinter callback Traceback (most recent call last): File "\Python35-32\lib\tkinter\__init__.py", line 1549, in __call__ return self.func(*args) File "twoclass.py", line 10, in command=lambda: self.txt.insert(END, 'Button pressed.\n') AttributeError: 'Ttoolbar' object has no attribute 'txt' CODE: from tkinter import * class Ttoolbar(Frame): def __init__(self, parent=None): Frame.__init__(self, parent) self.btn = Button( self, text='Button', command=lambda: self.txt.insert(END, 'Button pressed.\n') ) self.btn.pack(side=LEFT) self.pack(side=LEFT) class Eedit(Text): def __init__(self, parent=None): txt = Text.__init__(self, parent) self.pack(fill='both', expand=Y) class Aapp(Frame): def __init__(self, parent=None): Frame.__init__(self, parent) self.pack() self.makeWidgets() def makeWidgets(self): tb = Ttoolbar().pack(side=TOP, fill=X) ed = Eedit().pack() if __name__ == '__main__': Aapp().mainloop() From klappnase at web.de Sat Jan 23 05:35:43 2016 From: klappnase at web.de (Michael Lange) Date: Sat, 23 Jan 2016 11:35:43 +0100 Subject: [Tkinter-discuss] 'connect' widget classes in an application In-Reply-To: References: Message-ID: <20160123113543.530eee8af83d1bd01f094008@web.de> Hi, On Sat, 23 Jan 2016 10:05:21 +0100 ingo wrote: > In the code below I get the error below. > I'm trying to create a class for several widgets and make the > "interact" within a main Frame. Can't figure it out (lack of > programming experience) and couldn't find an eye opening example. > > I understand that the toolbar has no way to access the txt in the > editor, how do I make it so? > there are several problems with your example: First (not critical though), you pack() the editor and toolbar widgets twice, once in their respective __init__() methods and a second time in Aapp.makewidgets(). This is not really an error, but does of course not make much sense; in order to help you keep an overview of your widgets in more complex layouts I would strongly recommend to skip the pack'ing in the widget's __init__ and leave geometry management to the parent class. Second, as you noticed yourself, in your approach there is no way to access the Text widget from the toolbar. There are several possible ways to fix this; for a toolbar class my suggestion is to add method(s) to the class that allow to modify the toolbar from the outside. Third, you do not keep any reference to the child widgets (toolbar and editor) in the main Aapp class (a line like ed = Eedit().pack() simply sets ed to None). This modified example shows one possible way to handle these issues: from tkinter import * class Ttoolbar(Frame): def __init__(self, parent=None): Frame.__init__(self, parent) self._buttons = [] def add(self, **kw): b = Button(self, **kw) b.pack(side=LEFT) self._buttons.append(b) class Eedit(Text): def __init__(self, parent=None): txt = Text.__init__(self, parent) class Aapp(Frame): def __init__(self, parent=None): Frame.__init__(self, parent) self.tb = Ttoolbar() self.tb.pack(side=TOP, fill=X) self.ed = Eedit() self.ed.pack() self.tb.add(text='Button', command=lambda: self.ed.insert(END, 'Button pressed.\n')) if __name__ == '__main__': app = Aapp() app.pack() app.mainloop() I hope this helps. Michael .-.. .. ...- . .-.. --- -. --. .- -. -.. .--. .-. --- ... .--. . .-. Vulcans do not approve of violence. -- Spock, "Journey to Babel", stardate 3842.4 From ingoogni at gmail.com Sun Jan 24 06:58:05 2016 From: ingoogni at gmail.com (ingo) Date: Sun, 24 Jan 2016 12:58:05 +0100 Subject: [Tkinter-discuss] 'connect' widget classes in an application In-Reply-To: <20160123113543.530eee8af83d1bd01f094008@web.de> References: <20160123113543.530eee8af83d1bd01f094008@web.de> Message-ID: Extended the code with a ttk.notebook and a button. Seems to work. Text is added only at the last opened tab, by the button, I think I understand why but will look into that later. When I add a tab through the button, no event is generated. When adding through a double-click or ctrl-n it does. Where does this difference come from? Ingo import tkinter as tk from tkinter import ttk class Ttoolbar(ttk.Frame): def __init__(self, parent=None): ttk.Frame.__init__(self, parent) self._tb_items = [] def add_button(self, **kw): b = ttk.Button(self, **kw) b.pack(side=tk.LEFT) self._tb_items.append(b) class Eedit(tk.Text): def __init__(self, parent=None): txt = tk.Text.__init__(self, parent) class Nnotebook(ttk.Notebook): def __init__(self, parent=None): ttk.Notebook.__init__(self, parent) self.pack(fill=tk.BOTH, expand=tk.Y) self.config(width=400, height=400) self.bind_class("TNotebook", "", self.add_edtab) self.bind_all("", self.add_edtab) def add_edtab(self, event=None): if event: print(event) self.ed = Eedit() self.add(self.ed, text="test") class Aapp(ttk.Frame): def __init__(self, parent=None): ttk.Frame.__init__(self, parent) self.tb = Ttoolbar() self.tb.pack(side=tk.TOP, fill=tk.X) self.nb = Nnotebook() self.nb.pack() self.tb.add_button( text='Add Tab', command=lambda: self.nb.add_edtab() ) self.tb.add_button( text='Add Text', command=lambda: self.nb.ed.insert(tk.END, 'Button pressed.\n') ) if __name__ == '__main__': app = Aapp() app.pack() app.mainloop() From klappnase at web.de Sun Jan 24 12:52:14 2016 From: klappnase at web.de (Michael Lange) Date: Sun, 24 Jan 2016 18:52:14 +0100 Subject: [Tkinter-discuss] 'connect' widget classes in an application In-Reply-To: References: <20160123113543.530eee8af83d1bd01f094008@web.de> Message-ID: <20160124185214.2557cab92dc7dc1408d992aa@web.de> Hi, On Sun, 24 Jan 2016 12:58:05 +0100 ingo wrote: > Extended the code with a ttk.notebook and a button. Seems to work. Text > is added only at the last opened tab, by the button, I think I > understand why but will look into that later. when I run your code here, it seems to work as expected, there is a text widget being added to every new tab. However, you should be careful: in your add_edtab () method you override the value of self.ed each time a new tab is created, so if you need to access the text widgets later programatically you will only be able to get your hands on the one that was created last. You could use a list or a dictionary instead to keep references to the text widgets in the Nnotebook class. > > When I add a tab through the button, no event is generated. When adding > through a double-click or ctrl-n it does. Where does this difference > come from? This is because the event is not generated by the tab-adding procedure, but by clicking the button or pressing the keys ;-) Of course there is a