-1

I am trying to change the state of the button but I get an attribute error, here is a copy of the entire traeback for reference:

Traceback (most recent call last):
  File "C:/Users/Test_Practice.py", line 53, in <module>
middle_buttons_class().Run_Button()
  File "C:/Users/Test_Practice.py", line 14, in Run_Button
run_thread = threading.Thread(target=middle_buttons_class.Run_Robot_Files(self))
  File "C:/Users/Test_Practice.py", line 23, in Run_Robot_Files
progress_bar().done_progress.config(state=tkinter.NORMAL)
AttributeError: 'progress_bar' object has no attribute 'done_progress'

I believe this may be a funky threading problem but I am not sure, can someone take a look for me?

class MiddleButtonsClass():

    def run_button(self):
        run_thread = threading.Thread(target=middle_buttons_class.Run_Robot_Files(self))
        run_thread.daemon = True
        run_thread.start()

    def run_robot_files(self):

        print("Tasks started")
        progress_bar().progress_bar_thread()
        progress_bar().done_progress.config(state=tkinter.NORMAL)


class ProgressBar():

    def progress_bar_thread(self):
        progress_bar_class = progress_bar()
        progress_thread = threading.Thread(target=progress_bar_class.initialize_progress_bar())
        progress_thread.daemon = True
        progress_thread.start()

    def initialize_progress_bar(self):
        self.progress_window = tkinter.Toplevel()
        self.progress_window.geometry("500x250")
        self.progress_window.title("In Progress")
        self.percentage_variable = tkinter.DoubleVar()
        self.progressbar = tkinter.ttk.Progressbar(self.progress_window, style='text.Horizontal.TProgressbar',
                                   variable=self.percentage_variable, maximum=500,
                                   length=450, mode="determinate")
        self.progressbar.pack(pady=100)
        self.done_progress = tkinter.Button(self.progress_window, text="Done", state=tkinter.DISABLED,
                                   command=None)
        self.done_progress.pack()



if __name__ == "__main__":
    master = tkinter.Tk()
    master.title("Test Runner")
    master.geometry("750x500")
    middle_buttons_class().Run_Button()
    master.mainloop()
Dawid Fieluba
  • 1,271
  • 14
  • 34
S.McWhorter
  • 151
  • 1
  • 1
  • 15
  • Hi, could you please post the complete traceback? – toti08 Oct 29 '18 at 12:04
  • Yes I just added the complete traceback. – S.McWhorter Oct 29 '18 at 12:08
  • 1
    Please write your example as something testable. We need your root window and the call to your classes. Please provide [Minimal, Complete, and Verifiable example](https://stackoverflow.com/help/mcve). – Mike - SMT Oct 29 '18 at 12:54
  • Okay I have updated my code. – S.McWhorter Oct 29 '18 at 13:24
  • Could you explain why you're using so many threads? You're starting a thread in the `middle_buttons_class` and a thread for the progress bar. Maybe you can add some explanation as for what you're trying to achieve here... – toti08 Oct 29 '18 at 13:29
  • The problem I see is you create an instance of `progress_bar` twice back to back. The first time you try to thread a method within the class the 2nd time you try to configure a class attribute that has not been initialized. You seam to misunderstand how to call a part of a class and update a part of a class. You cannot just recall the class separately. You need to assign the class to a variable and then edit that variable. You also create a copy of the class from within the class. – Mike - SMT Oct 29 '18 at 13:31

2 Answers2

3

So your problem is you are trying to edit from 2 separate instance of progress_bar(). What you should be doing is creating a variable to work with and then edit the class attributes from there. I also changed your thread target to use self instead of trying to create another instance of class.

Here is your code reworked to actually produce a top level window and I added a command to the button to show you a simple update of the progress bar.

That said your code needs some refinement.

import tkinter
import threading
import tkinter.ttk as ttk

class middle_buttons_class():

    def Run_Button(self):
        run_thread = threading.Thread(target=self.Run_Robot_Files())
        run_thread.daemon = True
        run_thread.start()

    def Run_Robot_Files(self):

        print("Tasks started")
        progress_bar_var = progress_bar()
        progress_bar_var.progress_bar_thread()
        progress_bar_var.done_progress.config(state=tkinter.NORMAL)


class progress_bar():

    def progress_bar_thread(self):
        progress_bar_class = self
        progress_thread = threading.Thread(target=progress_bar_class.initialize_progress_bar())
        progress_thread.daemon = True
        progress_thread.start()

    def initialize_progress_bar(self):
        self.progress_window = tkinter.Toplevel()
        self.progress_window.geometry("500x250")
        self.progress_window.title("In Progress")
        self.percentage_variable = tkinter.DoubleVar()
        self.progressbar = tkinter.ttk.Progressbar(self.progress_window, style='text.Horizontal.TProgressbar',
                                variable=self.percentage_variable, maximum=500,length=450, mode="determinate")
        self.progressbar.pack(pady=100)
        self.done_progress = tkinter.Button(self.progress_window, text="Done", state=tkinter.DISABLED,command=self.update_progressbar)
        self.done_progress.pack()

    def update_progressbar(self):
        self.percentage_variable.set(self.percentage_variable.get() + 10)

if __name__ == "__main__":
    master = tkinter.Tk()
    master.title("Test Runner")
    master.geometry("750x500")
    middle_buttons_class().Run_Button()
    master.mainloop()
Mike - SMT
  • 14,784
  • 4
  • 35
  • 79
1

Please take a look at Python Naming Convention, it will help improve the readability of your code.

You have to initialize a new object:

def run_robot_files(self):

    print("Tasks started")
    progressBar = progress_bar()
    progressBar.progress_bar_thread()
    progressBar.done_progress.config(state=tkinter.NORMAL)

You cannot initialize new instance here:

def progress_bar_thread(self):
    progress_bar_class = progress_bar()

so change it to:

def progress_bar_thread(self):
    progress_bar_class = self
mdoc-2011
  • 2,747
  • 4
  • 21
  • 43
Dawid Fieluba
  • 1,271
  • 14
  • 34
  • Thank you for your answer, but it did not work. I have updated the code, maybe that'll help . – S.McWhorter Oct 29 '18 at 13:21
  • Well, I see you have changed your code in the meantime. Please update Traceback also – Dawid Fieluba Oct 29 '18 at 13:24
  • Thank you again for your answer but it does not appear to be working. – S.McWhorter Oct 29 '18 at 13:36
  • 1
    You need to re-name the variable `progress_bar `or you will end up getting an `UnboundLocalError: local variable 'progress_bar' referenced before assignment` error. Also the target needs to be changed to target self instead of a new instance. So `progress_bar_class = progress_bar()` should be `progress_bar_class = self`. – Mike - SMT Oct 29 '18 at 13:56