• Я зарабатываю 100 000 RUB / месяц на этом сайте!

    А знаешь как? Я всего-лишь публикую (создаю темы), а админ мне платит. Трачу деньги на мороженое, робуксы и сервера в Minecraft. А ещё на паль из Китая. 

    Хочешь так же? Пиши и узнавай условия: https://t.me/alex_redact
    Реклама: https://t.me/yougame_official

Вопрос Почему приближение сломано?

  • Автор темы Автор темы Tapok555
  • Дата начала Дата начала
Начинающий
Начинающий
Статус
Оффлайн
Регистрация
2 Дек 2024
Сообщения
40
Реакции
0
если загрузить изображение и создать точку то приближение сломано
Python:
Expand Collapse Copy
import os
import threading
import time
import customtkinter
from pynput import mouse
from pynput.mouse import Controller
import tkinter as tk
from tkinter import messagebox, filedialog, simpledialog
import json
from PIL import Image, ImageTk
from PIL import ImageChops

reference_drag_start = None
drag_start_editor = None
selected_editor_point = None
reference_image = None
reference_tk = None
reference_path = None
ref_pos = [0, 0]
ref_scale = 1.0
ref_angle = 0
offset_x = 0
offset_y = 0
drag_start = None
path_points = []
MACRO_FOLDER = "list"
mouse_controller = Controller()
macros_enabled = True
active_macro = {"weapon": None,"macro": None,"actions": [],"running": False,"filepath": None}
selected_point_index = None

def on_right_button_press_with_shift(event):
    global drag_start
    if event.state & 0x0001:
        drag_start = (event.x, event.y)
        canvas.config(cursor="fleur")
    else: drag_start = None

def on_right_button_release_with_shift(event):
    global drag_start
    drag_start = None
    canvas.config(cursor="")

def on_mouse_drag_with_shift(event):
    global offset_x, offset_y, drag_start
    if drag_start is None: return
    if event.state & 0x0001:
        dx, dy = event.x - drag_start[0], event.y - drag_start[1]
        offset_x += dx
        offset_y += dy
        drag_start = (event.x, event.y)
        draw_grid_and_path(active_macro["actions"])
    else:
        drag_start = None
        canvas.config(cursor="")

def update_reference_image():
    global reference_tk
    if not reference_image: return
    img = reference_image.resize((int(reference_image.width * ref_scale), int(reference_image.height * ref_scale)))
    img = img.rotate(ref_angle, expand=True)
    reference_tk = ImageTk.PhotoImage(img)
    redraw_editor()

def load_reference_image():
    global reference_image, reference_tk, reference_path
    path = filedialog.askopenfilename(filetypes=[("Images", "*.png;*.jpg;*.jpeg")])
    if not path: return
    reference_path = path
    reference_image = Image.open(reference_path)
    update_reference_image()
def on_editor_mouse_wheel(event):
    global editor_scale, editor_offset_x, editor_offset_y, ref_pos, ref_scale

    old_scale = editor_scale
    delta = 1 if event.delta > 0 else -1
    new_scale = editor_scale + delta
    if not (1 <= new_scale <= 100):
        return

    canvas_width = editor_canvas.winfo_width()
    canvas_height = editor_canvas.winfo_height()

    # Координаты мыши относительно центра холста с учётом смещения камеры (editor_offset)
    mouse_x = event.x - canvas_width // 2 - editor_offset_x
    mouse_y = event.y - canvas_height // 2 - editor_offset_y

    scale_ratio = new_scale / old_scale

    # Смещаем позицию референса так, чтобы точка под мышью не сдвигалась
    ref_pos[0] = int(ref_pos[0] - mouse_x * (scale_ratio - 1))
    ref_pos[1] = int(ref_pos[1] - mouse_y * (scale_ratio - 1))

    # Обновляем масштаб
    editor_scale = new_scale
    ref_scale *= scale_ratio

    redraw_editor()


def parse_macro_file(filepath):
    actions = []
    if not os.path.exists(filepath): return actions
    with open(filepath, 'r') as f:
        try:
            data = json.load(f)
            for entry in data:
                dx = float(entry.get("dx", 0))
                dy = float(entry.get("dy", 0))
                delay = float(entry.get("delay", 20)) / 1000.0
                actions.append((dx, dy, delay))
        except Exception:
            f.seek(0)
            for line in f.readlines():
                if ":" in line:
                    try:
                        dx, dy, delay = map(lambda x: float(x.strip()), line.strip().split(":"))
                        actions.append((dx, dy, delay / 1000.0))
                    except: continue
    return actions

