[ Foro de Python ]

Abrir ventana desde función con PyQt

22-Jul-2016 12:44
Guillermo Molleda Jimena
4 Respuestas

Buenos días:

Estoy empezando a aprender Python con pyQt y al crear una segunda ventana me sale vacía y no la que yo creo con QDialog.
Ya he creado una QMainWindows que funciona bien.
Desde el menú llamo a una función para crear una QDialog pero abre uno nuevo en vez del creado por mi.
Fichero principal MiPrograma.py:

 
#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
import sys
from PyQt4 import QtGui
from ventana1 import *
 
if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    myapp = LaVentana(None)
    myapp.show()
    sys.exit(app.exec_())
 
Fichero ventana1.py con la ventana QMainWindows:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
import sys
from PyQt4 import QtGui
from ventanaMenus import *
from MiVentanita import *
 
class LaVentana(QtGui.QMainWindow):
	def __init__(self, parent=None):
		# creada una ventana QMainWindow con QT-Designer, 
		# exportado con pyuic4 ventanaMenus.ui > ventanaMenus.py
		# o pyuic4 -o ventanaMenus.py ventanaMenus.ui
		# o pyuic4 -x ventanaMenus.ui -o ventanaMenus.py
		# -x para generar código extra para test y ver la clase al ejecutar
		QtGui.QMainWindow.__init__(self, parent)
		self.ui = Ui_MainWindow()
		self.ui.setupUi(self)
		self.setWindowTitle(u"¡Qué título!")
		self.cambiaboton()
		# self.connect(self, SIGNAL("lastWindowClosed()"), self.adios) # No funciona
		self.ui.actionNuevo.triggered.connect(self.hola)
		self.ui.actionAbrir.triggered.connect(self.abrete)
		self.ui.actionSalir.triggered.connect(self.adios)
		self.ventanuco = None # si no es global, se destruye si usas show()
 
	def cambiaboton(self):
		self.ui.actionNuevo.setText("hola")
 
	def hola(self):
		if self.ui.actionAbrir.text() == u"Abrir":
			self.ui.actionAbrir.setText(u"Sésamo")
		#else:
		#   print (u'Pulsaste el botón hola')
		# return
 
	def abrete(self):
		self.ventanuco = LaVentanita(self)
		self.ventanuco.exec_() # Modal: Bloquea resto ventanas hasta cerrarse.
		#self.ventanuco.show() # Modal si llamas a setModal(true)
 
	def adios(self):
		self.close() # cierra la ventana
		# sys.exit() # cierra el programa
		# QtGui.QApplication.quit() # sale del programa
 
 
if __name__ == "__main__":
    pass
 


Obviamente tengo dos ficheros salidos de QDesigner y pyuic4: ventanaMenus.py y ventanita.py
Y por último el fichero MiVentanita.py para desarrollo de la ventana definida en ventanita.py:

 
#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
import sys
from PyQt4 import QtGui
from ventanita import *
 
class LaVentanita(QtGui.QDialog):
	def __init__(self, parent = None):
		# creada una ventana QDialog con QT-Designer, 
		# exportado con pyuic4 ventananita.ui > ventanita.py
		# o pyuic4 -o ventananita.py ventananita.ui
		# o pyuic4 -x ventananita.ui -o ventananita.py
		# -x para generar código extra para test y ver la clase al ejecutar
		QtGui.QDialog.__init__(self, parent) # o super(LaVentanita, self).__init__(parent)
		self.ventana = QtGui.QDialog(parent)
 
		self.ui = Ui_Dialog()    
		self.ui.setupUi(self.ventana)
		#self.ventana.setWindowTitle("Esta ventanita")
		self.ui.buttonBox.button(QtGui.QDialogButtonBox.Ok).clicked.connect(self.MiBotonAceptar)
		self.ui.pushButton.clicked.connect(self.PulsaPushButton)
 
	def MiBotonAceptar(self):
		self.ui.buttonBox.button(QtGui.QDialogButtonBox.Cancel).setText(u"Cancélate")
 
	def PulsaPushButton(self):
		pass	
 
