【tkinter】アプリがうまく動作しない時の対処法まとめ

アプリがうまく動作しない時の対処法まとめページアイキャッチ

このページでは、tkinter で作成したアプリがうまく動作してくれない時の “原因” と “対処法” についてまとめています。

このページでは主に「エラーが出てないけどアプリが上手く動作しない」時の原因と対処法について解説しています。

エラーが発生した時の原因と対処法については下記ページにまとめていますので、これらを知りたい方は是非こちらを読んでみていただければと思います。

tkinterのエラーの対処法まとめページのアイキャッチ【tkinter】エラーが発生した時の対処法まとめ

私自身の「アプリがうまく動作してくれなくて困った時」の体験に基づいてまとめていっており、このような現象が発生するたびに随時このページに加筆していこうと思います。

アプリが起動しない

まずはスクリプト実行したのにアプリが起動しない(メインウィンドウが表示されない)場合の問題の対処法を紹介していきます。

アプリが起動しない場合のスクリプト例

例えば下記のようなスクリプトだとアプリが起動しません。

アプリが起動しない
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のエラーの対処法まとめページのアイキャッチ【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 に関しては下記ページで解説していますので、詳しく知りたい方はこちらを参考にしていただければと思います。aftersleep の違いについても具体的に解説しています。

Tkinterの使い方:after で処理を「遅らせて」or 処理を「定期的」に実行する

マルチスレッドを利用する

ただし、どうしてもイベント発生時に重い処理(時間のかかる処理)を実行したい場合もあると思います。

そのような場合はマルチスレッドを利用する手段があります。

前述の通り、mainloop 実行中でないとイベント処理が行えません。逆にいうと mainloop 実行中であれば基本的にイベント処理を即座に行うことができます。

なので、マルチスレッドを利用し、1つのスレッドを mainloop 実行専用のものにしてやれば、他のスレッドで重い処理実行中でもイベント処理を即座に行うことができ、アプリの反応を良くすることができます。

tkinter でマルチスレッドを利用する方法については下記ページで解説していますので、マルチスレッドを利用してアプリの反応を改善したい場合は是非読んでみてください。

tkinterでのマルチスレッドの使い方解説ページのアイキャッチ【Python/tkinter】tkinterでマルチスレッドを利用する

アプリの反応を悪くしないためには、mainloop についてしっかり理解しておくことが重要です。

mainloop について詳しく知りたい方は是非下記ページを読んでみてください。

tkinterのmainloopの解説ページのアイキャッチ【Python】tkinterの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 が表示されてしまいます。

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_VARxx は整数)となるので、ウィジェット変数オブジェクトを文字列として表示してしまうと、文字列を表示したつもりでも PY_VAR が表示されてしまうことになります。

スポンサーリンク

対処法

ウィジェット変数オブジェクトが保持している文字列や数値は、そのオブジェクトに get メソッドを実行させることで取得することが可能です。

ウィジェット変数からの文字列の取得
var = tkinter.StringVar()

var.get() 

したがって、PY_VAR が表示された時は、”ウィジェット変数オブジェクト自体” を表示してしまっている箇所を、ウィジェット変数オブジェクトから “getで取得した文字列や数値” を表示するように直してやれば問題は解決します。

例えばウィジェットの設定時には、設定項目によって変数オブジェクト自体を指定する必要がある場合や、文字列を指定する必要がある場合があるので注意が必要です。

例えば textvariable では変数オブジェクト自体を指定する必要があります。

textvariableの指定例
var = tkinter.StringVar()

entry = tkinter.Entry(
    # 〜略〜
    textvariable=var
)
entry.pack()

一方で、text では変数オブジェクト自体ではなく、文字列を指定する必要があります。

textの指定例
var = tkinter.StringVar()

label = tkinter.Label(
    # 〜略〜
    text=var.get() 
)
label.pack()

画像が表示されない

キャンバスの create_image メソッドを実行しても画像が表示されない原因と対処法は下記ページで別途まとめています。

【Python】Tkinter で画像などのオブジェクトが描画できない時の対処法

スポンサーリンク

まとめ

このページでは、tkinter で作成したアプリが上手く動作しない時の原因及びその対処法について解説しました!

原因としては割と初歩的なものも多いですが、特にプログラミング初心者の方だとハマる可能性があるので、解説内容を参考に対処してみていただければと思います。

また、このページの冒頭にも記載したとおり、アプリがうまく動作しない現象を見つけ次第このページも随時更新していきますので、アプリがうまく動作しないときは是非このページに立ち寄ってみてください!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です