zico.o 2022-05-26 21:42 采纳率: 100%
浏览 56
已结题

为什么使用python GUI制作交互时,子菜单菜单出现失灵情况?

在使用Python tkinter制作一个桌面便签简单小程序时,设置了可以新建便签、可以改变便签窗口颜色,但是新建后的便签无法调用颜色修改函数,求问应该如何处理?
附上整个程序
from tkinter import *   # 导入tkinter库

class gui:  # 定义class类,GUI界面

    #__init__方法,导入类时自动执行这里的语句
    def __init__(self,x=100,y=100):
        self.xr = 100
        self.yr = 100
        
        # 主题的字典
        self.colorthemes = {"yellow":["#FFFACD","#F0E68C"],
                            "blue":["#98F5FF","#00E5EE"],
                            "red":["#E9967A","#EE6363"],
                            "green":["#90ee90","#32CD32"]
                            }  
                            
        self.setgui(x,y)    # 调用self.setgui()方法做GUI界面

    #GUI界面    
    def setgui(self,x,y):
        self.root = Tk()    # 窗口
        self.root.title('jnote')    # 窗口标题
        self.root.geometry('200x200+{0}+{1}'.format(x,y))   # 改变窗口位置
        self.root.wm_attributes("-topmost", True)   # 窗口总在最前
        self.root.overrideredirect(True)    # 窗口去边框

        self.themecolor = list(self.colorthemes.values())[0]    # 获取主题名

        # 标题栏
        self.titleframe = Frame(self.root,bg=self.themecolor[0],bd=0)
        self.titleframe.grid(row=0,column=0,sticky='nswe')
        
        # 拖动窗体的按钮
        self.icon = Label(self.titleframe,text='N',font=('宋体',14),cursor='fleur',anchor='center',bg=self.themecolor[0]) 
        self.icon.grid(row=0,column=0,sticky='nswe')
        # 绑定拖动事件
        self.icon.bind('<ButtonPress-1>',self.setxy)
        self.icon.bind('<B1-Motion>',self.resize)      

        # 标题
        self.title = Entry(self.titleframe,font=("微软雅黑",14),bd=0,bg=self.themecolor[0])
        self.title.grid(row=0,column=1,sticky='nswe')
        self.title.insert(0,'untitled')

        # 设置按钮
        self.sets = Label(self.titleframe,text='…',font=("宋体",14),anchor='center',bg=self.themecolor[0])
        self.sets.grid(row=0,column=3,sticky='nswe')
        # 绑定单击事件,调用self.postsetsmenu()方法弹出菜单
        self.sets.bind('<ButtonRelease-1>',self.postsetsmenu)

        # 关闭按钮
        self.quit = Label(self.titleframe,text='×',font=("宋体",14),anchor='center',bg=self.themecolor[0])
        self.quit.grid(row=0,column=4,sticky='nswe')
        # 绑定单击事件,调用self.quitapp()方法卸载窗体
        self.quit.bind('<ButtonRelease-1>',self.quitapp)

        # 文本区域
        self.text = Text(self.root,font=(10),bd=0,bg=self.themecolor[0])
        self.text.grid(row=1,column=0,sticky='nswe')

        # 给所有组件绑定鼠标进入、离开事件
        self.root.bind_all('<Enter>',self.enter)
        self.root.bind_all('<Leave>',self.leave)

        # 设置填充
        self.root.grid_columnconfigure(0,weight=1)
        self.root.grid_rowconfigure(1,weight=1)
        self.titleframe.grid_columnconfigure(1,weight=1)

        # 颜色主题菜单的绑定变量
        self.themesvar = IntVar()
        self.themesvar.set(0)

        # 创建菜单
        self.setsmenu = Menu(self.root,tearoff=False)
        self.setsmenu.add_command(label='新建',command=lambda:gui(x=self.root.winfo_x()+self.root.winfo_width()+10,y=self.root.winfo_y()))  # 实例化新的gui,新建一个窗口
        self.setsmenu.add_cascade(label='保存',command=lambda:self.save(name=self.title.get(),text=self.text.get(1.0,'end'))) # 调用self.save()方法保存文件
        
        self.setsmenu.add_separator()   # 添加分隔线

        # 颜色主题菜单
        self.themesmenu = Menu(self.setsmenu,tearoff=False)
        for i in range(len(self.colorthemes.keys())):
            self.themesmenu.add_radiobutton(label=list(self.colorthemes.keys())[i],variable=self.themesvar,value=i,command=self.setcolor)   # 调用self.setcolor()方法设置所有组件的颜色
        self.setsmenu.add_cascade(label='颜色主题',menu=self.themesmenu)
        
        self.root.mainloop()    # 窗体进入事件循环

    # 鼠标进入组件事件
    def enter(self,event):
        event.widget['bg'] = list(self.colorthemes.values())[self.themesvar.get()][1]   # 背景颜色改变

    # 鼠标离开组件事件
    def leave(self,event):
        event.widget['bg'] = list(self.colorthemes.values())[self.themesvar.get()][0]   # 背景颜色还原

    # 下面两个为窗体移动的方法
    def setxy(self,event):
        self.xr = event.x
        self.yr = event.y

    def resize(self,event):        
        self.root.geometry('+{0}+{1}'.format(self.root.winfo_x()+event.x-self.xr,self.root.winfo_y()+event.y-self.yr))

    # 点击菜单的颜色选项后,设置所有组件的颜色
    def setcolor(self):
        self.includes = [self.titleframe,self.icon,self.title,self.sets,self.quit,self.text]    # 列出所有组件
        for r in self.includes:
            r.configure(bg=list(self.colorthemes.values())[self.themesvar.get()][0])    # 设置组件的颜色

    # 弹出设置菜单
    def postsetsmenu(self,event):
        self.setsmenu.post(event.x_root,event.y_root)

    # 保存文件
    def save(self,name,text):
        # 以标题命名保存文件
        with open('notes/{0}.txt'.format(name),'w') as f:
            f.write(text)    # 写入文件

    # 卸载窗体
    def quitapp(self,event):
        self.root.destroy()
        