def save_macro_file(filepath, actions):
    data = [{"dx": dx, "dy": dy, "delay": int(delay * 1000)} for dx, dy, delay in actions]
    with open(filepath, "w") as f:
        json.dump(data, f, indent=2)

def change_delay():
    global selected_editor_point
    if selected_editor_point is None: return
    old_dx, old_dy, old_delay = active_macro["actions"][selected_editor_point]
    new_delay = simpledialog.askfloat("Изменить задержку", "Введите новую задержку (сек):", initialvalue=old_delay, minvalue=0.001)
    if new_delay is not None:
        active_macro["actions"][selected_editor_point] = (old_dx, old_dy, new_delay)
        draw_editor_macro(active_macro["actions"])

def macro_runner():
    step_time = 0.01
    while active_macro["running"] and macros_enabled:
        for dx, dy, delay in active_macro["actions"]:
            if not active_macro["running"] or not macros_enabled:
                break
            start_x, start_y = mouse_controller.position
            end_x, end_y = start_x + dx, start_y + dy
            steps = max(int(delay / step_time), 1)
            step_dx = dx / steps
            step_dy = dy / steps
            for _ in range(steps):
                if not active_macro["running"] or not macros_enabled:
                    break
                cur_x = mouse_controller.position[0] + step_dx
                cur_y = mouse_controller.position[1] + step_dy
                mouse_controller.position = (cur_x, cur_y)
                time.sleep(step_time)

def on_click(x, y, button, pressed):
    if button == mouse.Button.left:
        if pressed and active_macro["actions"] and macros_enabled:
            active_macro["running"] = True
            threading.Thread(target=macro_runner, daemon=True).start()
        else:
            active_macro["running"] = False

mouse.Listener(on_click=on_click).start()

customtkinter.set_appearance_mode("dark")
customtkinter.set_default_color_theme("green")
root = customtkinter.CTk()
root.geometry("1000x600")
root.title("Rust Macro Selector")

tabs = customtkinter.CTkTabview(root)
tabs.pack(fill="both", expand=True, padx=10, pady=10)
visual_tab = tabs.add("Визуализация")
editor_tab = tabs.add("Редактор макросов")

main_container = customtkinter.CTkFrame(visual_tab)
main_container.pack(fill="both", expand=True)

left_frame = customtkinter.CTkFrame(main_container, width=150)
left_frame.pack(side="left", fill="y", padx=(0, 10))
scroll_frame = customtkinter.CTkScrollableFrame(left_frame)
scroll_frame.pack(fill="both", expand=True)

def toggle_enable():
    global macros_enabled
    macros_enabled = not macros_enabled
    toggle_switch.configure(text="ВКЛ" if macros_enabled else "ВЫКЛ")
    if not macros_enabled:
        active_macro["running"] = False

toggle_switch = customtkinter.CTkSwitch(master=left_frame, text="ВКЛ", command=toggle_enable)
toggle_switch.select()
toggle_switch.pack(pady=10)

right_frame = tk.Frame(main_container, bg="black")
right_frame.pack(side="left", fill="both", expand=True)

canvas = tk.Canvas(right_frame, bg="black", highlightthickness=0)
canvas.pack(fill="both", expand=True)

scale = 10
macro_coords = []

