2016-12-17 3 views
-1

в [предыдущем вопросе] [1] получил идеальный скрипт из @ acw1668 для создания всплывающих окон (см. Ниже).переключение окон в tkinter с классами

Как это можно переписать в форме, в которой новые окна не являются всплывающими окнами, а просто переключаться с одной страницы на другую (здесь не обязательно нужны списки/candvas)?

Редактировать: попытался внести изменения в код в соответствии с предложениями @Bryan Oakley. Мой вопрос здесь: мне не удается передать список lst от GUI класса к другим классам страниц без сообщения об ошибке:

File "/.spyder-py3/temp.py", line 25, in __init__ 
    frame = F(parent=container, controller=self) 

TypeError: __init__() missing 1 required positional argument: 'lst' 

Что я здесь отсутствует? И я не понимаю, что здесь происходит:

for F in (StartPage, PageOne, PageTwo): 
       page_name = F.__name__ 
       frame = F(parent=container, controller=self,) 

       self.frames[page_name] = frame 

Если кто-нибудь может объяснить, пожалуйста?

import tkinter as tk 
from tkinter import ttk 


class GUI(tk.Tk): 

    def __init__(self): 

     tk.Tk.__init__(self) 
     self.lst = ['a', 'b', 'c'] 
     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_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", self.lst) 

    def show_frame(self, page_name): 
     '''Show a frame for the given page name''' 
     frame = self.frames[page_name] 
     frame.tkraise() 


    def show_popup(self, page, lst): 

     win = page(self, lst) 
     win.grab_set()   # make window modal 
     self.wait_window(win) # make window modal 




class StartPage(tk.Frame): 

    def __init__(self, parent, controller, lst): 
     tk.Frame.__init__(self, parent) 
     self.controller = controller 
     self.lst = lst 
     # ------------------------------------------------------------------- # 
     label = tk.Label(self, text="Check this out")       
     label.pack(pady=10,padx=10) 

     # ------------------- create buttons --------------------------------- 
     button1 = ttk.Button(self, text="show all", 
          width = 25, command=lambda: 
           controller.show_popup(App, self.lst)) 
     button1.pack(pady=10, padx=10)   
     button2 = ttk.Button(self, text="show page one", 
          width = 25, command=lambda: 
           controller.show_frame(PageOne)) 
     button2.pack(pady=10, padx=10)   


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") 
     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") 
     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 App(tk.Toplevel): 

    def __init__(self, parent, lst): 
     tk.Toplevel.__init__(self, parent) 
     self.lst = lst 
     self.title('This is the pop up window') 
     self.geometry('400x200') 
     label = tk.Label(self, text=self.lst) 
     label.pack(side="top", fill="x", pady=10) 
     parent.grid_rowconfigure(0, weight = 1) 
     parent.grid_columnconfigure(0, weight = 1) 

if __name__ == '__main__': 
    app = GUI() 
    app.mainloop()     

    [1]: http://stackoverflow.com/questions/41181809/how-to-open-and-close-another-window-with-scrollbar-in-tkinter-for-python-3-5/41182843?noredirect=1#comment69580999_41182843 
+1

Если вы не хотите, всплывающее окно, не наследуют от 'tk.Toplevel'. Начните свое исследование здесь: http://stackoverflow.com/questions/7546050 –

+0

Я сделал это уже, но мне не удается адаптировать мой код к тому, с которым вы связались. В моем примере GUI класса также является/уже «StartPage». Я не могу интегрировать/включать дополнительные классы страниц. Любой намек, как это сделать? –

+1

'tk.Toplevel' используется для создания второго/третьего/и т. Д. окно - так что вам нужно использовать что-то другое - то есть. 'Tk.Frame'. И вам нужен метод для изменения страниц - и рано или поздно вы создадите что-то вроде кода в ссылке @BryanOakley. Это будет проще, если 'StartPage' будет в отдельном классе, а не в графическом интерфейсе. – furas

ответ

1

Ваш класс Инициализаторы определяются следующим образом:

class StartPage(tk.Frame): 
    def __init__(self, parent, controller, lst): 

Для того, чтобы создать экземпляр этого класса требует три аргумента (плюс): selfparent, controller и lst.

Теперь давайте посмотрим на то, как вы создаете экземпляр:

frame = F(parent=container, controller=self,) 

Обратите внимание, как у вас есть parent и у вас есть controller, но вы не прошли ни в чем для lst. Вот почему в этой ошибке указывается «отсутствующий 1 обязательный позиционный аргумент:« lst »- потому что вы буквально пропускаете один требуемый аргумент с именем« lst ».

Чтобы устранить эту проблему, вам просто нужно предоставить дополнительный аргумент. Например:

frame = F(parent=container, controller=self, lst=self.lst) 

ОДНАКО, вы, вероятно, не должны этого делать. Архитектура этого небольшого блока кода, который вы скопировали, позволяет получить доступ к значениям в GUI-классе из любого из классов «страницы» без необходимости выполнять дополнительную работу.

Поскольку этот переменный является атрибутом GUI класса, и вы передаете ссылку на экземпляр GUI класса каждую «страницу» (атрибут controller), вы можете получить доступ к этим данным в любое время вы хотите, не имея передать его во время строительства. Вы можете удалить его с __init__ и с того места, где вы создаете страницы (то есть: вернитесь к исходному коду перед вашими изменениями), а затем просто используйте self.controller.lst всякий раз, когда вам нужно это значение.

Например:

class SomePage(tk.Frame): 
    def __init__(self, parent, controller): 
     self.controller = controller 
     ... 
    def some_function(self): 
     print("The value of 'lst' is:", self.controller.lst) 
+0

большое спасибо @ Брайан Оукли. «Контроллер» в 'self.controller.lst' был недостающим звеном. Мне все еще трудно использовать и думать в 'parent' и' controller'terms. Btw, я попробовал 'frame = F (parent = container, controller = self, self.lst)' раньше, но, как вы сказали, это неверно, и это также вызвало ошибку 'SyntaxError: позиционный аргумент следует за аргументом ключевого слова'. –

+0

Можно ли вызвать классы страниц из команды меню в классе GUI? Я замечаю, что это не работает должным образом (страницы загружаются автоматически, если меню находится в графическом интерфейсе, а классы страниц вызываются с помощью скобок, например 'show_popup (App, self.lst)') –

+1

@Al_Iskander да, конечно, можно позвонить классы страниц из команды меню. Элементы меню могут вызывать те же функции, что и все остальное. Вы можете найти это полезным: http://stackoverflow.com/q/5767228/7432 –

Смежные вопросы