Maya + PyQt dialog. How to run a single copy of Qt window? - python-2.7

use this simple code for run a window based on qdialog:
import maya.OpenMayaUI as mui
import sip
from PyQt4 import QtGui, QtCore, uic
#----------------------------------------------------------------------
def getMayaWindow():
ptr = mui.MQtUtil.mainWindow()
return sip.wrapinstance(long(ptr), QtCore.QObject)
#----------------------------------------------------------------------
form_class, base_class = uic.loadUiType('perforceBrowserWnd.ui')
#----------------------------------------------------------------------
class PerforceWindow(base_class, form_class):
def __init__(self, parent=getMayaWindow()):
super(base_class, self).__init__(parent)
self.setupUi(self)
#----------------------------------------------------------------------
def perforceBrowser2():
perforceBrowserWnd = PerforceWindow()
perforceBrowserWnd.show()
perforceBrowser2()
every time you run the function perforceBrowser2() there is a new copy of windows.
how to find whether a window is already running and not to open a new copy of it, and go to the opened window? or just do not give a script to run a second copy of window?
ps. maya2014 + pyqt4 + python2.7

Keep a global reference to the window:
perforceBrowserWnd = None
def perforceBrowser2():
global perforceBrowserWnd
if perforceBrowserWnd is None:
perforceBrowserWnd = PerforceWindow()
perforceBrowserWnd.show()

Using global's are not the preferred way and there are ton's of articles why it is a bad idea.
Why are global variables evil?
It is cleaner to remember the instance in a static var of the class and whenever you load the UI, check if it does already exist and return it, if not create it. (There is a pattern called Singleton that describes this behaviour as well)
import sys
from Qt import QtGui, QtWidgets, QtCore
class Foo(QtWidgets.QDialog):
instance = None
def __init__(self, parent=None):
super(Foo, self).__init__(parent)
self.setWindowTitle('Test')
def loadUI():
if not Foo.instance:
Foo.instance = Foo()
Foo.instance.show()
Foo.instance.raise_()
loadUI()
Whenever you call loadUI it will return the same UI and will not recreate each time you call it.

Related

Print Message in Text Widget that is part of a class