def draw_grid_and_path(actions):
    canvas.delete("all")
    if not actions: return
    abs_coords = []
    x, y = 0, 0
    for dx, dy, _ in actions:
        x += dx
        y += dy
        abs_coords.append((x, y))
    min_x = min(c[0] for c in abs_coords)
    max_x = max(c[0] for c in abs_coords)
    min_y = min(c[1] for c in abs_coords)
    max_y = max(c[1] for c in abs_coords)
    center_macro_x = (min_x + max_x) / 2
    center_macro_y = (min_y + max_y) / 2
    canvas_width = canvas.winfo_width()
    canvas_height = canvas.winfo_height()
    center_x = canvas_width // 2 + offset_x
    center_y = canvas_height // 2 + offset_y
    for gx in range(int(min_x) - 50, int(max_x) + 50):
        screen_x = center_x + (gx - center_macro_x) * scale
        color = "gray" if gx % 5 == 0 else "#262626"
        canvas.create_line(screen_x, 0, screen_x, canvas_height, fill=color)
    for gy in range(int(min_y) - 50, int(max_y) + 50):
        screen_y = center_y + (gy - center_macro_y) * scale
        color = "gray" if gy % 5 == 0 else "#262626"
        canvas.create_line(0, screen_y, canvas_width, screen_y, fill=color)
    path_points.clear()
    x, y = 0, 0
    prev_x = center_x + (x - center_macro_x) * scale
    prev_y = center_y + (y - center_macro_y) * scale
    canvas.create_oval(prev_x - 3, prev_y - 3, prev_x + 3, prev_y + 3, fill="white")
    path_points.append((prev_x, prev_y))
    for dx, dy, _ in actions:
        x += dx
        y += dy
        screen_x = center_x + (x - center_macro_x) * scale
        screen_y = center_y + (y - center_macro_y) * scale
        canvas.create_line(prev_x, prev_y, screen_x, screen_y, fill="white", width=2)
        canvas.create_oval(screen_x - 2, screen_y - 2, screen_x + 2, screen_y + 2, fill="white")
        prev_x, prev_y = screen_x, screen_y
        path_points.append((screen_x, screen_y))

def on_mouse_wheel(event):
    global scale
    delta = 1 if event.delta > 0 else -1
    new_scale = scale + delta
    if 1 <= new_scale <= 100:
        scale = new_scale
        draw_grid_and_path(active_macro["actions"])

canvas.bind("<MouseWheel>", on_mouse_wheel)

editor_container = customtkinter.CTkFrame(editor_tab)
editor_container.pack(fill="both", expand=True)

editor_top_panel = customtkinter.CTkFrame(editor_container)
editor_top_panel.pack(fill="x", pady=5)

panel_visible = tk.BooleanVar(value=True)
show_grid_var = tk.BooleanVar(value=True)
show_speed_var = tk.BooleanVar(value=False)
show_coords_var = tk.BooleanVar(value=False)
free_move_mode = tk.BooleanVar(value=False)

def redraw_editor(_=None):
    draw_editor_macro(active_macro["actions"])

def toggle_panel_visibility():
    if panel_visible.get():
        control_frame.pack_forget()
        toggle_button.configure(text="Показать панель")
    else:
        control_frame.pack(side="left", padx=5)
        toggle_button.configure(text="Скрыть панель")
    panel_visible.set(not panel_visible.get())

toggle_button = customtkinter.CTkButton(editor_top_panel, text="Скрыть панель", command=toggle_panel_visibility)
toggle_button.pack(side="left", padx=5)

control_frame = customtkinter.CTkFrame(editor_top_panel)
control_frame.pack(side="left", padx=5)

customtkinter.CTkButton(control_frame, text="Загрузить фон", command=load_reference_image).pack(side="left", padx=5)
customtkinter.CTkButton(control_frame, text="Удалить фон", command=lambda: clear_reference()).pack(side="left", padx=5)

grid_switch = customtkinter.CTkCheckBox(control_frame, text="Сетка", variable=show_grid_var, command=redraw_editor)
grid_switch.select()
grid_switch.pack(side="left", padx=5)

speed_switch = customtkinter.CTkCheckBox(control_frame, text="Скорость", variable=show_speed_var, command=redraw_editor)
speed_switch.pack(side="left", padx=5)

coords_switch = customtkinter.CTkCheckBox(control_frame, text="Координаты", variable=show_coords_var, command=redraw_editor)
coords_switch.pack(side="left", padx=5)

free_move_switch = customtkinter.CTkSwitch(control_frame, text="Free Move", variable=free_move_mode)
free_move_switch.pack(side="left", padx=5)

def save_macro():
    if active_macro["filepath"] is None:
        f = filedialog.asksaveasfilename(defaultextension=".mbt", filetypes=[("JSON files", "*.mbt")])
        if not f: return
        active_macro["filepath"] = f
    save_macro_file(active_macro["filepath"], active_macro["actions"])
    messagebox.showinfo("Сохранено", f"Макрос сохранён в:\n{active_macro['filepath']}")

def load_macro():
    f = filedialog.askopenfilename(filetypes=[("JSON files", "*.mbt")])
    if not f: return
    active_macro["actions"] = parse_macro_file(f)
    active_macro["filepath"] = f
    active_macro["running"] = False
    global selected_editor_point
    selected_editor_point = None
    redraw_editor()
    draw_grid_and_path(active_macro["actions"])

