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

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

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

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

ラジオボタン

ラジオボタンはフォームに使われる要素のひとつであり、ユーザに限られた選択肢からひとつの答えを選んでもらうというものです。

Q&A

1回答

754閲覧

ラジオボタンによる機能切替が上手くいきません

Romaine

総合スコア1

Tkinter

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

ラジオボタン

ラジオボタンはフォームに使われる要素のひとつであり、ユーザに限られた選択肢からひとつの答えを選んでもらうというものです。

1グッド

0クリップ

投稿2021/10/16 02:48

"機能ボタンの設定"という
コメント周辺にラジオボタンを実装しています。
この2つのボタンを使って以下の機能を実装したいのですが上手くいかず、困っています。

実装したい機能
ラジオボタンを"二値化処理"に切り替えるたびに、testが表示される

原因を教えていただけますと、助かります。
エラーの内容として、以下の内容が出現します。

Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\kuron\anaconda3\lib\tkinter_init_.py", line 1883, in call
return self.func(*args)
TypeError: 'NoneType' object is not callable

# -*- coding: utf-8 -*- import os import sys import tkinter as tk import tkinter.filedialog as tkf import tkinter.ttk as ttk from PIL import Image, ImageTk import math import cv2 import numpy as np radiobutton_text = ['二値化処理', 'test'] x_interval = 10 y_interval = 30 class Application(tk.Tk): def __init__(self): super().__init__() # rootメインウィンドウの設定 self.minsize(width = 600, height = 400) self.title("画像処理") self.geometry("1200x960+0+0") self.thread = None self.canvas_width = 1080 self.canvas_height = 720 # メインフレームの作成と設置 mainframe = ttk.Frame(self) mainframe.place(x=0, y=0) # 表示する画像の設定 self.canvas = tk.Canvas( self, width = self.canvas_width, height= self.canvas_height, bg = "black") self.canvas.place(x=0, y=0, anchor = tk.NW) self.canvas_obj = None self.image_cv = None y_interval_num = 0 # readボタンの設定 self.button = tk.Button( self, text = "画像読込", command = self.readFile ).place(x = self.canvas_width + x_interval, y=y_interval * y_interval_num) y_interval_num += 1 # saveボタンの設定 self.button = tk.Button( self, text = "画像保存", command = self.saveFile ).place(x=self.canvas_width + x_interval, y=y_interval * y_interval_num) y_interval_num += 1 # 機能ボタンの設定 try: rdo_var = tk.IntVar() for i in range(len(radiobutton_text)): self.radiobutton = tk.Radiobutton( self, value=i, variable= rdo_var, text= radiobutton_text[i] ).place(x=self.canvas_width + x_interval, y=y_interval * y_interval_num) y_interval_num += 1 function_mode = rdo_var.get() rdo_var.trace("w", self.functionCollection(function_mode)) except Exception as e: print(str(sys.exc_info()[0])) print(str(sys.exc_info()[1])) print(str(sys.exc_info()[2])) # 画像読込ボタンの設定 def readFile(self): # 読み込むファイルの種類と開始場所を決める fileType = [("", "*.png;*.jpg")] iDir = os.path.abspath(os.path.dirname(__file__)) readfilename = tkf.askopenfilename( filetypes = fileType, initialdir = iDir) if (readfilename == ''): return image_cv = cv2.imread(readfilename) # ファイルのリサイズ height, width, _ = image_cv.shape[:3] while(1): if(width > self.canvas_width or height > self.canvas_height): width = width * 0.99 height = height * 0.99 else: break image_cv = cv2.resize( image_cv, dsize = (math.floor(width), math.floor(height))) # cvからPILへ変換 image_rgb = cv2.cvtColor(image_cv, cv2.COLOR_BGR2RGB) self.baseimage = Image.fromarray(image_rgb) self.tk_image = ImageTk.PhotoImage(self.baseimage) if self.canvas_obj != None: self.canvas_obj = None self.canvas_obj = self.canvas.create_image( 0, 0, image = self.tk_image, anchor="nw" ) # 画像保存ボタンの設定 def saveFile(self): if self.canvas_obj != None: savefilename = tkf.asksaveasfilename( filetypes = [("JPEG", ".jpg")]) if (".jpg" not in savefilename ): savefilename = savefilename + ".jpg" image_rgb = np.asarray(self.baseimage) image_bgr = cv2.cvtColor(image_rgb, cv2.COLOR_RGB2BGR) cv2.imwrite(savefilename, image_bgr) def functionCollection(self, function_mode): if function_mode == 0: result = self.binallization() elif function_mode == 1: pass def binallization(self): try: print('test') except Exception as e: print(str(sys.exc_info()[0])) print(str(sys.exc_info()[1])) print(str(sys.exc_info()[2])) def main(): app = Application() app.mainloop() if __name__ == '__main__': main()
teamikl👍を押しています

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

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

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

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

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

guest

回答1

0

問題点: ラジオボタンの状態を保持する IntVar オブジェクトの生存期間

python

1 rdo_var = tk.IntVar()

Tkinter では、非ウィジェットの PhotoImage, IntVar 等は
ローカル変数にしか参照を持たない場合、
デストラクタにより関数の終わりで破棄されてしまいます。

python

1 variable= rdo_var,

ラジオボタン生成時に、一見参照を持たせているようにも見えますが、
Tkinter ライブラリ内部では IntVar の ID情報(文字列)
Pythonのオブジェクトとして参照はカウントされません。

解決策:
PhotoImage と同じように、インスタンス変数に保持することで回避できます。


問題点2:
ラジオボタンを保持するインスタンス変数を上書きしている。

python

1for i in range(len(radiobutton_text)): 2 self.radiobutton = tk.Radiobutton( 3

self.radiobutton は最後のラジオボタンを保持することになります。

解決策: リストに保持する

投稿2021/10/16 09:11

編集2021/10/16 09:32
teamikl

総合スコア8664

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

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

Romaine

2021/10/17 06:11

ご指摘いただき、ありがとうございます。 ご指摘いただいた通り、rdo_varにselfを付けて解決することが出来ました。 listについてはまだ時間が掛かりそうです。 解決出来次第、追記します。
teamikl

2021/10/17 14:58

エラーにはなってないようですが、他にも問題点があり、 self.button = tk.Button(...).place(...) は、想定されてる挙動になりません。self.button は None になってます。 変数にButtonを入れたい場合は、複数行に別けて書く必要があります。 また、後でself.buttonを参照してないので問題にはなってませんが、 read/save ボタンも同じ変数に上書きしてます。 ** 変数に保存する必要がない場合 ** に、繋げて tk.Button(...).place(...) と書くのはよく使われます。 ウィジェットの管理はtcl/tkのライブラリ側で行われているので、 戻り値を保持していなくても、ウィジェットはPython側のデストラクタでは破棄はされません。 >TypeError: 'NoneType' object is not callable 後から気がついたのですが、 質問に記載されているこのエラーは別の問題です。 tkinter\__init__.py ファイルではなく、自分の書いたコードでの エラーが出た場所の行番号が出てるはずなので、該当箇所を確認してください。
Romaine

2021/10/19 02:45

追加コメントしてくださり、ありがとうございます。 self.button = tk.Button(...).place(...) と記載するとself.ButtonがNoneになるのはテスト中に確認していましたが、 原因がわかっていませんでした。 この後、追加したい処理に”ボタンを非表示にする”処理があったのですが、 同じエラーに遭遇していたため、これも解決できそうです。 本当にありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問