Ребята, с Новым годом,

Так что я довольно новичок в Python и еще новее в Tkinter. Я пытаюсь создать пользовательскую строку заголовка для своего пользовательского интерфейса и пока что у меня все получается, используя некоторые статьи и видео. Проблема в том, что при создании пользовательской строки заголовка и попытке переместить окно оно перемещается из левого верхнего угла, таким образом "телепортируя" окно.

Посмотрев на это: Тред есть ответ на мой вопрос, но я не смог заставить его работать.

Так вот код:

from Tkinter import *

root = Tk()
# turns off title bar, geometry
root.overrideredirect(True)
# set new geometry
root.geometry('400x100+200+200')
# set background color of title bar
back_ground = "#2c2c2c"

# set background of window
content_color = "#ffffff"
# make a frame for the title bar
title_bar = Frame(root, bg=back_ground, relief='raised', bd=1, 
highlightcolor=back_ground,highlightthickness=0)

# put a close button on the title bar
close_button = Button(title_bar, text='x',  command=root.destroy,bg=back_ground, padx=5, pady=2, 
activebackground="red", bd=0,    font="bold", fg='white',        activeforeground="white", 
highlightthickness=0)
# window title
title_window = "Title Name"
title_name = Label(title_bar, text=title_window, bg=back_ground, fg="white")
# a canvas for the main area of the window
window = Canvas(root, bg="white", highlightthickness=0)

# pack the widgets
title_bar.pack(expand=1, fill=X)
title_name.pack(side=LEFT)
close_button.pack(side=RIGHT)
window.pack(expand=1, fill=BOTH)
x_axis = None
y_axis = None
# bind title bar motion to the move window function

xwin = root.winfo_x()
ywin = root.winfo_y()

def get_pos(event):

    global xwin
    global ywin

    xwin = xwin - event.x_root
    ywin = ywin - event.y_root

def move_window(event):
    root.geometry(f'+{event.x_root - xwin}+{event.y_root}')

def change_on_hovering(event):
    global close_button
    close_button['bg'] = 'red'

def return_to_normal_state(event):
   global close_button
   close_button['bg'] = back_ground

title_bar.bind("", move_window)
title_bar.bind("", get_pos)
close_button.bind('', change_on_hovering)
close_button.bind('', return_to_normal_state)
root.mainloop()

В этой версии все немного отличается от того, что показано в теме выше, потому что я продолжал получать ошибки в другую сторону. Проблема в том, что теперь окно телепортируется в новое место, и я не могу заставить его работать правильно.

Заранее спасибо!

Ответы (1)

Код работает для меня, когда я использую

def get_pos(event):

    global xwin
    global ywin

    xwin = event.x
    ywin = event.y

И вы забыли ywin в

def move_window(event):
    root.geometry(f'+{event.x_root - xwin}+{event.y_root - ywin}')

EDIT:

Полностью рабочий код с реоганизированным кодом.

Тестировалось на Python 3, поэтому пришлось использовать tkinter вместо Tkinter

PEP 8 -- Руководство по стилю для кода Python

#from tkinter import *  # PEP8: `import *` is not preferred
import tkinter as tk

# --- classes ---

# empty

# --- functions ---

def get_pos(event):
    global xwin
    global ywin

    xwin = event.x
    ywin = event.y

def move_window(event):
    root.geometry(f'+{event.x_root - xwin}+{event.y_root - ywin}')

def change_on_hovering(event):
    close_button['bg'] = 'red'

def return_to_normal_state(event):
    close_button['bg'] = back_ground

# --- main ---

# set background color of title bar
back_ground = "#2c2c2c"
# set background of window
content_color = "#ffffff"

# ---

root = tk.Tk()
# turns off title bar, geometry
root.overrideredirect(True)

# set new geometry
root.geometry('400x100+200+200')

# make a frame for the title bar
title_bar = tk.Frame(root, bg=back_ground, relief='raised', bd=1, 
                     highlightcolor=back_ground, 
                     highlightthickness=0)

# put a close button on the title bar
close_button = tk.Button(title_bar, text='x', bg=back_ground, padx=5, pady=2, 
                         bd=0, font="bold", fg='white',
                         activebackground="red",
                         activeforeground="white", 
                         highlightthickness=0, 
                         command=root.destroy)
                         
# window title
title_window = "Title Name"
title_name = tk.Label(title_bar, text=title_window, bg=back_ground, fg="white")

