bugfix> python > 投稿

1つの列に2つのボタンとプログレスバーが積み重なったGUIがあります。各ボタンは、実行に時間がかかる異なる関数を呼び出します。誰かが2つのボタンのいずれかをクリックしたときにプログレスバーが移動し、機能が終了して停止するまで(不定に)移動し続けるようにします。マルチスレッドを使用する必要があることは知っていますが、コードを正しく取得できないようです!

コード

from tkinter import Tk
import time 
from tkinter import *
from tkinter import Button
from tkinter import Frame
from tkinter import ttk
import threading

def sample_function():
    time.sleep(2)  # SAMPLE FUNCTION BEING CALLED
def prepare_clicked():
    sample_function()  
def social_clicked():
    sample_function()
def anomaly_clicked():
    sample_function()             

window = Toplevel() # Tried using Tk but I am using image to design each buttons through the button config in my actual code and tk throws error
topFrame = Frame(window)
topFrame.pack()
prepare_btn = Button(topFrame, command=prepare_clicked,text='Button1')
anomaly_btn = Button(topFrame,command=anomaly_clicked,text='Button2')
social_btn = Button(topFrame, command=social_clicked,text='Button3')
processing_bar = ttk.Progressbar(topFrame, orient='horizontal', mode='indeterminate')

window.rowconfigure((0,1), weight=1)  # make buttons stretch when
window.columnconfigure((0,3), weight=1)  # when window is resized
prepare_btn.grid(row=0, column=1, columnspan=1, sticky='EWNS')
anomaly_btn.grid(row=1, column=1, columnspan=1, sticky='EWNS')
social_btn.grid(row=2, column=1, columnspan=1, sticky='EWNS')
processing_bar.grid(row=3, column=1, columnspan=1, sticky='EWNS')

window.mainloop()

回答 1 件
  • コードにスレッドを追加しました。機能の進行中はボタンを押したくないと思います。必要ない場合は、 for を削除してください   run_function のループ   btn['state'] を変更する 。また、行と列の構成コードを修正して、ユーザーがウィンドウのサイズを変更したときにウィジェットが拡大/縮小するようにしました。そして、私は邪悪な「スター」インポートを取り除きました。

    import tkinter as tk
    from tkinter import ttk
    import time
    from threading import Thread
    def sample_function():
        time.sleep(2)
    def run_function(name, func):
        # Disable all buttons
        for btn in buttons:
            btn['state'] = 'disabled'
        processing_bar.start(interval=10)
        print(name, 'started')
        func()
        processing_bar.stop()
        print(name, 'stopped')
        # Enable all buttons
        for btn in buttons:
            btn['state'] = 'normal'
    def run_thread(name, func):
        Thread(target=run_function, args=(name, func)).start()
    def prepare_clicked():
        run_thread('prepare', sample_function)
    def social_clicked():
        run_thread('social', sample_function)
    def anomaly_clicked():
        run_thread('anomaly', sample_function)
    
    window = tk.Tk()
    #window = tk.Toplevel()
    topFrame = tk.Frame(window)
    # Tell the Frame to fill the whole window
    topFrame.pack(fill=tk.BOTH, expand=1)
    # Make the Frame grid contents expand & contract with the window
    topFrame.columnconfigure(0, weight=1)
    for i in range(4):
        topFrame.rowconfigure(i, weight=1)
    prepare_btn = tk.Button(topFrame, command=prepare_clicked, text='Button1')
    anomaly_btn = tk.Button(topFrame,command=anomaly_clicked, text='Button2')
    social_btn = tk.Button(topFrame, command=social_clicked, text='Button3')
    buttons = [prepare_btn, anomaly_btn, social_btn]
    processing_bar = ttk.Progressbar(topFrame, orient='horizontal', mode='indeterminate')
    prepare_btn.grid(row=0, column=0, columnspan=1, sticky='EWNS')
    anomaly_btn.grid(row=1, column=0, columnspan=1, sticky='EWNS')
    social_btn.grid(row=2, column=0, columnspan=1, sticky='EWNS')
    processing_bar.grid(row=3, column=0, columnspan=1, sticky='EWNS')
    window.mainloop()
    
    

    更新

    これは、すべての機能を順番に実行する「すべて」ボタンを備えた新しい改良バージョンです。楽しい!

    import tkinter as tk
    from tkinter import ttk
    import time
    from threading import Thread
    def prepare_func():
        print('prepare started')
        time.sleep(2)
        print('prepare stopped')
    def anomaly_func():
        print('anomaly started')
        time.sleep(2)
        print('anomaly stopped')
    def social_func():
        print('social started')
        time.sleep(2)
        print('social stopped')
    def all_func():
        print('all started')
        show_and_run(prepare_func, buttons['Prepare'])
        show_and_run(anomaly_func, buttons['Anomaly'])
        show_and_run(social_func, buttons['Social'])
        print('all stopped')
    def show_and_run(func, btn):
        # Save current button color and change it to green
        oldcolor = btn['bg']
        btn['bg'] = 'green'
        # Call the function
        func()
        # Restore original button color
        btn['bg'] = oldcolor
    def run_function(func, btn):
        # Disable all buttons
        for b in buttons.values():
            b['state'] = 'disabled'
        processing_bar.start(interval=10)
        show_and_run(func, btn)
        processing_bar.stop()
        # Enable all buttons
        for b in buttons.values():
            b['state'] = 'normal'
    def clicked(func, btn):
        Thread(target=run_function, args=(func, btn)).start()
    window = tk.Tk()
    #window = tk.Toplevel()
    topFrame = tk.Frame(window)
    # Tell the Frame to fill the whole window
    topFrame.pack(fill=tk.BOTH, expand=1)
    # Make the Frame grid contents expand & contract with the window
    topFrame.columnconfigure(0, weight=1)
    for i in range(4):
        topFrame.rowconfigure(i, weight=1)
    button_data = (
        ('Prepare', prepare_func),
        ('Anomaly', anomaly_func),
        ('Social', social_func),
        ('All', all_func),
    )
    # Make all the buttons and save them in a dict
    buttons = {}
    for row, (name, func) in enumerate(button_data):
        btn = tk.Button(topFrame, text=name)
        btn.config(command=lambda f=func, b=btn: clicked(f, b))
        btn.grid(row=row, column=0, columnspan=1, sticky='EWNS')
        buttons[name] = btn
    row += 1
    processing_bar = ttk.Progressbar(topFrame, 
        orient='horizontal', mode='indeterminate')
    processing_bar.grid(row=row, column=0, columnspan=1, sticky='EWNS')
    window.mainloop()
    
    

あなたの答え