How do I layout, and close this dialogbox in PyQt? - python

I'm writing a Flash Card application using Python and PyQt and I have a problem with dialogboxes. First, here's the section of my code which concerns the aforementioned dialogbox:
def openFile(self):
dialog = QDialog()
dialog.setGeometry(200, 100, 50, 100)
list = QListWidget(dialog)
for file in files:
list.addItem(file.replace('.flashcard', ''))
list.itemClicked.connect(self.listClicked)
dialog.exec_()
def listClicked(self, item):
file_to_read = item.text() + '.flashcard'
self.flashcard_list = FlashCard.read_card(file_to_read)
self.front_text.clear()
self.back_text.clear()
self.front_text.insertPlainText(self.flashcard_list[0].front)
self.back_text.insertPlainText(self.flashcard_list[0].back)
Although I'm using PyCharm, I can't actually debug the code since deubgging these sorts of applications is beyond my skill level. That's why I don't know why when I add codes like dialog.setLayout(layout) to the script, it won't run and it doesn't produce any errors. Also, I would like to know how to close this dialogbox since if I change the dialog to self.dialog to carry it over to another function, the code won't run, again, without producing any errors.
Thanks for your help.

Related

Reload Tkinter application after code change

I am building a relatively large application based on Tkinter. Whenever I make a code change, I have to reload the application manually, and then use the GUI to go back to the desired state.
For instance, if I had open an image in the app before changing the code, and I want to open it again, I have first to open the GUI, select the image from the drop-down list and so on... This is a waste of time. Is there a way to automatically reload the application/GUI after a code change in the last state it was?
This question has been asked a number of times
Proper way to reload a python module from the console
You can use reload(module) for this, but beware of nasty side effects. For example, existing code will be based on the original code, it will not magically get new attributes or baseclasses added.
Another great resource on this would be https://code.activestate.com/recipes/580707-reload-tkinter-application-like-a-browser/
After you've described you're problem a bit further in the comments, I was able to reconstruct the issue better on my end.
Here's my basic implementation for a solution to your issue:
from tkinter import *
import json
application_state = {"background": "white"}
background_colors = ["white", "red", "blue", "yellow", "green"]
def main():
root = Tk()
root.title("Test")
root.geometry("400x400")
reload_state(root)
for color in background_colors:
def change_background_wrapper(color=color, root=root):
change_background(color, root)
Button(root, text=color,command=change_background_wrapper).pack()
root.mainloop()
def change_background(color, window):
print("new color: " + color)
window.configure(bg=color)
application_state["background"] = color
update_config()
def reload_state(window):
config_file = open("config.json")
conf = json.load(config_file)
window.configure(bg=conf["background"])
def update_config():
with open("config.json", "w") as conf:
conf.write(json.dumps(application_state))
if __name__ == "__main__":
main()
In this instance, we're able to update the background color of the GUI and it will persist on each rerun of the script, until it gets manually changed again. You can apply this concept to pretty much any sort of state you have inside your application, I think this should get you started!

PyQt5: Using DeleteOnClose when switching to new window

I am currently creating a GUI in Python 3.7, using PyQt5 and Qt Designer in the Spyder environment. The GUI has many different windows. Basically I am starting with the UI_Start window and then open the next window when a button is pressed. The GUI is working kind of fine, however after approximately 50 windows the program suddenly doesn't show the next window anymore but also doesn't stop the execution. The weird thing about this issue is that:
the exact same window class has been called a lot of times beforehand and there have never been any issues
the problem does not only occur for one window but it can also occur for another window class (but after the same amount of windows being shown)
I tried to figure out why the .show() command is suddenly not working anymore. I used print statements to see where the program "breaks down". I saw that even the print statements after the .show() command are working but then as the window isn't shown I can't press any button to trigger the next event. So basically the program is hanging.
I am relatively new to programming in Python and creating GUIs but I thought that maybe the problem occurs due to memory leak. This is why I am now trying to open memory space when closing a window by using self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True). However, now I am facing the problem that the next window doesn't show up anymore. So how can I use DeleteOnClose if I want to show a new window afterwards?
Also if anyone has a suggestion for the original problem, please let me know. I am trying to figure out the problem since like a week but have not come any further.
Thank you already!
Some part of my code to work with:
class UI_Start(QtWidgets.QMainWindow):
def __init__(self):
super(UI_Start, self).__init__() # Call the inherited classes __init__ method
uic.loadUi('Screen_Start.ui', self) # Load the .ui file
self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True) # added newly
self.Start_pushButton_Start.clicked.connect(self.openKommiScreen)
def openKommiScreen(self):
self.close()
self.KommiScreen = UI_Kommi(self)
class UI_Kommi(QtWidgets.QMainWindow):
def __init__(self, parent = None):
super(UI_Kommi, self).__init__(parent)
uic.loadUi('Screen_Kommi.ui', self)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
global sheetNo
sheetNo = 1
self.WeiterButton = self.findChild(QtWidgets.QPushButton,'pushButton_Weiter')
self.WeiterButton.clicked.connect(self.openScanScreen)
self.show()
def openScanScreen(self):
self.close()
self.ScanScreen = UI_Scan(self)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = UI_Start()
window.show()
sys.exit(app.exec_())
At first I would guess it's a garbage collection problem. The only reference to your new window is stored in your previous one. Which is deleted, so there is no more reference to your window object and python may delete it automatically.
In these cases I often goes for a global variable to store the current windows references.

pyside widget.show not blocking

