このページでは、tkinter で作成したアプリがうまく動作してくれない時の “原因” と “対処法” についてまとめています。
このページでは主に「エラーが出てないけどアプリが上手く動作しない」時の原因と対処法について解説しています。
エラーが発生した時の原因と対処法については下記ページにまとめていますので、これらを知りたい方は是非こちらを読んでみていただければと思います。
【tkinter】エラーが発生した時の対処法まとめ私自身の「アプリがうまく動作してくれなくて困った時」の体験に基づいてまとめていっており、このような現象が発生するたびに随時このページに加筆していこうと思います。
Contents
アプリが起動しない
まずはスクリプト実行したのにアプリが起動しない(メインウィンドウが表示されない)場合の問題の対処法を紹介していきます。
アプリが起動しない場合のスクリプト例
例えば下記のようなスクリプトだとアプリが起動しません。
import tkinter
app = tkinter.Tk()
button1 = tkinter.Button(
app,
text="ボタン1"
)
button1.pack()
スポンサーリンク
原因1
アプリが起動しない原因で一番多いのは「mainloop
が実行されていない」だと思います。
tkinter では mainloop
を実行することで初めてメインウィンドウを含むウィジェットが画面が表示されます。
また、mainloop
が実行されないとスクリプトの最後まで処理が実行された際に即座にスクリプトが終了します。
なので、mainloop
を実行していないと、アプリが起動せずに即終了してしまう現象が発生します。
スポンサーリンク
対処法1
原因は「mainloop
が実行されていない」ことなので、mainloop
を実行することによって問題は解決できます。
tkinter においてはこの mainloop
が非常に重要なメソッドになります。
後述で解説する「アプリの反応が悪い」ような現象も、この mainloop
が原因である可能性があります。
原因2
アプリが起動しない原因のもう1つはスクリプト実行時のエラーです。
通常の Python スクリプトでもエラーが発生すると動作してくれないように、当然 tkinter でもエラーが発生するとアプリが動作してくれません。
特にアプリが起動すらしない場合は、Python としての文法が間違っている or mainloop
実行までの処理でエラーが発生している可能性が高いと思います。
スポンサーリンク
対処法2
この対処法は当然エラーを解消することです。
tkinter 実行時に発生するエラーとその対処法は下記ページでまとめていっていますので、是非こちらも参考にしてエラーを解消してください。
【tkinter】エラーが発生した時の対処法まとめウィジェットが表示されない
続いて、作成したウィジェットがアプリ上に表示されない時の原因と対処法について解説します。
ウィジェットが表示されない場合のスクリプト例
例えば下記のようなスクリプトだとウィジェットが表示されません。
import tkinter
app = tkinter.Tk()
button1 = tkinter.Button(
app,
text="ボタン1"
)
app.mainloop()
スポンサーリンク
スポンサーリンク
原因
ウィジェットが表示されない原因で一番多いのは「ウィジェットの配置が行われていない」だと思います。
tkinter ではウィジェットを作成するだけでは画面に表示されません。作成と「配置」を行うことで初めて画面が表示されます。
割とウィジェットを作成して満足してしまい、配置することを忘れてしまうことがありますので注意してください。
スポンサーリンク
対処法
原因はウィジェットの「配置が実行されていない」ことなので、配置を実行するようにすることで問題は解決できます。
ウィジェットの配置は、ウィジェットのオブジェクトに下記のどれかのメソッド実行させることで行うことができます。
pack
grid
place
配置やこれらのメソッドについては下記ページで解説していますので、詳しく知りたい方は下記ページをご覧ください。
Tkinterの使い方:ウィジェットの配置(pack・grid・place)アプリの反応が悪い
次は「アプリの反応が悪い時」の原因と対処法について解説します。主に mainloop
の観点での解説になります。
スポンサーリンク
アプリの反応が悪い場合のスクリプト例
下記はボタンが押されるたびにラベルに表示する数字をカウントアップしていくアプリのスクリプトになります。
例えば下記のようなスクリプトだとアプリの反応が悪くなってしまいます。
import tkinter
count = 0
def click():
global count
global label
count += 1
label.config(
text=count
)
import time
time.sleep(2)
app = tkinter.Tk()
label = tkinter.Label(
app,
text=count,
)
label.pack()
button = tkinter.Button(
app,
text="ボタン",
command=click
)
button.pack()
app.mainloop()
実行してボタンのクリックを素早く連続して行うと、アプリが固まってしまいます。
スポンサーリンク
原因1
アプリの反応が悪い時の原因で一番多いのは「イベントハンドラで時間のかかる処理を実行している」だと思います。
イベントについては下記ページで解説していますので、イベントについて詳しく知りたい方はこちらを参考にしていただければと思います。tkinter を利用する上で非常に重要な機能になります。
Tkinterの使い方:イベント処理を行うtkinter では、通常ではイベントハンドラ実行中は他のイベントの処理が行えません。もっと正確に言うと、mainloop
実行中でないとイベントの処理が行えません。
イベントハンドラの処理が終わらないと mainloop
に処理が戻らないため、結果的にイベントハンドラの処理時間が長いとイベント処理が行えない時間が長くなります。
例えば、他のイベントハンドラが実行されている間にボタンを押下しても、そのボタン押下に対する処理はそのイベントハンドラ実行中は実行されません。
なので、ボタン押下してもアプリが即座に反応せず、ユーザーからするとアプリの反応が悪いと感じることになります。
スポンサーリンク
対処法1
対処の方針としては下記の2つが考えられます。
- イベントハンドラの処理時間を減らす
- マルチスレッドを利用する
イベントハンドラの処理時間を減らす
対処方針の1つ目は「イベントハンドラの処理時間を減らす」です。
例えば sleep
を行なっているような場合は after
に置き換えることでイベントハンドラの処理時間を減らすことができます。
after
に関しては下記ページで解説していますので、詳しく知りたい方はこちらを参考にしていただければと思います。after
と sleep
の違いについても具体的に解説しています。
マルチスレッドを利用する
ただし、どうしてもイベント発生時に重い処理(時間のかかる処理)を実行したい場合もあると思います。
そのような場合はマルチスレッドを利用する手段があります。
前述の通り、mainloop
実行中でないとイベント処理が行えません。逆にいうと mainloop
実行中であれば基本的にイベント処理を即座に行うことができます。
なので、マルチスレッドを利用し、1つのスレッドを mainloop
実行専用のものにしてやれば、他のスレッドで重い処理実行中でもイベント処理を即座に行うことができ、アプリの反応を良くすることができます。
tkinter でマルチスレッドを利用する方法については下記ページで解説していますので、マルチスレッドを利用してアプリの反応を改善したい場合は是非読んでみてください。
【Python/tkinter】tkinterでマルチスレッドを利用するアプリの反応を悪くしないためには、mainloop
についてしっかり理解しておくことが重要です。
mainloop
について詳しく知りたい方は是非下記ページを読んでみてください。
スポンサーリンク
ウィジェットへの設定が反映されない
次はウィジェットの設定を行っても、その設定がウィジェットに反映されない場合の原因と対処法について解説していきます。諦めるしかないものもありそうです…。
ウィジェットへの設定が反映されない場合のスクリプト例
下記のスクリプトではキャンバスウィジェットの見た目を relief
で設定しているのですが、アプリを実行してもキャンバスウィジェットの見た目が変化しません。
import tkinter
app = tkinter.Tk()
canvas = tkinter.Canvas(
app,
width=300,
height=300,
bg="white",
relief=tkinter.RAISED
)
canvas.pack()
app.mainloop()
スポンサーリンク
原因1
この原因の一つ目はとしては「その設定が単体のウィジェット設定では効果がないものである」が挙げられます。
単体のウィジェット設定だと効果が現れない設定があります。
分かりやすいのは relief
設定です。
relief
はウィジェットの見た目を変更する設定ですが、このウィジェットの見た目の変更は枠線の見た目を変更することで実現されているようです。
ですので、そもそも枠線が細すぎる or 枠線がない場合は relief
の設定を行ってもウィジェットの見た目が変わらないことになります。
スポンサーリンク
対処法1
単体のウィジェット設定で効果が現れないような場合でも、他のウィジェット設定と組み合わせて設定することで効果が現れるようになることがあります。
例えば前述でも挙げた relief
を変更してもウィジェットの見た目が変わらない場合は、bd
(枠線の太さ指定)も併せて設定してやれば、ウィジェットの見た目が変わるような場合があります。
私の環境では下記ではキャンバスのウィジェットの見た目は変わりませんでしたが、
canvas = tkinter.Canvas(
app,
width=300,
height=300,
bg="white",
relief=tkinter.RAISED
)
下記のように bd
も併せて設定してやればウィジェットの見た目が変わるようになりました。
canvas = tkinter.Canvas(
app,
width=300,
height=300,
bg="white",
relief=tkinter.RAISED,
bd=10
)
じゃあ具体的にどの設定が「単体のウィジェット設定で効果が現れない」のかというと、私も全ては把握できていません…。ただし、枠線の色や見た目を変更するようなものは枠線の太さが 0
(枠線なし)の場合は単体の設定では効果が現れないのは確実です。
このサイトの各ウィジェットの解説ページでは「設定項目(コンストラクタ実行時や config
メソッド実行時に設定可能な項目)」について解説しており、効果が現れるときの設定例も併せて紹介していますので、そちらも参考にしていただければと思います。
原因2
もう一つ考えられる原因として「使用している環境がその設定に対応していない」がありそうです。
私も各ウィジェットの解説ページ作成時に設定可能な設定項目は全て動作確認してみているのですが、設定が反映されない設定項目を実際に確認しています(例えばボタンウィジェットに対する bd
設定など)。
ただし、(tkinter の help やドキュメントで確認できる)マニュアル的には設定可能な設定項目にはなっていますので、おそらく環境によって設定が反映されない場合があるのではないかと予想しています。
スポンサーリンク
対処法2
この場合は対処しようがないですね…。
ウィジェットに設定しても効果が現れないようなものは、その設定をするのを諦めるしかないと思っています…。割り切りも大事です…。
スポンサーリンク
ウィジェットの設定がうまく取得できない
次はウィジェットの設定がうまく取得できない時の原因と対処法について解説します。
縁のない人も多いかもしれませんが、私は tkinter 始めたての頃にこの問題にハマって困りました…。
ウィジェットの設定がうまく取得できない場合のスクリプト例
下記は配置済みのキャンバスウィジェットに winfo
関連のメソッドを実行させて、キャンバスウィジェットの情報を取得して表示するスクリプトです
import tkinter
app = tkinter.Tk()
canvas = tkinter.Canvas(
app,
width=300,
height=200,
bg="white"
)
canvas.pack(padx=10,pady=10)
button = tkinter.Button(
app,
text="ボタン",
)
button.pack()
print(canvas.winfo_width(), canvas.winfo_height())
print(canvas.winfo_x(), canvas.winfo_y())
app.mainloop()
このスクリプトで実行している winfo
関連のメソッドでは、それぞれ下記の情報を取得するものになります。
winfo_width
:ウィジェットの表示サイズ(横方向)winfo_height
:ウィジェットの表示サイズ(縦方向)winfo_x
:ウィジェットの配置位置(横方向)winfo_y
:ウィジェットの配置位置(縦方向)
ただし、上記のスクリプトを実行しても下記のように表示されてしまい、上手くウィジェットの情報が取得できていないことが確認できます。
1 1 0 0
スポンサーリンク
スポンサーリンク
原因
winfo
関連のメソッドでは、ウィジェット作成・配置 “直後” から正常に情報が取得できるものと、正常に情報が取得できないものが存在します。
後者においては、ウィジェット作成・配置してから次にアプリが暇になった時(mainloop
に処理が戻った時)に設定が反映され、それ以降は正常に情報が取得できるようになります。
例えば下記のようなメソッドではウィジェット作成・配置 “直後” には正常に情報が取得できません。
winfo_width
:ウィジェットの表示サイズ(横方向)winfo_height
:ウィジェットの表示サイズ(縦方向)winfo_x
:ウィジェットの配置位置(横方向)winfo_y
:ウィジェットの配置位置(縦方向)winfo_geometry
:ウィジェットのサイズと配置位置
スポンサーリンク
対処法
この問題の対処法は2つあります。
mainloop
実行後に情報を取得するようにする- 情報取得前に
update
を実行する
mainloop
実行後に情報を取得するようにする
特に winfo
関連のメソッドを用いて正常にウィジェットの情報が取得できない場合は、ウィジェット作成・配置 “直後” ではなく、mainloop
実行後(mainloop
に処理が戻った後)に情報を取得するようにすれば問題は解決します。
かといって mainloop
の直後に情報を取得するような処理を記述しても、mainloop
の後ろ側の処理はアプリが終了するまで実行されません。
いざアプリが終了してウィジェットの情報を取得するような処理が実行されたとしても、その時点ではアプリが終了しているのでウィジェットのオブジェクトも削除されてしまっているので情報が取得できるどころかエラーが発生してしまいます。
なので、結局はイベントハンドラや after
メソッドで遅らせて実行する関数の中で winfo
関連のメソッドを実行する必要があります。
情報取得前に update
を実行する
もう一つの対処法は update
メソッドを実行してから winfo
関連のメソッドを実行する方法です。
update
メソッドを実行すれば、mainloop
に処理が戻る前に、即座にウィジェットの設定を反映することができます。
文字列や数字ではなく PY_VAR
が表示される
次は PY_VAR
という文字列が表示される問題について解説します。
冷静に考えれば当たり前の話なのですが、割とやってしまいがちな問題だと思います。
PY_VAR
が表示される場合のスクリプト例
下記のスクリプトを実行すると文字列ではなく PY_VAR
が表示されてしまいます。
import tkinter
def update_label():
global label
global var
label.config(
text=var
)
app = tkinter.Tk()
var = tkinter.StringVar()
label = tkinter.Label(
app,
font=("",40),
)
label.pack()
entry = tkinter.Entry(
app,
font=("",40),
textvariable=var
)
entry.pack()
button = tkinter.Button(
app,
text="ボタン",
command=update_label
)
button.pack()
app.mainloop()
このスクリプトでは、ボタンが押された時にエントリーウィジェットに入力中の文字列をラベルに表示しようとしていますが、実際にはボタンを押すとラベルに PY_VAR
と表示されてしまいます。
スポンサーリンク
スポンサーリンク
原因
「文字列や数字ではなく PY_VAR
が表示される」問題は、ウィジェット変数オブジェクトそのものを文字列として表示したしまった時に発生します。
tklnter では、エントリーなどのウィジェットに入力中の文字列を動的に更新する変数として「ウィジェット変数オブジェクト」が利用できます。
例えば下記のようにエントリー作成時に textvariable
にウィジェット変数オブジェクトを設定しておけば、エントリーに入力されている文字列が変化した際にこのオブジェクトの変数も自動的に更新されます。
var = tkinter.StringVar()
entry = tkinter.Entry(
# 〜略〜
textvariable=var
)
entry.pack()
ただし、このウィジェット変数オブジェクト自体が “文字列や数値ではない” ことに注意が必要です。
このオブジェクトはウィジェットに入力中の文字列や数値を保持しているだけのもので、文字列や数値そのものではありません。
ですので、このウィジェット変数オブジェクト自体を文字列として表示しても、そのオブジェクトが保持している文字列が表示されるわけではなく、そのオブジェクトの名前が表示されてしまいます。
ウィジェット変数オブジェクトの名前は PY_VARx
(x
は整数)となるので、ウィジェット変数オブジェクトを文字列として表示してしまうと、文字列を表示したつもりでも PY_VAR
が表示されてしまうことになります。
スポンサーリンク
対処法
ウィジェット変数オブジェクトが保持している文字列や数値は、そのオブジェクトに get
メソッドを実行させることで取得することが可能です。
var = tkinter.StringVar()
var.get()
したがって、PY_VAR
が表示された時は、”ウィジェット変数オブジェクト自体” を表示してしまっている箇所を、ウィジェット変数オブジェクトから “get
で取得した文字列や数値” を表示するように直してやれば問題は解決します。
例えばウィジェットの設定時には、設定項目によって変数オブジェクト自体を指定する必要がある場合や、文字列を指定する必要がある場合があるので注意が必要です。
例えば textvariable
では変数オブジェクト自体を指定する必要があります。
var = tkinter.StringVar()
entry = tkinter.Entry(
# 〜略〜
textvariable=var
)
entry.pack()
一方で、text
では変数オブジェクト自体ではなく、文字列を指定する必要があります。
var = tkinter.StringVar()
label = tkinter.Label(
# 〜略〜
text=var.get()
)
label.pack()
画像が表示されない
キャンバスの create_image
メソッドを実行しても画像が表示されない原因と対処法は下記ページで別途まとめています。
スポンサーリンク
まとめ
このページでは、tkinter で作成したアプリが上手く動作しない時の原因及びその対処法について解説しました!
原因としては割と初歩的なものも多いですが、特にプログラミング初心者の方だとハマる可能性があるので、解説内容を参考に対処してみていただければと思います。
また、このページの冒頭にも記載したとおり、アプリがうまく動作しない現象を見つけ次第このページも随時更新していきますので、アプリがうまく動作しないときは是非このページに立ち寄ってみてください!