3

Based on Classes, i have window which contain a button and progressbar, whenever the button is clicked there two things should happen :

1 - should entried value from dialog pass to class ABCD

2 - While our class ABCD() do his stuff, should our progressbar do regular pulsing untill the class ABCD() finish process.

So the problem is that the progressbar pulse only one time,then stucked there till the class ABCD() finished, then its start pulsing regulary later.

Here is my try:

import gi,time
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GObject

class DialogExample(Gtk.Dialog):

    def __init__(self, parent):
        Gtk.Dialog.__init__(self, "My Dialog", parent, 0,
            (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
             Gtk.STOCK_OK, Gtk.ResponseType.OK))

        self.set_default_size(150, 100)

        self.Myinput = Gtk.Entry()

        box = self.get_content_area()
        box.add(self.Myinput)
        self.show_all()

class DialogWindow(Gtk.Window):

    def __init__(self):
        Gtk.Window.__init__(self, title="Dialog Example")

        self.set_border_width(6)
        Hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
        self.add(Hbox)

        self.button = Gtk.Button("Open dialog")
        self.button.connect("clicked", self.on_button_clicked)

        Hbox.pack_start(self.button, True, True, 0)

        self.progressbar = Gtk.ProgressBar()
        Hbox.pack_start(self.progressbar, True, True, 0)

#~~~~~~ Progress Bar
    def on_timeout(self, user_data):
        """
        Update value on the progress bar
        """
        if self.activity_mode:
            self.progressbar.pulse()
        else:
            new_value = self.progressbar.get_fraction() + 0.01

            if new_value > 1:
                new_value = 0

            self.progressbar.set_fraction(new_value)

        # As this is a timeout function, return True so that it
        # continues to get called
        return True

    def on_button_clicked(self, widget):
        dialog = DialogExample(self)
        response = dialog.run()

        if response == Gtk.ResponseType.OK:
            variable = dialog.Myinput.get_text()
            print("start")
        dialog.destroy()

        #ProgressBar time function

        self.timeout_id = GObject.timeout_add(50, self.on_timeout, None)
        self.activity_mode = False
        self.progressbar.pulse()

        #this for Updating the Windows and make the progressbar pulsing while waiting
        # the class ABCD finish his stuff, finally should stop pulsing.
        while Gtk.events_pending():
            Gtk.main_iteration_do(False)
        passing_instance = ABCD(variable)


class ABCD(object):
    def __init__(self,value_of_dialog):
        self.get_value = value_of_dialog
        self.for_add = "______ add was done"
        self.final_value = self.get_value+self.for_add
        time.sleep(10)
        print("gonna be finished")
        print(self.final_value)



win = DialogWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()

As we can see here i already try to make pulse and refresh the windows in this part of code

self.timeout_id = GObject.timeout_add(50, self.on_timeout, None)
self.activity_mode = False
self.progressbar.pulse()

#this for Updating the Windows and make the progressbar pulsing while waiting
# the class ABCD finish his stuff, finally should stop pulsing.
while Gtk.events_pending():
    Gtk.main_iteration_do(False)

Otherwise because in my class ABCD() i have time.sleep(10) should the progress bar pulse only for that time 10 seconds later only then stop.

How should this code gonna be, i need someone provide me the correct code, with little explain.

  • But your `self.activity_mode` on True, that will make `self.on_timeout` pulse the progressbar instead of increasing it's progress with 0.01. But a small note regarding `time.sleep` this will put the complete GTK loop to sleep which you should avoid at all cost. – B8vrede May 19 '16 at 09:16
  • @B8vrede actually i used the time module in my dynamic class the ensure that passing between graphical and dynamic classes took much time, so my main problem is how could i make the code to force the progress bar pulsing untill the `class ABCD()` finish processing, please could you provide me the correct code to reach my goal? – Ahmed Bouabid May 19 '16 at 09:32
  • Just a quick note based on the fact that you are a new user and never accepted an answer. If someone's answer solved your problem, you might want to accept it as the answer using the big checkbox. This does require a minimum reputation unlike upvoting. – B8vrede May 19 '16 at 10:05

1 Answers1

1

