2013-09-30 6 views
6

vedere il seguente codice: (sto fondamentalmente cercando di creare un widget di testo con una barra di scorrimento verticale, pur mantenendo tutti i metodi/funzioni da Tkinter.Text nella mia classe)Subclassing Tkinter per creare un costume Widget

class ScrollableTextWidget(Tkinter.Text): 
    def __init__(self, parent): 
     self.parent = parent 
     self.Frame = ttk.Frame(self.parent) 
     Tkinter.Text.__init__(self, self.Frame, width=1, height=1) 
     self.__initWidget() 

    def __initWidget(self): 
     self.Frame.grid(sticky="NSEW") 
     self.ScrollbarY = ttk.Scrollbar(self.Frame, orient="vertical", command=self.yview) 
     self.configure(yscrollcommand=self.ScrollbarY.set) 
     self.grid(column=0, row=0, sticky="NSEW") 
     self.ScrollbarY.grid(column=1, row=0, sticky="NS") 
     self.Frame.columnconfigure(0, weight=1) 
     self.Frame.rowconfigure(0, weight=1) 

È ok creare il mio widget personalizzato come questo o dovrei piuttosto metterlo in una cornice e scrivere i miei metodi?

risposta

2

Vorrei utilizzare sottoclasse per il progetto medio, grande o per il progetto con supporto in futuro perché la sottoclasse può essere facilmente sostituita o aggiornata. In ogni caso i costi per la sottoclasse sono piccoli. Ma se il tuo compito è monouso fallo sporco e veloce.

In questo caso vorrei sottoclasse da Frame perché widget più generale e non è necessario eseguire l'override di pack, grid e altri metodi.

+0

Quello che sto cercando di chiedere è, è una buona pratica sottoclasse il Tkinter.Text (o qualsiasi altro widget per mantenere i suoi metodi e funzioni) per creare un widget personalizzato. In questo caso sto sottoclassi Tkinter.Text, posizionandolo con una barra di scorrimento su un frame all'interno della mia classe. O dovrei creare una sottoclasse di Frame e posizionare il Text Widget e la barra di scorrimento direttamente su di esso e creare i miei metodi e le mie funzioni? – user2830098

+0

Vedere l'aggiornamento della mia risposta –

16

È molto normale creare una sottoclasse di un widget per crearne uno personalizzato. Tuttavia, se questo widget personalizzato è composto da più di un widget, normalmente sottoclassi Frame. Ad esempio, per creare un widget che è un widget di testo con una barra di scorrimento che vorrei fare qualcosa di simile:

import Tkinter as tk 

class ScrolledText(tk.Frame): 
    def __init__(self, parent, *args, **kwargs): 
     tk.Frame.__init__(self, parent) 
     self.text = tk.Text(self, *args, **kwargs) 
     self.vsb = tk.Scrollbar(self, orient="vertical", command=self.text.yview) 
     self.text.configure(yscrollcommand=self.vsb.set) 
     self.vsb.pack(side="right", fill="y") 
     self.text.pack(side="left", fill="both", expand=True) 

class Example(tk.Frame): 
    def __init__(self, parent): 
     tk.Frame.__init__(self, parent) 
     self.scrolled_text = ScrolledText(self) 
     self.scrolled_text.pack(side="top", fill="both", expand=True) 
     with open(__file__, "r") as f: 
      self.scrolled_text.text.insert("1.0", f.read()) 

root = tk.Tk() 
Example(root).pack(side="top", fill="both", expand=True) 
root.mainloop() 

Con questo approccio, nota come è necessario fare riferimento al widget di testo interno durante l'inserimento del testo. Se si desidera che questo widget assomigli più ad un widget di testo reale, è possibile creare una mappatura per alcune o tutte le funzioni del widget di testo. Ad esempio:

import Tkinter as tk 

class ScrolledText(tk.Frame): 
    def __init__(self, parent, *args, **kwargs): 
     tk.Frame.__init__(self, parent) 
     self.text = tk.Text(self, *args, **kwargs) 
     self.vsb = tk.Scrollbar(self, orient="vertical", command=self.text.yview) 
     self.text.configure(yscrollcommand=self.vsb.set) 
     self.vsb.pack(side="right", fill="y") 
     self.text.pack(side="left", fill="both", expand=True) 

     # expose some text methods as methods on this object 
     self.insert = self.text.insert 
     self.delete = self.text.delete 
     self.mark_set = self.text.mark_set 
     self.get = self.text.get 
     self.index = self.text.index 
     self.search = self.text.search 

class Example(tk.Frame): 
    def __init__(self, parent): 
     tk.Frame.__init__(self, parent) 
     self.scrolled_text = ScrolledText(self) 
     self.scrolled_text.pack(side="top", fill="both", expand=True) 
     with open(__file__, "r") as f: 
      self.scrolled_text.insert("1.0", f.read()) 

root = tk.Tk() 
Example(root).pack(side="top", fill="both", expand=True) 
root.mainloop() 
+0

Grazie, è stato davvero utile. Ho provato a votare/accettare la tua risposta, ma purtroppo la mia reputazione è troppo bassa. Un'altra cosa è, come potrei fare per creare un ttk.Trekiew nello stesso modo ed essere in grado di associare un evento ad esso ?, Devo esporre e utilizzare l'istanza di treeview all'interno del frame? – user2830098

+1

Il problema con la tua soluzione è precisamente che devi esporre manualmente i metodi dei membri del testo, mentre l'OP spera di ottenere questo gratuitamente. Quindi, credo che la sua idea originale di sottoclasse del testo fosse la giusta via da seguire. Il mio mastering Tkinter è troppo superficiale per rispondere al problema, ma sarei felice se qualcuno potesse farlo. – quickbug