I'm having an issues and I would kindly ask you to help me as I am not able to find a solution.
Basically I am trying to inherit the DataFrame loaded into a variable in one Class (Window1) and I'm trying to use the same DataFrame in another Class (Window1). Please find below my current simplified code (Thank you):
import tkinter as tk
from PIL import ImageTk, Image
from tkinter import filedialog, messagebox
import time, os, random, string
from datetime import datetime
from time import gmtime, strftime
import pandas as pd
class Page(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container=tk.Frame(self)
container.grid()
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames={}
for F in (PageOne, PageTwo, PageThree):
frame=F(container, self)
self.frames[F]=frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(PageOne)
def show_frame(self, cont):
frame=self.frames[cont]
frame.tkraise()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
start_btn = tk.Button(self, text = "Start >>>", command=lambda:controller.show_frame(PageTwo), width = 10, activebackground = "#ffffff", relief="flat").grid()
pass
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.browse_btn = tk.Button(self, text=" Browse ", command=self.select_file)
self.browse_btn.grid(row=4, column=0, padx=290, pady=10, columnspan=3, sticky="w")
self.browse_entry = tk.Entry(self, text="", width=30)
self.browse_entry.grid(row=4, column=0, columnspan=3, padx=100, pady=10, sticky="w")
self.continue_btn = tk.Button(self, text="Continue >>", borderwidth=2, width=10, bg="#00c441", fg="#ffffff", command=lambda:[self.print_df(), controller.show_frame(PageThree)])
self.continue_btn.grid(row=19, column=0, columnspan=3, padx=312, pady=5, sticky="w")
self.continue_btn.config(state=tk.NORMAL)
def select_file(self):
self.path = filedialog.askopenfilename(defaultextension="*.csv", filetypes = (("csv files","*.csv"),("All Files", "*.*")))
self.browse_entry.delete(0, tk.END)
self.browse_entry.insert(0, self.path)
###following DataFrame I would like to use in in the PageThree class.
self.df = pd.read_csv(self.path)
def print_df(self):
return self.df.head()
class PageThree(PageTwo):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
PageTwo.__init__(self, parent, controller)
start_btn = tk.Button(self, text = "Data Frame", command=self.funct01, width = 10).grid()
def funct01(self):
##this is where I would like to utilize the DataFrame (inside the function)
instance=PageTwo(parent,controller)
print(instance.select_file(self))
if __name__=="__main__":
app=Page()
app.geometry("400x400+100+100")
app.mainloop()
You have to ask the Page instance (controller) to return the PageTwo instance, and you need to store the controller in the PageTwo "constructor".
I was not aware that you can hash a class definition (use it has the key of a dictionary).
import tkinter as tk
from PIL import ImageTk, Image
from tkinter import filedialog, messagebox
import time, os, random, string
from datetime import datetime
from time import gmtime, strftime
import pandas as pd
class Page(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
container=tk.Frame(self)
container.grid()
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames={}
for F in (PageOne, PageTwo, PageThree):
frame=F(container, self)
self.frames[F]=frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(PageOne)
def show_frame(self, cont):
frame=self.frames[cont]
frame.tkraise()
def getFrame(self, frame):
return self.frames[frame]
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
start_btn = tk.Button(self, text = "Start >>>", command=lambda:controller.show_frame(PageTwo), width = 10, activebackground = "#ffffff", relief="flat").grid()
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
self.browse_btn = tk.Button(self, text=" Browse ", command=self.select_file)
self.browse_btn.grid(row=4, column=0, padx=290, pady=10, columnspan=3, sticky="w")
self.browse_entry = tk.Entry(self, text="", width=30)
self.browse_entry.grid(row=4, column=0, columnspan=3, padx=100, pady=10, sticky="w")
self.continue_btn = tk.Button(self, text="Continue >>", borderwidth=2, width=10, bg="#00c441", fg="#ffffff", command=lambda:[self.print_df(), controller.show_frame(PageThree)])
self.continue_btn.grid(row=19, column=0, columnspan=3, padx=312, pady=5, sticky="w")
self.continue_btn.config(state=tk.NORMAL)
def select_file(self):
self.path = filedialog.askopenfilename(defaultextension="*.csv", filetypes = (("csv files","*.csv"),("All Files", "*.*")))
self.browse_entry.delete(0, tk.END)
self.browse_entry.insert(0, self.path)
###following DataFrame I would like to use in in the PageThree class.
self.df = pd.read_csv(self.path)
def print_df(self):
return self.df.head()
class PageThree(PageTwo):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
PageTwo.__init__(self, parent, controller)
start_btn = tk.Button(self, text = "Data Frame", command=self.funct01, width = 10).grid()
def funct01(self):
instance = self.controller.getFrame(PageTwo)
dataFrame = instance.df
print(dataFrame.head())
if __name__=="__main__":
app=Page()
app.geometry("400x400+100+100")
app.mainloop()
Related
I want to know how to keep scene widgets after add them to scene for later.
After user's click on marker button, marker feature active and with rightclick can mark points in QGraphicscene.
Here is my code:
from PyQt5.QtWidgets import QMainWindow, QToolButton, QGraphicsScene, QGraphicsPixmapItem
from PyQt5.QtGui import QPixmap, QIcon, QPainter
from PyQt5 import uic
from PyQt5.QtCore import Qt
class MarkerButton(QToolButton):
def __init__(self, *args, **kwargs):
super(MarkerButton, self).__init__(*args, **kwargs)
def mousePressEvent(self, event):
if event.buttons() & Qt.LeftButton:
self.deleteLater()
super().mousePressEvent(event)
class MarkerScene(QGraphicsScene):
def __init__(self, *args, **kwargs):
super(MarkerScene, self).__init__(*args, **kwargs)
self.marker_widgets = dict()
def mousePressEvent(self, event):
if event.buttons() & Qt.RightButton:
self.start_point = event.scenePos()
self.update_path()
super().mousePressEvent(event)
def update_path(self):
if not self.start_point.isNull():
pushButton_icon = QIcon()
pushButton_icon.addPixmap(QPixmap('assets/mark.png'))
new_marker = MarkerButton()
new_marker.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
new_marker.move(int(self.start_point.x()), int(self.start_point.y()))
new_marker.setIcon(pushButton_icon)
new_marker.setText(str(len(self.marker_widgets)))
self.addWidget(new_marker)
self.marker_widgets[new_marker] = self.start_point
class Ui(QMainWindow):
def __init__(self):
super(Ui, self).__init__() # Call the inherited classes __init__ method
self.Window_obj= uic.loadUi('main.ui')
self.Window_obj.setWindowFlags(Qt.FramelessWindowHint)
pix = QPixmap('assets/data.png')
item = QGraphicsPixmapItem(pix)
scene = QGraphicsScene(self)
scene.addItem(item)
self.Window_obj.graphicsViewScene1.setScene(scene)
self.Window_obj.show()
def AddMarker(self):
if not self.active_toolbox_markers:
self.active_toolbox_markers = True
self.main_Window_obj.graphicsViewScene1.setRenderHint(QPainter.Antialiasing)
self.Window_obj.graphicsViewScene1.setMouseTracking(True)
scene = MarkerScene()
self.main_Window_obj.graphicsViewScene1.setScene(scene)
else:
self.active_toolbox_markers = False
I need to save this markers for later but user have to be able to hide them, the reason is because I have another tool that I want not conflict with this markers.
At the end, after add markers, the main Qpixmap removed.
my app something like this
I´m using this very known script from Mr. Bryan Oakley. My question is: How make class PageOne child of ScrolledWindow from Mr. Mikhail (https://stackoverflow.com/users/6470235/mikhail-tin). His script is in the question: Tkinter scrollbar for frame. But I wrote both bellow.
When I try
PageOne = ScrolledWindow(parent=SampleApp) python asks for controller, if I use container, it doesnot recognize it.
If I use PageOne = ScrolledWindow(parent=SampleApp, controller = SampleApp.container)
it says:
SampleApp has no attribute 'container'
I´m very curious about the answer of this puzzle.
Thanks in advance.
import tkinter as tk # python 3
from tkinter import font as tkfont # python 3
from tkinter import ttk
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")
# the container is where we'll stack a bunch of frames
# on top of each other, then the one we want visible
# will be raised above the others
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (StartPage, PageOne, ScrolledWindow):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
# put all of the pages in the same location;
# the one on the top of the stacking order
# will be the one that is visible.
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is the start page", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button1 = tk.Button(self, text="Go to Page One",
command=lambda: controller.show_frame("PageOne"))
button2 = tk.Button(self, text="ScrolledWindow",
command=lambda: controller.show_frame("ScrolledWindow"))
button1.pack()
button2.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 1", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
class ScrolledWindow(tk.Frame):
"""
1. Master widget gets scrollbars and a canvas. Scrollbars are connected
to canvas scrollregion.
2. self.scrollwindow is created and inserted into canvas
Usage Guideline:
Assign any widgets as children of <ScrolledWindow instance>.scrollwindow
to get them inserted into canvas
__init__(self, parent, canv_w = 400, canv_h = 400, *args, **kwargs)
docstring:
Parent = master of scrolled window
canv_w - width of canvas
canv_h - height of canvas
"""
def __init__(self, parent, controller, canv_w = 400, canv_h = 400, *args, **kwargs):
"""Parent = master of scrolled window
canv_w - width of canvas
canv_h - height of canvas
"""
super().__init__(parent, *args, **kwargs)
self.parent = parent
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
# creating a scrollbars
self.xscrlbr = ttk.Scrollbar(self.parent, orient = 'horizontal')
self.xscrlbr.grid(column = 0, row = 1, sticky = 'ew', columnspan = 2)
self.yscrlbr = ttk.Scrollbar(self.parent)
self.yscrlbr.grid(column = 1, row = 0, sticky = 'ns')
# creating a canvas
self.canv = tk.Canvas(self.parent)
self.canv.config(relief = 'flat',
width = 10,
heigh = 10, bd = 2)
# placing a canvas into frame
self.canv.grid(column = 0, row = 0, sticky = 'nsew')
# accociating scrollbar comands to canvas scroling
self.xscrlbr.config(command = self.canv.xview)
self.yscrlbr.config(command = self.canv.yview)
# creating a frame to inserto to canvas
self.scrollwindow = ttk.Frame(self.parent)
self.canv.create_window(0, 0, window = self.scrollwindow, anchor = 'nw')
self.canv.config(xscrollcommand = self.xscrlbr.set,
yscrollcommand = self.yscrlbr.set,
scrollregion = (0, 0, 100, 100))
self.yscrlbr.lift(self.scrollwindow)
self.xscrlbr.lift(self.scrollwindow)
self.scrollwindow.bind('<Configure>', self._configure_window)
self.scrollwindow.bind('<Enter>', self._bound_to_mousewheel)
self.scrollwindow.bind('<Leave>', self._unbound_to_mousewheel)
return
def _bound_to_mousewheel(self, event):
self.canv.bind_all("<MouseWheel>", self._on_mousewheel)
def _unbound_to_mousewheel(self, event):
self.canv.unbind_all("<MouseWheel>")
def _on_mousewheel(self, event):
self.canv.yview_scroll(int(-1*(event.delta/120)), "units")
def _configure_window(self, event):
# update the scrollbars to match the size of the inner frame
size = (self.scrollwindow.winfo_reqwidth(), self.scrollwindow.winfo_reqheight())
self.canv.config(scrollregion='0 0 %s %s' % size)
if self.scrollwindow.winfo_reqwidth() != self.canv.winfo_width():
# update the canvas's width to fit the inner frame
self.canv.config(width = self.scrollwindow.winfo_reqwidth())
if self.scrollwindow.winfo_reqheight() != self.canv.winfo_height():
# update the canvas's width to fit the inner frame
self.canv.config(height= self.scrollwindow.winfo_reqheight())
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
After a lot of try and error I found a solution:
The Idea is to do a complete class with frame --> canvas --> desired frame outside the SampleApp and send it to the constructor loop:
This is the code to build a scrolled frame window inside the main class in a loop (after that you can change "Page_with_Scrooll_bar" to "PageOne" as I've asked in question):
import tkinter as tk # python 3
from tkinter import font as tkfont # python 3
from tkinter import ttk
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title_font = tkfont.Font(family='Helvetica', size=18, weight="bold", slant="italic")
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (StartPage, PageOne, PageTwo, Page_with_Scroll_bar):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name):
'''Show a frame for the given page name'''
frame = self.frames[page_name]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is the start page", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button1 = tk.Button(self, text="Go to Page One",
command=lambda: controller.show_frame("PageOne"))
button2 = tk.Button(self, text="Go to Page two",
command=lambda: controller.show_frame("PageTwo"))
button3 = tk.Button(self, text="Example with Scrollbar",
command=lambda: controller.show_frame("Page_with_Scroll_bar"))
button1.pack()
button2.pack()
button3.pack()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 1", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
class PageTwo(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="This is page 2", font=controller.title_font)
label.pack(side="top", fill="x", pady=10)
button = tk.Button(self, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
button.pack()
class Page_with_Scroll_bar(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.canvas = tk.Canvas(self, borderwidth=0, background="#ffffff")
self.frame = tk.Frame(self.canvas, background="#ffffff")
self.vsb = tk.Scrollbar(self, orient="vertical", command=self.canvas.yview)
self.canvas.configure(yscrollcommand=self.vsb.set)
self.vsb.pack(side="right", fill="y")
self.canvas.pack(side="left", fill="both", expand=True)
self.canvas.create_window((4,4), window=self.frame, anchor="nw",
tags="self.frame")
self.frame.bind("<Configure>", self.onFrameConfigure)
self.populate()
self.button = tk.Button(self.frame, text="Go to the start page",
command=lambda: controller.show_frame("StartPage"))
self.button.grid(row=102, column=1)
def populate(self):
'''Put in some fake data'''
for row in range(100):
tk.Label(self.frame, text="%s" % row, width=3, borderwidth="1",
relief="solid").grid(row=row, column=0)
t="this is the second column for row %s" %row
tk.Label(self.frame, text=t).grid(row=row, column=1)
def onFrameConfigure(self, event):
'''Reset the scroll region to encompass the inner frame'''
self.canvas.configure(scrollregion=self.canvas.bbox("all"))
if __name__ == "__main__":
app = SampleApp()
app.mainloop()
I have a scene like this
class Scene(QtWidgets.QGraphicsScene):
def __init__(self, parent=None):
super(Scene, self).__init__(parent)
def mousePressEvent(self, event):
print('scene pressed')
self.wid = MyRect(event.pos(), event.pos())
self.addItem(self.wid)
self.wid.show()
I would like class MyRect(QtWidgets.QGraphicsRectItem) with painter, mouse event and so on to be a draggable rectangle.
all stuff in MyRect
So then I could have many Rectangle to the scene and even after draw line between them and so on (kind of diagram app), but keeping objects related editable options in MyRect, MyLine , ....
I thought :
class MyRect(QtWidgets.QGraphicsRectItem):
def __init__(self, begin, end, parent=None):
super().__init__(parent)
self.begin = begin
self.end = end
def paintEvent(self, event):
print('painting')
qp = QtGui.QPainter(self)
qp.drawRect(QtCore.QRect(self.begin, self.end))
def mousePressEvent(self, event):
self.begin = event.pos()
self.end = event.pos()
self.update()
def mouseMoveEvent(self, event):
self.end = event.pos()
self.update()
def mouseReleaseEvent(self, event):
self.begin = event.pos()
self.end = event.pos()
self.update()
But I does not work (paint event not initiated whereas mousepressed event in scene is intiated)
I did not find what I wanted through the web so started totry do it by myself. I'm pretty sure it is a must known starting point but I cannot find it
First of all a QGraphicsItem is not a QWidget, so it has those events and does not handle them directly, that's what QGraphicsView and QGraphicsScene do. For example you say that you want to have a moveable rectangle because that task is simple is QGraphicsView, it is not necessary to overwrite:
from PyQt5 import QtCore, QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
scene = QtWidgets.QGraphicsScene(self)
view = QtWidgets.QGraphicsView(scene)
self.setCentralWidget(view)
rect_item = QtWidgets.QGraphicsRectItem(QtCore.QRectF(0, 0, 100, 100))
rect_item.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)
scene.addItem(rect_item)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
If you want to change the way you paint the rectangle you must overwrite the paint() method as shown below:
from PyQt5 import QtCore, QtGui, QtWidgets
class RectItem(QtWidgets.QGraphicsRectItem):
def paint(self, painter, option, widget=None):
super(RectItem, self).paint(painter, option, widget)
painter.save()
painter.setRenderHint(QtGui.QPainter.Antialiasing)
painter.setBrush(QtCore.Qt.red)
painter.drawEllipse(option.rect)
painter.restore()
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
scene = QtWidgets.QGraphicsScene(self)
view = QtWidgets.QGraphicsView(scene)
self.setCentralWidget(view)
rect_item = RectItem(QtCore.QRectF(0, 0, 100, 100))
rect_item.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)
scene.addItem(rect_item)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
Update:
from PyQt5 import QtCore, QtGui, QtWidgets
class GraphicsScene(QtWidgets.QGraphicsScene):
def __init__(self, parent=None):
super(GraphicsScene, self).__init__(QtCore.QRectF(-500, -500, 1000, 1000), parent)
self._start = QtCore.QPointF()
self._current_rect_item = None
def mousePressEvent(self, event):
if self.itemAt(event.scenePos(), QtGui.QTransform()) is None:
self._current_rect_item = QtWidgets.QGraphicsRectItem()
self._current_rect_item.setBrush(QtCore.Qt.red)
self._current_rect_item.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True)
self.addItem(self._current_rect_item)
self._start = event.scenePos()
r = QtCore.QRectF(self._start, self._start)
self._current_rect_item.setRect(r)
super(GraphicsScene, self).mousePressEvent(event)
def mouseMoveEvent(self, event):
if self._current_rect_item is not None:
r = QtCore.QRectF(self._start, event.scenePos()).normalized()
self._current_rect_item.setRect(r)
super(GraphicsScene, self).mouseMoveEvent(event)
def mouseReleaseEvent(self, event):
self._current_rect_item = None
super(GraphicsScene, self).mouseReleaseEvent(event)
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
scene =GraphicsScene(self)
view = QtWidgets.QGraphicsView(scene)
self.setCentralWidget(view)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.resize(640, 480)
w.show()
sys.exit(app.exec_())
first, see code below:
import sys
from PyQt5.QtCore import (Qt, pyqtSignal, pyqtSlot)
from PyQt5.QtWidgets import (QWidget, QLCDNumber, QSlider,
QVBoxLayout, QApplication)
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def printLabel(self, str):
print(str)
#pyqtSlot(int)
def on_sld_valueChanged(self, value):
self.lcd.display(value)
self.printLabel(value)
def initUI(self):
self.lcd = QLCDNumber(self)
self.sld = QSlider(Qt.Horizontal, self)
vbox = QVBoxLayout()
vbox.addWidget(self.lcd)
vbox.addWidget(self.sld)
self.setLayout(vbox)
self.sld.valueChanged.connect(self.on_sld_valueChanged)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('Signal & slot')
self.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
I'm a little puzzled about how the true value in sld is transmitted to the formal parameter 'value' in the slot function : def sld_valChanged(self, value).
Because i can't see something like this: self.sld.valueChanged.connect(partial(self.sld_valChanged, self.sld.value))
Could someone explain that?
I want to pass the value stored in self.pin, which we get from the user through entry() in StartPage to the __init__ method of Options class but only when I click the submit button. Also this must be noted that there are multiple pages and I have used tkraise() to raise one page over the other. Explanation will be appreciated as I'm new to tkinter and oop. My whole code is given below:
import tkinter as tk
from tkinter import font as tkfont
from tkinter import messagebox
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.title_font = tkfont.Font(family='Courier New', size=18, weight="bold")
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (StartPage, PageOne, PageTwo, PageThree, PageFour, Options):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name):
frame = self.frames[page_name]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="Enter 4 digit pin", font=controller.title_font, fg="red")
label.pack(side="top", fill="x", pady=10)
self.pin = tk.Entry(self, bd = 4, relief="groove", show="*", font=20, justify='center')
# self.pin="786125"
self.pin.pack()
submit = tk.Button(self, text="Submit", width=12,font=tkfont.Font(size=12),command=lambda: [controller.show_frame("Options")], cursor="hand2")
submit.pack()
class Options(StartPage):
def __init__(self, parent, controller):
# StartPage.__init__(self, parent, controller)
# print(self.pin.get())
tk.Frame.__init__(self, parent)
self.controller = controller
f1=tk.Frame(self)
f1.pack()
f2=tk.Frame(self)
f2.pack(side="bottom")
button1 = tk.Button(f1, text="Balance Inquiry",relief="flat", padx=30, justify='left', cursor="hand2", fg="red", font=tkfont.Font(size=10),
command=lambda: controller.show_frame("PageOne"))
button1.pack(side="left")
button2 = tk.Button(f1, text="Deposit",relief="flat", padx=50, justify='right', cursor="hand2", fg="red", font=tkfont.Font(size=10),
command=lambda: controller.show_frame("PageTwo"))
button2.pack(side="left")
button3 = tk.Button(f2, text="Withdraw",relief="flat", padx=50, justify='left', cursor="hand2", fg="red", font=tkfont.Font(size=10),
command=lambda: controller.show_frame("PageThree"))
button3.pack(side="left")
button4 = tk.Button(f2, text="Pin Change",relief="flat", padx=50, justify='right', cursor="hand2", fg="red", font=tkfont.Font(size=10),
command=lambda: controller.show_frame("PageFour"))
button4.pack(side="left")
Personally I would keep the value stored in the controller and then access it from the other pages. Here is a modified version of your code that can access the stored pin.
This is done by adding a command to the buttons lambda and saving the entry value to the controller.
import tkinter as tk
from tkinter import font as tkfont
from tkinter import messagebox
class SampleApp(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.pin_stored = ""
self.title_font = tkfont.Font(family='Courier New', size=18, weight="bold")
container = tk.Frame(self)
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (StartPage, Options):
page_name = F.__name__
frame = F(parent=container, controller=self)
self.frames[page_name] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame("StartPage")
def show_frame(self, page_name):
frame = self.frames[page_name]
frame.tkraise()
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
label = tk.Label(self, text="Enter 4 digit pin", font=controller.title_font, fg="red")
label.pack(side="top", fill="x", pady=10)
self.pin = tk.Entry(self, bd = 4, relief="groove", show="*", font=20, justify='center')
self.pin.pack()
submit = tk.Button(self, text="Submit", width=12,font=tkfont.Font(size=12), command=lambda: [controller.show_frame("Options"), self.store_pin()], cursor="hand2")
submit.pack()
def store_pin(self):
print("test")
self.controller.pin_stored = self.pin.get()
class Options(StartPage):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent)
self.controller = controller
f1=tk.Frame(self)
f1.pack()
f2=tk.Frame(self)
f2.pack(side="bottom")
button1 = tk.Button(f1, text="Balance Inquiry",relief="flat", padx=30, justify='left', cursor="hand2", fg="red", font=tkfont.Font(size=10),
command=lambda: controller.show_frame("PageOne"))
button1.pack(side="left")
button2 = tk.Button(f1, text="Deposit",relief="flat", padx=50, justify='right', cursor="hand2", fg="red", font=tkfont.Font(size=10),
command=lambda: controller.show_frame("PageTwo"))
button2.pack(side="left")
button3 = tk.Button(f2, text="Withdraw",relief="flat", padx=50, justify='left', cursor="hand2", fg="red", font=tkfont.Font(size=10),
command=lambda: controller.show_frame("PageThree"))
button3.pack(side="left")
button4 = tk.Button(f2, text="Pin Change",relief="flat", padx=50, justify='right', cursor="hand2", fg="red", font=tkfont.Font(size=10),
command=lambda: controller.show_frame("PageFour"))
button4.pack(side="left")
tk.Button(self, text="print stored pin", command=self.print_pin).pack()
def print_pin(self):
print(self.controller.pin_stored)
if __name__ == "__main__":
SampleApp().mainloop()