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

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

ただいまの
回答率

88.93%

Shellで実行されるコードを、tkinter ボタンに割り当て実行しようとしたのですが、うまくいきません

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 199

swing

score 2

下記、プログラムをShellで実行すると問題なく動きます。内容は、
➀、質問に対して、OKなら表示されているランダムな数字を入力して、OKボタンを押す
➁、同じ数字が入力されていれば、リスト内の次の質問と次の(ランダムな)数字が表示される
➂、異なる数字が入力されれば、再度、同じ質問と先ほどとは異なる数字が表示される

import random

q=["Aでいいですか?","Bでもいいですか?","Cでもいいですよね?"]
q.append("Dも追加していいですか?")

g=len(q)
n=0

while True :
    print(q[n])
    a=random.randint(0,100)
    print(a)
    b=int(input("""OKなら同じ数字を入力してください
→"""))

    if a!=b:
        continue
    else:
        n=(n+1)% g


実行しますとShellで下記のように表示されます
~・~・~・~・~・~・~・~・~・~・~・~・~・~・
Aでいいですか?
8
OKなら同じ数字を入力してください
→8
Bでもいいですか?
55
OKなら同じ数字を入力してください
→55
Cでもいいですよね?
19
OKなら同じ数字を入力してください
→19
Dも追加していいですか?
21
OKなら同じ数字を入力してください
→21
Aでいいですか?
~・~・~・~・~・~・~・~・~・~・~・~・~・~・

これをtkinterを使って再現したく、ネットにあった構文を拝借して、上記のコードを各所の思う所に当て込んで下記のように実行すると、
「line 45, in <module>
if a != c:
NameError: name 'c' is not defined」
と、エラーになります。

import tkinter as tk
import random


# ウィンドウを作成 
win = tk.Tk()
win.title("質問")
win.geometry("500x250")

# 部品を作成 
label1 = tk.Label(win, text="----")
label1.pack()

label2 = tk.Label(win, text="----")
label2.pack()

label3 = tk.Label(win, text="OKなら同じ数字を入力してokを押してください")
label3.pack()

text1 = tk.Entry(win)
text1.insert(tk.END, '')
text1.pack()

# 作業を作製
q=["Aでいいですか?","Bでもいいですか?","Cでもいいですよね?"]
q.append("Dも追加していいですか?")

g=len(q)
n=0

while True :
    label1["text"]=q[n]
    a=random.randint(0,100)
    label2["text"]=a

    def ok_click():
        c= int(text1.get())

    if a != c:
        continue
    else:
        n=(n+1)% g



# ボタンを作成 
okButton = tk.Button(win, text='ok',command=ok_click)
okButton.pack()


# ウィンドウを動かす
win.mainloop()


ifの後ろにある、cが定義されていないとの事で、def関数の中にあるcが受け渡せていないのだと思います
def関数の位置が悪いのかなと思い、

def ok_click():
    while True :
        label1["text"]=q[n]
        a=random.randint(0,100)
        label2["text"]=a
        c= int(text1.get())

    if a != c:
        continue
    else:
        n=(n+1)% g


とすると、エディタ上でcontinueが赤くハイライトされ、SyntaxError「'continue'not properly in loop」が表示されます

●ご教授頂きたいこと
➀、冒頭のShellで実行できるコードを、tkinterで実行できるコード
➁、tkinter内でOKボタンをクリックする以外にも、キーボードの「Enter」ボタンで次の質問に進めるコード
➂、text内に半透明で「ここに数字を入力してください」とデフォルト表示されており、クリックすると消えるコード

欲張ってすみません、どれか一つだけでも結構です
よろしくお願いいたします

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+1

クリック1回分の処理をする関数を定義して、呼び出すようにしないといけないです。
もろもろ対応してみました。

import tkinter as tk
import random

# ウィンドウを作成
win = tk.Tk()
win.title("質問")
win.geometry("500x250")

# 部品用変数を用意
question = tk.StringVar()
value = tk.StringVar()
entry = tk.StringVar()

# 質問
q = ["Aでいいですか?", "Bでもいいですか?", "Cでもいいですよね?"]
q.append("Dも追加していいですか?")