def clear_macro():
    if messagebox.askyesno("Очистить макрос", "Вы уверены?"):
        active_macro["actions"].clear()
        active_macro["running"] = False
        global selected_editor_point
        selected_editor_point = None
        redraw_editor()
        draw_grid_and_path(active_macro["actions"])

def duplicate_selected_point():
    global selected_editor_point
    if selected_editor_point is None:
        messagebox.showwarning("Нет точки", "Выберите точку для дублирования")
        return
    point = active_macro["actions"][selected_editor_point]
    active_macro["actions"].insert(selected_editor_point + 1, point)
    selected_editor_point += 1
    redraw_editor()

def add_point_after():
    global selected_editor_point
    if selected_editor_point is None:
        active_macro["actions"].append((0.0, 0.0, 0.02))
        selected_editor_point = len(active_macro["actions"]) - 1
    else:
        active_macro["actions"].insert(selected_editor_point + 1, (0.0, 0.0, 0.02))
        selected_editor_point += 1
    redraw_editor()

save_button = customtkinter.CTkButton(control_frame, text="Сохранить", command=save_macro)
save_button.pack(side="left", padx=5)
load_button = customtkinter.CTkButton(control_frame, text="Загрузить", command=load_macro)
load_button.pack(side="left", padx=5)
clear_button = customtkinter.CTkButton(control_frame, text="Очистить", command=clear_macro)
clear_button.pack(side="left", padx=5)
duplicate_button = customtkinter.CTkButton(control_frame, text="Дублировать точку", command=duplicate_selected_point)
duplicate_button.pack(side="left", padx=5)
add_point_button = customtkinter.CTkButton(control_frame, text="Добавить точку", command=add_point_after)
add_point_button.pack(side="left", padx=5)

editor_canvas = tk.Canvas(editor_container, bg="black", highlightthickness=0)
def on_reference_drag_start(event):
    global ref_drag_start
    if event.state & 0x0004 and event.num == 1:  # Ctrl + ЛКМ
        ref_drag_start = (event.x, event.y)

def on_reference_drag_stop(event):
    global ref_drag_start
    if event.num == 1:
        ref_drag_start = None

def on_reference_drag_motion(event):
    global ref_drag_start
    if ref_drag_start is None:
        return
    dx = event.x - ref_drag_start[0]
    dy = event.y - ref_drag_start[1]
    ref_pos[0] += dx
    ref_pos[1] += dy
    ref_drag_start = (event.x, event.y)
    redraw_editor()
def editor_on_mouse_down(event):
    global drag_start_editor
    # Проверяем, зажат ли Shift (0x0001)
    if event.state & 0x0001 and event.num == 1:  # Shift + ЛКМ
        drag_start_editor = (event.x, event.y)

def editor_on_mouse_up(event):
    global drag_start_editor
    if event.num == 1:
        drag_start_editor = None

def editor_on_mouse_move(event):
    global drag_start_editor, editor_offset_x, editor_offset_y
    if drag_start_editor is None:
        return
    dx = event.x - drag_start_editor[0]
    dy = event.y - drag_start_editor[1]
    editor_offset_x += dx
    editor_offset_y += dy
    drag_start_editor = (event.x, event.y)
    redraw_editor()
def editor_show_context_menu(event):
    if event.state & 0x0001:
        return  # если зажат shift — не показывать меню
    menu = tk.Menu(editor_canvas, tearoff=0)
    menu.add_command(label="Изменить задержку", command=change_delay)
    menu.add_command(label="Удалить точку", command=delete_selected_point)
    menu.add_command(label="Дублировать точку", command=duplicate_selected_point)
    menu.tk_popup(event.x_root, event.y_root)

def delete_selected_point():
    global selected_editor_point
    if selected_editor_point is None:
        messagebox.showwarning("Нет точки", "Выберите точку для удаления")
        return
    del active_macro["actions"][selected_editor_point]
    selected_editor_point = None
    redraw_editor()
editor_canvas.pack(fill="both", expand=True)

editor_scale = 10
editor_offset_x = 0
editor_offset_y = 0
editor_path_points = []
selected_editor_point = None
editor_context_menu = None
editor_point_data = []