if __name__ == '__main__':
	pass
 


¿Qué falla para que no parece ejecutarse nada de la segunda ventana? Simplemente aparece una ventana vacía como si se creara nueva de la nada.
También sale un segmentation fault tras cerrar la aplicación en el caso de haber creado tal segunda ventana.


23-Jul-2016 08:42
Guillermo Molleda Jimena

Ya lo conseguí ayer, comprobé que salía vacía incluso ejecutando directamente el fichero .py y aprendí que cuando separas las ventanas en ficheros y clases distintas, se les debe poner su función de show() en el constructor de la clase y no desde donde la llamas. Es decir, que al hacer el show() estaba creando la ventana antes de definirla y por eso aparecía vacía.
Así la ventana se llama y se crea desde la función de otra clase simplemente con:

 
self.ventanuco = LaVentanita(self)
 


Y el constructor de la ventanita sería:

 
class LaVentanita(QtGui.QDialog):
 def __init__(self, parent = None):
  # creada una ventana QDialog con QT-Designer, 
  # exportado con pyside-uic ventananita.ui > ventanita.py
  # o pyside-uic -o ventananita.py ventananita.ui
  # o pyside-uic -x ventananita.ui -o ventananita.py
  # -x para generar código extra para test y ver la clase al ejecutar
  QtGui.QDialog.__init__(self, parent) # o super(LaVentanita, self).__init__(parent)
 
  self.ventana = QtGui.QDialog()
  self.ui = Ui_Dialog()    
  self.ui.setupUi(self.ventana)
  self.ventana.setWindowTitle("Esta ventanita")
  self.ui.buttonBox.button(QtGui.QDialogButtonBox.Ok).clicked.connect(self.MiBotonAceptar)
  self.ui.pushButton.clicked.connect(self.PulsaPushButton)
  self.ventana.show() # por último se enseña tras haberla creado.
 


Saludos.


23-Jul-2016 08:54
Guillermo Molleda Jimena

Vaya, he cambiado las tabulaciones por espacios y sigue perdiendo la sangría, sería bueno que en preguntas frecuentes pusieran información de cómo poder escribir un fragmento de código sin perder sangrías ni nada, que salga el texto tal cual.


23-Jul-2016 16:58
Nacho Cabanes (+32)

Enhorabuena, Guillermo. Yo no habría podido ayudarte, porque apenas he usado PyQt.

Para enfatizar el código (y que entonces se vea con colores y con todos sus espacios) basta incluirlo dentro una etiqueta "code", así:

 
[code python]
 


(Y terminarías con /code).


 


23-Jul-2016 17:52
Guillermo Molleda Jimena

Gracias, para redondear:
1.- He cambiado donde pone PyQt4 por PySide que es un clon prácticamente idéntico pero desarrollado y mantenido por los mismos que hicieron QT.

2.- La ventana que se abre se puede quedar abierta incluso cerrando la ventana principal, depende de lo que pongamos en el constructor de la ventanita segunda:
con self.ventana = QtGui.QDialog() # se queda abierta independientemente de la principal
self.ventana = QtGui.QDialog(parent) # se queda dependiendo, como hija (child), de la principal y se cierra si la principal se cierra.

3.- Si queremos que la ventanita segunda deje sin interacción la principal, que no podamos usar la principal mientras no cerremos la ventanita, entonces hacerla modal añadiendo antes de self.ventana.show() la función self.ventana.setModal(True):

 
        self.ventana.setModal(True) # solamente esta ventana activa en el programa, por ejemplo para elegir y modificar opciones del programa.
        self.ventana.show()
 






(No se puede continuar esta discusión porque tiene más de dos meses de antigüedad. Si tienes dudas parecidas, abre un nuevo hilo.)