The issue with using sleep in order to emulate the passing of time is that sleep will stop everything that is happening in the thread which in this case prevents the thread to reach Gtk.main() which is needed to make your progressbar pulse or update.

So in order to do this properly there are 2 options:

  1. Run ABCD in a separate thread such that the main thread can reach Gtk.main(). Which than will make sure that the progressbar moves as expected. A quick example of this looks like this:

    self.abcd_thread = ABCD(variable)
    self.abcd_thread.start()
    
    class ABCD(Thread):
        def __init__(self, value_of_dialog):
            super(ABCD, self).__init__()
            self.get_value = value_of_dialog
            self.for_add = "______ add was done"
            self.final_value = self.get_value+self.for_add
    
        def run(self):
            print "Starting " + self.name
    
            time.sleep(10)
            print("gonna be finished")
            print(self.final_value)
    
            print "Exiting " + self.name
    

    When using this you can use self.abcd_thread.isAlive() to see whether the thread is still computing things. The way to return information heavily depends on the job placed in the thread.

  2. Replace the time.sleep with the following fragment:

    now = time.time()
    while time.time() - now < 10:
        # Insert any code here
        Gtk.main_iteration_do(False)
    

    This will still emulate ABCD doing stuff for 10 seconds but because we call Gtk.main_iteration_do(False) in each iteration of the loop GTK is able to update the interface during the loop.

In general the second option is the easiest as it only involves making Gtk.main_iteration_do(False) call during whatever your doing. The first option on the other hand is more useful when dealing with complex computations where adding Gtk calls doesn't fit in easily.

B8vrede
  • 4,432
  • 3
  • 27
  • 40
  • great and thx for suggestiona and explain, but not this properly what i need, ok let me tell you my main problem, i do program which gonna try to connect live website, so how long is my Target website, that long time my program going to spend time in my dynamic class, in our case now is `class ABCD()`, so from the Gtk.Window i am going to pass url, then that Url gonna pass to my class ABCD, the laster will crawl many url/paths and try all them of course `inside my class ABCD` so here is it my problem i want to pulse the progress bar untill the test from the class ABCD is finished. – Ahmed Bouabid May 19 '16 at 10:16
  • hmm srry, but plz could you give me an example i will present my project so soon but i've to fix the progress bar issue :( – Ahmed Bouabid May 19 '16 at 10:20
  • In that case you should definitely look into the first option, do the loading of the website in thread X, while the main thread has the `Gtk.main()` loop running. Check out this tutorial to see how to set up the new thread: http://www.tutorialspoint.com/python/python_multithreading.htm – B8vrede May 19 '16 at 10:21
  • i did many try to fix it by thread but i fail, could you provide me something to contact you, i PM my code to look for solution with me, it my first python project , i'm not such expert with Gtk !! – Ahmed Bouabid May 19 '16 at 10:24
  • Hold on I will post an example in a bit. – B8vrede May 19 '16 at 10:25
  • I added an example to the first option, this should help you in the right direction. – B8vrede May 19 '16 at 10:44
  • great, thanks but the progress bar still pulsing here after finish the process of my class `abcd` – Ahmed Bouabid May 19 '16 at 11:08
  • Oh yeah forgot to post that line. In the `on_timeout` place `if self.abcd_thread is not None and self.abcd_thread.isAlive():` before the `if self.activity_mode:` that will stop the bar from pulsing when the thread dies. – B8vrede May 19 '16 at 11:10
  • Yeah that should work, this is the complete code that I used for testing: http://pastebin.com/VrJr9XEz – B8vrede May 19 '16 at 11:22
  • turning back value to my Gui class isn't possible using your code architecutre?? check my try here, the progress bar work fine but no value turn back the graphical class. http://pastebin.com/E7iB4tyx – Ahmed Bouabid May 19 '16 at 12:39
  • Sorry for the late response, the issue here is that as soon as the thread finishes the information in it is lost. To counter this you can use several techniques, one that might be the easiest for you is to use a `Queue` to store the return value and get it's results from there in the main thread. Check out this answer for a hint on how to do so: http://stackoverflow.com/a/14331755/2263652 – B8vrede May 22 '16 at 09:38