def draw_editor_macro(actions):
    editor_canvas.delete("all")
    global reference_tk
    if reference_image:
        if reference_image:
            try:
                canvas_width = editor_canvas.winfo_width()
                canvas_height = editor_canvas.winfo_height()
                center_x = canvas_width // 2 + editor_offset_x + ref_pos[0]
                center_y = canvas_height // 2 + editor_offset_y + ref_pos[1]

                final_scale = editor_scale / 10 * ref_scale
                scaled_width = int(reference_image.width * final_scale)
                scaled_height = int(reference_image.height * final_scale)

                img = reference_image.resize((scaled_width, scaled_height), Image.Resampling.LANCZOS)
                img = img.rotate(ref_angle, expand=True)

                # Центр зсунутий, треба компенсувати
                dx = (img.width - scaled_width) // 2
                dy = (img.height - scaled_height) // 2

                reference_tk = ImageTk.PhotoImage(img)
                editor_canvas.create_image(center_x + dx, center_y + dy, image=reference_tk, anchor="center")
            except Exception as e:
                print("Ошибка отрисовки изображения:", e)
    if not actions: return
    abs_coords = []
    x, y = 0, 0
    for dx, dy, _ in actions:
        x += dx
        y += dy
        abs_coords.append((x, y))
    min_x = min(c[0] for c in abs_coords)
    max_x = max(c[0] for c in abs_coords)
    min_y = min(c[1] for c in abs_coords)
    max_y = max(c[1] for c in abs_coords)
    center_macro_x = (min_x + max_x) / 2
    center_macro_y = (min_y + max_y) / 2
    canvas_width = editor_canvas.winfo_width()
    canvas_height = editor_canvas.winfo_height()
    center_x = canvas_width // 2 + editor_offset_x
    center_y = canvas_height // 2 + editor_offset_y
    if show_grid_var.get():
        for gx in range(int(min_x) - 50, int(max_x) + 50):
            screen_x = center_x + (gx - center_macro_x) * editor_scale
            color = "gray" if gx % 5 == 0 else "#262626"
            editor_canvas.create_line(screen_x, 0, screen_x, canvas_height, fill=color)
        for gy in range(int(min_y) - 50, int(max_y) + 50):
            screen_y = center_y + (gy - center_macro_y) * editor_scale
            color = "gray" if gy % 5 == 0 else "#262626"
            editor_canvas.create_line(0, screen_y, canvas_width, screen_y, fill=color)
    editor_path_points.clear()
    editor_point_data.clear()
    x, y = 0, 0
    prev_x = center_x + (x - center_macro_x) * editor_scale
    prev_y = center_y + (y - center_macro_y) * editor_scale
    editor_canvas.create_oval(prev_x - 3, prev_y - 3, prev_x + 3, prev_y + 3, fill="white")
    editor_path_points.append((prev_x, prev_y))
    editor_point_data.append((0, prev_x, prev_y))
    for i, (dx, dy, delay) in enumerate(actions):
        x += dx
        y += dy
        screen_x = center_x + (x - center_macro_x) * editor_scale
        screen_y = center_y + (y - center_macro_y) * editor_scale
        editor_canvas.create_line(prev_x, prev_y, screen_x, screen_y, fill="white", width=2)
        editor_canvas.create_oval(screen_x - 4, screen_y - 4, screen_x + 4, screen_y + 4,
                                  fill="red" if selected_editor_point == i else "white", outline="")
        editor_path_points.append((screen_x, screen_y))
        editor_point_data.append((i + 1, screen_x, screen_y))
        if show_speed_var.get():
            speed_text = f"{delay:.3f}s"
            editor_canvas.create_text(screen_x + 10, screen_y - 10, text=speed_text, fill="lime", font=("Arial", 8))
        if show_coords_var.get():
            coord_text = f"({int(x)}, {int(y)})"
            editor_canvas.create_text(screen_x + 10, screen_y + 10, text=coord_text, fill="yellow", font=("Arial", 8))
        prev_x, prev_y = screen_x, screen_y

def on_editor_mouse_down(event):
    global selected_editor_point
    closest_point = None
    min_dist = 10
    for idx, (i, px, py) in enumerate(editor_point_data):
        dist = ((px - event.x) ** 2 + (py - event.y) ** 2) ** 0.5
        if dist < min_dist:
            min_dist = dist
            closest_point = i - 1  # because i starts at 1 for second point
            if closest_point < 0: closest_point = 0
    selected_editor_point = closest_point
    redraw_editor()

