亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

創建此類的兩個實例,會產生奇怪的行為 tkinter python

創建此類的兩個實例,會產生奇怪的行為 tkinter python

慕婉清6462132 2024-01-24 15:30:49
我制作了一個繼承自ttk.Entry. 問題是,它只適用于實例化一次,如果我為同一個條目創建兩個實例,它將開始顯示一些奇怪的效果。類及其用法:import tkinter as tkfrom tkinter import ttkclass PlaceholderEntry(ttk.Entry):    '''    Custom modern Placeholder Entry box, takes positional argument master and placeholder\n    Use acquire() for getting output from entry widget\n    Use shove() for inserting into entry widget\n    Use remove() for deleting from entry widget\n    Use length() for getting the length of text in the widget\n    BUG 1: Possible bugs with binding to this class\n    BUG 2: Anomalous behaviour with config or configure method    '''    def __init__(self, master, placeholder, **kwargs):        # style for ttk widget        self.s = ttk.Style()        self.s.configure('my.TEntry')        # init entry box        ttk.Entry.__init__(self, master, style='my.TEntry', **kwargs)        self.text = placeholder        self.__has_placeholder = False  # placeholder flag        # add placeholder if box empty        self._add()        # bindings of the widget        self.bind('<FocusIn>', self._clear)        self.bind('<FocusOut>', self._add)        self.bind_all('<Key>', self._normal)        self.bind_all('<Button-1>', self._cursor)    def _clear(self, *args):  # method to remove the placeholder        if self.get() == self.text and self.__has_placeholder:  # remove placeholder when focus gain            self.delete(0, tk.END)            self.s.configure('my.TEntry', foreground='black',                             font=(0, 0, 'normal'))            self.__has_placeholder = False  # set flag to false單擊其中一個條目并將焦點更改到下一個條目時,您可以注意到兩個實例在某種程度上有關聯的“行為”?盡管單個實例工作得很好。這是我的第一個 OOP 項目,所以我不確定出了什么問題。先謝謝了
查看完整描述

1 回答

?
BIG陽

TA貢獻1859條經驗 獲得超6個贊

您有兩個問題,都與您的類依賴于全局數據這一事實有關:您正在使用bind_all它有效地創建全局綁定,并且您對普通和占位符使用相同的樣式,但樣式是全局的。


第一個問題是您對bind_all. 每次創建實例時,bind_all該實例的綁定都會替換前一個實例的綁定。兩個實例都將繼承一個綁定,該綁定僅調用最后創建的實例的_normal和方法。_cursor


作為一般經驗法則,像這樣的類應該始終只在其自身上創建綁定。您需要更改self.bind_all為僅self.bind.


self.bind('<Key>', self._normal)

self.bind('<Button-1>', self._cursor)

第二個問題是您對樣式的使用。您在兩種狀態下的兩個小部件都使用單一樣式,但由于樣式是全局的,因此當您更改一個小部件中的樣式時,它會影響另一個小部件。


您不應該重新配置單一樣式,而應該配置兩種樣式并在它們之間切換。例如,您可以my.TEntry為正常情況創建一個樣式,并placeholder.TEntry為您想要顯示占位符時創建一個樣式。


首先在方法中配置樣式__init__:


def __init__(self, master, placeholder, **kwargs):

? ? # style for ttk widget

? ? self.s = ttk.Style()

? ? self.s.configure('my.TEntry', foreground='black', font=(0, 0, 'normal'))

? ? self.s.configure('placeholder.TEntry', foreground='grey', font=(0, 0, 'bold'))

接下來,無需重新配置樣式定義,只需交換小部件上的樣式即可。例如,_clear看起來像這樣:


def _clear(self, *args):? # method to remove the placeholder

? ? if self.get() == self.text and self.__has_placeholder:??

? ? ? ? self.configure(style="my.TEntry")

? ? ? ? ...

同樣,_add應該看起來像這樣:


def _add(self, *args):? # method to add placeholder

? ? if self.get() == '' and not self.__has_placeholder:? # if no text add placeholder

? ? ? ? self.configure(style="placeholder.TEntry")

? ? ? ? ...

最后,您的邏輯有一個錯誤,可能是由于誤解了綁定的工作原理。當您綁定到 時<Key>,該綁定發生在默認綁定之前。因此,您檢查條目self._add是否為空的位置發生在插入您剛剛鍵入的密鑰之前。因此,代碼認為條目小部件是空的,并將樣式切換為具有占位符。因此,它添加占位符文本,然后發生鍵的默認處理并插入鍵。

該特定問題至少有三種解決方案。

  1. 您可以綁定 on<KeyRelease>而不是,<Key>因為它將在默認綁定插入字符后觸發。

  2. 您可以在默認綁定之后添加自定義綁定標簽,以便首先發生默認綁定,然后再發生您的綁定。

  3. 你可以堅持使用bind_all.?在這種情況下,您只需要進行一次綁定,而不是每個小部件一次,并且您需要調整您的函數以使用event.widget而不是self.

查看完整回答
反對 回復 2024-01-24
  • 1 回答
  • 0 關注
  • 145 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號