My main target is to add something like an hidden tag or string to a widget, to save short information on it.
I got the idea of creating a new custom Button class (in this case I need buttons), which inherits all the old options.
This is the code:
form tkinter import *
class NButton(Button):
def __init__(self, master, tag=None, *args, **kwargs):
Button.__init__(self, master, *args, **kwargs)
self.master, self.tag = master, tag
No trouble when creating a new NButton instance:
aria1 = NButton(treewindow, bd=2, relief=GROOVE, text="Trasmissione\naerea 1", bg="#99c4ff", tag="aria 1")
aria1.place(x=20, y=20)
The problems come out when I try to get the value of tag:
aria1["tag"]
it returns:
_tkinter.TclError: unknown option "-tag"
How can I solve this?
You need to access your custom options as object attributes:
print(aria1.tag)
Related
I am trying to get PyCharm to understand that the subclass of my base controller class only takes a specific type of widget.
Minimal example:
import tkinter as tk
class BaseWidgetController:
def __init__(self, parent: 'tk.Widget'): # Parent is always __some__ kind of widget
self._parent = parent
class EntryWidgetController(BaseWidgetController):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._parent: 'tk.Entry' # On this class, I want Pycharm to understand _parent is only ever an Entry (a subclass of tk.Widget), but even adding this line doesn't change its mind.
def say_type(self) -> None:
print(type(self._parent)) # PyCharm still thinks _parent is a tk.Widget
ew = EntryWidgetController(parent=tk.Frame())
ew.say_type() # Obviously this works fine at runtime.
If you want to constrain the EntryWidgetController so that it only accepts tk.Entry or subclasses, the fix is rather simple - just do
class EntryWidgetController(BaseWidgetController):
def __init__(self, parent: 'tk.Entry', **kwargs):
super().__init__(parent=parent, **kwargs)
That way
ew = EntryWidgetController(parent=tk.Frame())
will make PyCharm complain that Expected type 'Entry', got 'Frame' instead.
Following the examples outlined in "Create simple GUI" I have tried to create Custom Widget, but nothing seems to by shown. It seems to be the simplest widget that I can imagine but still something is missing and I have no idea what.
from PyQt5.QtWidgets import *
import sys
class customWidget(QWidget):
def __init__(self, *args, **kwargs):
super(customWidget, self).__init__(*args, **kwargs)
layout = QHBoxLayout()
label = QLabel("Que chinga")
layout.addWidget(label)
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setWindowTitle("Esta locura")
label = customWidget()
self.setCentralWidget(label)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
Do any of the following in the __init__ of customWidget (they are the conceptually the same thing):
add self.setLayout(layout) after creating the layout;
change layout = QHBoxLayout() to layout = QHBoxLayout(self);
The reason is that you're not setting the layout for the widget, so the QLabel has no parent and won't be shown on its own.
In practice, the customWidget instance could know anything about those objects, so there's no reason for which it should show them.
I also suggest you to:
read about classes and instances: while it's not directly related to this issue, it has lots of aspects in common, since the parenthood relation of Qt objects (such as QWidget subclasses) is closely related to the OOP aspects of instances.
always use capitalized names for classes (CustomWidget, not customWidget), as lower cased names should only be used for variable and function names.
I'm relatively new to OOPs and thus know it theoretically. I need a project to be implemented in Tkinter. So, I was going through it. I was just playing around with the most basic code like below
# https://python-textbok.readthedocs.io/en/1.0/Introduction_to_GUI_Programming.html
import tkinter as tk
class MainApplication(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.parent = parent
root = tk.Tk()
app = MainApplication(root)
app.mainloop()
Here, I can say confidently that MainApplication inherits tk.Frame. So, the root is a TK object and it is passed in MainApplication constructor which assigns it as the parent of the MainApplication object.
So, when we call the app.mainloop(), the MainApplication object is called which in turn can invoke the root somehow because we have the root as a parent of the app object.
Correct me if I understood it wrong.
Now, as I browsed and another popular method people are using is
# https://docs.python.org/2/library/tkinter.html#a-simple-hello-world-program
import tkinter as tk
class MainApplication(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.parent = parent
root = tk.Tk()
MainApplication(root)
root.mainloop()
Here also, as I can understand the MainApplication is invoked and root becomes the parent of it. But how does that link the MainApplication object with the root object, so that when the root.mainloop() is called, it can refer back to MainApplication object?
Any help is appreciated. Thanks in advance.
This is more about the actual structure of the tkinter module than it is about OOP principles.
mainloop is a method of the Misc class, which is an ancestor of both Tk and Frame. When called, it essentially calls the mainloop method using a reference it has to the root Tk object, so whether you invoke it from root or app, the result is the same.
In the spirit of decoupling, rather than cramming many widgets into one giant class, I tried splitting them into separate classes.
The problem I ran into is the FileMenu class does not know about root, and so cannot call root.quit or root.destroy. On a whim I tried self.quit, and it works, but I have not seen this used before.
My questions are:
Is self.quit a safe way to quit the app?
Is sys.exit a safe way to quit the app?
If neither are safe, is there a good way to approach decoupling the design and safely quit without passing root as a parameter everywhere or making it a global?
My example:
import Tkinter as tk
class FileMenu(tk.Menu):
def __init__ (self, parent):
tk.Menu.__init__(self, parent, tearoff=False)
self.add_command(label='Exit', command=self.quit)
class MainMenu(tk.Menu):
def __init__ (self, parent):
tk.Menu.__init__(self, parent, tearoff=False)
self.file_menu = FileMenu(self)
self.add_cascade(label='File', menu=self.file_menu)
class View:
def __init__ (self, parent):
self.frame = tk.Frame(parent)
self.parent = parent
self.menu = MainMenu(self.frame)
self.parent.configure(menu=self.menu)
self.parent.geometry('200x200')
self.frame.pack(fill='both', expand=True)
class App:
def __init__ (self):
self.root = tk.Tk()
self.view = View(self.root)
def run (self):
self.root.title('Window Title')
self.root.mainloop()
if __name__ == '__main__':
app = App()
app.run()
Both use for different purpose:
sys.exit(): Close complete application.
self.quit: If you have multiple windows in your application and you don't want to close your whole application then you should use self.quit().
Both are safe to use but uses are different.
If the class doesn't know about the root object but you expect it to act on the root object, you should pass it in.
In App, you pass the root object into View:
self.view = View(self.root)
In View, you create a MainMenu and pass it self.frame:
self.menu = MainMenu(self.frame)
Instead, also pass it the root object:
self.menu = MainMenu(self.frame, parent)
And make MainMenu expect a parameter of that object, and pass it to FileMenu:
class MainMenu(tk.Menu):
def __init__ (self, parent, root):
tk.Menu.__init__(self, parent, tearoff=False)
self.file_menu = FileMenu(self, root)
self.add_cascade(label='File', menu=self.file_menu)
Then make FileMenu expect a parameter of that root object. Now it has access to it:
class FileMenu(tk.Menu):
def __init__ (self, parent, root):
tk.Menu.__init__(self, parent, tearoff=False)
self.add_command(label='Exit', command=root.destroy)
And you can use the Tkinter root object's destroy method to quit the application properly.
I am designing a gui using python Tkinter. I try to wrap my code in classes. I use different class for each frame. The code is more or less like this.
Class GetEntry():
"""This class will acquire the text in entry widget"""
Class Frame1():
"""Consist of all entry widget"""
Class Frame2():
"""Consist of all button widget"""
Class Main_App()
"""All classes are called here"""
However, I want to call GetEntry class when one of the button in class Frame2 is clicked to acquire the text in entry widget located in class Frame1. Any suggestion to do that?
Thanks in advance.
I Finally get it works. I simply instantiate the GetEntry command inside Frame2, and add attribute entry from Frame1 when calling Frame2. My code is as follows.
class CommadCallback():
def __init__(self, object)
self.object = object
def function(self):
self.object.get()
class Frame1():
#Entry instantiation
class Frame2():
def __init__(self, object):
self.object = object
self.function1()
def function1(self):
self.function = CommandCallback(self.object).function()
Class MainApp():
.....
self.frame1 = Frame1(self)
self.frame2 = Frame2(self, self.frame1.entry)