Python Forum
[Tkinter] Call a function when switching layouts
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Tkinter] Call a function when switching layouts
#1
I am writing a flashcard program in Python 3.7 using tkinter. I have many interfaces, like one for selecting a file, and one for reviewing cards, one with a list of decks to choose from. I also have an interface to edit a card which shows the data for one card at a time, with buttons to switch to the next or previous card. I have another interface with 25 rows all showing data for one card. I have classes for keeping track of all the data being edited. I have a View class which has methods that draw the interfaces. Separate methods draw the single-edit interface and the multi-edit interface. Both methods have local functions which are triggered by the buttons in the interface, and both have a local variable which is an instance of a class to keep track of the data.

I want to be able to switch between the multiple/single editing modes and keep the data that was edited in the other interface. The method for switching between the two layouts is:
    def switchLayout(self,newLayout):
        if self.currentLayout is not None:
            self.currentLayout.pack_forget()
        self.prevLayout = self.currentLayout
        self.lay[newLayout].pack(fill="both")
        self.currentLayout = self.lay[newLayout]
I could try using a class member instead of a local variable in the two methods (the method that draws the single-edit interface, and the one that draws the multiple-edit interface). However, I don't like the idea of a class member used by only two methods. Even if I did it that way, I would need to load the data into the next widgets of the new interface when I switch the interfaces.

The class that keeps track of data keeps track of what was entered on a form if I went to another page or something. The actual widgets are stored in local variables of the method.

If there is a way the calls to pack and pack_forget on a widget could trigger an event, I think I can solve this. Can an event be triggered that way? I think my problem is that I need access to local variables of a method. If I made them global, it would clutter things. Should my class that keeps track of data also keep track of the widget objects themselves? What if it kept a reference to a function local to a method of the View class? Would that be bad practice?

The only way I can think of is to have a class member set to True when switching between single/multiple edit mode. Then I could have an event bound to the main frame widget to trigger when the mouse moves, that would call a function that check to see if the flag were true, and if it were true, update the forms, and set the flag to False. Some problems with this are that the function would be called repeatedly while the mouse is moving; to allow a user to edit only from the keyboard instead of the mouse I would need to bind more events, possibly to all widgets in the interface; and the forms would not be filled out until the mouse is moved. Even if the user was using the mouse, they would not be able to do anything until moving it, but it would still look funny to leave the form blank and then it would suddenly update once the mouse is moved.

I found another thread https://python-forum.io/Thread-PyQt-Mana...module-GUI where it is said that it is not good practice to use global or semi-global variables. I'd expect a class member to qualify as semi-global. It is also said to pass variables to the parent, but I don't think that would apply to my case.

Is there a way to trigger an event when switching interfaces? If not, does anyone have any ideas?

To help clarify, here is part of the classes for keeping track of data (if I pasted the whole thing it would be too long; mostly I want to show how I use members and local variables):
class EditCards(ModelInfo):
    def __init__(self, databaseConnection, userID):
        super().__init__(databaseConnection, userID)
        self.resetData()
    def resetData(self):
        self.deckID = 0 # ID of deck currently being edited
        self.edited = None # collection of cards that have been edited (to be saved)
        self.original = None # deck of cards without edits in the current session
        self.cardOrder = None # list of card IDs; the order in which cards are browsed
        self.numNewCards = 0 # number of cards inserted during the editing session
        self.numSides = 2 # number of sides of the deck currently being edited
        self.totalCards = 0 # Total number of cards being edited in the deck
    def selectDeckForEditing(self, deckID):
        self.deckID = deckID
        self.original = ReferenceDeck()
        self.edited = ReferenceDeck()
        self.original.fill(self.getCardsFromDeck(deckID))
        self.cardOrder = list(self.original.keys())
        self.numSides = self.getNumDeckSides(deckID)
        self.totalCards = self.original.size()

