質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
canvas

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

1回答

3268閲覧

Python(tkinter)で採点ソフトを自作 消しゴム機能を実現したい

tasoyou

総合スコア14

canvas

HTML5の<canvas>要素用のタグです。CanvasはHTML5から導入された、二次元の図形描写が可能な要素です。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Tkinter

Tkinterは、GUIツールキットである“Tk”をPythonから利用できるようにした標準ライブラリである。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/12/11 05:17

前提・実現したいこと

学校の課題でPython(tkinter)にて採点ソフトを作っています。
朱入れを行う場面にて消しゴム機能を実装したいのですがいい方法が思いつきません..

発生している問題・エラーメッセージ

現在,ペイントソフトなどを自作するサイトなどでは,白地のcanvasの上に線を描画し,消しゴム機能を線の上から白で上塗りすることで実現させています.しかし,採点ソフトであるため背景に解答用紙を表示してあり,その上に朱入れを行っているため,白で上書きしてしまうと背景の解答用紙まで白くなってしまうため,朱入れした線のみを消す機能を実現したいと思っています..

該当のソースコード

python

1# -*- coding: utf-8 -*- 2import sys 3import subprocess 4import os, tkinter, tkinter.filedialog, tkinter.messagebox 5import os 6from pathlib import Path 7from pdf2image import convert_from_path 8from PIL import Image, ImageTk, ImageDraw 9import tkinter as tk 10from functools import partial 11class Application(tkinter.Frame): 12 def __init__(self, master=None): 13 super().__init__(master) 14 self.master = master 15 self.master.title('tkinter canvas trial') 16 self.pack() 17 self.create_widgets() 18 self.setup() 19 def create_widgets(self): 20 self.vr = tkinter.IntVar() 21 self.vr.set(1) 22 self.write_radio = tkinter.Radiobutton(self, text='write', variable=self.vr, value=1, command=self.change_radio) 23 self.write_radio.grid(row=0, column=0) 24 self.erase_radio = tkinter.Radiobutton(self, text='erase', variable=self.vr, value=2, command=self.change_radio) 25 self.erase_radio.grid(row=0, column=1) 26 self.clear_button = tkinter.Button(self, text='clear all', command=self.clear_canvas) 27 self.clear_button.grid(row=0, column=2) 28 self.save_button = tkinter.Button(self, text='save', command=self.save_canvas) 29 self.save_button.grid(row=0, column=3) 30 self.test_canvas = tkinter.Canvas(self, bg='white', width=600, height=600) 31 self.test_canvas.grid(row=1, column=0, columnspan=4) 32 self.test_canvas.bind('<B1-Motion>', self.paint) 33 self.test_canvas.bind('<ButtonRelease-1>', self.reset) 34 img = Image.open('./image_file/kaitouyoushi_01.png') 35 img = img.resize((600, 600)) 36 img = ImageTk.PhotoImage(img) 37 self.test_canvas.photo = img 38 self.test_canvas.create_image(300, 300, image=self.test_canvas.photo) 39 def setup(self): 40 self.old_x = None 41 self.old_y = None 42 self.color = 'black' 43 self.eraser_on = False 44 self.im = Image.new('RGBA', (200, 200), 'red') 45 self.draw = ImageDraw.Draw(self.im) 46 def change_radio(self): 47 if self.vr.get() == 1: 48 self.eraser_on = False 49 else: 50 self.eraser_on = True 51 def clear_canvas(self): 52 self.test_canvas.delete(tkinter.ALL) 53 self.test_canvas = tkinter.Canvas(self, bg='white', width=600, height=600) 54 self.test_canvas.grid(row=1, column=0, columnspan=4) 55 self.test_canvas.bind('<B1-Motion>', self.paint) 56 self.test_canvas.bind('<ButtonRelease-1>', self.reset) 57 img = Image.open('./image_file/kaitouyoushi_01.png') 58 img = img.resize((600, 600)) 59 img = ImageTk.PhotoImage(img) 60 self.test_canvas.photo = img 61 self.test_canvas.create_image(300, 300, image=self.test_canvas.photo) 62 def save_canvas(self): 63 self.test_canvas.postscript(file='out.ps', colormode='color') 64 def paint(self, event): 65 if self.eraser_on: 66 paint_color = 'white' 67 else: 68 paint_color = 'red' 69 if self.old_x and self.old_y: 70 self.test_canvas.create_line(self.old_x, self.old_y, event.x, event.y, width=5.0, fill=paint_color, capstyle=tkinter.ROUND, smooth=tkinter.TRUE, splinesteps=36) 71 self.draw.line((self.old_x, self.old_y, event.x, event.y), fill=paint_color, width=5) 72 self.old_x = event.x 73 self.old_y = event.y 74 def reset(self, event): 75 self.old_x, self.old_y = None, None 76def btn_click(): 77 #ファイル指定 78 fTyp = [("","*")] 79 iDir = os.path.abspath(os.path.dirname(__file__)) 80 #tkinter.messagebox.showinfo('○×プログラム','処理ファイルを選択してください!') 81 file = tkinter.filedialog.askopenfilename(filetypes = fTyp,initialdir = iDir) 82 # poppler/binを環境変数PATHに追加する 83 poppler_dir = Path(__file__).parent.absolute() / "poppler/bin" 84 os.environ["PATH"] += os.pathsep + str(poppler_dir) 85 # PDFファイルのパス 86 pdf_path = Path(file) 87 # PDF -> Image に変換(150dpi) 88 pages = convert_from_path(str(pdf_path), 150) 89 # 画像ファイルを1ページずつ保存 90 image_dir = Path("./image_file") 91 for i, page in enumerate(pages): 92 file_name = pdf_path.stem + "_{:02d}".format(i + 1) + ".png" 93 image_path = image_dir / file_name 94 # JPEGで保存 95 page.save(str(image_path), "PNG") 96 # ウィンドウ作成 97 # 画像表示 98 #fileに適当なpng画像を指定してください。 99 #img = Image.open('./image_file/kaitouyoushi_01.png') 100 #img = img.resize((400, 400)) 101 #img = ImageTk.PhotoImage(img) 102 #canvas = tk.Canvas(bg="gray", width=400, height=400) 103 #canvas.place(x=0, y=0) 104 #canvas.create_image(0, 0, image=img, anchor=tk.NW) 105 #root.mainloop() 106root = tkinter.Tk() 107# 画面サイズ 108root.geometry('800x800') 109#画面タイトル 110root.title(u"採点") 111lbl_search_words = tkinter.Label(text='') 112lbl_search_words.place(x=10, y=70) 113# ボタン 114btn = tkinter.Button(root, text='採点', command=btn_click) 115btn2 = tkinter.Button(root, text='書き込み', command=partial(Application, master=root)) 116btn.place(x=10, y=90) 117btn2.place(x=10, y=180) 118#表示 119root.mainloop() 120

