When I am trying to reference in a different class in a function I get a error saying their is not attribute between the widget I am referencing and the class. Here is the code displaying the referencing:
class Window(tk.Tk):
def __init__(self):
super().__init__()
self.init_csv()
def init_csv(self):
LeftFrame.spellings_listbox.insert(tk.END,i)
class LeftFrame(tk.Frame):
def __init__(self, container):
super().__init__(container,width=400,height=600,bg="red")
self.pack(side=tk.LEFT)
self.pack_propagate(0)
self.widgets()
def widgets(self):
self.spellings_listbox = tk.Listbox(self)
self.spellings_listbox.pack(expand=True,fill=tk.BOTH,side=tk.BOTTOM)
You have to create an instance of the LeftFrame class before you can use it or the widgets inside. This isn't something unique to tkinter, it's a fundamental aspect of using classes.
Usually the solution looks something like this:
class Window(tk.Tk):
def __init__(self):
super().__init__()
self.init_csv()
self.left_frame = LeftFrame(self)
def init_csv(self):
self.left_frame.spellings_listbox.insert(tk.END,i)
Related
I have a main class for my gui and I added a ttk.NoteBook after a label:
class MainApplication(tk.Tk):
def __init__(self):
super().__init__()
self.geometry('1000x500')
self.configure(background='#F0F8FF')
#TOP LABEL
load = Image.open("my_image")
load = load.resize((200, 67), Image.ANTIALIAS)
self.render = ImageTk.PhotoImage(load)
self.Label_top = tk.Label(self, image=self.render, compound=tk.LEFT, text="TOOL")
self.Label_top.pack()
#--Notebook---------
self.notebook = ttk.Notebook(self)
self.Page1 = Page1(self.notebook)
self.Page2 = Page2(self.notebook)
self.Page3 = Page3(self.notebook)
self.Page4 = Page4(self.notebook)
self.notebook.add(self.Page1, text='PAGE1')
self.notebook.add(self.Page2, text='PAGE2')
self.notebook.add(self.Page3, text='PAGE3')
self.notebook.add(self.Page4, text='PAGE4')
self.notebook.pack(fill='x', side=TOP)
#expand=True create empty space between my top label and my notebook, even with side=TOP
And I defined each frame in a class like this :
class Page1(ttk.Frame):
def __init__(self, container):
super().__init__()
self.(width=400, height=280) #Error message
self.pack(expand=True) #Doesn't work
Do you know how can I expand my frame for that it fills my page and pack the notebook just after my top label
I think this will do what you want. I've incorporated most of the things #Bryan Oakley mentioned in his answer except I also added a BasePage class and derived all the other Page classes from it. This was done to provide a place to put code that would otherwise need to be repeated each of the subclasses.
I also changed some of your variable names to conform to PEP 8 Naming Conventions.
import tkinter as tk
import tkinter.ttk as ttk
from tkinter.constants import *
class BasePage(ttk.Frame):
def __init__(self, container):
super().__init__(container, width=400, height=280)
classname = type(self).__name__
tk.Label(self, text=f'Welcome to {classname}').place(relx=0.5, rely=0.25,
anchor=CENTER)
class Page1(BasePage):
def __init__(self, container):
super().__init__(container)
class Page2(BasePage):
def __init__(self, container):
super().__init__(container)
class Page3(BasePage):
def __init__(self, container):
super().__init__(container)
class Page4(BasePage):
def __init__(self, container):
super().__init__(container)
class MainApplication(tk.Tk):
def __init__(self):
super().__init__()
self.geometry('1000x500')
self.configure(background='#F0F8FF')
#--Notebook---------
self.notebook = ttk.Notebook(self)
self.page1 = Page1(self.notebook)
self.page2 = Page2(self.notebook)
self.page3 = Page3(self.notebook)
self.page4 = Page4(self.notebook)
self.notebook.add(self.page1, text='Page1')
self.notebook.add(self.page2, text='Page2')
self.notebook.add(self.page3, text='Page3')
self.notebook.add(self.page4, text='Page4')
self.notebook.pack(expand=True, fill=BOTH)
app = MainApplication()
app.mainloop()
I see three problems.
First, each "page" needs to be a child of the notebook. You do that by making sure the notebook is passed to the __init__ of the frame:
class Page1(ttk.Frame):
def __init__(self, container):
super().__init__(container)
Second, you need to not call pack on the page. self.notebook.add is already adding the frame to the notebook. So, remove the line self.pack(expand=True) from each page.
Third, self.(width=400, height=280) needs to be self.configure(width=400, height=280)
I'm trying to create a set of PySide classes that inherit QWidget, QMainWindow, and QDialog. Also, I would like to inherit another class to overrides a few functions, and also set the layout of the widget.
Example:
Mixin:
class Mixin(object):
def __init__(self, parent, arg):
self.arg = arg
self.parent = parent
# Setup the UI from QDesigner
ui = Ui_widget()
ui.setupUi(self.parent)
def setLayout(self, layout, title):
self.parent.setWindowTitle(title)
self.parent.setLayout(layout)
def doSomething(self):
# Do something awesome.
pass
Widget:
class Widget(Mixin, QtGui.QWidget):
def __init__(self, parent, arg):
super(Widget, self).__init__(parent=parent, arg=arg)
This won't work, but doing this through composition works
Widget (Composition):
class Widget(QtGui.QWidget):
def __init__(self, parent, arg):
super(Widget, self).__init__(parent=parent)
mixin = Mixin(parent=self, arg=arg)
self.setLayout = mixin.setLayout
self.doSomething = mixin.doSomething
I would like to try to have the widget inherit everything instead of having part of it done through composition. Thanks!
Keep class Widget(Mixin, QtGui.Widget):, but add a super call in Mixin.__init__. This should ensure the __init__ method of both Mixin and QWidget are called, and that the Mixin implementation of the setLayout method is found first in the MRO for Widget.
class Mixin(object):
def __init__(self, parent=None, arg=None):
super(Mixin, self).__init__(parent=parent) # This will call QWidget.__init__
self.arg = arg
self.parent = parent
# Setup the UI from QDesigner
ui = Ui_widget()
ui.setupUi(self.parent)
def setLayout(self, layout, title):
self.parent.setWindowTitle(title)
self.parent.setLayout(layout)
def doSomething(self):
# Do something awesome.
pass
class Widget(Mixin, QtGui.QWidget):
def __init__(self, parent, arg):
super(Widget, self).__init__(parent=parent, arg=arg) # Calls Mixin.__init__
I'm trying to make a custom widget getting more and more descriptive with each sub class. For instance below, I'm adding to a list of boxes as I make them. I want do_stuff() to only run once but I want it to run on initialization. My problem is that I need all of the __setupUi() functions to run before I finish it. Any help is appreciated.
from PyQt5 import QtCore, QtWidgets
class layer4:
def __init__(self):
self.boxes = []
self.__setupUi()
# I want to run this once AFTER all of the children (regardless of how deep it goes) have run
self.do_stuff()
def __setupUi(self):
self.qsb = QtWidgets.QSpinBox()
self.boxes.append(self.qsb)
def do_stuff(self):
print(self.boxes)
class layer3(layer4):
def __init__(self):
super().__init__()
self.__setupUi()
def __setupUi(self):
self.qsb2 = QtWidgets.QSpinBox()
self.boxes.append(self.qsb2)
class layer2(layer3):
def __init__(self):
super().__init__()
self.__setupUi()
def __setupUi(self):
self.datetimebox = QtWidgets.QDateTimeEdit()
self.boxes.append(self.datetimebox)
class layer1(layer2):
def __init__(self):
super().__init__()
self.__setupUi()
def __setupUi(self):
self.other = QtWidgets.QDateTimeEdit()
self.boxes.append(self.other)
So if I run
t = layer2()
It should return 2 QSpinboxes and 1 datetimeedit
The issue that I'm facing is when I want to split the functionality of the menubar into multiple files (classes), each of them specific for handling options (File/Help/Edit and so on).
In the Main UI class I have:
class MyFrame(QMainWindow):
def __init__(self):
super().__init__()
self.menu_bar = self.menuBar()
# Create menu
self.add_menu()
def add_menu(self):
help_menu = MenuHelp(self)
def getMenuBar(self):
return self.menu_bar
In the MenuHelp (class):
class MenuHelp(QMenu):
def __init__(self, parrent_widget):
super(MenuHelp, self).__init__()
self.menu_variable = parrent_widget.getMenuBar().addMenu('Help')
about_action = self.menu_variable.addAction('About')
about_action.setStatusTip('About')
about_action.triggered.connect(self.handle_trigger)
def handle_trigger(self):
print('Im here')
The menubar is correctly shown, but handle_trigger method is never called, any ideas on what am I doing wrong?
You must pass a parent to your QMenu. You must change:
class MenuHelp(QMenu):
def __init__(self, parrent_widget):
super(MenuHelp, self).__init__()
to:
class MenuHelp(QMenu):
def __init__(self, parrent_widget):
super(MenuHelp, self).__init__(parrent_widget)
I created a ttk/Treeview Widget in Tkinter using Python 3. I would like to connect an object to its name which is listed in the tree view. To illustrate this I created following example.
import tkinter as tk
from tkinter import ttk
class myclass:
def __init__(self, name, value):
self.name=name
self.value=value
class maintree(ttk.Treeview):
def __init__(self, master):
super().__init__(master)
self.master = master
self.my_objects= [myclass("object"+str(_), _) for _ in range(1,11)]
for my_object in self.my_objects:
self.insert("", "end", text=my_object.name)
def main():
root = tk.Tk()
maintree(root).grid()
root.mainloop()
if __name__ == '__main__':
main()
In this example I would like to get the my_class instance corresponding to the selected name in the treeview to do something (ie, display the value of the currently selected my_class object).
I only know about the item IDs but I don't know how to connect something to an item itself. I have the feeling that I have some misconception about how treeview is supposed to work.
I appreciate your Help!
The insert method has no command option. However, you can tag each inserted item and bind the tag to an event. So, I used the object name as tag and then bound it to execute some method of the object on mouse left click.
import tkinter as tk
from tkinter import ttk
class MyClass:
def __init__(self, name, value):
self.name=name
self.value=value
def callback(self, event=None):
# event=None is a trick to be able to call the method both directly and
# from a binding (that will pass the event argument to the function)
print(self.name, self.value)
class MainTree(ttk.Treeview):
def __init__(self, master):
super().__init__(master)
self.master = master
self.my_objects= [MyClass("object"+str(_), _) for _ in range(1,11)]
for my_object in self.my_objects:
self.insert("", "end", text=my_object.name, tags=(my_object.name,))
self.tag_bind(my_object.name, '<Button-1>', my_object.callback)
def main():
root = tk.Tk()
MainTree(root).grid()
root.mainloop()
if __name__ == '__main__':
main()