class EditSingleCard(EditCards):
    def resetData(self):
        super().resetData()
        self.cardNumber = 0 # the card currently being edited, given as an index of cardOrder
        self.hintNumber = [0] * (self.numSides+1) # Number of the hint currently being edited
        self.totalHints = [0] * (self.numSides+1) # Total number of hints for the card currently being edited
        self.currentHints = [[] for i in range(self.numSides+1)] # Hints of the card currently being edited
        self.isTextModified = False
    def selectDeckForEditing(self, deckID):
        super().selectDeckForEditing(deckID)
        if self.totalCards >= 1:
            self.cardNumber = 1
        else:
            self.cardNumber = 0
        self.resetHintNumbers()

class EditMultiCards(EditCards):
    ROWS = 25
    def resetData(self):
        super().resetData()
        self.pageNumber = 1 # the page currently being edited
    def selectDeckForEditing(self, deckID):
        super().selectDeckForEditing(deckID)
        self.pageNumber = 1
        self.totalPages = 1 + self.original.size() // self.__class__.ROWS
Here are part of the methods within the View class:
    def editSingleCardGUI(self):
        deckHeadingEntry = tk.StringVar()
        cardNumberVar = tk.StringVar()
        hintNumberVars = [tk.StringVar()]
        layout = tk.Frame(self.mainFrame)
        sideFrame = tk.Frame(layout)
        hintFrame = tk.Frame(layout)
        deckFrame = tk.Frame(layout)
        self.lay["editSingleCard"] = layout
        sideLabels = []
        sideTexts = []
        sideHintTexts = []
        hintFrames = []
        tagsText = tk.Text(layout, height=5, width=40)
        hintsText = tk.Text(hintFrame, height=5, width=40)
        ec = None # Instance of EditSingleCard
    def editMultiCardGUI(self):
        ROWS = EditMultiCards.ROWS
        ec = None
        layout = tk.Frame(self.mainFrame)
        topFrame = tk.Frame(layout)
        bodyFrame = tk.Frame(layout)
        self.lay["editMultiCard"] = layout
        deckNameVar = tk.StringVar()
        pageNumberVar = tk.StringVar()
        rowCheckVars = [tk.BooleanVar() for i in range(ROWS)]
        sideTexts = [[] for i in range(ROWS)]
        hintTexts = [[] for i in range(ROWS)]
        tagTexts = [tk.Text(bodyFrame, height=4, width=15) for i in range(ROWS)]
        sideLabels = [tk.Label(bodyFrame, text="Side 1"), tk.Label(bodyFrame,\
            text="Side 2")]
        rowChecks = [tk.Checkbutton(bodyFrame) for i in range(ROWS)]
        isHintOpen = [True for i in range(ROWS)]
        dividers = []
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  GUI Problem / call another function / fill QListwidget flash77 5 836 Jul-30-2023, 04:29 PM
Last Post: flash77
Star [PyQt] Python GUI - PyQt Containers and Layouts Explained panofish 0 910 Aug-28-2022, 07:29 PM
Last Post: panofish
  Switching from tkinter to gtk is difficult! snakes 1 1,421 Aug-08-2022, 10:35 PM
Last Post: woooee
  simple tkinter question function call not opening image gr3yali3n 5 3,301 Aug-02-2022, 09:13 PM
Last Post: woooee
  [PyQt] Call a function in FormA from FormB panoss 3 1,861 Jan-30-2022, 07:45 PM
Last Post: panoss
  Displaying various layouts in a single window arbiel 6 4,014 Nov-08-2020, 09:21 PM
Last Post: arbiel
  Call local variable of previous function from another function with Python3 & tkinter Hannibal 5 4,357 Oct-12-2020, 09:16 PM
Last Post: deanhystad
  [PyQt] call a function with parametrs from another class atlass218 3 4,715 Feb-29-2020, 11:00 AM
Last Post: atlass218
  [Tkinter] Unable to Access global Variable when switching between frames tziyong 1 3,423 Nov-03-2019, 01:08 AM
Last Post: balenaucigasa
  [PyGUI] Switching between two frames using Tkinter jenkins43 1 4,581 Jul-17-2019, 10:53 AM
Last Post: metulburr

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020