Tkinter Indeterminate Progress Bar

Merhaba,
Tkinter ile indeterminate progress bar yapıp, programımda ki baştan aşağıya çalıştırması çok uzun süren bir fonksiyonu çalıştırırken ekrana vermek istiyorum. kullanıcı işlem yapılırken süresi belirsiz bir ekran görsün istiyorum, ne kadar kaldığını görmesi pek mühim değil. Ancak bir türlü beceremedim, tkinter ile mainloop yapınca zaten bir alt satırı okumuyor loop u bitirmedikce. thread ile örneklerini gördüm fakat yapamadım. Yardım edebilecek olan varsa basit bir örnek görsem yeterli.

tkinter kodum şu:

def progress_window():
    global yukleme_penceresi
    yukleme_penceresi = tk.Tk()
    yukleme_penceresi.title("Yükleniyor...")
    yukleme_penceresi.overrideredirect(True)
    yukleme_penceresi.geometry("300x100")

    ekran_genislik = yukleme_penceresi.winfo_screenwidth()
    ekran_yukseklik = yukleme_penceresi.winfo_screenheight()
    pencere_genislik = 300
    
    pencere_yukseklik = 100
    x_konum = (ekran_genislik - pencere_genislik) // 2
    y_konum = (ekran_yukseklik - pencere_yukseklik) // 2
    yukleme_penceresi.geometry(f"{pencere_genislik}x{pencere_yukseklik}+{x_konum}+{y_konum}")

    yukleme_etiket = ttk.Label(yukleme_penceresi, text="Dosya değişiyor, lütfen bekleyin...")
    yukleme_etiket.pack(pady=20)

    progress_bar = ttk.Progressbar(yukleme_penceresi, orient="horizontal", mode="indeterminate")
    progress_bar.pack()

    progress_bar.start()

    # Ana pencerenin üstte kalmasını sağlar
    yukleme_penceresi.lift()
    yukleme_penceresi.attributes('-topmost', True)
    yukleme_penceresi.update()

    root = tk.Tk()
    root.withdraw() 
    root.mainloop()

    

    def kapat():
        yukleme_penceresi.destroy()

Şimdi şu şekilde paylaştığınız kodlar bir kaç değişiklikten sonra gayet düzgün çalışıyor, çok uzun süren fonksiyonu vs paylaşmadığınız için kabaca bu haliyle ben bir hata göremedim;

import tkinter as tk
from tkinter import ttk
def progress_window():

    global yukleme_penceresi
    yukleme_penceresi = tk.Tk()
    yukleme_penceresi.title("Yükleniyor...")
    yukleme_penceresi.overrideredirect(True)
    yukleme_penceresi.geometry("300x100")

    ekran_genislik = yukleme_penceresi.winfo_screenwidth()
    ekran_yukseklik = yukleme_penceresi.winfo_screenheight()
    pencere_genislik = 300

    pencere_yukseklik = 100
    x_konum = (ekran_genislik - pencere_genislik) // 2
    y_konum = (ekran_yukseklik - pencere_yukseklik) // 2
    yukleme_penceresi.geometry(f"{pencere_genislik}x{pencere_yukseklik}+{x_konum}+{y_konum}")

    yukleme_etiket = tk.Label(yukleme_penceresi, text="Dosya değişiyor, lütfen bekleyin...")
    yukleme_etiket.pack(pady=20)
    progress_bar = ttk.Progressbar(yukleme_penceresi, orient="horizontal", mode="indeterminate")
    progress_bar.pack()

    progress_bar.start()


    # Ana pencerenin üstte kalmasını sağlar
    yukleme_penceresi.lift()
    yukleme_penceresi.attributes('-topmost', True)
    yukleme_penceresi.update()

    root = tk.Tk()
    root.withdraw()
    root.mainloop()

    def kapat():
        yukleme_penceresi.destroy()
progress_window()

yukleme_etiket = tk.Label(yukleme_penceresi, text=“Dosya değişiyor, lütfen bekleyin…”)

Sadece bu satırda ttk.Label olarak girmişsiniz tk.Label olarak düzeltince gayet de çalışıyor programınız…

Not: Ben sadece kabaca verdiğiniz tkinter kodlarını inceledim. Diğer fonksiyonlarla etkileşimi vb. bunun hakkında yourm yapamıyorum çünkü kodları bilmiyorum :slight_smile:

1 Beğeni