試したこと

現在はclear allにて解答用紙を上書きすることで朱入れ部分の削除を実装しています

補足情報(FW/ツールのバージョンなど)

python3
tkinter

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

tkinter のキャンバスへの描画は、個別に削除可能です

python

1line = canvas.create_line(..., tags="red") 2 3canvas.delete("red") # "red" タグの要素をすべて削除 4canvas.delete(line) # キャンバス上に描画された特定の要素を削除

deque に create_line の戻り値を追加していけば、
直近の線を delete することで undo 操作を実装出来ます。Demo

追記: 消しゴム機能

python

1 def on_erase(e, r=20): # r=消しゴムの範囲 2 x = canvas.canvasx(e.x) 3 y = canvas.canvasy(e.y) 4 # カーソル周辺(指定座標範囲内)の要素を所得 5 for item in canvas.find_enclosed(x-r, y-r, x+r, y+r): 6 if canvas.type(item) == "line": # 画像を削除してしまわないように、種類判別 7 canvas.delete(item) 8 9 canvas.bind("<B3-Motion>", on_erase) # マウスの右ボタンをドラッグで消しゴム

ImageDraw への直接描画の取り消し操作は、出来ません。
(ラスター画像なので、上書きされた時点で元の画素データは失われてしまいます)

朱入れには、レイヤー用の画像を別に用意して、
保存時など必要になった時に、元の回答用紙と重ね合わせる等の実装が考えられます。

投稿2020/12/11 06:31

編集2020/12/11 12:37
teamikl

総合スコア8664

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tasoyou

2020/12/18 02:00

ありがとうございます。大変助かりました????
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問