如何在没有主按钮的情况下创建用于移动 window 的按钮?

How to create a button for moving the window without the main button?

我是法国人所以我的英语有点差所以不要注意。 我做了一个 tkinter 计算器,为此我删除了标题和关闭按钮所在的 window 的顶部,并用 canvas 替换它,它看起来非常好,但是我无法再移动屏幕上的 window,window 停留在 upper-left 角 ,我无法移动它方式...我希望有人能有想法。

用于删除顶部的 window 我使用了 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()...

给出这个参数

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

设置根.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()

这里有一个简单的移动方法canvas。

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()

我添加了一个 window 居中函数 稍作修改,使其 2.x 兼容。

我已经找到解决方案及其工作完美!!!

希望帮助人做一个个性化的标题栏!!!

我的代码:

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()