if __name__ == '__main__':
    gui(x=100,y=100) # 实例化gui


新建后的便签无法调用颜色修改函数,像初始窗口一样改变其颜色,请问代码应该如何修改?
我试图修改一些函数,但是没办法正常调用
希望修改后的代码可以正常修改新建便签的主题颜色
  • 写回答

1条回答 默认 最新

  • 请叫我问哥 Python领域新星创作者 2022-05-27 01:26
    关注

    因为你创建了多个Tk()窗口,程序会选第一个作为主窗口,复选框的值只和主窗口有关联。当你关了主窗口后,再新建一个Tk()窗口,会发现又有关联了。但无论多少个窗口,复选框只会和一个Tk()窗口产生关联。
    在创建子窗口的时候,一般建议使用Toplevel()方法,你的代码可以这样改实现子窗口的颜色改变效果:

    1. 把self.root = Tk()提到初始化init()函数里
    2. 创建一个子类subwindow,继承gui类
    3. 在子类的初始化init()函数里使用self.root = Toplevel(root),然后继承父类gui所有方法
    4. 创建新窗口的labmda函数改成subwindow
    class subwindow(gui):
        def __init__(self,root,x=100,y=100):
            self.root = Toplevel(root)
            self.setgui(x,y)
    
    class gui():
        def __init__(self,x=100,y=100):
            self.root = Tk()
            self.setgui(x,y)
        def setgui(self,x,y):
            self.setsmenu.add_command(label='新建',command=lambda:subwindow(self.root, x=self.root.winfo_x()+self.root.winfo_width()+10,y=self.root.winfo_y()))
    

    而且不能用bind_all为所有窗体绑定事件,这样会把所有窗口的组件都绑在一起,还需要这样改:

            #self.root.bind_all('<Enter>',self.enter)
            #self.root.bind_all('<Leave>',self.leave)
            self.text.bind('<Enter>',self.enter)
            self.text.bind('<Leave>',self.leave)
    

    但是这样做也有很大的缺点:toplevel窗口是附着在父窗口的,如果关闭了父窗口,toplevel窗口也会被关闭。
    所以tkinter可能没办法实现你想要的完美效果,大概率需要重新设计了

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录

报告相同问题?

问题事件

  • 系统已结题 6月4日
  • 已采纳回答 5月27日
  • 创建了问题 5月26日

悬赏问题

  • ¥15 echarts动画效果失效的问题。官网下载的例子。
  • ¥60 许可证msc licensing软件报错显示已有相同版本软件,但是下一步显示无法读取日志目录。
  • ¥15 Attention is all you need 的代码运行
  • ¥15 一个服务器已经有一个系统了如果用usb再装一个系统,原来的系统会被覆盖掉吗
  • ¥15 使用esm_msa1_t12_100M_UR50S蛋白质语言模型进行零样本预测时,终端显示出了sequence handled的进度条,但是并不出结果就自动终止回到命令提示行了是怎么回事:
  • ¥15 前置放大电路与功率放大电路相连放大倍数出现问题
  • ¥30 关于<main>标签页面跳转的问题
  • ¥80 部署运行web自动化项目
  • ¥15 腾讯云如何建立同一个项目中物模型之间的联系
  • ¥30 VMware 云桌面水印如何添加