closing qDialog (if exists) in pySide - python

I created a UI in designer, converted it to python using pyside-uic and then following a tutorial I did this:
from PySide import QtCore, QtGui
import mirroratorUI as customUI
#import mirroratorCore as mirroratorCore
from shiboken import wrapInstance
import maya.OpenMayaUI as omui
reload(customUI)
def maya_main_window():
main_window_ptr = omui.MQtUtil.mainWindow()
return wrapInstance(long(main_window_ptr), QtGui.QWidget)
class ControlMainWindow(QtGui.QDialog):
def __init__(self, parent=None):
super(ControlMainWindow, self).__init__(parent)
self.setWindowFlags(QtCore.Qt.Tool)
self.ui = customUI.Ui_MainWindow()
self.ui.setupUi(self)
myWin = ControlMainWindow(parent=maya_main_window())
myWin.show()
The UI will be used into Maya, and it appears, but if I open it 3 times, I will have 3 dialgos. I remember there is a way to check if the dialog already exists, and if it does, deleting it. I found some info on google but I either didn't understand how to sue those info or they were not fit to my case...
Many thanks for your help,
Daniele

Please try the below code.
global myWin
try:
myWin.close()
except:
pass
myWin = ControlMainWindow(parent=maya_main_window())
myWin.show()
The above code just finds out whether the windows exists and if it exists it will close and creates the window as usual.

Related

PyQt5 Getting second screen functions to work

how are you doing?
I have been coding for a couple months. I started with Python, now I am trying to learn PyQt5.
I have created two windows using the Designer Tool. I created a subclass for each specific page, so that it wont mess up my software once i make changes in the Designer.
I managed to make my second window open from the first window. It works well. However, nothing works in window 2 when its opened by window 1. However, when i run window 2 by itself, it does not work.
I am sure it is a inheritance problem that I am messing up. It seems my sofware is inheriting the window 2 layout but not its functions.
I have attached the code. Is it possible for someone to help me out? If possible, i would like a brief explanation on how to fix it too. I want to learn so I can teach others as well.
This is my main window:
from nonregusrscreen1 import NonReg
from Main import Ui_MainWindow # needs to import from the main file
from PyQt5 import QtCore, QtGui, QtWidgets #importing PyQt functionality
class mainWin(QtWidgets.QMainWindow, Ui_MainWindow): #mainWin is new subclass. QtWidgets.Whatever the window was / you need to get inheritance from Ui_MainWindow, otherwise you wil lahve to use self.ui.pushbutton....
def __init__(self, *args, **kwargs): #passing arguments from whatever was called
super().__init__(*args, **kwargs)
self.ui = Ui_MainWindow()
self.setupUi(self)
self.pushButton_2.clicked.connect(self.openwindow) # you have to include UI, otherwise it will not work.
def openwindow(self):
self.window = QtWidgets.QDialog()
self.ui = NonReg()
self.ui.setupUi(self.window)
self.window.show()
if __name__ == '__main__':
app = QtWidgets.QApplication([])
w = mainWin()
w.show()
app.exec_()
This is my second window, here you can see the pushbutton_2 function that only works when the file is opened by itself (not opened using the first window)
from nonregusrscreen import Ui_NonRegUserScreen
from PyQt5 import QtCore, QtGui, QtWidgets
class NonReg(QtWidgets.QDialog, Ui_NonRegUserScreen):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.ui = Ui_NonRegUserScreen
self.setupUi(self)
self.pushButton_2.clicked.connect(self.closewindow)
def closewindow(self):
self.window = exit()
if __name__ == '__main__':
app = QtWidgets.QApplication([])
w = NonReg()
w.show()
app.exec_()
Thank you, i truly appreciate your help.

Image copied to clipboard doesn't persist on Linux