I am fairly new to object-oriented programming. I have a class called MessageWindow which generates a Tkinter text widget inside of a Frame. In my main function I want to write a message into the text widget but when I run the program I get: Class MessageWindow has no attribute text1
I've tried following other responses here on Stack overflow, and another tutorial on the web and I always end up back at the same error
from Tkinter import *
class MessageWindow(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.pack(fill='both', expand='yes')
self.text1 =Text(self,height=9, width=13)
self.text1.pack()
def main():
root=Tk()
root.title("MessageWindow")
app = MessageWindow(root)
root.mainloop()
MessageWindow.text1.insert(END,"This is a test Message")
MessageWindow.text1.pack()
if __name__=='__main__':
main()
Any help would be appreciated. I need to understand this for a larger GUI project that I am working on.
Ok so
1. You are referring to MessageWindow as your class object when you should be referring to app, as you have instantiated the class as 'app' in your main definition.
2. Your root.mainloop() should be after all your GUI code as it will not take affect if it is after/outisde the mainloop.
So this is the How the code is supposed to be:
from Tkinter import *
class MessageWindow(Frame):
def __init__(self, master):
Frame.__init__(self, master)
self.pack(fill='both', expand='yes')
self.text1 = Text(self,height=9, width=13)
self.text1.pack()
def main():
root=Tk()
root.title("MessageWindow")
app = MessageWindow(root)
# Fix one
app.text1.insert(END,"This is a test Message")
app.text1.pack()
# Fix two
root.mainloop()
if __name__=='__main__':
main()

PyQt :Parent Window not waiting until child window closes.

PyQt :Parent Window not waiting until child window closes. with reference to code shared below ,My welcome class object should wait till first_time class object completely finishes executing , but instead goes ahead and closes it self before first_time object finishes executing .
code :
from PyQt4.QtGui import *
from PyQt4.QtCore import *
from PySide.QtCore import QSettings
import sys
from PyQt4 import uic
#importing first configuration class
import configure as config_first
#loading initial settings
settings=QSettings('settings.ini',QSettings.IniFormat)
#loading the ui screens
form_class=uic.loadUiType("screens/firstscreen.ui")[0]
class welcome(QDialog,form_class):
#this signal is emitted when first configuration is done and ready to go
done_and_go_to_use = pyqtSignal()
def __init__(self):
super(welcome, self).__init__()
self.setupUi(self)
self.done_and_go_to_use.connect(self.close)
self.ready_btn.clicked.connect(self.ready)
def ready(self):
if_configured = settings.value('isConfigured', False)
if not if_configured :
first_time=config_first.configureFirst(self)
first_time.show()
self.close()
app = QApplication(sys.argv)
p = welcome()
p.show()
app.exec_()
below is the code for configure.py
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sqlite3
import csv
from PySide.QtCore import QSettings
from PyQt4 import uic
#loading initial settings
settings=QSettings('settings.ini',QSettings.IniFormat)
#loading ui screens
form_class=uic.loadUiType("screens/config_first.ui")[0]
#database connecting
con = sqlite3.connect("local.db")
cur = con.cursor()
cur.execute("CREATE TABLE if not exists marks (student_id int,student_name varchar(200));")
class configureFirst(QDialog,form_class):
done_configuring=pyqtSignal()
try_again=pyqtSignal()
def __init__(self,parent=None):
super(configureFirst, self).__init__(parent)
self.setupUi(self)
self.ok_btn.clicked.connect(self.ok_clicked)
self.cancel_btn.clicked.connect(self.cancel_clicked)
self.try_again.connect(self.ok_clicked)
self.done_configuring.connect(self.cancel_clicked)
self.show()
def ok_clicked(self):
file_select=QFileDialog.getOpenFileName(self,"open file","/")
if file_select:
with open(file_select, 'rb') as f:
reader = csv.reader(f)
ed = list(reader)
for row in ed:
if "name" not in row or "id" not in row:
cur.execute("Insert into marks Values (?,?);",(row[0],row[1]))
con.commit()
settings.setValue("isConfigured",True)
self.done_configuring.emit()
else:
#if recurssion is used the no of time it has to close increases and leads to integration problems
self.try_again.emit()
def cancel_clicked(self):
if_configured=settings.value("isConfigured")
if if_configured:
self.close()
else:
QMessageBox.critical(self,"PerfAnalyser","You Need to Configure For PerfAnalyser To Work")
def closeEvent(self,event):
#this method is triggered when 'X' is clicked i.e close button is clicked at the upper right corner
if_configured = settings.value("isConfigured")
if if_configured:
event.accept()
else:
QMessageBox.critical(self, "PerfAnalyser", "You Need to Configure For PerfAnalyser To Work")
event.ignore()
Thanks for the help in advance ...
I will try to help out since I notice few people have seen your post. I have had this happen a long time ago so I need a reminder, but I was unable to get your code running, I also tried to recreate your ui files and the screens directory but I was not successful. However, maybe the following is still useful.
In my working code, any time I needed to create a subwindow, I executed subwindows as follows from the main window's module:
dlg = SubWindowModuleName.StartSub()
dlg.exec_()
This will execute the subwindow and waits for it to close. Then, on the subwindow module (SubWindowModuleName in the above code, "configure" for you), I did this:
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName(_fromUtf8("Dialog"))
Dialog.resize(982, 521)
... # here I build the window (I noticed that you import UI files which is a much better way of doing this)
...
class StartSub(QtGui.QDialog, Ui_Dialog):
def __init__(self,parent=None):
QtGui.QDialog.__init__(self,parent)
self.setupUi(self)

PyQt 4: Get Position of Toolbar

Hy guys,
in my executable program there is a toolbar. Well, the user decides to move the toolbar. Now the toolbar is floating. I know I have to conntect the floating-signals that is emittted when the toolbar ist arranged by the user. How can I save the new position of the toolbar? I know the method of adding the toolbar to the main window with a position:self.addToolBar( Qt.LeftToolBarArea , toolbar_name). In the handle_floating()-method you see what I want: There I want to get the position currently, but how? You also see I have just added one member variable, named self.toolbar_pos, to hold the position of the toolbar. My idea is, when application is terminated I want to serialize this value to a file, and later, when application is ran again its will read that file and set the toolbar accordingly. But this is no problem. Currently I don't have no idea to get the position of the toolbar.
I need your help :)
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtGui, QtCore
class Example(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QMainWindow.__init__(self, parent)
self.toolbar_pos = None
self.initUI()
def initUI(self):
exitAction = QtGui.QAction(QtGui.QIcon('exit24.png'), 'Exit', self)
exitAction.setShortcut('Ctrl+Q')
exitAction.triggered.connect(QtGui.qApp.quit)
self.toolbar = QtGui.QToolBar(self)
self.toolbar.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon)
self.addToolBar(self.toolbar )
self.toolbar.addAction(exitAction)
self.toolbar.setAllowedAreas(QtCore.Qt.TopToolBarArea
| QtCore.Qt.BottomToolBarArea
| QtCore.Qt.LeftToolBarArea
| QtCore.Qt.RightToolBarArea)
self.addToolBar( QtCore.Qt.LeftToolBarArea , self.toolbar )
self.toolbar.topLevelChanged.connect(self.handle_floating)
def handle_floating(self, event):
# The topLevel parameter is true
# if the toolbar is now floating
if not event:
# If the toolbar no longer floats,
# then calculate the position where the
# toolbar is located currently.
self.toolbar_pos = None
print "Get position: ?"
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
ex.setGeometry(300, 300, 300, 200)
ex.setWindowTitle('Toolbar example')
ex.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
The QMainWindow class already has APIs for this: i.e. saveState and restoreState. These can be used to save and restore the state of all the toolbars and dock-widgets in your application.
To use them, you first need to make sure that all your toolbars and dock-widgets are given a unique object-name when they are created:
class Example(QtGui.QMainWindow):
...
def initUI(self):
...
self.toolbar = QtGui.QToolBar(self)
self.toolbar.setObjectName('foobar')
Then you can override closeEvent to save the state:
class Example(QtGui.QMainWindow):
...
def closeEvent(self, event):
with open('/tmp/test.conf', 'wb') as stream:
stream.write(self.saveState().data())
(NB: I've just used a temporary file here for testing, but it would obviously be much better to use something like QSettings in your real application).
Finally, you can restore the state that was saved previously:
class Example(QtGui.QMainWindow):
def __init__(self, parent=None):
...
self.initUI()
try:
with open('/tmp/test.conf', 'rb') as stream:
self.restoreState(QtCore.QByteArray(stream.read()))
except IOError:
pass

Terminate All QThreads on GUI Close

I have a PyQT gui that has one gui thread, and 24 "tester threads." They work fine, but still seem to stay up when I close the gui. How can I gracefully close the threads to avoid python crashing?
#!/usr/bin/python
# Standard Lib
from datetime import datetime
import logging
import os
import random
import sys
import time
# Third Party
from PyQt4 import QtGui, QtCore
# Local Kung Fu
stuff
class SSITesterThread(QtCore.QThread):
# vars for updating gui using signals
updateText = QtCore.pyqtSignal(str)
updateColor = QtCore.pyqtSignal(str)
updateSN = QtCore.pyqtSignal(str)
def __init__(self, thread_number, port, path, parent=None):
super(SSITesterThread, self).__init__(parent)
self.delay = random.random()
def run(self):
self.ssitester()
def ssitester(self):
# stuff
class SSITestSuiteGUI(QtGui.QMainWindow):
def __init__(self, parent=None):
self._threads = []
QtGui.QWidget.__init__(self, parent)
# Init class from template and paths
self.launch_tester_threads()
def init_gui_nodes(self, com_ports_list):
for num, port, in zip(range(1, 25), range(0, 24)):
label = getattr(self.ui, 'com_{}'.format(num))
label.setText("COM Port: {}".format(com_ports_list[port]["COM"]))
def launch_tester_threads(self):
logging.info("Spinning up threads...")
for num, com_port_chunk in zip(range(1, 25), self.com_ports_list):
tester_thread = SSITesterThread(thread_number=num, port=com_port_chunk["COM"], path=self.vc_test_path)
# get a reference to the associated textbox somehow...
status_box = getattr(self.ui, 'status_{}'.format(num))
tester_thread.updateText.connect(status_box.setText)
status_box = getattr(self.ui, 'status_{}'.format(num))
tester_thread.updateColor.connect(status_box.setStyleSheet)
sn_label = getattr(self.ui, 'sn_{}'.format(num))
tester_thread.updateSN.connect(sn_label.setText)
sn_label.setText("S/N: None")
tester_thread.start()
self._threads.append(tester_thread)
logging.info("Ready for tests.")
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
test_suite = SSITestSuiteGUI()
test_suite.show()
# Close app only when window is closed.
sys.exit(app.exec_())
I tried implementing this solution: https://gist.githubusercontent.com/metalman/10721983/raw/15c6f115f9918fee7c1b88d0a549d4cc59a5b346/qapplication_about_to_quit_signal.py
But got an error:
attributeerror: 'function' object has no attribute '__pyqtSignature__'
Thanks for your time.
UPDATE:
Added the suggestion below as:
#QtCore.pyqtSlot()
def stop(self):
return
in my SSITesterThread Class, and it errors out when various "emits" I've used as singals in the thread sudden try to access NoneType objects:
File in gui.py, line 75 in tester,
self.updateColor.emit("{}".format(thread_colors.green_alert)
AttributeError: "NoneType" object has no attribute 'green alert'
Did the fix work, and this is a new problem? Because it seems like things still aren't shutting down gracefully.
It looks like you're importing your GUI from a form generated by QTDesigner. Try this:
self.ui.closeEvent = self.closeEvent
I believe your problem is that you're editing the wrong QMainWindow instance in the wrong place.
You probably just need to decorate the stop method as a slot.
#QtCore.pyqtSlot()
def stop(self):
# do thread cleanup, stop thread

How to integrate a Ipython console in a PyQT application

I am developing PyQt software for my lab. In this software, I am loading different kind of RAW and analyzed data from a mySQL database (usually in arrays).
I would like to integrate an Iython console in a Widget, so that I could interact easily with these data.
I had some difficulties with Ipython 0.13 to do this.
Here is what I already have (The whole code is very long, so I just show the part containing the widget, the Ipython console and the corresponding import line, if you need more, just tell me):
##I load everything useful to my application, including the following line
from IPython.frontend.qt.console.qtconsoleapp import IPythonQtConsoleApp
##then is my whole software
##here is a class containing the Graphical User Interface elements. A button call the following function. self.Shell_Widget is the widget containing the Ipython console, self.MainWindow is the application mainwindow
def EmbeddedIpython(self):
"""
This function should launch an Ipython console
"""
self.Shell_Widget = QtGui.QDockWidget(self.MainWindow) #Widget creation
self.MainWindow.addDockWidget(4,self.Shell_Widget)
self.Shell_Widget.setMinimumSize(400,420)
console = IPythonQtConsoleApp() #Console Creation
console.initialize()
console.start()
self.Shell_Widget.show()
So, as wanted, an Ipython console is launched, and seems to work, but I can not access the whole application variables ,arrays etc... I think the Ipython console is launched independently from my software, but here is my limit in programming...
Does someone know how to launch Ipython within my application? Maybe a missing parameter, or a different way to integrate Ipython.
for information, this doesn't work:
Embedding IPython Qt console in a PyQt application
Thank you for your help!!
The mentioned link seems to be working flawless here:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
import atexit
from IPython.zmq.ipkernel import IPKernelApp
from IPython.lib.kernel import find_connection_file
from IPython.frontend.qt.kernelmanager import QtKernelManager
from IPython.frontend.qt.console.rich_ipython_widget import RichIPythonWidget
from IPython.utils.traitlets import TraitError
from PyQt4 import QtGui, QtCore
def event_loop(kernel):
kernel.timer = QtCore.QTimer()
kernel.timer.timeout.connect(kernel.do_one_iteration)
kernel.timer.start(1000*kernel._poll_interval)
def default_kernel_app():
app = IPKernelApp.instance()
app.initialize(['python', '--pylab=qt'])
app.kernel.eventloop = event_loop
return app
def default_manager(kernel):
connection_file = find_connection_file(kernel.connection_file)
manager = QtKernelManager(connection_file=connection_file)
manager.load_connection_file()
manager.start_channels()
atexit.register(manager.cleanup_connection_file)
return manager
def console_widget(manager):
try: # Ipython v0.13
widget = RichIPythonWidget(gui_completion='droplist')
except TraitError: # IPython v0.12
widget = RichIPythonWidget(gui_completion=True)
widget.kernel_manager = manager
return widget
def terminal_widget(**kwargs):
kernel_app = default_kernel_app()
manager = default_manager(kernel_app)
widget = console_widget(manager)
#update namespace
kernel_app.shell.user_ns.update(kwargs)
kernel_app.start()
return widget
class mainWindow(QtGui.QMainWindow):
def __init__(self, parent=None):
super(mainWindow, self).__init__(parent)
self.console = terminal_widget(testing=123)
print "\nAn Embeded Ipython Console!"
self.textEdit = QtGui.QTextEdit()
self.dockShell = QtGui.QDockWidget(self)
self.dockShell.setWidget(self.textEdit)
self.addDockWidget(4, self.dockShell)
self.setCentralWidget(self.console)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
main = mainWindow()
main.show()
sys.exit(app.exec_())