can I create/push custom event in Tkinter python?
in the code https://stackoverflow.com/a/10575137/933882
the redraw callback is still invoked on a fixed schedule, every 100 milliseconds etc.
but is it possible to trigger the callback immediately as the external serial data is available ? from usage point of view it's probably not much different, but the mechanisms are very different.
thanks
Related
Looking for help on where to start with this, not too good with Python. What I trying to do is use tkinter for a gui interface but i need to be able to process recieved data and update labels widgets as information changes. I all ready have the communication portion of my program working fine in the shell but when I try to tie it to tkinter it will stop processing as soon as the interface is generated. Anyone have a simple code for me to modify to my needs or point me to a reference example somewhere. Spent days so far trying different options and I still have yet to find something that works.
Thanks for any help
Convert your working program into functions that you can register as callbacks in the tkinter UI (say buttons, or other widgets), that is, make it event-driven, and then, for background processing register some of the functions with the after widget method. The root.mainloop() will never return (only on UI close), use it as the last instruction.
So you can't just write your logic in a top-down structure, and hope that it will work well with the UI. The mainloop will be permanently looping, and will call specific funtions in your code, as appropriate to the received events from the user, or to callbacks you registered to run after some time with after.
See here for the after part
Take a look here for structuring tkinter programs. It should have enough info and links for you to study and learn how to do it in a right way.
I want to show a loading gif until a function is completed.
The code I have is
self.LoadingGif = QtGui.QLabel(MainWindow)
movie = QtGui.QMovie("hashUpdate.gif")
self.LoadingGif.setMovie(movie)
self.LoadingGif.setAlignment(QtCore.Qt.AlignCenter)
self.gridLayout_2.addWidget(self.LoadingGif, 4, 1, 1, 1)
movie.start()
self.MYFUNCTION()
The problem is that the gif shows but it is not playing. It starts to play only when the function is completed.
How can I make the gif play while the function is executing ?
The GIF stops playing because your function self.MYFUNCTION is blocking the Qt Event loop. The Event loop is the part of Qt which (among other things) processes mouse/keyboard events, handles redrawing of widgets (like buttons when you hover over them or click on them) and updating the current frame displayed when playing an animation.
So the Qt event loop is responsible for executing your code in response to various things that happen in your program, but while it is executing your code, it can't do anything else.
So you need to change your code. There are several solutions to this:
Run MYFUNCTION in a secondary thread so it doesn't block the Qt event loop. However, this is not an option if your function interacts with the Qt GUI in any way. If you call any Qt GUI methods in MYFUNCTION (like updating a label, or whatever), this must never be done from a secondary thread (if you try, your program will randomly crash). It is recommended to use a QThread with Qt rather than a Python thread, but a Python thread will work fine if you don't ever need to communicate back to the main thread from your function.
If MYFUNCTION runs for a long time because you have a for/while loop, you could consider using a QTimer to periodically call the code in the loop. Control is returned to the Qt event loop after a QTimer executes so it can deal with other things (like updating your animation) between iterations of your loop.
Periodically call QApplication.instance().processEvents() during your function. This also returns control to the Qt event loop, but you may get unexpected behaviour if your function is also doing things with Qt.
You'll need to move self.your_function to another thread, letting Qt update the GUI and so your GIF!
I am building an app that, when the user hits a 'run' button, generates a table of buttons.
Because this process takes a while, I want to add a popup or progress bar to alert the user that the function is running and not frozen. To do this I decided to create a popup and call my function using threading so that the screen will be updated when the function starts (as opposed to once it is done).
mythread = threading.Thread(target=run_function)
mythread.start()
The trouble is that when I call my function from the above code it works very strangely: the columns of my table are the wrong width, some of my buttons are arbitrarily empty, and others have the wrong fill color. To fix this, all I need to do is to remove the threading operation and simply call run_function()
Any idea why this is happening?
I am new to Python, so it is likely some dumb mistake, but I have no idea. What is different between a process running as a thread and its default operation?
Disclaimer: I haven't worked with Kivy.
Not every framework works well with multithreading.
But most of the GUI frameworks have an event loop which is responsible for managing user events (mouse clicks, keyboard) and queued drawing operations (widgets).
In your case if don't want the UI to be freezed, you should regularly give control to your framework's event loop.
I guess kivy.base.EventLoopBase.dispatch_input is what you need to call to show an added widget or to handle user events.
I am writing an app in kivy which does cpu-heavy calculations at launch. I want the app to display what it's doing at the moment along with the progress, however, since the main loop is not reached yet, it just displays empty white screen until it finishes working. Can I force kivy to update the interface?
Basically I'm looking for kivy's equivalent of Tkinter's root.update()
I could create a workaround by defining a series of functions with each calling the next one through Clock.schedule_once(nextFunction, 1), but that would be very sloppy.
Thanks in advance.
Leaving aside the question of whether you should be using threading or something instead (which possibly you should), the answer is just that you should move your cpu calculations to somewhere else. Display something simple initially (i.e. returning a simple widget from your build method), then do the calculations after that, such as by clock scheduling them.
Your calculations will still block the gui in this case. You can work around this by doing them in a thread or by manually breaking them up into small pieces that can be sequentially scheduled.
It might be possible to update the gui by manually calling something like Clock.tick(), but I'm not sure if this will work right, and even if so it won't be able to display graphics before they have been initialised.
I'm currently porting a small application from PyGTK to PySide which sits in your systray and periodically checks a server for updates.
When I initially wrote this, I used a custom state model to represent its behaviour:
init: initial state
check: check server for updates
disconnected: no connection to server (wait for some time to try again)
error: server reported an error (user needs to check settings before proceeding)
idle: wait for POLLING INTERVAL seconds before checking again
quit
I since discovered that Qt has QStateMachine, which seems perfect for this type of structure. However, I was not able to apply the examples satisfyingly to my problem!
In particular:
In the context of QStateMachine, what is the difference between Signal and QEvent?
How do I define a conditional transition, i.e. on error go to... ?
Should program logic happen in Transition.onTransition() or in QState.onEnter()?
Any pointers are appreciated muchly!
Ok. Pyside.QtCore.Signal is Signals & Slots derivative.
As for your questions
I'd say there is no difference in QEvent and Signal in context of QStateMachine (although QEvent and Signals & Slots are totally different concepts). Depending on your needs you can trigger transition with QEvent or Signal. See QAbstactTransition for the list of out of the box transitions:
Inherited by: QSignalTransition, QEventTransition,
QMouseEventTransition, QKeyEventTransition
Again depending on what happens inside your application your error may be either signal from QObject or you can send (post) custom QEvent. You'll need to implement your custom QEvent and/or custom QEventTransition to trigger transition only on your events.
And again it depends:) Transition is the glue. It has knowledge about source and destination states. So I'd put only preparatory code inside onTransition() and state initialization code inside onEnter(). Also it seems wrong for me to put code that changes state inside onTransition() like in example you've shown:
def onTransition(self, e):
x = e.arguments()[0]
fac = self.fact.fac
self.fact.fac = x * fac
self.fact.x = x - 1
but as you can see it works well.
NB: If you have iOS experience then UIStoryboardSegue is analogue for transition. Mainly it is used to pass data between UIView's i.e. UI states.