I am trying to write a function that launches a popup in a kivy gui based on a conditional. The method is outside of the main app because I am using multithreading to have both run at the same time. Every time I try to initialize a new popup in the method which is outside of the main app, it crashes. If I don't initialize it, it runs fine. Any ideas?
You must perform GUI related operations (like opening or dismissing a Popup) on the kivy thread.
In your code, where you would call sm.open_unrecognized() do Clock.schedule_once(sm.open_unrecognized, 0). This will schedule the call to open_unrecognized on the kivy thread after the next frame is displayed.
Dismissing the Popup can be done automatically (any click outside the Popup) or explicitly using something like a Button in the Popup. Note that any code called by a Button event is performed on the kivy thread.
See the Clock documentation for more information
Related
I have been trying to use tkinter to make a gui to select some excel files and sheets from those files.
I have a lot of experience in python, but I'd probably say a novice at tkinter.
The code I have written to select the files is shown below (typos are likely because I cannot access the internet on the machine these files are on, so I am typing it up here).
My question is about mainloop(), the update functions, and after(). I had mainloop() at the end of my code, but my program wouldn't terminate (i.e. the terminal would remain) after it did what it does. So I removed the mainloop() and now it functions perfectly without any mainloop(), update(), or after() calls.
I don't really understand this and would really like to. I get that mainloop() stops the code from progressing until the root closes, but I thought nothing would show up without mainloop(), and this code does wait for the user to close the windows before continuing.
I was also wondering if I do not have mainloop (or the like), the code still closes fine whether or not I have root.destroy() at the end of the App class (commented in the code). I don't get that either.
This information would help me make better and correct code in the future and hopefully improve this one. FYI, I have searched for the answer to this everywhere and could not find one, at least one I could understand. Thanks a bunch.
This is as minimal as I can think of for this code.
Code (Edited from original post):
import tkinter as tk
from tkinter import ttk
class App:
def __init__(self, parent):
self.root = parent
self.root.withdraw()
tl = tk.Toplevel(parent)
b = ttk.Button(tl, text="Test widget")
b.grid()
tl.wait_window()
# This line does not change how the code functions at all
#self.root.destroy()
def run(self):
# Whether or not this is a function in the class or called globally doesn't matter.
self.root.mainloop()
if __name__ == "__main__":
root = tk.Tk()
app = App(root)
# This is the mainloop() call. If I include it, the program does not close after
# running the code in App.__init__. Without it, it runs perfectly.
# app.run()
mainloop enters an event listening loop for your tk.Tk() application.
You should create only one object with Tk() in every tkinter application.
Now this loop will "globally" listen for GUI events and will call your registered callbacks (event handlers). Code before the mainloop call will run but nothing will be shown or updated in the screen until you call it. No event (user input, mouse movement, keyboard and others) will be queued and responded to before that. But the widgets are created and configured, just not shown yet. If you call root.update() without ever entering the mainloop you will eventually see the window flash and disappear because everything is running, and you force window refresh, but then suddenly the program ends.
So configure your GUI and in the end always run root.mainloop()
Now when you call wait_window, you are creating a local event loop (and blocking the mainloop if it was running). For a perfect explanation of wait_window by Brian see here
What happened to you is that your app is happily running with your local event loop, but without mainloop. That would be a strange thing to do. Even if you are making as Brian explains, a modal window, you want to "return" to the mainloop after the window closes.
As for the after method it just registers a callback function to run after your choosen time, or after the mainloop becames idle, with after_idle (nothing more to refresh, no events in the queue..., also think as soon as possible). And if you want to re-run that function again in the same way it should re-register with after or after_idle before returning.
So always use your mainloop() ending call - or should I say event loop starting call :)
Edit:
Also, don't do things in your code that are slow, or that may block the loops, such as calling sleep or any other blocking function. That will freeze the GUI, until the block ends.
I am new to PyQT and I have just started learning about it through this video: https://www.youtube.com/watch?v=JBME1ZyHiP8
When I ran the code on my Ubuntu 14.04
import sys
from PyQt4 import QtGui # Always have these two imports
app = QtGui.QApplication(sys.argv)
window = QtGui.QWidget()
window.setGeometry(50,50,500,300)
window.setWindowTitle("PyQt start")
window.show()
The window crated just flashes and closes down. How do I get the window
to stay so that I can interact with it? The code in the Youtube video
above demonstrated it on a Windows platform. Do I have to append anything Ubuntu specific to my code?
You aren't running the app, add this line to the end:
sys.exit(app.exec_())
From the relevant documentation:
int QApplication.exec_ ()
Enters the main event loop and waits until exit() is called, then returns the value that was set to exit() (which is 0 if exit() is called via quit()).
It is necessary to call this function to start event handling. The main event loop receives events from the window system and dispatches these to the application widgets.
Generally, no user interaction can take place before calling exec(). As a special case, modal widgets like QMessageBox can be used before calling exec(), because modal widgets call exec() to start a local event loop.
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.
How can I register a callback for when a Kivy gui is loaded?
In my Kivy app, as soon as the GUI is loaded (aka the window pops up with the initial view), I need to kick off a function that loads expensive data and updates the UI.
So far i've been using the on_start method in App but this runs before the GUI is loaded.
essentially, i want something like $( document ).ready() (from jquery) but for ivy
You could Clock.schedule(some_function, 0) in your build method, I think that would run after everything is initialised but before the next frame.
I am writing a python app using Tkinter for buttons and graphics and having trouble getting a timer working, what I need is a sample app that has three buttons and a label.
[start timer] [stop timer] [quit]
When I press the start button a function allows the label to count up from zero every 5 seconds, the stop button stops the timer and the quit button quits the app.
I need to be able to press stop timer and quit at any time, and the time.sleep(5) function locks everything up so I can't use that.
currently i'm using threading.timer(5,do_count_function) and getting nowhere !
I'm a vb.net programmer, so python is a bit new to me, but hey, i'm trying.
Check the .after method of your Tk() object. This allows you to use Tk's timer to fire events within the gui's own loop by giving it a length of time and a callback method.