我创建了一个MessageBox,它显示了像电子邮件客户端这样的消息。 就像在电子邮件客户端中一样,用户应该能够使用上下文菜单将消息标记为已读或未读。建立一个不是问题。根据选择既不在消息窗口中显示消息。
但是当我使用上下文菜单将消息标记为已读或未读时,它始终是突出显示的最后一条消息。
到目前为止,我无法找到解决方案。无法在ddg或SO上找到,回答或暗示。
程序流程的小概述:
- 通过MessageObject
显示/表示消息。
- 它们存储在self.__messages
- 对象内的名为InBox
的列表中
- 通过左键单击消息对象来完成选择,使用右键单击打开上下文菜单。
- 选择在InBox
对象内完成,以便只允许单个选择
- 注册了上下文菜单,并在MessageObject
。
不幸的是,我无法删除下面的示例以获取仍在运行的代码。
任何帮助,提示或想法都非常受欢迎,因为我无法弄清楚错误的来源。
from sys import hexversion, modules
if hexversion>0x03000000:
import Tkinter
modules['Tkinter'] = tkinter
modules['ttk'] = tkinter.ttk
import Tkinter as tk
import ttk
__DEBUG__=2
class MessageObject(ttk.Frame):
def __init__(self, master=None, **options):
ttk.Frame.__init__(self, master, **options)
self.pack(expand=True, fill=tk.BOTH)
self.master=master
self.takefocus=True
self.read=tk.BooleanVar()
self.sender=tk.StringVar()
self.date=tk.StringVar()
self.text=tk.StringVar()
self.subject=tk.StringVar()
self.mID=tk.IntVar()
self.__loadUI()
def __loadUI(self, event=None):
self.grid_columnconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
self.Labels=[]
self.Labels.append(ttk.Label(self, text="Subject:", justify=tk.LEFT))
self.Labels.append(ttk.Label(self, text="Sender:", justify=tk.LEFT))
self.Labels.append(ttk.Label(self, textvariable=self.subject, justify=tk.RIGHT))
self.Labels.append(ttk.Label(self, textvariable=self.sender, justify=tk.RIGHT))
self.Labels[0].grid(row=0, column=0, sticky=tk.N+tk.SW)
self.Labels[1].grid(row=1, column=0, sticky=tk.N+tk.SW)
self.Labels[2].grid(row=0, column=1, sticky=tk.N+tk.SE)
self.Labels[3].grid(row=1, column=1, sticky=tk.N+tk.SE)
#Context Menu
self.__cMenu=tk.Menu(self, tearoff=0)
self.__cMenu.add_command(label="Mark as read", command=lambda: self.Read(True))
self.__cMenu.add_command(label="Mark as unread", command=lambda: self.Read(False))
self.bind_all("", self.__showContextMenu)
def __showContextMenu(self, event=None):
self.__cMenu.post(event.x_root, event.y_root)
def Read(self, value=False):
self.read.set(value)
if value:
self.config(style='Read.TFrame')
for Label in self.Labels:
Label.config(style='Read.TLabel')
else:
self.config(style='Unread.TFrame')
for Label in self.Labels:
Label.config(style='Unread.TLabel')
def Selected(self, value=False):
#TODO: keep Font, only change for- and background
if value:
self.config(style='Selected.TFrame')
for Label in self.Labels:
Label.config(style='Selected.TLabel')
else:
for Label in self.Labels:
if self.read.get():
Label.config(style='Read.TLabel')
self.config(style='Read.TFrame')
else:
Label.config(style='Unread.TLabel')
self.config(style='Unread.TFrame')
class InBox(ttk.Frame):
def __init__(self, master=None, **options):
ttk.Frame.__init__(self, master, **options)
self.pack(expand=True, fill=tk.BOTH)
self.master=master
self.grid_columnconfigure(0, weight=2)
self.grid_columnconfigure(1, weight=0)
self.grid_columnconfigure(2, weight=0)
self.grid_columnconfigure(3, weight=0)
self.grid_rowconfigure(0, weight=0)
self.grid_rowconfigure(1, weight=1)
self.grid_rowconfigure(2, weight=1)
self.grid_rowconfigure(3, weight=1)
self.__text=tk.StringVar()
self.__currentSubject=tk.StringVar()
self.__currentTimestamp=tk.StringVar()
self.__itemCount=0
self.__messages=[]
self.__loadUI()
def __loadUI(self):
ttk.Label(self, text="Inbox:", anchor=tk.W).grid(row=0, column=0, sticky=tk.NW+tk.SE)
ttk.Label(self, text="Selected Message:", anchor=tk.W).grid(row=0, column=1, sticky=tk.NW+tk.SE)
ttk.Label(self, textvariable=self.__currentSubject).grid(row=0, column=2, sticky=tk.NW)
ttk.Label(self, textvariable=self.__currentTimestamp).grid(row=0, column=3, sticky=tk.NW)
self.InBoxList=ttk.Frame(self)
self.InBoxList.grid(row=1, rowspan=3, column=0, sticky=tk.NW+tk.SE)
self.TextDisplay=tk.Text(self)
self.TextDisplay.grid(row=1, rowspan=3, column=1, columnspan=3, sticky=tk.NW+tk.SE)
self.__messages=[]
def insert(self,index=0, mID=0, sender=None, subject=None, message=None, date=None, Read=False):
if sender!=None and subject!=None and message!=None:
self.InBoxList.grid_rowconfigure(self.__itemCount, weight=0)
self.__messages.append(MessageObject(self.InBoxList))
self.__messages[-1].mID.set(mID)
self.__messages[-1].text.set(message)
self.__messages[-1].sender.set(sender)
self.__messages[-1].subject.set(subject)
self.__messages[-1].date.set(date)
self.__messages[-1].Read(Read)
self.__messages[-1].grid(row=self.__itemCount, column=0, sticky=tk.NE+tk.SW)
self.__messages[-1].bind_all("", self.__selectionChanged)
self.__itemCount=self.__itemCount+1
return 0
else:
return 1
def Messages(self):
return self.__messages
def __selectionChanged(self, event):
try:
item=event.widget
#Empty Message Display
self.TextDisplay.delete(1.0, tk.END)
self.__currentSubject.set("")
self.__currentTimestamp.set("")
#Deactivate all but the selected one (the one calling)
for i in range(0,len(self.__messages)):
print("EventItem: %s"%item)
print("Message: %s"%self.__messages[i])
found=False
if "%s"%self.__messages[i] in "%s"%item :
self.__messages[i].Selected(True)
#Refresh Message Display
self.TextDisplay.insert(tk.END, self.__messages[i].text.get())
self.__currentSubject.set(self.__messages[i].subject.get())
self.__currentTimestamp.set(self.__messages[i].date.get())
else:
self.__messages[i].Selected(False)
except Exception as ex:
#Not in clickable Area?
if __DEBUG__>1: print("Got click but cannot link it to item - %s"%ex)
pass
def delete(self, index=0, messageObject=None):
self.__logger.debug("")
if messageObject!=None:
for i in range(len(self.__itemCount)):
if self.__messages[i]==messageObject:
self.__messages[i].destroy()
else:
self.__messages[index].destroy()
self.__itemCount=self.__itemCount-1
if __name__=="__main__":
# Styling
__msg_style=ttk.Style()
__msg_style.configure('Read.TFrame', background='#ffffff')
__msg_style.configure('Read.TFrame', foreground='#000000')
__msg_style.configure('Read.TFrame', font='Segue\ UI 8 normal')
__msg_style.configure('Unread.TFrame', background='#fafafa')
__msg_style.configure('Unread.TFrame', foreground='#0000ff')
__msg_style.configure('Unread.TFrame', font='Segue\ UI 8 bold')
__msg_style.configure('Selected.TFrame', background='#8888ff')
__msg_style.configure('Selected.TFrame', foreground='#ffffff')
#__msg_style.configure('Selected.TFrame', font='Segue\ UI 8 italic')
__msg_style.configure('Read.TLabel', background='#ffffff')
__msg_style.configure('Read.TLabel', foreground='#000000')
__msg_style.configure('Read.TLabel', font='Segue\ UI 8 normal')
__msg_style.configure('Unread.TLabel', background='#fafafa')
__msg_style.configure('Unread.TLabel', foreground='#0000ff')
__msg_style.configure('Unread.TLabel', font='Segue\ UI 8 bold')
__msg_style.configure('Selected.TLabel', background='#8888ff')
__msg_style.configure('Selected.TLabel', foreground='#ffffff')
#__msg_style.configure('Selected.TLabel', font='Segue\ UI 8 italic')
app=InBox()
app.insert(sender="Hans Dampf", subject="Read Subject", message="Lorem ipsum Read", date="14/01/2013", Read=True)
app.insert(sender="Test Name", subject="UnRead Subject", message="Lorem ipsum UnRead", date="14/01/2016", Read=False)
app.bind_all("", app.destroy)
app.mainloop()
答案 0 :(得分:1)
我设法让它发挥作用。好像我没有正确地得到documentation。
引发活动的窗口小部件不是窗口小部件MessageObject
的实例,而是使用了整个应用程序bind_all
。
但是Tkinter还允许您在类和应用程序级别创建绑定;实际上,您可以在四个不同的级别上创建绑定:
小部件实例,使用bind。
小部件的顶层窗口(Toplevel或root),也使用bind。
widget类,使用bind_class(Tkinter使用它来提供标准绑定)。
整个应用程序,使用bind_all。
我稍微修改了代码:
self.bind("<Button-3>", self.__showContextMenu)
for label in self.Labels:
label.bind("<Button-3>", self.__showContextMenu)
现在,小部件的实例会调用处理程序,一切正常。