program zaten çalışıyor, konuyu okumadınız sanırım. ekranda progress bar kullanıcıya gösterilirken arka planda bir fonksiyon çalıştırmak istiyorum. fonksiyon bitince otomatik progress bar da kapanacak. deniyorum fakat özellikle “RuntimeError: main thread is not in main loop” hatası alıyorum

Şöyle bir düzenleme yaptım;

import time
import tkinter as tk
from tkinter import ttk
import threading

def progress_window():
    global yukleme_penceresi
    yukleme_penceresi = tk.Tk()
    yukleme_penceresi.title("Yükleniyor...")
    yukleme_penceresi.overrideredirect(True)
    yukleme_penceresi.geometry("300x100")

    ekran_genislik = yukleme_penceresi.winfo_screenwidth()
    ekran_yukseklik = yukleme_penceresi.winfo_screenheight()
    pencere_genislik = 300
    pencere_yukseklik = 100
    x_konum = (ekran_genislik - pencere_genislik) // 2
    y_konum = (ekran_yukseklik - pencere_yukseklik) // 2
    yukleme_penceresi.geometry(f"{pencere_genislik}x{pencere_yukseklik}+{x_konum}+{y_konum}")

    yukleme_etiket = tk.Label(yukleme_penceresi, text="Dosya değişiyor, lütfen bekleyin...")
    yukleme_etiket.pack(pady=20)
    progress_bar = ttk.Progressbar(yukleme_penceresi, orient="horizontal", mode="indeterminate")
    progress_bar.pack()

    progress_bar.start()

    yukleme_penceresi.lift()
    yukleme_penceresi.attributes('-topmost', True)
    yukleme_penceresi.update()

def kapat():
        yukleme_penceresi.destroy()



def sayi_yazdirmaca_vs_islemler():
    for i in range(10):
        print(i)
        time.sleep(1)
    kapat()

progress_window()
thread_ornegi = threading.Thread(target=sayi_yazdirmaca_vs_islemler)
thread_ornegi.start()

yukleme_penceresi.mainloop()

Thread ile bazı denemeler yaptım ancak en sonda
root = tk.Tk()
root.withdraw()
root.mainloop()

şu ifadenin sorun çıkardığını farkettim burayı temizleyince…Örnek uygulama yukarıdaki gibi oldu…
Sayı yazdırma,sizin dediğiniz uzun işlemler gibi fonksiyonlar çalıştırılıyor ardından progressbar kapanıyor. Umarım doğru anlamışımdır :slight_smile:

Edit: Çok fazla threading kullanmadım kodlar sağlıklı mı tam emin değilim ama sanırım yukarıdaki sildiğim üç satır aynı fonksiyon üzerinde iki tane main pencere tanımlanmasından kaynaklanıyor .

1 Beğeni

evet bu düzgün çalıştı ama progress barın kapanmasına gelince kapatıyor, sonra tekrar açılıp hata veriyor onu anlamadım

1 Beğeni

Aşağıdaki linkte, alternatif mainloopları nasıl oluşturabileceğimiz hakkında bir yazı var.

Mesela, herhangi bir kütüphane kullanmadan, hatta tk widgetlerinin mainloop fonksiyonunu da kullanmadan, pencereyi görünür kılabilirsiniz. Ve pencere görünür olduğu sürece de, istediğiniz işlemleri aynı anda yapabilirsiniz.

Öncelikle, eğer daha önce hiç karşılaşmadıysanız, yield, generator, coroutine kavramları hakkında da araştırmalar yapmanızı tavsiye ederim.

İzninizle sizinle bir kod paylaşayım, döngüler birbirlerini engellemeden nasıl çalışıyorlar anlamaya çalışın.

import tkinter as tk
from tkinter import ttk


class App(tk.Tk):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.tasks = []
        self.button = tk.Button(master=self, text="Create Task", command=self.create_task)
        self.button.pack()
        self.protocol("WM_DELETE_WINDOW", lambda: self.tasks.clear())

    def run(self):
        self.tasks = [self.display()]
        i = 0
        while self.tasks:
            index = i % len(self.tasks)
            try:
                self.tasks[index].send(None)
                i += 1
            except StopIteration:
                self.tasks.pop(index)
                i -= 1

    def display(self):
        while True:
            self.update()
            yield

    def task(self):
        pbar = ttk.Progressbar(master=self, orient="horizontal", mode="indeterminate")
        pbar.pack()
        pbar.start()
        for i in range(1000000):
            yield
        pbar.stop()
        pbar.destroy()

    def create_task(self):
        self.tasks += [self.task()]


App().run()


Task’ın işi bitince, o taskla ilgili ilerleme çubuğu kapanıyor.