【问题标题】:How to create a button for moving the window without the main button?如何在没有主按钮的情况下创建一个用于移动窗口的按钮?
【发布时间】:2021-06-29 20:51:52
【问题描述】:

我是法国人,所以我的英语有点差所以不要注意。 我制作了一个tkinter 计算器,为此我删除了标题和关闭按钮所在的窗口顶部并将其替换为画布,它看起来非常漂亮,但我无法再在我的屏幕上移动窗口,窗口停留在左上角,我不能以任何方式移动它...希望有人能有一个想法。

为了删除窗口顶部,我使用了win.overrideredirect(1)

我尝试了一些方法,但这不起作用:

import tkinter as tk
win = tk.Tk()

def coordsSouris(event):
    # win.geometry()
    print(event.x, event.y)
    win.after(100, coordsSouris)

can = tk.Canvas(height = 400, width = 400)
can.pack()

can.bind("<Button-1>", coordsSouris)

win.mainloop()

函数缺少参数event,我不能用after() 给出这个参数...

我有另一个想法:是否可以将标题栏放在我的画布前面并在它位于我的退出按钮和菜单前面时将它隐藏起来并且可爱我?所以我们没有看到它,但它工作正常

【问题讨论】:

    标签: python python-3.x tkinter tkinter-canvas


    【解决方案1】:

    设置根.geometry( Width x Height + X + Y ).
    保持宽度和高度不变,只需更改 X 和 Y 参数即可。


    编辑:是的,这有点复杂。您需要存储初始拖动位置,然后从后续事件中减去它。释放按钮后清除值。您还想设置最小值/最大值以确保它不会离开屏幕。

    #! /usr/bin/env python3
    import tkinter 
    
    Width, Height, = 100, 33
    Xpos, Ypos = 20, 20
    dragposX, dragposY = 0, 0
    
    root = tkinter .Tk() 
    root .geometry( f'{Width}x{Height}+{Xpos}+{Ypos}')
    root .overrideredirect( 1 )  ##  no titlebar
    
    Screenwidth = root .winfo_screenwidth()
    Screenheight = root .winfo_screenheight()
    Xmax = Screenwidth -Width
    Ymax = Screenheight -Height
    
    fontname = 'ariel'
    fontsize = 8
    fontstyle = 'normal'
    font = fontname, fontsize, fontstyle
    
    def left():
        global Xpos ; Xpos -= 5
        if Xpos < 0:  Xpos = 0
        root .geometry( f'{Width}x{Height}+{Xpos}+{Ypos}')
    
    def right():
        global Xpos ; Xpos += 5
        if Xpos > Xmax:  Xpos = Xmax
        root .geometry( f'{Width}x{Height}+{Xpos}+{Ypos}')
    
    def up():
        global Ypos ; Ypos -= 5
        if Ypos < 0:  Ypos = 0
        root .geometry( f'{Width}x{Height}+{Xpos}+{Ypos}')
    
    def down():
        global Ypos ; Ypos += 5
        if Ypos > Ymax:  Ypos = Ymax
        root .geometry( f'{Width}x{Height}+{Xpos}+{Ypos}')
    
    def drag( event ):
        global Xpos, Ypos, dragposX, dragposY
        if dragposX == 0 and dragposY == 0:
            dragposX = event .x
            dragposY = event .y
    
        Xpos += event .x -dragposX
        Ypos += event .y -dragposY
        if Xpos < 0:  Xpos = 0
        if Ypos < 0:  Ypos = 0
        if Xpos > Xmax:  Xpos = Xmax
        if Ypos > Ymax:  Ypos = Ymax
        root .geometry( f'{Width}x{Height}+{Xpos}+{Ypos}')
    
    def clear( event ):
        global dragposX, dragposY
        dragposX, dragposY = 0, 0
    
    left_button = tkinter .Button( root, text='<', font=font, padx=2, pady=0, bg='blue', activebackground='lightblue', command=left )
    left_button .grid( row=0, column=0, padx=1, pady=4 )
    
    right_button = tkinter .Button( root, text='>', font=font, padx=2, pady=0, bg='blue', activebackground='lightblue', command=right )
    right_button .grid( row=0, column=1, padx=1, pady=4 )
    
    down_button = tkinter .Button( root, text='v', font=font, padx=2, pady=0, command=down )
    down_button .grid( row=0, column=2, padx=1, pady=4 )
    
    up_button = tkinter .Button( root, text='^', font=font, padx=2, pady=0, command=up ) 
    up_button .grid( row=0, column=3, padx=1, pady=4 )
    
    close_button = tkinter .Button( root, text='X', font=font, padx=2, pady=0, bg='red', activebackground='pink', command=root.destroy )
    close_button .grid( row=0, column=4, padx=1, pady=4 )
    
    root .bind( '<B1-Motion>', drag )
    root .bind( '<ButtonRelease-1>', clear )
    
    root .mainloop()
    

    【讨论】:

    • 谢谢,但我真的不能像平常一样拥有相同的东西吗?
    • 好吧,您可以自定义它们以任何您想要的方式显示。只需设置按钮宽度和高度,然后使用 ^ v X 字符而不是文本。 ...或图像。
    • 当我点击位于窗口顶部的画布并将位置添加到 .geometry 时,可能会跟踪鼠标?
    【解决方案2】:

    这是移动画布的简化方法。

    import tkinter as tk
    
    def realcenter( o, w, h ) ->'o(w,h) centered on screen':
        x = o.winfo_screenwidth( ) - w
        y = o.winfo_screenheight( ) - h
        o.geometry( '{0:d}x{1:d}+{2:d}+{3:d}'.format( w, h, int( x/2 ), int( y/2 ) ) )
    
    def restore( ev ):
        master.overrideredirect( 0 )
    
    def unrestore( ev ):
        master.overrideredirect( 1 )
    
    master = tk.Tk()
    sizew, sizeh = 400, 400
    canvas_box = tk.Canvas(master, width=sizew, height=sizeh )
    canvas_box.grid(row=0,column=0)
    
    master.geometry( '400x400' )
    realcenter( master, 400, 400 )
    
    master.update_idletasks()
    
    master.overrideredirect( 1 )
    
    master.bind( '<F1>', restore )
    master.bind( '<F2>', unrestore )
    
    tk.mainloop()
    
    

    我已经包含了一个窗口居中功能 稍作修改使其与 2.x 兼容。

    【讨论】:

    • 感谢您的工作!我有另一个想法:是否可以将标题栏放在我的画布前面并隐藏它并且当它在我的退出按钮和菜单前面时很可爱。所以我们没有看到它,但它工作正常
    • 你的意思是你想让你的按钮“替换”正常的标题栏,然后在真正的标题栏恢复时隐藏它们?
    • 我有一个画布,而不是标题栏,我有一个退出按钮和一个小菜单。我这样做是因为标题栏很难看。所以我希望这个画布可以移动像标题栏一样的窗口。因此,如果可能的话,我可以隐藏标题栏以查看她身后的画布,当我单击画布时,它会单击标题栏,因为她在前面,因此我可以正常移动窗口。
    • overrideredirect被强制执行时,你不能移动窗口,但如果你把@Doyousketch2整洁的按钮放在FrameLabelFrame中,那么可以使用grid_forget来隐藏当正常的标题栏出现时。
    【解决方案3】:

    我找到了解决方案及其完美的工作!!!

    我希望它能帮助人们做一个个性化的标题栏!!!

    我的代码:

    from tkinter import *
    import tkinter as tk
    root = Tk()
    x = 0
    y = 0
    def move_window(event):
        # global x, y
        print(x, y)
        #event.x_the_name_of_the_widows is false you have to use x_root
        #event if your page is called win or ...
        root.geometry('+{0}+{1}'.format(event.x_root - x, event.y_root - y))
    
    root.overrideredirect(True) # turns off title bar, geometry
    root.geometry('400x200+200+200') # set new geometry
    
    # make a frame for the title bar
    title_bar = Frame(root, bg='white', relief='raised', bd=2)
    
    # put a close button on the title bar
    close_button = Button(title_bar, text='X', command=root.destroy)
    
    # a canvas for the main area of the window
    window = Canvas(root, bg='black')
    
    # pack the widgets
    title_bar.pack(expand=1, fill=X)
    close_button.pack(side=RIGHT)
    window.pack(expand=1, fill=BOTH)
    
    # find the position of the cursor on the window and not on the screen
    
    def set_xy(event):
        global x,y
        x=event.x_root - root.winfo_x()
        y=event.y_root - root.winfo_y()
        # print(x,y)
        return x,y;
    
    title_bar.bind('<1>',set_xy)
    
    # bind title bar motion to the move window function
    
    title_bar.bind('<B1-Motion>', move_window)
    
    root.mainloop()
    
    

    【讨论】:

      猜你喜欢
      • 2019-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-10
      • 1970-01-01
      • 2017-08-24
      相关资源
      最近更新 更多