# 処理定義
n = 0
question.set(q[n])
value.set(random.randint(0, 100))

def ok_click(event=None):
    if entry.get() == value.get():
        global n
        n = (n + 1) % len(q)
        question.set(q[n])
    entry.set("")
    value.set(random.randint(0, 100))

# 部品を作成
tk.Label(win, textvariable=question).pack()
tk.Label(win, textvariable=value).pack()
tk.Label(win, text="OKなら同じ数字を入力してokを押してください").pack()
text = tk.Entry(win, textvariable=entry)
text.bind('<Return>', ok_click)
text.pack()
tk.Button(win, text='ok', command=ok_click).pack()

# ウィンドウイベント処理開始
win.mainloop()

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/05/06 15:59

    早々にご回答ありがとうございます
    書いて頂いたコードをコピペして実行すると、作りたかったGUIを得れました
    ありがとうございます
    そして、すごくシンプルで美しいコードですね
    必要最低限で書いてあるのでしょうね
    初めて見たキーワードもあり、これから1行づつコピペしてどのコードがどの仕事をしているのかを勉強致します
    ありがとうございました

    キャンセル

+1

(1) (2) のみの回答です。

while ループを廃止し、以下のようにします。

def next_question():
    global a
    label1["text"] = q[n]
    label2["text"] = a = random.randint(0,100)
    text1.delete(0, tk.END)

def ok_click(event=None):
    global c, n
    c = int(text1.get())
    if a != c:
        win.destroy()
    else:
        n = (n+1) % g
        next_question()

next_question()

text1.bind("<Return>", ok_click)

コンソールのプログラムにGUIを導入するにあたり、
「イベント駆動」という事を意識する必要があります。

通常のプログラムであれば、プログラムは上から下へ流れるように実行されますが、
Tkinter 等のGUIを使ったプログラムでは、
メインのループはマウスのイベントや描画を更新する処理(mainloop)になる為、
メインスレッドでは他のメインループを持つことはできません。
(描画や入力等の操作が出来なくなりウィンドウが固まります)

GUIプログラミングで、どのようにプログラムを構成するかというと、
入力があった時、ボタンが押された時等をトリガーに、
何かイベントが起きた時に呼ばれる関数を登録 (この場合 ok_click) しておき、
そこでイベントが起こった場合の処理、入力がの判定や次の質問へ進む処理を行います。


キーボードの「Enter」ボタンで次の質問に進めるコード

text1.bind("<Return>", ok_click)

Enter キーが押された時に、ok_click関数が呼ばれるように登録。

※ "<Enter>" ではありません。<Enter> もありますが、
カーソルが入った時・離れた時のイベントに<Enter>, <Leave>が使われてます。

bindで登録した場合、関数にはイベントオブジェクトが渡されるので、
引数が異なります。

ok_click() # <-- ボタンが押された時
ok_click(event) # <-- Enter キーが押された時

引数なしの呼び出し両方に対応する為、デフォルト引数を設定してます。(変更点)

def ok_click(event=None):
    ...

(3) に関しては、Tkinter のEnter 標準の機能にはないので、
自分で実装するかコードを借用する必要があります。

「Placeholder」 で検索すると幾つかサンプルコードが見つかります。

イメージ説明

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/05/06 15:50

    早々にご回答ありがとうございます
    Sellで動きさえすれば、GUIで表現するのは、割り当てるぐらいに考えていたのですが、
    書き方も変わってしまうのですね
    ご指摘頂いておりますように、何度もウィンドウが固まりました
    (自分で書いたモノがちゃんとフリーズするというちょっとした感動がありましたが。。)
    ご教授頂いた内容ですと、GUIにて作成する際はwhile文は使えなく、トリガー→処理を意識して書くのですね。➁、③も回答頂き、ありがとうございます。「Placeholder」実装できるようにします。
    ありがとうございました。

    キャンセル

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

  • ただいまの回答率 88.93%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • トップ
  • Pythonに関する質問
  • Shellで実行されるコードを、tkinter ボタンに割り当て実行しようとしたのですが、うまくいきません