Terminate All QThreads on GUI Close - python-2.7

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

Related

PyQt4/QProcess issues with Nuke v9

PyQt4/QProcess issues with Nuke v9...
I am trying to utilize a QProcess to run renders in Nuke at my workplace. The reason why I want to use a QProcess is because I've setup this Task Manager with the help of the community at stackoverflow, which takes a list of commands and sequentially runs it one by one, and also allows me to display an output. You can view the question I posted here:
How to update UI with output from QProcess loop without the UI freezing?
Now I am trying to basically run Nuke renders through this "Task Manager". But every time I do it just gives me an error that the QProcess is destroyed while still running. I mean I tested this with subprocess and that worked totally fine. So i am not sure why the renders are not working through QProcess.
So to do more testing I just wrote a simplified version at home. The first issue I ran into though is that apparently PyQt4 couldn't be found from Nuke's python.exe. Even though I have PyQt4 for my main Python version. However apparently there is a compatibility issue with my installed PyQt4 since my main Python version is 2.7.12, while my Nuke's python version is 2.7.3. So i thought "fine then i'll just directly install PyQt4 inside my Nuke directory". So i grabbed this link and installed this PyQt version into my Nuke directory:
http://sourceforge.net/projects/pyqt/files/PyQt4/PyQt-4.10.3/PyQt4-4.10.3-gpl-Py2.7-Qt4.8.5-x64.exe
So i run my little test and seems to be doing the same thing as it does in my workplace, where the QProcess just gets destoryed. So i thought maybe adding "waitForFinished()" would maybe do something different, but then it gives me this error that reads:
The procedure entry point ??4QString##QEAAAEAV0#$$QEAV0##Z could not be located in the dynamic link library QtCore4.dll
And gives me this error as well:
ImportError: Failed to load C:\Program Files\Nuke9.0v8\nuke-9.0.8.dll
Now at this point I can't really do any more testing at home, and my studio is closed for the holidays. So i have two questions i'd like to ask:
1) What is this error I am seeing about "procedure entry point"? It only happens when i try to call something in a QProcess instance.
2) Why is my QProcess being destroyed before the render is finished?? How come this doesn't happen with subprocess? How can I submit a Nuke render job while acheiving the same results as subprocess?
Here is my test code:
import os
import sys
import subprocess
import PyQt4
from PyQt4 import QtCore
class Task:
def __init__(self, program, args=None):
self._program = program
self._args = args or []
#property
def program(self):
return self._program
#property
def args(self):
return self._args
class SequentialManager(QtCore.QObject):
started = QtCore.pyqtSignal()
finished = QtCore.pyqtSignal()
progressChanged = QtCore.pyqtSignal(int)
dataChanged = QtCore.pyqtSignal(str)
#^ this is how we can send a signal and can declare what type
# of information we want to pass with this signal
def __init__(self, parent=None):
# super(SequentialManager, self).__init__(parent)
# QtCore.QObject.__init__(self,parent)
QtCore.QObject.__init__(self)
self._progress = 0
self._tasks = []
self._process = QtCore.QProcess(self)
self._process.setProcessChannelMode(QtCore.QProcess.MergedChannels)
self._process.finished.connect(self._on_finished)
self._process.readyReadStandardOutput.connect(self._on_readyReadStandardOutput)
def execute(self, tasks):
self._tasks = iter(tasks)
#this 'iter()' method creates an iterator object
self.started.emit()
self._progress = 0
self.progressChanged.emit(self._progress)
self._execute_next()
def _execute_next(self):
try:
task = next(self._tasks)
except StopIteration:
return False
else:
print 'starting %s' % task.args
self._process.start(task.program, task.args)
return True
def _on_finished(self):
self._process_task()
if not self._execute_next():
self.finished.emit()
def _on_readyReadStandardOutput(self):
output = self._process.readAllStandardOutput()
result = output.data().decode()
self.dataChanged.emit(result)
def _process_task(self):
self._progress += 1
self.progressChanged.emit(self._progress)
class outputLog(QtCore.QObject):
def __init__(self, parent=None, parentWindow=None):
QtCore.QObject.__init__(self)
self._manager = SequentialManager(self)
def startProcess(self, tasks):
# self._manager.progressChanged.connect(self._progressbar.setValue)
self._manager.dataChanged.connect(self.on_dataChanged)
self._manager.started.connect(self.on_started)
self._manager.finished.connect(self.on_finished)
self._manager.execute(tasks)
#QtCore.pyqtSlot()
def on_started(self):
print 'process started'
#QtCore.pyqtSlot()
def on_finished(self):
print 'finished'
#QtCore.pyqtSlot(str)
def on_dataChanged(self, message):
if message:
print message
def nukeTestRender():
import nuke
nuke.scriptOpen('D:/PC6/Documents/nukeTestRender/nukeTestRender.nk')
writeNode = None
for node in nuke.allNodes():
if node.Class() == 'Write':
writeNode = node
framesList = [1, 20, 30, 40]
fr = nuke.FrameRanges(framesList)
# nuke.execute(writeNode, fr)
for x in range(20):
print 'random'
def run():
nukePythonEXE = 'C:/Program Files/Nuke9.0v8/python.exe'
thisFile = os.path.dirname(os.path.abspath("__file__"))
print thisFile
cmd = '"%s" %s renderCheck' %(nukePythonEXE, __file__)
cmd2 = [__file__, 'renderCheck']
cmdList = [Task(nukePythonEXE, cmd2)]
# subprocess.call(cmd, stdin=None, stdout=None, stderr=None, shell=False)
taskManager = outputLog()
taskManager.startProcess(cmdList)
taskManager._manager._process.waitForFinished()
if __name__ == "__main__":
print sys.argv
if len(sys.argv) == 1:
run()
elif len(sys.argv) == 2:
nukeTestRender()
I have managed to come up with an answer, so I will write in the details below:
Basically, I was getting the error with the installed PyQt4 because it was not compatible with my version of Nuke, so it is apparently more recommended to use PySide included in Nuke. However Nuke's Python executable cannot natively find PySide, a few paths needed to be added to the sys.path:
paths = ['C:\\Program Files\\Nuke9.0v8\\lib\\site-packages,
C:\\Users\\Desktop02\\.nuke',
'C:\\Program Files\\Nuke9.0v8\\plugins',
'C:\\Program Files\\Nuke9.0v8\\pythonextensions\\site-packages\\setuptools-0.6c11-py2.6.egg',
'C:\\Program Files\\Nuke9.0v8\\pythonextensions\\site-packages\\protobuf-2.5.0-py2.6.egg',
'C:\\Program Files\\Nuke9.0v8\\pythonextensions\\site-packages',
'C:\\Program Files\\Nuke9.0v8\\plugins\\modules',
'C:\\Program Files\\Nuke9.0v8\\configs\\Python\\site-packages',
'C:\\Users\\Desktop02\\.nuke\\Python\\site-packages']
for path in paths:
sys.path.append(path)
I found the missing paths by opening up both Nuke in GUI mode and the Python executable, and comparing both sys.path to see what the Python executable was lacking.
And to answer my own main question: if I call waitForFinished(-1) on the QProcess instance, this ignores the default 30sec limit of this function... Answer came from this thread:
QProcess and shell : Destroyed while process is still running
So here is my resulting working code:
import os
import sys
import subprocess
sysArgs = sys.argv
try:
import nuke
from PySide import QtCore
except ImportError:
raise ImportError('nuke not currently importable')
class Task:
def __init__(self, program, args=None):
self._program = program
self._args = args or []
#property
def program(self):
return self._program
#property
def args(self):
return self._args
class SequentialManager(QtCore.QObject):
started = QtCore.Signal()
finished = QtCore.Signal()
progressChanged = QtCore.Signal(int)
dataChanged = QtCore.Signal(str)
#^ this is how we can send a signal and can declare what type
# of information we want to pass with this signal
def __init__(self, parent=None):
# super(SequentialManager, self).__init__(parent)
# QtCore.QObject.__init__(self,parent)
QtCore.QObject.__init__(self)
self._progress = 0
self._tasks = []
self._process = QtCore.QProcess(self)
self._process.setProcessChannelMode(QtCore.QProcess.MergedChannels)
self._process.finished.connect(self._on_finished)
self._process.readyReadStandardOutput.connect(self._on_readyReadStandardOutput)
def execute(self, tasks):
self._tasks = iter(tasks)
#this 'iter()' method creates an iterator object
self.started.emit()
self._progress = 0
self.progressChanged.emit(self._progress)
self._execute_next()
def _execute_next(self):
try:
task = next(self._tasks)
except StopIteration:
return False
else:
print 'starting %s' % task.args
self._process.start(task.program, task.args)
return True
def _on_finished(self):
self._process_task()
if not self._execute_next():
self.finished.emit()
def _on_readyReadStandardOutput(self):
output = self._process.readAllStandardOutput()
result = output.data().decode()
self.dataChanged.emit(result)
def _process_task(self):
self._progress += 1
self.progressChanged.emit(self._progress)
class outputLog(QtCore.QObject):
def __init__(self, parent=None, parentWindow=None):
QtCore.QObject.__init__(self)
self._manager = SequentialManager(self)
def startProcess(self, tasks):
# self._manager.progressChanged.connect(self._progressbar.setValue)
self._manager.dataChanged.connect(self.on_dataChanged)
self._manager.started.connect(self.on_started)
self._manager.finished.connect(self.on_finished)
self._manager.execute(tasks)
#QtCore.Slot()
def on_started(self):
print 'process started'
#QtCore.Slot()
def on_finished(self):
print 'finished'
#QtCore.Slot(str)
def on_dataChanged(self, message):
if message:
print message
def nukeTestRender():
import nuke
nuke.scriptOpen('D:/PC6/Documents/nukeTestRender/nukeTestRender.nk')
writeNode = None
for node in nuke.allNodes():
if node.Class() == 'Write':
writeNode = node
framesList = [1, 20, 30, 40]
fr = nuke.FrameRanges(framesList)
nuke.execute(writeNode, fr)
# nuke.execute(writeNode, start=1, end=285)
for x in range(20):
print 'random'
def run():
nukePythonEXE = 'C:/Program Files/Nuke9.0v8/python.exe'
thisFile = os.path.dirname(os.path.abspath("__file__"))
print thisFile
cmd = '"%s" %s renderCheck' %(nukePythonEXE, sysArgs[0])
cmd2 = [sysArgs[0], 'renderCheck']
cmdList = [Task(nukePythonEXE, cmd2)]
# subprocess.call(cmd, stdin=None, stdout=None, stderr=None, shell=False)
taskManager = outputLog()
taskManager.startProcess(cmdList)
taskManager._manager._process.waitForFinished(-1)
if __name__ == "__main__":
print sys.argv
if len(sysArgs) == 1:
run()
elif len(sysArgs) == 2:
nukeTestRender()
For whatever reason, PySide refuses to load for me without the nuke module imported first. and also theres a known error when importing nuke it deletes all sys.argv arguments so thats gotta be stored somewhere first before the nuke import...

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