I'm trying to save an image to the system clipboard, so I wrote some code like this:
#!/usr/bin/python3
from PyQt5.Qt import QApplication
from PyQt5.QtWidgets import QWidget, QPushButton
from PyQt5.Qt import QImage
import sys
class MyWidget(QWidget):
def __init__(self):
super(MyWidget, self).__init__()
self.button = QPushButton(self)
self.button.clicked.connect(self.copyPicToClip)
def copyPicToClip(self):
image = QImage('./test.jpg')
QApplication.clipboard().setImage(image)
self.close()
if __name__ == '__main__':
a = QApplication(sys.argv)
myW = MyWidget()
myW.show()
a.exec()
Sadly, I found it doesn't work at all. Then I tried to find a solution. The first thing I tried was this:
def copyPicToClip(self):
image = QImage('./test.jpg')
QApplication.clipboard().setImage(image)
# self.close()
After this, I just found that it worked, but the window does not close automatically.
Then I tried with copying text:
#!/usr/bin/python3
from PyQt5.Qt import QApplication, QClipboard
from PyQt5.QtWidgets import QWidget, QPushButton
from PyQt5.Qt import QImage
import sys
class MyWidget(QWidget):
def __init__(self):
super(MyWidget, self).__init__()
self.button = QPushButton(self)
self.button.clicked.connect(self.copyPicToClip)
QApplication.clipboard().dataChanged.connect(self.testFunc)
def copyPicToClip(self):
image = QImage('./test.jpg')
QApplication.clipboard().setImage(image)
def testFunc(self):
print('Here')
self.close()
if __name__ == '__main__':
a = QApplication(sys.argv)
myW = MyWidget()
myW.show()
a.exec()
Sadly, it failed again.
So, it seems that if I close the application to early, the image won't be saved to the clipboard. But I want to close it after copying the image to the clipboard.
Any suggestions?
(PyQt5, ubuntu 16.10, if helps).
Unfortunately for you, this is "normal" behaviour on Linux. By default, clipboard data is not persisted when an application closes. The usual work-around for this problem is to install a clipboard manager. For Ubuntu, see this wiki article for more details:
Ubuntu Wiki: Clipboard Persistence
(NB: I have not actually tested any of the suggested solutions myself, so I don't know whether any of them will work with PyQt).
The basic problem is that on Linux, the clipboard only stores a reference to the underlying data. This is very efficient in terms of storage, because the data is only copied when the client program actually requests it. But of course if the source application closes, the reference will be invalidated, and the clipboard will become empty.

Is it possible to have PySide's QUIloader act like PyQt's uic.loadUi? [duplicate]

This question already has an answer here:
How do I load children from .ui file in PySide?
(1 answer)
Closed 12 months ago.
So I have an application where I'm considering moving from PyQt4 to PySide. In this application, I use .ui files pretty frequently, with the following usage pattern:
class BaseGUIWidget(QWidget):
def __init__(self, parent = None, ui_file = None):
'''
:param parent: parent widget of this widget
:param ui_file: path to UI file to load (optional)
'''
super(BaseGUIWidget, self).__init__(parent)
if ui_file is not None:
uic.loadUi(ui_file, self)
Let's assume I have similar classes for QFrame, QMainWindow, QGroupBox, etc.
This allows me to create python classes that use the data from the UI file, as well as any additional functionality I add manually in the code. Essentially, my BaseGUIWidget class acts as if it was extending the class generated by the UI file. A lot of the functionality in the application is pretty reliant on this behavior.
However, from what I can tell, PySide's QUIloader doesn't have a similar functionality. Instead of 'shimming' the UI file's contents into your class, it simply builds a widget from the UI file internally, then returns it, and you then embed it into your widget in a layout like you would any other widget., I.E:
class BaseGUIWidget(QWidget):
def __init__(self, parent = None, ui_file = None):
'''
:param parent: parent widget of this widget
:param ui_file: path to UI file to load (optional)
'''
super(BaseGUIWidget, self).__init__(parent)
self.setLayout(QVBoxLayout())
if ui_file is not None:
loader = QUILoader()
uifile = QFile(ui_file)
uifile.open(QFile.ReadOnly)
self.ui_widget = loader.load(ui_file, self)
self.layout().addWidget(self.ui_widget)
uifile.close()
This is a pretty massive difference. If, for example, you wanted your UI file to contain a QMainWindow and your python class to still be an extension of QMainWindow so it acts like one to other classes, you'd wind up with a QMainWindow inside a QMainWindow, which isn't what you want. It also means you have to do widget.ui_widget.XXX to access the widgets produced by the UI file.
Is there any way to make PySide's uic implementation act like PyQt's?
use QtPy package
pip3 install QtPy
it autodetect used binding(pyqt5 or pyside2)
from QtPy import uic # and all other QT modules
w = uic.loadUi("mywidget.ui")
w.show()
Yes it is possible.
I know it is old question, but suddenly someone will come in handy.
I found this solution on:
https://robonobodojo.wordpress.com/2017/10/03/loading-a-pyside-ui-via-a-class/
ui_loader.py:
#!/usr/bin/env python
from PySide.QtUiTools import QUiLoader
from PySide.QtCore import QMetaObject
class UiLoader(QUiLoader):
def __init__(self, base_instance):
QUiLoader.__init__(self, base_instance)
self.base_instance = base_instance
def createWidget(self, class_name, parent=None, name=''):
if parent is None and self.base_instance:
return self.base_instance
else:
# create a new widget for child widgets
widget = QUiLoader.createWidget(self, class_name, parent, name)
if self.base_instance:
setattr(self.base_instance, name, widget)
return widget
def load_ui(ui_file, base_instance=None):
loader = UiLoader(base_instance)
widget = loader.load(ui_file)
QMetaObject.connectSlotsByName(widget)
return widget
example:
#!/usr/bin/env python
from PySide import QtGui
from ui_loader import load_ui
import sys
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
load_ui('my_interface.ui', self)
def main():
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec_()
if __name__ == '__main__':
main()
Actually I was wondering about the same thing and just tried this:
Copy the uic package from a PyQt4 installation to your PySide package(its all python modules, no compiled libraries, so there should not be any incompatibilities)
Do a search & replace on the uic package, replacing "PyQt4" with "PySide"
Use it:
from PySide import uic
w = uic.loadUi("mywidget.ui")
w.show()
It also worked for me with the use case you describe (uic.loadUi(ui_file, self)) :)
Of course there is no guarantee that everything will work, but I was surprised that this hack made it work.

