I am trying improve my Python and tkinter skills. At this moment I am reading a book on tkinter. I noticed that in an object oriented GUI application the author defines the button callbacks this way:
def on_fast_forward_button_clicked(self):
self.player.fast_forward()
def on_rewind_button_clicked(self):
self.player.rewind()
So, if I understand correctly, we are writing to methods for each button in the application class. One with the "indirect" callback, called but the event, and other with the intended action itself, called by the previous one. Why should we write code like this, instead of just using a single method?
There's no specific reason, and in the example you give I absolutely wouldn't do it that way.
It's really quite simple: in general terms, every button should be associated with a function. That's it. That's the rule. What that function does is totally up to you.
If all it ever does is a single thing, there's no reason it can't directly call that single thing. If it needs to do more than one thing, create a special purpose function that does everything the button should do, and have that button call that function.
That being said, there's a conceptual difference between "responding to a button" and "performing an action". For example, you might have two or three ways to do the fast-forward function: you might have a command on the menubar, a command on a right-click menu, a dedicated fast-forward button, and a keyboard accelerator.
Depending on how these are implemented, the functions they call may or may not require extra arguments (eg: a function bound to an event always gets an event object). In that case it is often easier to have a special purpose function that is designed to respond to the event, and that special purpose function call the more general-purpose fast_forward function.
At the end of the day, it's all about clarity. If you think it makes the program easier to understand when you have a single function perform two roles (fastforward, and respond to a button click), by all means do it that way.
Think about it like this: currently, all the button does is have the player fast forward. What if in the future however you also wanted the clock, or some other entity to fast forward with it? Would it make any sense to stick those fast forward calls inside player.fast_forward()? Should the player's methods really have access to information like that?
on_fast_forward_button_clicked is acting as a wrapper to encompass everything that may need to be fast forwarded. If you ever need to add any functionality, all you need to do is make a minor modification:
def on_fast_forward_button_clicked(self):
self.player.fast_forward()
self.clock.fast_forward()
Related
I have following code for click handler in my PyQT4 program:
def click_btn_get_info(self):
task = self.window.le_task.text()
self.statusBar().showMessage('Getting task info...')
def thread_routine(task_id):
order = self.ae.get_task_info(task_id)
if order:
info_str = "Customer: {email}\nTitle: {title}".format(**order)
self.window.lbl_order_info.setText(info_str)
self.statusBar().showMessage('Done')
else:
self.statusBar().showMessage('Authentication: failed!')
thread = threading.Thread(target=thread_routine, args=(task,))
thread.start()
Is it a good practice to declare function in function for using with threads?
In general, yes, this is perfectly reasonable. However, the alternative of creating a separate method (or, for top-level code, a separate function) is also perfectly reasonable. And so is creating a Thread subclass. So, there's no rule saying to always do one of the three; there are different cases where each one seems more reasonable than the others, but there's overlap between those cases, so it's usually a judgment call.
As Maxime pointed out, you probably want to use Qt's threading, not native Python threading. Especially since you want to call methods on your GUI objects. The Qt docs article Threads, Events and QObjects in the Qt documentation gives you an overview (although from a C++, not Python, viewpoint). And if you're using a QThread rather than a threading.Thread, it is much more common to use the OO method—define a subclass of QThread and override its run method than to define a function, which makes your question moot.
But if you do stick with Python threading, here's how I'd decide.
Pro separate method:
You're doing this in a class method, rather than a function, and that the only state you want to share with the new thread is self.
Non-trivial code, longer than the function it's embedded in.
Pro local function:
Pretty specific to the info button callback; no one else will ever want to call it.
I'd probably make it a method, but I wouldn't complain about someone else's code that made it a local function.
In a different case—e.g., if the thread needed access to a local variable that had no business being part of the object, or if it were a trivial function I could write as an inline lambda, or if this were a top-level function sharing globals rather than a method sharing self, I'd go the other direction.
This is quite an essential part of my program and I need to have sorted out as soon as possible so anything would be a massive help.
My program consists of three modules which are imported to each other. One module consists of my user interface for which I am using tkinter. The user inputs data on a canvas which is sent to a second program to be processed and is then sent to the third module which contains the algorithm which I intend to step through with the user.
The "first" and "third" modules can interact with each other and during certain points in explaining the algorithm I change the appearance of the canvas and some text on the interface. The third module should then pause (for which I'm currently using a basic sleep method), and wait (ideally it will wait for the user to press the "Next Step" button on the user interface). It is during this step that my interface decides that it wants to freeze.
Is there any way I can stop this?
Many thanks in advance.
Edit: I've found a way to fix this. Thank you for all the suggestions!
Calling time.sleep() will stop your program doing anything until it finishes sleeping. You need Tkinter to keep processing events until it should run the next part of your code.
To do that, put the next part of your code in a separate function, and get Tkinter to call it when it's ready. Typically, you want this to happen when the user triggers it (e.g. by clicking a button), so you need to bind it to an event (docs). If you actually want it to happen after a fixed time, you can use the .after() method on any tkinter widget (docs).
GUI programming takes a bit of getting used to. You don't code as a series of things happening one after the other, you write separate bits of code which are triggered by what the user does.
Terminology note: if your Python files import each other, you have three modules, but it's still all one program. Talking about the "first program" will confuse people.
H.E.P -
The traditional way to do this does indeed involve using a separate thread and co-ordinating the work between the "worker" thread and the GUI thread using some sort of polling or eventing mechanism.
But, as Thomas K. points out, that can get very complex and tricky, especially regarding Python's use of the Global Interpreter Lock (GIL) etc. and having to also contend with Tkinter's processing loop.
(The only good reason to use a multi-threaded GUI is if you absolutely MUST ensure that the GUI remains responsive during a potentially long-running background task, which I don't believe is the issue in this case.)
What I would suggest instead is a generator-based "co-routine"-type architecture.
As noted in "The Python (2.7) Language Reference", Section 6.8, [the "yield" statement is used when defining a generator function and is only used in the body of the generator function. Using a yield statement in a function definition is sufficient to cause that definition to create a generator function instead of a normal function.]
(This effectively forms the basis of a co-routine architecture. (ed.))
[When a generator function is called, it returns an iterator known as a generator iterator, or more commonly, a generator. The body of the generator function is executed by calling the generator’s next() method repeatedly until it raises an exception.
When a yield statement is executed, the state of the generator is frozen and the value of expression_list is returned to next()‘s caller. By “frozen” we mean that all local state is retained, including the current bindings of local variables, the instruction pointer, and the internal evaluation stack: enough information is saved so that the next time next() is invoked, the function can proceed exactly as if the yield statement were just another external call.]
(Also see "PEP 0342 - Coroutines via Enhanced Generators " for additional background and general info.)
This should allow your GUI to call the next part of your algorithm specification generator, on demand, without it having to be put to sleep until the operator presses the "Next" button.
You would basically just be creating a little 'domain-specific language', (DSL), consisting of just the list of steps for your presentation of this particular algorithm, and the generator (iterator) would simply execute each next step when called (on demand).
Much simpler and easier to maintain.
A GUI program is always waiting for some action to occur. When actions do occur, the event code corresponding to that action is executed. Therefore, there is no need to call sleep(). All you need to do is set it up so that the third program is executed from the appropriate event.
I have a module for a physical process simulation. Now I want to do a GUI for it. I've used PyQt to create application, which allows to control calculation, its parameters and graphical output. But there is a problem - if I want to add some new feature to simulation, then in addition to coding it in computational module, I need to create wrapper function for calling it in GUI module, GUI element for calling it, set up GUI representation and bind it to the function I need. That's annoying, because I need to write an amount of obvious code instead of working on logic. I have a few ideas on automatization of process, but first I want to ask: are there some recommended ways to reduce this boilerplate work?
Welcome to GUI programming! :)
In PyQt, you can slightly reduce the amount of boilerplate by autoconnecting slots by name.
You can also create any GUI element at runtime, without resorting to QtDesigner, so you can do things like generate a list of checkboxes in a for loop.
This is a follow-up question to this other one.
I am trying to extend gtk.Builder but I found out that once the builder is instantiated one can only call the connect_signals method once: if called more than once, any call after the second will return None (which would mean: all signals have been connected, which is a blatant lie!).
The problem is that in my design I would need to pass around the builder instance to various modules (each of them has some of the handlers for managing the GUI), but this way, I can't.
I tried to see if I could understand how/where gtk.Builder stores the handler names that assigned withing the Glade GUI, in order to write my own method to overcome this limitation, but after more than an hour of console experiments I still haven't understand where this information is stored.
Any help or pointer is highly appreciated! :)
That connect_signals only works once is an old but undocumented limitation of the GtkBuilder C code. Especially from Python there is no way to access its internals to remedy that.
Instead of the builder you could pass around a dictionary. After everyone added their handlers you call connect_signals with it.
i think if you want to call connect_signals multiple times you must disconnect inbetween, kindof like
x = self.menu.connect('activate', self.func1)
self.menu.disconnect(x)
x = self.menu.connect('activate', self.func2)
I'm wondering how to go about implementing a macro recorder for a python gui (probably PyQt, but ideally agnostic). Something much like in Excel but instead of getting VB macros, it would create python code. Previously I made something for Tkinter where all callbacks pass through a single class that logged actions. Unfortunately my class doing the logging was a bit ugly and I'm looking for a nicer one. While this did make a nice separation of the gui from the rest of the code, it seems to be unusual in terms of the usual signals/slots wiring. Is there a better way?
The intention is that a user can work their way through a data analysis procedure in a graphical interface, seeing the effect of their decisions. Later the recorded procedure could be applied to other data with minor modification and without needing the start up the gui.
You could apply the command design pattern: when your user executes an action, generate a command that represents the changes required. You then implement some sort of command pipeline that executes the commands themselves, most likely just calling the methods you already have. Once the commands are executed, you can serialize them or take note of them the way you want and load the series of commands when you need to re-execute the procedure.
Thinking in high level, this is what I'd do:
Develop a decorator function, with which I'd decorate every event-handling functions.
This decorator functions would take note of thee function called, and its parameters (and possibly returning values) in a unified data-structure - taking care, on this data structure, to mark Widget and Control instances as a special type of object. That is because in other runs these widgets won't be the same instances - ah, you can't even serialize a toolkit widget instances, be it Qt or otherwise.
When the time comes to play a macro, you fill-in the gaps replacing the widget-representating object with the instances of the actually running objects, and simply call the original functions with the remaining parameters.
In toolkits that have an specialized "event" parameter that is passed down to event-handling functions, you will have to take care of serializing and de-serializing this event as well.
I hope this can help. I could come up with some proof of concept code for that (although I am in a mood to use tkinter today - would have to read a lot to come up with a Qt4 example).
An example of what you're looking for is in mayavi2. For your purposes, mayavi2's "script record" functionality will generate a Python script that can then be trivially modified for other cases. I hear that it works pretty well.