Connected Signal clicked doesnt execute callback

im trying to make an application in python 2.7 with QtDesigner and PyQT 4.11.
In the application I want to have two QPushButtons that change the value of a QSpinBox when clicked. I've read several pages of StackOverflow answers concerning problems with the Signal Slot mechanic, but couldnt find an answer to my problem.
Im using pyuic4 to generate the Ui_W_Setup.py, here the rellevant part:
class Ui_W_Setup(object):
def setupUi(self, W_Setup):
W_Setup.setObjectName(_fromUtf8("W_Setup"))
self.Motorsteuerung = QtGui.QDockWidget(W_Setup)
self.Motorsteuerung.setEnabled(True)
self.Motorsteuerung.setMinimumSize(QtCore.QSize(140, 365))
self.Motorsteuerung.setFeatures(QtGui.QDockWidget.DockWidgetFloatable|QtGui.QDockWidget.DockWidgetMovable)
self.Motorsteuerung.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea)
self.Motorsteuerung.setObjectName(_fromUtf8("Motorsteuerung"))
self.dockWidgetContents = QtGui.QWidget()
self.dockWidgetContents.setObjectName(_fromUtf8("dockWidgetContents"))
self.B_ZuNehm = QtGui.QPushButton(self.dockWidgetContents)
self.B_ZuNehm.setGeometry(QtCore.QRect(40, 250, 81, 71))
self.B_ZuNehm.setObjectName(_fromUtf8("B_ZuNehm"))
self.B_ZuTast = QtGui.QPushButton(self.dockWidgetContents)
self.B_ZuTast.setGeometry(QtCore.QRect(40, 180, 81, 71))
self.B_ZuTast.setObjectName(_fromUtf8("B_ZuTast"))
self.SB_Position = QtGui.QDoubleSpinBox(self.dockWidgetContents)
self.SB_Position.setGeometry(QtCore.QRect(40, 21, 81, 31))
font = QtGui.QFont()
font.setPointSize(10)
self.SB_Position.setFont(font)
self.SB_Position.setFrame(True)
self.SB_Position.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.SB_Position.setButtonSymbols(QtGui.QAbstractSpinBox.NoButtons)
self.SB_Position.setSpecialValueText(_fromUtf8(""))
self.SB_Position.setCorrectionMode(QtGui.QAbstractSpinBox.CorrectToNearestValue)
self.SB_Position.setDecimals(1)
self.SB_Position.setMaximum(50.0)
self.SB_Position.setSingleStep(0.2)
self.SB_Position.setProperty("value", 0.0)
self.SB_Position.setObjectName(_fromUtf8("SB_Position"))
Then I have a main python file to load the ui.py and execute the application:
import sys
from PyQt4 import QtGui,QtCore
from Setup import Ui_W_Setup
app = QtGui.QApplication(sys.argv)
class MainWindow(QtGui.QMainWindow, Ui_W_Setup):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setupUi(self)
motor = MotorClass()
self.B_ZuNehm.clicked.connect(motor.zuNehm)
self.B_ZuTast.clicked.connect(motor.zuTast)
class MotorClass(QtCore.QObject):
def __init__(self):
super(MotorClass, self).__init__()
global window
confirm = QtGui.QMessageBox()
confirm.setText('Verfahrweg frei?')
confirm.setStandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)
confirm.setDefaultButton(QtGui.QMessageBox.Yes)
#QtCore.pyqtSlot() #shouldnt be needed with my current knowledge
def zuNehm(self):
print("TestNehm")
response = self.confirm.exec_()
if response == 16384: #seems to be the return value for "Yes"
window.SB_Position.setValue(float(1))
#QtCore.pyqtSlot() #shouldnt be needed aswell with my current knowledge
def zuTast(self):
print("TestTast")
response = self.confirm.exec_()
if response == 16384:
window.SB_Position.setValue(float(2))
def main():
global window #I dont like declaring it globally , is there a better way
window = MainWindow()
window.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
There is no exeption thrown and the prints don't show up in the console aswell.
The signal connections don't work because you are not keeping a reference to the instance of MotorClass you created. When it gets garbage-collected, the signal connections are automatically removed.
The code below fixes this problem, as well as some other problems with the MotorClass (e.g. global references to the window variable).
class MainWindow(QtGui.QMainWindow, Ui_W_Setup):
def __init__(self):
QtGui.QMainWindow.__init__(self)
self.setupUi(self)
self.motor = MotorClass(self)
self.B_ZuNehm.clicked.connect(self.motor.zuNehm)
self.B_ZuTast.clicked.connect(self.motor.zuTast)
class MotorClass(QtCore.QObject):
def __init__(self, parent):
super(MotorClass, self).__init__(parent)
self.confirm = QtGui.QMessageBox()
self.confirm.setText('Verfahrweg frei?')
self.confirm.setStandardButtons(QtGui.QMessageBox.No | QtGui.QMessageBox.Yes)
self.confirm.setDefaultButton(QtGui.QMessageBox.Yes)
def zuNehm(self):
print("TestNehm")
response = self.confirm.exec_()
if response == QtGui.QMessageBox.Yes:
self.parent().SB_Position.setValue(float(1))
def zuTast(self):
print("TestTast")
response = self.confirm.exec_()
if response == QtGui.QMessageBox.Yes:
self.parent().SB_Position.setValue(float(2))
def main():
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
For example this line>>
self.B_FileOpen.clicked.connect(fileSelect)
when you make this connection your function "fileSelect" still doesn't exists.
Try make your "connections" after you have all declared.
If it's not the "fileSelect" specifically it's some of the others. But this behavior is usually when you try to connect something you haven't still declared.

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

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.