# a canvas for the main area of the window
window = tk.Canvas(root, bg="white", highlightthickness=0)

# pack the widgets
title_bar.pack(expand=True, fill='x')
title_name.pack(side='left')
close_button.pack(side='right')
window.pack(expand=True, fill='both')

# bind title bar motion to the move window function
title_bar.bind("", move_window)
title_bar.bind("", get_pos)
close_button.bind('', change_on_hovering)
close_button.bind('', return_to_normal_state)

root.mainloop()

EDIT:

В то же время я создал версию, которая использует классы - так что я могу легко добавить больше кнопок.
Она также может менять цвет заголовка и текст при движении.

введите описание изображения здесь

import tkinter as tk

# --- constants --- (UPPER_CASE_NAMES)

# title bar colors
TITLE_FOREGROUND = "white"
TITLE_BACKGROUND = "#2c2c2c"
TITLE_BACKGROUND_HOVER = "green"

BUTTON_FOREGROUND = "white"
BUTTON_BACKGROUND = TITLE_BACKGROUND
BUTTON_FOREGROUND_HOVER = BUTTON_FOREGROUND
BUTTON_BACKGROUND_HOVER = 'red'

# window colors
WINDOW_BACKGROUND = "white"
WINDOW_FOREGROUND = "black"

# --- classes --- (CamelCaseNames)

class MyButton(tk.Button):

    def __init__(self, master, text='x', command=None, **kwargs):
        super().__init__(master, bd=0, font="bold", padx=5, pady=2, 
                         fg=BUTTON_FOREGROUND, 
                         bg=BUTTON_BACKGROUND,
                         activebackground=BUTTON_BACKGROUND_HOVER,
                         activeforeground=BUTTON_FOREGROUND_HOVER, 
                         highlightthickness=0, 
                         text=text,
                         command=command)

        self.bind('', self.on_enter)
        self.bind('', self.on_leave)

    def on_enter(self, event):
        self['bg'] = BUTTON_BACKGROUND_HOVER

    def on_leave(self, event):
        self['bg'] = BUTTON_BACKGROUND

class MyTitleBar(tk.Frame):

    def __init__(self, master, *args, **kwargs):
        super().__init__(master, relief='raised', bd=1, 
                         bg=TITLE_BACKGROUND,
                         highlightcolor=TITLE_BACKGROUND, 
                         highlightthickness=0)

        self.title_label = tk.Label(self, 
                                    bg=TITLE_BACKGROUND, 
                                    fg=TITLE_FOREGROUND)
                                    
        self.set_title("Title Name")

        self.close_button = MyButton(self, text='x', command=master.destroy)
        self.minimize_button = MyButton(self, text='-', command=self.on_minimize)
        self.other_button = MyButton(self, text='#', command=self.on_other)
                         
        self.pack(expand=True, fill='x')
        self.title_label.pack(side='left')
        self.close_button.pack(side='right')
        self.minimize_button.pack(side='right')
        self.other_button.pack(side='right')

        self.bind("", self.on_press)
        self.bind("", self.on_release)
        self.bind("", self.on_move)
        
    def set_title(self, title):
        self.title = title
        self.title_label['text'] = title
        
    def on_press(self, event):
        self.xwin = event.x
        self.ywin = event.y
        self.set_title("Title Name - ... I'm moving! ...")
        self['bg'] = 'green'
        self.title_label['bg'] = TITLE_BACKGROUND_HOVER

    def on_release(self, event):
        self.set_title("Title Name")
        self['bg'] = TITLE_BACKGROUND
        self.title_label['bg'] = TITLE_BACKGROUND
        
    def on_move(self, event):
        x = event.x_root - self.xwin
        y = event.y_root - self.ywin
        self.master.geometry(f'+{x}+{y}')
        
    def on_minimize(self):
        print('TODO: minimize')
                
    def on_other(self):
        print('TODO: other')

# --- functions ---

# empty

# --- main ---

root = tk.Tk()
# turns off title bar, geometry
root.overrideredirect(True)

# set new geometry
root.geometry('400x100+200+200')

title_bar = MyTitleBar(root) 
#title_bar.pack()  # it is inside `TitleBar.__init__()`

# a canvas for the main area of the window
window = tk.Canvas(root, bg=WINDOW_BACKGROUND, highlightthickness=0)

# pack the widgets
window.pack(expand=True, fill='both')

root.mainloop()

2022 WebDevInsider