PyQt: custom widget appearing along with main window - python

I have created a main GUI and coded in a single file called one.py. There is a need to call a custom GUI/widget in from the main script. The second custom GUI/widget is created with qt designer and the working script is called second.py.
It works fine when I execute second.py. The second GUI must be triggered when a variable from one.py changes. The GUI pops up fine as expected when variable is change in one.py. However, along with the second GUI, the next widget from one.py also shows as well. The example script of one.py looks like this:
if variable:
self.child_win = PersistenceGui(self)
self.child_win.show()
QtGui.QMessageBox.information("Some info to the users.")
In the above case, the child window and info box are shown together. But I want Info box to be shown only after closing the child window/GUI box. Where am I making a mistake?

Make PersistenceGui a subclass of QDialog, and then show it like this:
self.child_win.exec_()
This will block until the user closes the dialog, and then the message-box will be shown.
EDIT:
If you want to know if the user cancelled the dialog, then try this:
if self.child_win.exec_() == QtGui.QDialog.Accepted:
QtGui.QMessageBox.information("Some info to the users.")
else:
# ask if user wants to close main window, or whatever...

Related

Python Tkinter GUI application query

I have built a Python tkinter GUI application which is an application for running different tasks. The application window is divided into 2 halves horizontally, first half shows the options the user can choose for the selected menu option and second half shows the progress of the task by showing the log messages. Each task has a separate menu option, the user selects the menu option and first half is refreshed with user option along with a Submit button.
The GUI is built using the object oriented method where each task in the menu option is an class method of the GUI object.
I now have about 5-6 menu options and working fine but the code size is becoming huge and it is becoming hard to debug any issue or add new features.
Is there any way to write the method of a class in separate file which can be called from within the main class. The logging of messages in the GUI is written in the main class so if the method is written in a separate file the how will the log messages written in the other file appear in the main window.
Please suggest alternatives.
This might not help you completely, but this is what I use. I divide my tkinter code into 2 files. First gui.py contains the GUI components (widgets) and the second methods.py contains the methods.
Both the files should be in same directory.
Here is an example of a simple app that changes the label on a button click. The method change() is stored in a different file.
gui.py
from tkinter import *
from tkinter import ttk
from methods import change #Using absolute import instead of wildcard imports
class ClassNameGoesHere:
def __init__(self,app):
self.testbtn = ttk.Button(app,text="Test",command = lambda: change(self))
#calling the change method.
self.testbtn.grid(row=0,column=0,padx=10,pady=10)
self.testlabel = ttk.Label(app,text="Before Button Click")
self.testlabel.grid(row=1,column=0,padx=10,pady=10)
def main():
root = Tk()
root.title("Title Goes Here")
obj = ClassNameGoesHere(root)
root.mainloop()
if __name__ == "__main__":
main()
methods.py
from tkinter import *
from tkinter import ttk
def change(self):
self.testlabel.config(text="After Button Click")

Closing Python Tkinter window mainloop without a button

I would like to refresh a python Tkinter window every 1 seconds :
animation=TFS(test) #animation is a list, each item in the list is a table with drawing input information.
for item in animation:
Display(item) #display function is creating a Tkinter window with a mainloop
time.sleep(1)
The only solution about closing a mainloop for Tkinter that i found on the internet, is by using .quit() or .destroy() in a button.
But I don't want the user to close the window manually, the window should be closed automatically every x second in order to be able to display a new window with updated information.
Note : the display is made of about 2 hundreds rectangles and labels.
The .destroy() method can be called anywhere in the code, not necessarily when button is pressed. To close the window, it has to be called on Tk object (main window, the first one you created). But, like #Billal BEGUERADJ said, you don't need to close the window to refresh widgets inside it. Just call .config() method on the widget you'd like to modify and pass options you'd like to change as arguments.
The display in the canva is procedural with hundreds of shapes, so the .configure seems hard to used.
So i deleted the .mainloop() in the function Display and replaced it by :
TK.update()
time.sleep(RefreshTime)
TK.destroy()
return
and changed the main code to the following :
animation=TFS(test)
for step in animation:
Display.display(step,RefreshTime)

Python Tkinter - How do I change variables from outside the main window class?

