соедините 2 контрольные кнопки со строкой в python tkinter

#python #python-3.x #dictionary #tkinter #canvas

#python #python-3.x #словарь #tkinter #холст

Вопрос:

У меня есть программа для размещения контрольных кнопок в canvas, когда выбран параметр (другая контрольная кнопка). У меня есть другой вариант (другая контрольная кнопка) для рисования линии. Чтобы нарисовать линию, сначала я должен выбрать контрольную кнопку «нарисовать линию», затем щелкнуть любую контрольную кнопку, размещенную на холсте, а другую щелкнуть в любом месте на холсте. Это работает с первой контрольной кнопкой, которую я размещаю, но если я размещаю несколько контрольных кнопок, она рисует линию только от последнего места checkbutton в canvas, а не от контрольной точки, которую я выбираю. Я считаю, что мне следует создать словарь для отслеживания контрольных кнопок, которые я размещаю, чтобы я мог вызывать их обратно, но я не знаю, как это реализовать, есть идеи, как это сделать?

     from tkinter import *

root = Tk()
top_canvas = Canvas(root,width=1376,height=768, bg='light blue')
top_canvas.pack()

buttons = []

class CMD:  #Auxilliary function for callbacks using parameters. Syntax: CMD(function, argument1, argument2, ...)
    def __init__(s1, func, *args):
        s1.func = func
        s1.args = args
    def __call__(s1, *args):
        args = s1.args args
        s1.func(*args)

def color_checkbutton(pos):  # define the colors of the checkbutton
    checkbutton_available()
    if buttons[pos][0].get() == 1:
        buttons[pos][2].configure(bg='red')
    else:
        buttons[pos][2].configure(bg='green')

def place_checkbutton_in_canvas(e):  # order to insert the checkbutton
    if len(str(e.widget))<12: ## Don't place a new one if a checkbox was clicked
        b = IntVar()
        pos = len(buttons)
        global xx, yy
        xx = e.x
        yy = e.y
        buttons.append([b,pos, Checkbutton(top_canvas, variable=b, textvariable=b, command=CMD(color_checkbutton, pos))])
        buttons[-1][2].place(x=xx, y=yy)
        color_checkbutton(pos)

def place_checkbutton():  #to run when checkbutton is selected. Now the checkbutton will be placed where mouse clicked if choose_line is selected
    top_canvas.bind('<Button-1>', place_checkbutton_in_canvas)

def checkbutton_available():
    def drawline(ev):
        flx = ev.x
        fly = ev.y
        def auxiliary():
           lineor = top_canvas.create_line(xx, yy, flx, fly, width =3, fill = 'red')
        auxiliary()
    if chosen_option.get() == 2:
            top_canvas.bind('<Button-1>', drawline)

chosen_option = IntVar()
choose_checkbutton = Radiobutton(top_canvas, text = "place checkbutton", variable=chosen_option, value = 1, command = place_checkbutton)
choose_checkbutton.place(x=10, y=10)
choose_line = Radiobutton(top_canvas, text = "draw line", variable=chosen_option, value = 2)
choose_line.place(x=10, y=100)

top_canvas.bind('<Button-1>', place_checkbutton_in_canvas)

root.mainloop()
  

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

Ответ №1:

В вашем коде вы проводите линию от (xx, yy) до (flx, fly), но ваши координаты (xx, yy), похоже, являются глобальной переменной, определенной только в функции place_checkbutton_in_canvas(e).

Итак, (xx, yy) содержат координаты последнего установленного вами флажка. И начальная точка вашей строки переопределяется только тогда, когда вы устанавливаете новую контрольную кнопку.

Чтобы исправить это, вы должны назначить глобальную переменную (xx, yy), когда установлен флажок.

Также, если вы хотите рисовать линии из нескольких начальных точек, только двух переменных int (xx и yy) недостаточно. Вам нужно иметь два массива целых чисел (или массив пар) для хранения позиций всех текущих проверяемых значений.

Если вместо этого вы не хотите рисовать несколько строк одновременно, возможно, вам следует использовать радиокнопки вместо флажков.

Комментарии:

1. Я хочу рисовать линии из нескольких начальных точек, и я понимаю, что мне нужно использовать словарь или массивы, но я не знаю, как это реализовать. каждый раз, когда я устанавливаю контрольную кнопку, новая запись должна попадать в словарь. Чего я не вижу, так это того, как я могу создать новый ключ со значением переменной pos (которую я использую, чтобы присвоить checkbutton номер).

2. Я не совсем уверен, зачем вам нужен словарь. Моим первым подходом было бы создать массив, и каждый раз, когда вы добавляете флажок, помещайте в него его координаты. В итоге вы получите что-то вроде этого [(x1, y1), (x2, y2), (x3, y3), …], где это может стать сложнее, если позже вы захотите их удалить, потому что позиция в массиве может измениться.

3. Более продвинутым решением было бы не сохранять координаты вашего флажка и добавлять / удалять их в соответствии с состоянием флажка, а просто сохранять указатель на все ваши флажки objectdirectly. Действительно, поскольку ваши объекты checkbox уже сами сохраняют свою позицию, вы можете легко получить эту информацию. Кроме того, вы можете одновременно проверить, установлен ли ваш флажок или нет.