0

I want to draw on a canvas and write the logic to capture that canvas.

So, I tried to make a drawing board with tkinter and capture it with PIL.

However, only a part of the canvas was captured, probably because the coordinate values ​​were incorrectly obtained.

import tkinter as tk
from PIL import ImageGrab

# 선택:0, 점:1, 선:2, 사각형3, 원:4, 텍스트 5
draw_mode = 0

# 색
draw_color = "black"

# x1, y1: 시작점
x1 = None
y1 = None

# 마우스 왼쪽 버튼을 눌렀을 때
def mouseLDown(event):
    global x1, y1
    mouse_text.set("X:"+str(event.x)+" Y:"+str(event.y)+" L Down")

    # 점 그리기 모드라면
    if draw_mode == 1:
        canvas.create_oval(event.x-2, event.y-2, event.x+2, event.y+2, fill=draw_color, outline=draw_color)
    # 텍스트 그리기 모드라면
    elif draw_mode == 5:
        canvas.create_text(event.x, event.y, text=input_text.get(), fill=draw_color)
        
    # 선 그리기 모드라면
    elif draw_mode >= 2 and draw_mode <= 4:
        x1 = event.x
        y1 = event.y

# 마우스를 움직일 때
def mouseMove(event):
    global x1, y1
    mouse_text.set("X:"+str(event.x)+" Y:"+str(event.y)+" Move")
    canvas.create_oval(event.x-2, event.y-2, event.x+2, event.y+2, fill=draw_color, outline=draw_color)

# 마우스 왼쪽 버튼을 뗐을 때
def mouseLUp(event):
    global x1, y1
    mouse_text.set("X:"+str(event.x)+" Y:"+str(event.y)+" L Up")

    # 선 그리기 모드라면
    if draw_mode == 2:
        canvas.create_line(x1, y1, event.x, event.y, width=2, fill=draw_color)
    # 네모 그리기 모드라면
    elif draw_mode == 3:
        canvas.create_rectangle(x1, y1, event.x, event.y, width=2, outline=draw_color, fill=draw_color)
    # 원 그리기 모드라면
    elif draw_mode == 4:
        canvas.create_oval(x1, y1, event.x, event.y, width=2, outline=draw_color)
# 선택 버튼 함수
def selectButton():
    global draw_mode
    draw_mode = 0
    
# 점 그리기 버튼 함수
def pointButton():
    global draw_mode
    draw_mode = 1
    
# 선 그리기 버튼 함수
def lineButton():
    global draw_mode
    draw_mode = 2
    
# 사각형 버튼 함수
def rectangleButton():
    global draw_mode
    draw_mode = 3
    
# 원 그리기 버튼 함수
def circleButton():
    global draw_mode
    draw_mode = 4
    
# 텍스트 그리기 버튼 함수
def textButton():
    global draw_mode
    draw_mode = 5
    
# 하얀색 버튼 함수
def whiteButton():
    global draw_color
    draw_color = "white"

# 검은색 버튼 함수
def blackButton():
    global draw_color
    draw_color = "black"

# 빨간색 버튼 함수
def redButton():
    global draw_color
    draw_color = "red"

# 노란색 버튼 함수
def yellowButton():
    global draw_color
    draw_color = "yellow"

# 파란색 버튼 함수
def blueButton():
    global draw_color
    draw_color = "blue"

# 녹색 버튼 함수
def greenButton():
    global draw_color
    draw_color = "green"
    

    
    
    
def get_absolute_coordinates(widget):
    x = widget.winfo_rootx()
    y = widget.winfo_rooty()
    return x, y

def get_relative_coordinates(widget):
    x = widget.winfo_x()
    y = widget.winfo_y()
    return x, y

def saveButton():
    # 캔버스의 절대 좌표 구하기
    c_a_x, c_a_y = get_absolute_coordinates(canvas)
    
    c_r_x, c_r_y = get_relative_coordinates(canvas) # canvas의 상대 좌표
    
    cf_r_x, cf_r_y = get_relative_coordinates(canvas_frame) # frame의 상대 좌표
    
    cf_a_x, cf_a_y = get_absolute_coordinates(canvas_frame) # frame의 절대 좌표
    
    w_a_x, w_a_y = get_absolute_coordinates(canvas.winfo_toplevel()) # 최상위 윈도우의 절대 좌표
    
    print('캔버스의 절대 좌표1 ({}, {})'.format(c_a_x, c_a_y))
    print('캔버스의 상대 좌표1 ({}, {})'.format(c_r_x, c_r_y))
    print('캔버스 프레임의 절대 좌표1 ({}, {})'.format(cf_a_x, cf_a_y))
    print('캔버스 프레임의 상대 좌표1 ({}, {})'.format(cf_r_x, cf_r_y))
    print('최상위 윈도우의 절대 좌표1 ({}, {})'.format(w_a_x, w_a_y))
    
    # canvas width, heigth
    cw = canvas.winfo_width()
    ch = canvas.winfo_height()
    
    width = c_a_x + cw
    height = c_a_y + ch
    
    print('캔버스의 길이 {}'.format(cw))
    print('캔버스의 높이 {}'.format(ch))
    print('---------------------------------------')
    # canvas area capture
    image = ImageGrab.grab((c_a_x, c_a_y, width, height))
    
    # save image
    image.save("D:/jupyter/image/test{}.png".format(3))
    