I wrote a little application, that saves small videos it generates. The code pasted should do the following:
show dialog to the user to choose a directory
if directory is not empty show widget that has a circle running around so there's a feedback that something is going on
then generate the movies (which takes some time and most if it has handled with multiprocessing pool)
(not included in snippet, but the code would go on to do more background stuff, so the loading widget would stay on for a while
Code:
def saveMovie(self):
self.pause()
if not os.path.exists("outputs"):
os.makedirs("outputs")
dir = QtGui.QFileDialog.getExistingDirectory(self,dir="outputs",options=QtGui.QFileDialog.ShowDirsOnly)
if not dir == '':
self.loading = True
self.loadingWidget.show()
name = os.path.basename(dir) + "_"
settings = sm.fetch_settings()
swarms,l,l1,l2 = self.generate_movies()
Now instead of this, what happens is that the dialog disappears and the loading widget is shown only after the program has existed from self.generate_movies(). What am I missing?

Multiple windows in PyQt4?

I've just begun using pyqt4. I followed a tutorial (http://zetcode.com/tutorials/pyqt4/)
One thing that puzzles me is this part:
def main():
app = QtGui.QApplication(sys.argv)
ex = GUI()
sys.exit(app.exec())
And the reason for this I explain here:
I have made a small program that opens four more windows except for the first main window.
So I tried to replicate what I saw worked with main-window and created a class for every new window and tried to do like with the above. Currently it looks like this:
def main2():
#app = QtGui.QApplication(sys.argv)
ex2 = Settings()
sys.exit(app.exec())
As you can see I have modified it. If I left the first line in the function uncommented the program would crash. I tried to do without the sys.exit(app.exec_())-part but that would only make the new window close milliseconds after it showed.
This way though, everything runs and works. Only that in the command window, an error message displays. I don't know how to fix this, since I cannot remove the last line, and I dont't know what to replace "app" with.
I know I'm probably doing the new windows wrong from the beginning, but I don't know how to make these windows open from the original window in any other way. I haven't been able to get anything else to work, and this at least runs and works right now. So the only problem is error messages in the prompt, it would be nice to get rid of them :)
Thanks for any help (complicated and easy ones)!
Forgot to mention, I made the classes start like this:
class GUI(QtGui.QMainWindow):
def __init__(self):
super(GUI, self).__init__()
self.initUI()
and
class Settings(QtGui.QWidget):
def __init__(self):
super(Settings, self).__init__()
...here goes some more...
self.initUI2()
and I open Settings-window by calling main2()
You must create one and only one QApplication in your program.
Keep in mind that GUI programming is event-driven, you first declare widgets and then run the main loop with app.exec(), when the user quit your application, app.exec() returns.
The QApplication purpose is to handle user events and propagate them to your code with Qt signals. I suggest you check Qt documentation, it's very complete, even if it's targetting C++ programmers.
So for instance, a way to create two widgets would be:
def main():
app = QtGui.QApplication(sys.argv)
ex = QtGui.QWidget()
ex.show()
ex2 = QtGui.QWidget()
ex2.show()
sys.exit(app.exec())

Adding a program icon in Python GTK

I know this is very simple, just use the command self.set_icon_from_file("icon.png"), however my program still does not display the icon. I made sure the icon.png is in the same working directory as the Python file. I also tried giving the complete file path, but still it does not display the icon.
I am using Ubuntu 10.10 if that helps and using Python V2.6. I use Glade Interface Designer to design the GUI. However, I tried setting the icon both using Glade and using the command above.
I hope I have provided sufficient information.
EDIT: I got the status icon to work in my program.. However in the question I meant the program icon displayed in the task bar and also on the left side of the application bar.
I made sure the icon.png is in the same working directory of the python file.
This may be your problem — paths are looked up relative to the working directory of the Python interpreter, not the file containing the code. I often find myself defining a function like:
def get_resource_path(rel_path):
dir_of_py_file = os.path.dirname(__file__)
rel_path_to_resource = os.path.join(dir_of_py_file, rel_path)
abs_path_to_resource = os.path.abspath(rel_path_to_resource)
return abs_path_to_resource
Mine isn't actually quite that verbose, but hopefully the variable names make it clear what's going on. Also, getting the absolute path isn't strictly necessary, but might help if you need to debug.
Then you can just do:
self.set_icon_from_file(get_resource_path("icon.png"))
Update: Here is a demo program. "icon.png" is in the same directory as this script, and I run it using ./gtktest.py. I see the icon in the top left corner (standard place for my theme). icon.png is just a shape drawn in Inkscape and exported as a bitmap (it works with the original SVG too, anyway).
#!/usr/bin/env python
import pygtk
pygtk.require('2.0')
import gtk
class HelloWorld:
def delete_event(self, widget, event, data=None):
return False
def destroy(self, widget, data=None):
gtk.main_quit()
def __init__(self):
# create a new window
self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.set_icon_from_file('icon.png')
self.window.connect("delete_event", self.delete_event)
self.window.connect("destroy", self.destroy)
# Creates a new button with the label "Hello World".
self.button = gtk.Button("Hello World")
self.window.add(self.button)
self.button.show()
self.window.show()
def main(self):
gtk.main()
if __name__ == "__main__":
hello = HelloWorld()
hello.main()
I am not sure what icon you are creating, but try this smallest PyGTK icon-showing example of taskbar icon I have thought of:
#!/usr/bin/env python
import pygtk
pygtk.require('2.0')
import gtk
# create icon object
statusIcon = gtk.StatusIcon()
# load it
statusIcon.set_from_file("icon.ico")
# show it
statusIcon.set_visible(True)
# and run main gtk loop
gtk.main()
Maybe you just missed the command statusIcon.set_visible(True)
For standard icons, use stock items, and find icons that suits your needs. that way
You don't have to pack icons whith your program
The icons change
according to the user's theme and will blend nicely in her
environment.
for pyGTK :
gtk.icon_theme_get_default().load_icon("folder-open", 128, 0)

Categories