Open a GUI file from another file PyQT

I've created many GUI interfaces in PyQT using QT Designer, but now I'm trying to open an interface from another one, and I don't know how to do it..
Start.py is the file which run the GUI Interface Authentification_1 and Acceuil_start.py is the file which run the GUI interface Acceuil_2.py, now I want from Start.py to lunch Acceuil_start.py.
Do you have any idea about that ? Thank you.
Here's my code :
Start.py :
import sys
from PyQt4 import QtCore, QtGui
from Authentification_1 import Ui_Fenetre_auth
from Acceuil_2 import Ui_MainWindow #??? Acceuil_2.py is the file which I want to open
class StartQT4(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_Fenetre_auth()
self.ui.setupUi(self)
def authentifier(val): #Slot method
self.Acceuil = Acceuil() #???
self.Acceuil.show() #???
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp = StartQT4()
myapp.show()
sys.exit(app.exec_())
Acceuil_start.py
import sys
from PyQt4 import QtCore, QtGui
from Authentification_1 import Ui_Fenetre_auth
from Acceuil_2 import Ui_MainWindow
class StartQT4(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp = StartQT4()
myapp.show()
sys.exit(app.exec_())
First, you should to name your GUI classes so they have a different name, and not the generic one, so you could distinct them.
Why you would need to do that? Well - simply, because it makes sense - if every class is representing different type of dialog, so it is the different type - and it should be named differently. Some of the names are/may be: QMessageBox, AboutBox, AddUserDialog, and so on.
In Acceuil_start.py (you should rename class in other module, too).
import sys
from PyQt4 import QtCore, QtGui
from Authentification_1 import Ui_Fenetre_auth
from Acceuil_2 import Ui_MainWindow
class Acceuil(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp = Acceuil()
myapp.show()
sys.exit(app.exec_())
in the parent class, when you want to create the window, you are close (but it should work in any case):
def authentifier(val): #Slot method
self.Acceuil = Acceuil(self) # You should always pass the parent to the child control
self.Acceuil.show() #???
About parent issue: If your widget/window is creating another widget, setting creator object to be parent is always a good idea (apart from some singular cases), and you should read this to see why is that so:
QObjects organize themselves in object trees. When you create a QObject with another object as parent, it's added to the parent's children() list, and is deleted when the parent is. It turns out that this approach fits the needs of GUI objects very well. For example, a QShortcut (keyboard shortcut) is a child of the relevant window, so when the user closes that window, the shorcut is deleted too.
Edit - Minimal Working Sample
To see what I am trying to tell you, I've built a simple example. You have two classes - MainWindow and
ChildWindow. Every class can work without other class by creating separate QApplication objects. But, if you import ChildWindow in MainWindow, you will create ChildWindow in slot connected to singleshot timer which will trigger in 5 seconds.
MainWindow.py:
import sys
from PyQt4 import QtCore, QtGui
from ChildWindow import ChildWindow
class MainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
QtCore.QTimer.singleShot(5000, self.showChildWindow)
def showChildWindow(self):
self.child_win = ChildWindow(self)
self.child_win.show()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp = MainWindow()
myapp.show()
sys.exit(app.exec_())
ChildWindow.py:
import sys
from PyQt4 import QtCore, QtGui
class ChildWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setWindowTitle("Child Window!")
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp = ChildWindow()
myapp.show()
sys.exit(app.exec_())
To reference the other dialog from Start.py, you must prefix it by the module name, which in this case is Acceuil_start. As such, it is OK if there are duplicated function names in each module. So, you would have:
def authentifier(val): #Slot method
dlg = Acceuil_start.StartQT4()
dlg.exec_()
However, if you want these to run from the same process, keep in mind that you can't have two app objects. You would probably want to structure Acceuil_start.py to act like a dialog, rather than a main window. If these are two distinct main windows, you might find it easier to just invoke another Python interpreter with the Acceuil_start.py as a parameter.

Running python files

I am working on pyqt4 and python26 application.I created forms using qt designer (.ui files).
I converted them to .py and .pyc files.But when i try to run .py file ,python command line comes and goes within a second,the form (corresponding .ui file) cannot be seen...what can be the problem??
this is my code:(.py file)
from DlgAbout_ui import Ui_DlgAbout
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import resources
class DlgAbout(QDialog, Ui_DlgAbout):
def __init__(self, parent=None):
QDialog.__init__(self, parent)
self.setupUi(self)
self.logo.setPixmap( QPixmap( ":/icons/faunalia_logo.png" ) )
text = self.txt.toHtml()
text = text.replace( "$PLUGIN_NAME$", "RT Sql Layer" )
self.txt.setHtml(text)
First, don't use:
from PyQt4.QtCore import *
from PyQt4.QtGui import *
Instead:
from PyQt4 import QtCore, QtGui
And reference the modules explicitly.
class DlgAbout(QtGui.QDialog, Ui_DlgAbout):
etc.
In your code, all you've done is defined a dialog box. You haven't defined any main application to run, or any way to show the dialog box.
For an example, here's a basic main application to run:
from PyQt4 import QtGui
import sys
class MyMainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(MyMainWindow, self).__init__(parent)
self.form_widget = FormWidget(self)
self.setCentralWidget(self.form_widget)
class FormWidget(QtGui.QWidget):
def __init__(self, parent):
super(FormWidget, self).__init__(parent)
self.layout = QtGui.QVBoxLayout(self)
self.button = QtGui.QPushButton("Button!")
self.layout.addWidget(self.button)
if __name__ == "__main__":
app = QtGui.QApplication([])
foo = MyMainWindow()
foo.show()
sys.exit(app.exec_())
This defines a main window, and a form (Which MyMainWindow sets up, as you can see).
I then check if this is the main file being run (if __name__ == "__main__":), and I start the application (The app = QtGui.QApplication([]), create the main window, and show the main window.
In your case, you could define a main application like I did, and make it alert your QDialog.
Your python code just imports some modules and then defines a new class. It doesn't do anything with the class it has defined, though. In other words, once Python is done creating the new class, it is finished, and it exits.
I don't know PyQT at all, but most likely you need to start the GUI's main loop, and also instantiate an instance of your new class and pass it to PyQT.

Categories