# 윈도우를 생성한다
window = tk.Tk()
window.title("점선면 그림판")
window.configure(bg='blue')

# 스타일 프레임을 생성한다
style_frame = tk.Frame(window)
style_frame.grid(row=0, column=0, sticky=tk.W)

# 선택 그리기 버튼
select_button = tk.Button(style_frame, text="선택", width=3, command=selectButton)
select_button.grid(row=0, column=0, sticky=tk.W)

# 점그리기 버튼
point_button = tk.Button(style_frame, text=".", width=3, command=pointButton)
point_button.grid(row=0, column=1, sticky=tk.W)

# 선그리기 버튼
line_button = tk.Button(style_frame, text="/", width=3, command=lineButton)
line_button.grid(row=0, column=2, sticky=tk.W)

# 네모그리기 버튼
rectangle_button = tk.Button(style_frame, text="□", width=3, command=rectangleButton)
rectangle_button.grid(row=0, column=3, sticky=tk.W)

# 원그리기 버튼
circle_button = tk.Button(style_frame, text="○", width=3, command=circleButton)
circle_button.grid(row=0, column=4, sticky=tk.W)

# 텍스트 버튼
text_button = tk.Button(style_frame, text="T", width=3, command=textButton)
text_button.grid(row=0, column=5, sticky=tk.W)

# 저장 버튼 - TEST
save_button = tk.Button(style_frame, text="저장", width=3, command=saveButton)
save_button.grid(row=0, column=6, sticky=tk.W)


# 색상 프레임을 생성한다
color_frame = tk.Frame(window)
color_frame.grid(row=0, column=1, sticky=tk.E)

# 하얀색 버튼
white_button = tk.Button(color_frame, bg="white", width=3, command=whiteButton)
white_button.grid(row=0, column=0, sticky=tk.E)

# 검은색 버튼
black_button = tk.Button(color_frame, bg="black", width=3, command=blackButton)
black_button.grid(row=0, column=1, sticky=tk.E)

# 빨간색 버튼
red_button = tk.Button(color_frame, bg="red", width=3, command=redButton)
red_button.grid(row=0, column=2, sticky=tk.E)

# 파란색 버튼
blue_button = tk.Button(color_frame, bg="blue", width=3, command=blueButton)
blue_button.grid(row=0, column=3, sticky=tk.E)

# 노란색 버튼
yellow_button = tk.Button(color_frame, bg="yellow", width=3, command=yellowButton)
yellow_button.grid(row=0, column=4, sticky=tk.E)

# 초록색 버튼
green_button = tk.Button(color_frame, bg="green", width=3, command=greenButton)
green_button.grid(row=0, column=5, sticky=tk.E)

# 인포 프레임을 생성한다
info_frame = tk.Frame(window)
info_frame.grid(row=1, column=0, columnspan=2)

# 마우스 엔트리
mouse_text = tk.StringVar()
mouse_entry = tk.Entry(info_frame, textvariable=mouse_text, width=25)
mouse_entry.grid(row=0, column=0)

# 텍스트 라벨
input_label = tk.Label(info_frame, text="              Text Input:")
input_label.grid(row=0, column=1)

# 텍스트 엔트리
input_text = tk.StringVar()
input_entry = tk.Entry(info_frame, textvariable=input_text, width=15)
input_entry.grid(row=0, column=2)
 
# 캔버스 프레임을 생성한다
canvas_frame = tk.Frame(window, bd=2, bg="green")
canvas_frame.grid(row=2, column=0, columnspan=2, sticky=tk.W)

# 캔버스 생성한다
canvas = tk.Canvas(canvas_frame, width=400, height=300, bg="white")
canvas.pack()

# 마우스 이벤트 연결
canvas.bind("<Button-1>", mouseLDown) # 마우스 왼쪽 버튼 누렀을 때 이벤트
canvas.bind("<B1-Motion>", mouseMove) # 마우스 클릭하고 움직일 때 이벤트
canvas.bind("<ButtonRelease-1>", mouseLUp) # 마우스 왼쪽 버튼 클릭 해제할 때 이벤트

window.mainloop()

above is my code. The following is a picture of the result I expect with this code.

enter image description here

And here is a picture of the actual result.

enter image description here

나성진
  • 1
  • 1

1 Answers1

0
I want to draw on a canvas and write the logic to capture that canvas.

Your code is working.

You don't need global scope and canvas.create_oval for mouseMove() function.

Snippet:

def mouseMove(event):
    #global x1, y1
    mouse_text.set("X:"+str(event.x)+" Y:"+str(event.y)+" Move")
    #canvas.create_oval(event.x-2, event.y-2, event.x+2, event.y+2, fill=draw_color, outline=draw_color)

Screenshot:

enter image description here

toyota Supra
  • 3,181
  • 4
  • 15
  • 19