def move_selected_point(dx, dy):
    global selected_editor_point
    if selected_editor_point is None: return
    dx_old, dy_old, delay = active_macro["actions"][selected_editor_point]
    active_macro["actions"][selected_editor_point] = (dx_old + dx, dy_old + dy, delay)
    redraw_editor()

def on_key_press(event):
    if selected_editor_point is None: return
    step = 1
    if event.keysym == 'Up':
        move_selected_point(0, -step)
    elif event.keysym == 'Down':
        move_selected_point(0, step)
    elif event.keysym == 'Left':
        move_selected_point(-step, 0)
    elif event.keysym == 'Right':
        move_selected_point(step, 0)

editor_canvas.bind("<Button-1>", on_editor_mouse_down)
root.bind("<Key>", on_key_press)

def clear_reference():
    global reference_image, reference_tk, reference_path
    reference_image = None
    reference_tk = None
    reference_path = None
    redraw_editor()

def redraw_editor():
    draw_editor_macro(active_macro["actions"])

# При запуске загружаем макросы в левый список (упрощённо)
def load_macros():
    for widget in scroll_frame.winfo_children():
        widget.destroy()
    if not os.path.exists(MACRO_FOLDER):
        os.makedirs(MACRO_FOLDER)
    switches = []
    for weapon in sorted(os.listdir(MACRO_FOLDER)):
        wp = os.path.join(MACRO_FOLDER, weapon)
        if not os.path.isdir(wp):
            continue
        label = customtkinter.CTkLabel(scroll_frame, text=f"{weapon}>", font=("Arial", 14, "bold"))
        label.pack(anchor="w", padx=10, pady=5)
        for macro_file in sorted(os.listdir(wp)):
            if macro_file.endswith(".mbt"):
                path = os.path.join(wp, macro_file)
                var = tk.IntVar()
                def toggle_macro(v=var, sw=None, w=weapon, m=macro_file, p=path):
                    if v.get():
                        for wgt in switches:
                            if wgt != sw:
                                wgt.deselect()
                        active_macro["weapon"] = w
                        active_macro["macro"] = m
                        active_macro["actions"] = parse_macro_file(p)
                        active_macro["filepath"] = p
                        active_macro["running"] = False
                        redraw_editor()
                        draw_grid_and_path(active_macro["actions"])
                    else:
                        active_macro["actions"] = []
                        active_macro["filepath"] = None
                        active_macro["running"] = False
                        redraw_editor()
                        draw_grid_and_path([])

                sw = customtkinter.CTkSwitch(scroll_frame, text=macro_file, variable=var)
                sw.configure(command=lambda v=var, sw=sw, w=weapon, m=macro_file, p=path: toggle_macro(v, sw, w, m, p))
                sw.pack(anchor="w", padx=20, pady=2)
                switches.append(sw)

load_macros()

canvas.bind("<ButtonPress-3>", on_right_button_press_with_shift)
canvas.bind("<ButtonRelease-3>", on_right_button_release_with_shift, add="+")
canvas.bind("<B3-Motion>", on_mouse_drag_with_shift)
canvas.bind("<ButtonRelease-3>", lambda e: show_context_menu(e) if not (e.state & 0x0001) else None, add="+")
canvas.bind("<Configure>", lambda e: draw_grid_and_path(active_macro["actions"]))
editor_canvas.bind("<Button-3>", editor_show_context_menu)
editor_canvas.bind("<ButtonPress-1>", editor_on_mouse_down)
editor_canvas.bind("<ButtonRelease-1>", editor_on_mouse_up)
editor_canvas.bind("<B1-Motion>", editor_on_mouse_move)
editor_canvas.bind("<ButtonPress-1>", on_reference_drag_start, add="+")
editor_canvas.bind("<ButtonRelease-1>", on_reference_drag_stop, add="+")
editor_canvas.bind("<B1-Motion>", on_reference_drag_motion, add="+")
editor_canvas.bind("<MouseWheel>", on_editor_mouse_wheel)

def show_context_menu(event):
    if event.state & 0x0001: return
    menu = tk.Menu(canvas, tearoff=0)
    menu.add_command(label="Очистить макрос", command=clear_macro)
    menu.add_command(label="Загрузить макрос", command=load_macro)
    menu.add_command(label="Сохранить макрос", command=save_macro)
    menu.tk_popup(event.x_root, event.y_root)

root.mainloop()
 
Назад
Сверху Снизу