PyQt4 window not properly closing with signals and slots, only "x" button - window

As the title suggests, when I create a push button, or a menu option for ending the program, the window doesn't close.
so I'm trying to figure out to end the program and close the window simultaneously. I've been using the tutorial:
http://zetcode.com/tutorials/pyqt4/
which is great otherwise. So how do i connect the push button with ending & closing a widget?
Here is some sample code (copied from the tutorial) that I have been using. I cant seem to get the ending to copy exactly, but I don't think that's the issue anyways:
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
ZetCode PyQt4 tutorial
This program creates a quit
button. When we press the button,
the application terminates.
author: Jan Bodnar
website: zetcode.com
last edited: October 2011
"""
import sys
from PyQt4 import QtGui, QtCore
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
qbtn = QtGui.QPushButton('Quit', self)
qbtn.clicked.connect(QtCore.QCoreApplication.instance().quit)
qbtn.resize(qbtn.sizeHint())
qbtn.move(50, 50)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('Quit button')
self.show()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Thanks!

The code works. I have the same issue, but running it outside IDLE it works. No need to change the code to call the quit method on the QtGui module.

Your app is a QtGui.QApplication, so why are you connecting to the quit signal using QtCore.QCoreApplication? Changing that to QtGui.QApplication.instance().quit works.

replace qbtn.clicked.connect(QtCore.QCoreApplication.instance().quit) with
qbtn.clicked.connect(self.close)
I too faced the same problem (trying to learn Qt4 from the same zetcode tutorials) and came here to look for a solution

Related

Pygame's window opens than closes immediately, why?

When i run this on Pycharm it opens than closes immediately. Whereas in the video tutorial it just stays open, why?
import pygame
pygame.init()
win = pygame.display.set_mode((500, 500))
pygame.display.set_caption("hello")
i am using windows os, python version 3.7.2, and pygame 1.9.4
I don't know which tutorial you talk about, but if the process that created the window finishes, the window will be closed.
E.g. when you create the window via a python shell, the window will stay open as long as the shell is open.
If you open the window via a script (a file), you need to keep the script from finishing. You do this by creating what is called a main loop and usually looks like this:
import pygame
def main():
pygame.init()
win = pygame.display.set_mode((500, 500))
pygame.display.set_caption("hello")
clock = pygame.time.Clock()
while True:
for e in pygame.event.get():
if e.type == pygame.QUIT:
return
win.fill((30, 30, 30))
pygame.display.update()
clock.tick(60)
if __name__ == '__main__':
main()
pygame.quit()
I had the same problem as you (and I was following the same tutorial) and i found that if you enclose the whole thing in a while loop (excluding import pygame, pygame.init() and the variable you use for the while loop) it works quite well.
import pygame
pygame.init()
Game = True
while Game is True:
window1 = pygame.display.set_mode((500, 500))
pygame.display.set_caption("First Game")
I have just started learning Python so this might not be the best way to do it but I hope it helps in some way :)

Gtk+3 Grid Blocking Background Image In Overlay

I've been trying to get into GUI programming with Python on Xubuntu 14.04 by following a few guides like this one here. I wanted to have a background image in my GUI with whatever buttons on top of it. I searched on stackoverflow and came across a person having a similar issue. His solution worked, but the grid filled up the entire window and I can no longer see the background image. How do I fix this? Here is my code:
#!/usr/bin/env python
# -*- coding: utf-8 -*-:
from gi.repository import Gtk #Here we are importing the GTK3 library to use in our program
class mywindow(Gtk.Window):
def __init__(self):
#In the class's constructor, we have to call the constructor of the super class. In addition, we tell it to set
#the value of the property title to Media Manager v1.0
Gtk.Window.__init__(self, title="Media Manager v1.0") #Creates an Empty Window
#use an overlay for the background image
self.overlay = Gtk.Overlay()
self.add(self.overlay)
self.background = Gtk.Image.new_from_file('Background.jpg')
self.overlay.add(self.background)
self.grid = Gtk.Grid()
self.button1 = Gtk.Button(label="Hello")
self.button1.connect("clicked", self.on_button1_clicked)
self.grid.add(self.button1)
self.overlay.add_overlay(self.grid)
#Gtk.Window.set_default_size(self, 400,325)
Gtk.Window.set_position(self, Gtk.WindowPosition.CENTER)
def on_button1_clicked(self, button):
print "Hello"
def on_button2_clicked(self, button):
print "Exiting..."
def main():
window = mywindow()
#connect to the window's delete event to ensure that the application is terminated if we click on the x to close the window
window.connect("delete-event", Gtk.main_quit)
#Display the window
window.show_all()
#Finally, start the GTK+ processing loop which we quit when the winndow is closed.
Gtk.main()
return 0
if __name__ == '__main__':
main()
Pass values for the valign and halign properties when creating the grid and/or the button. The default for these properties is Gtk.Align.FILL which causes them to cover all the space given to them. Instead, pick Gtk.Align.START, Gtk.Align.END, or Gtk.Align.CENTER.

How can I dynamically add actions to a QMenu while it is open on a Mac?

I have QSystemTrayIcon with a QMenu. In order to fill the menu, I need to fetch some things from the network, so I want to do that in the background.
So I have a QThread with a slot that is connected to the activated signal of the tray icon. Then the thread fetches the resources and updates the menu using another signal.
However, these updates do not show until I close and reopen the menu.
This seems to be a Mac specific problem. I ran my code on Windows, and there it updated more or less correctly. Is there any workaround?
Below is an extracted version of the problem. When the menu is opened, it will sleep 1 second in a thread and then change the menu. This change is not seen.
import sys
import time
from PySide import QtCore, QtGui
class PeerMenu(QtGui.QMenu):
def __init__(self):
QtGui.QMenu.__init__(self)
self.set_peers("prestine")
#QtCore.Slot(object)
def set_peers(self, label):
self.clear()
self.addAction(QtGui.QAction(label, self))
self.addSeparator()
self.addAction(QtGui.QAction("Hello", self))
class GUIListener(QtCore.QObject):
files = QtCore.Signal(object)
def __init__(self):
QtCore.QObject.__init__(self)
self.counter = 0
#QtCore.Slot()
def check(self):
time.sleep(1)
self.counter += 1
self.files.emit(str(self.counter))
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
icon = QtGui.QSystemTrayIcon(QtGui.QIcon('images/glyphicons-206-electricity.png'), app)
listener = GUIListener()
t = QtCore.QThread()
t.start()
listener.moveToThread(t)
menu = PeerMenu()
icon.activated.connect(listener.check)
listener.files.connect(menu.set_peers)
icon.setContextMenu(menu)
icon.show()
app.exec_()
After a few hours of extensive googling I finally figured it out.
You can create a borderless window using QtGui.QMainWindow(parent=None, flags=QtCore.Qt.Popup) and then find the location of the icon with icon.geometry().center() and finally move the window there with window.move(icon_point).
There is some hackery involved in deciding how to place the window relative to the icon. Full code can be found at https://github.com/pepijndevos/gierzwaluw/blob/master/gui.py

Run thread in main window for both Windows and Linux

I am creating a game to run inside a GUI (text area, button, menu etc) I've created a GUI with wxpython. I create a panel inside the main window, which runs a pygame thread.
Problem:
On Windows, the pygame thread runs perfectly inside the main window. But on Linux, the pygame pop up on a new window. How can I set this such that both windows and Linux run the thread in the main window?
Code:
class SDLPanel(wx.Panel):
def __init__(self,parent,ID,tplSize):
global pygame
global pygame_init_flag
wx.Panel.__init__(self, parent, ID, size=tplSize)
self.Fit()
if (sys.platform == 'win32'):
os.environ['SDL_WINDOWID'] = str(self.GetHandle())
os.environ['SDL_VIDEODRIVER'] = 'windib'
else:
os.environ['SDL_VIDEODRIVER'] = 'x11'
#here is where things change if pygame has already been initialized
#we need to do so again
if pygame_init_flag:
#call pygame.init() on subsaquent windows
pygame.init()
else:
#import if this is the first time
import pygame
pygame_init_flag = True #make sure we know that pygame has been imported
pygame.display.init()
window = pygame.display.set_mode(tplSize)
self.thread = SDLThread(window)
self.thread.Start()
def __del__(self):
self.thread.Stop()
print "thread stoped"
#very important line, this makes sure that pygame exits before we
#reinitialize it other wise we get errors
pygame.quit()
Solved problem.
In main window we must self.Show()
Idk why in linux the main window must be showed . Same code.
Tks all
This is a disclaimer alert, according to https://forums.libsdl.org/viewtopic.php?p=39332, the solution works only with SDL 1.2 and not 2.0.

Threading wxPython app with background process for multitouch detection

So basically I have some code for multitouch detection and I would like to run it as a separate thread which sends custom events to a wxPython GUI upon a multitouch event.
Now I could post the code for the multitouch tracking but to use it you would require a trackpad, the server app and the detection code, so I think it's better to consider a simple example for the sake of the question.
So for example lets assume an event simulator sending an event every 10 seconds:
import wx
import wx.lib.newevent
import time
MultiTouchEvent, EVT_MULTITOUCH = wx.lib.newevent.NewEvent()
class EventSimulator:
def __init__(self):
self.eventdata = 0
def Start(self):
self.RunTUIO()
def RunTUIO(self):
while True:
time.sleep(10)
wx.PostEvent(GUI, MultiTouchEvent(self.eventdata))
self.eventdata += 1
if __name__ == '__main__':
MultiTouchTracker = EventSimulator()
MultiTouchTracker.Start()
Now I would like to receive these events whenever they occur within a wxPython GUI (something like this):
import wx
class Frame(wx.Frame):
def __init__(self, title):
wx.Frame.__init__(self, None, title=title, size=(350,200))
self.Bind(EVT_MULTITOUCH, self.handler)
def handler(self, event):
data = event.data,
print data
if __name__ == '__main__':
app = wx.App(redirect=False)
window = Frame("My Basic GUI")
window.Show()
app.MainLoop()
The problem is I cannot workout how to combine these two pieces of code into a working example. As I understand it I need to run the event simulator as a separate thread from within the GUI code. Please can someone explain how to do this, thanks!
For details on multi-threading in Python see the docs for the threading module in the stock Python library. There is an example of using it in a GUI in the Threads module in the wxPython demo, although there are other viable approaches as well. (Deriving from the Thread class instead of just using one, etc.) That demo module also shows a convenient way to make a new event class and binder using the wx.lib.newevent module.

Resources