Now i understand the concept of instance variables and classes, I've never had a problem with them before and I use them frequently. However when I make my MainWindow class, everything is peachy until i try accessing instance variables.
http://pastebin.com/tDs5EJhi is the full code, but at this point it's just placing labels and frames and whatnot, no actual logic is going on. The window looks fine and nothing bad happens.
My question comes to be when I try changing things inside of the window externally. I figured I could just make an instance of the class and change variables from there (namely instancevariable.ImageCanvas.itemconfig()) like i can normally, but Tkinter isn't being nice about it and I think it's a result of Tkinter's mainloop().
Here's the tidbit of my class MainWindow() that i'm having trouble with (ln 207)
...
self.C4 = Tk.PhotoImage(file="temp.png")
self.card4 = self.CardCanvas.create_image(120,46,image=self.C4, state=Tk.NORMAL)
#self.CardCanvas.itemconfig(4, state=Tk.HIDDEN) # < It works here
...
self.root.mainloop()
window = MainWindow()
window.CardCanvas.itemconfig(4, state=Tk.HIDDEN) # < It doesn't work here
That's how i learned how to edit instance variables. When the window pops up, the itemconfig command doesn't actually apply like it would were it inside the class (or maybe it did and the window just didn't update?) and after closing the window I get this error:
_tkinter.TclError: invalid command name
which I assume is just because it's trying to apply a method to variables that don't exist anymore, now that the window has closed.
So I guess here's my big question - I have a MainWindow class, and from what I can tell, nothing can be changed from outside of the class because the Tk.mainloop() is running and won't stop to let other code after it run, like the itemconfig. How do I go about changing those variables? Code after the instance variable declaration doesn't seem to run until the MainWindow() is closed.
You are correct that code after mainloop doesn't run. It does, but only after the GUI has been destroyed. Tkinter is designed for the call to mainloop be the last (or very nearly last) line of executable code. Once it is called, all other work must be done as reaction to events. That is the essence of GUI programming.
The answer to "how do I go about changing the variables" is simple: do it before you call mainloop, or do it in reaction to an event. For example, do it in a callback to a button, do it in a function bound to an event, or to a time-based event via after, and so on.

Black empty window Kivy

I made GUI for my program. When I launch app, then it appears empty black screen.
This isn't completed program, but I expect a working application.
Python code: http://pastebin.com/RbMKAd9t
Kivy interface: http://pastebin.com/12eHp0y4
I infer that your kv file is called interface.kv, and you load it only with Builder.load_string. In this case the problem is that Builder.load_string doesn't return anything because there is no root widget definition (i.e. without the <>) in the file.
Add a root widget definition, or change the build method to return Main().

Destroyed about dialog doesn't reappear properly

I'm working on a GUI application in Python / Glade, and have the following issue.
I am trying to get an About dialog properly working...however when I click 'Close' (in the About dialog) and then attempt to open it again, this is all I see:
So, just a tiny little snippet of the window, and a non-functioning close button.
This is my class for my Glade window:
# glade object
class MainWindow(object):
builder_ = None
# load main window
def __init__(self):
handler = {
"sigWindowDestroy" : gtk.main_quit,
"sigShowAbout" : self.show_about
}
projfile = "proj.glade"
self.builder_ = gtk.Builder()
self.builder_.add_from_file(projfile)
self.builder_.connect_signals(handler)
window = self.builder_.get_object("main_window")
window.show()
# show about dialog
def show_about(self, *args):
dAbout = self.builder_.get_object("dAbout")
dAbout.run()
dAbout.destroy()
And in my main function:
# load glade gui
app = MainWindow()
gtk.main()
On the second click, I see the following output in my terminal window (using Mac OS X).
GtkWarning: gtk_widget_show: assertion `GTK_IS_WIDGET (widget)' failed
dAbout.run()
GtkWarning: gtk_label_set_markup: assertion `GTK_IS_LABEL (label)' failed
dAbout.run()
Edit: sorry, must reopen for general unfamiliarity with PyGTK.
I've used the show()/hide() methods instead of run()/destroy() as proposed. Now, I was following along with another SO post, which highlighted this tutorial (who said to use run()/destroy()), and am seeing this behavior.
First, the Close button does nothing. I had thought for some reason its behavior was pre-defined.
Second, closing the dialog with the corner close button still provides the same behavior that I see with run()/destroy() as above.
Edit 2: Solved by adding the following:
dAbout.connect("response", lambda d, r: d.hide())
Don't try to (deep-)copy a widget. It doesn't work, as you found out.
Instead, hide() the dialog instead of destroy()ing it.
You could have even used run(). You just shouldn't use destroy(). What made you think, you shouldn't use run() and hide() together? See, when you destroy a widget, that means removing it from memory as if it never had been build. If you hide it, you can reuse it later, but take care of changes a user might have done to it, as the window will re-appear in the state it was in before being hidden. You can manipulate a widgets properties from code while hidden.
The "predefined" action of your close button was caused by run(). The solution you posted, using the lambda function is little more than what run() does for you. Basically it does the following:
Connect the "response" signal of your DialogWindow
Connect the "delete-event" signal of your DialogWindow
Start a new Gtk main loop to block the application
Show your widget
Disconnect the signals
Return the response
You just need to hide() it afterwards and are able to run() it again.

Categories