purupann
@purupann

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

tkinterのボタンに関しての質問

tkinterのボタンに関しての質問

「開始」ボタンを押したら「終了」にtextが変わって
「終了」ボタンを押したら「開始」になるものを作り、
その間に「開始」が押されたら関数を動かすようにしたかったのですが、
ボタンが「開始」のままで関数が終わるまで「終了」になりません。
そこで、非同期処理にしてみたのですが、それでも治りませんでした。
どうすればよいでしょうか?

プログラムはこちらです

import pyautogui,tkinter,time,asyncio

with open("memo.txt","w") as memo:
    memo.write("")

class Main:
    def __init__(self):
        self.aaa = 0
    
    def click_btn(self):
        if button["text"] == "開始":
            button["text"] = "終了"
            while button["text"] != "終了":
                pass
            self.aaa = 0
            asyncio.run(main.loop())
        else:
            button["text"] = "開始"
            self.aaa = 1
    async def loop(self):
        button["text"] = "終了"
        i = 0
        while self.aaa == 0:
            i += 1
            if i >= 10:
                break
            print(pyautogui.position())
            with open("memo.txt","a") as memo:
                memo.write(f"{pyautogui.position()}\n")
            time.sleep(0.5)
main = Main()
    
root = tkinter.Tk()
root.title("pc操作自動化アプリ")
root.resizable(False, False)
root.geometry("400x200")

label = tkinter.Label(text='記録するdataの間隔(ミリ秒)', font=("MSゴシック", "10", "bold"))
label.pack()

boxa = tkinter.Entry()
boxa.pack()

button = tkinter.Button(root, text="開始", font=("Times New Roman", 10), command=main.click_btn)
button.place(x=170,y=80)



root.mainloop()#start
0

3Answer

「開始」ボタンを押したら「終了」にtextが変わって
「終了」ボタンを押したら「開始」になるものを作り、
その間に「開始」が押されたら関数を動かすようにしたかったのですが、

イメージが浮かばなかったのですが、「ボタン」は1つですか?
上記の"その間"というのはどういう時間のことを指しているのでしょうか?

1Like

Comments

  1. @purupann

    Questioner

    ボタンは1つです。
    最初は「開始」と表記されていて、その状態で押すと「終了」と表記されるようにし、
    逆に「終了」の時に押すと「開始」と表記されるものを作り、
    「開始」のときに押したら関数を動かすようにしたのですが、関数が終わるまで開始という文字が、「終了」にならないということです。分かりにくくてすいません

まずクラスの書き方がめちゃくちゃです。こちら基本ですからしっかりと学習なさってください(探せば優秀なHowToはいくらでもあります)。
外で宣言した変数button(44行目)とクラスMain__init__で宣言されてる変数buttonは全く別の世界ですから互いを呼び出すことは出来ません。
グローバルも多用すると混乱の元ですから控えるべきです。
クラスで書くのでしたらtkinterの初期処理を中途半端にせず__init__内に書いてしまえば良いのです。またクラスにこだわらないのでしたら、クラスを扱わないというのも手です。

import tkinter
from tkinter import ttk

class Main:
	def __init__(self):
		self.root: tkinter.Tk = tkinter.Tk()
		self.root.title(string='Main')

		self.button: ttk.Button = ttk.Button(master=self.root, text='開始', command=self.button_click_event)
		self.button.pack()

	def button_click_event(self) -> None:
		if self.button.cget('text') == '開始':
			self.button.configure(text='終了')
		else:
			self.button.configure(text='開始')

	def mainloop(self) -> None:
		self.root.mainloop()

if __name__ == '__main__':
	main = Main()
	main.mainloop()

余計なことをせず、まず最初はシンプルなコードで始めて下さい。

変数buttonはDictでもありますからbutton["text"]でも内容は書き換えることは出来ます。
ここでは安全にcget()で取得、configure()でテキストの置き換えを行っています。

1Like

他の方々がコードの構成について課題を挙げていらっしゃるので
コードの構成が変わることを想定し、どう変更するかはあえて書きません。

いまのコードの問題点を挙げます。

メインループのブロック

ブロックされている処理1

click_btn メソッド内で while button["text"] != "終了" の無限ループを使用しているため、ボタンのテキストを「終了」に変更する処理がブロックされています。

ブロックされている処理2

asyncio.run(main.loop()) も同様にメインスレッドをブロックしてしまいます。これにより、GUIが更新される前に時間がかかる処理が完了するまで待たされます。

GUIの更新が遅れる

tkinterのイベントループ(root.mainloop())がブロックされると、ボタンのテキストの変更や他のGUI更新が行われません。これが、ボタンのテキストが期待通りに更新されない原因です。

1Like

Your answer might help someone💌