I have created a tool with help of a custom widget.
This widget fits into the main window
like so. User can create new instances of custom widget with a click of a
button.
custom widget :
class RenderWidget(QWidget):
def __init__(self, toolname, process_queue):
QWidget.__init__(self)
self.initSubject()
self.organize()
self.toolname = toolname
self.process_queue = process_queue
def initSubject(self):
self.script_dir = os.path.dirname(os.path.realpath(__file__))
self.scene_widget = uic.loadUi(os.path.join(self.script_dir, 'ui', 'test_widget.ui'))
self.scene_widget.pushButton_scenefile.clicked.connect(lambda x: self.open_file_name_dialog(x))
def organize(self):
grid = QGridLayout(self)
self.setLayout(grid)
grid.addWidget(self.scene_widget)
def open_file_name_dialog(self, x):
dialog = QFileDialog(
self,
'submit_render',
"path",
"*.ma",
# supportedSchemes=["file"],
options=QFileDialog.DontUseNativeDialog,
)
self.change_button_name(dialog)
dialog.findChild(QTreeView).selectionModel().currentChanged.connect(
lambda: self.change_button_name(dialog)
)
if dialog.exec_() == QDialog.Accepted:
filename = dialog.selectedUrls()[0]
filename = filename.toLocalFile()
self.scene_widget.lineEdit_scenefile.setText(filename)
if validate_path(self.toolname, filename):
self.process_queue.put((filename, _count))
def change_button_name(self, dialog):
for btn in dialog.findChildren(QPushButton):
if btn.text() == self.tr("&Open"):
QTimer.singleShot(0, lambda btn=btn: btn.setText("open"))
Main Widget :
class MyAppView(QWidget):
def __init__(self, toolname, process_queue):
self.toolname = toolname
self.process_queue = process_queue
super(MyAppView, self).__init__()
self.initUi()
def initUi(self):
self.layoutV = QVBoxLayout(self)
self.area = QScrollArea(self)
self.area.setWidgetResizable(True)
self.scrollAreaWidgetContents = QWidget()
self.scrollAreaWidgetContents.setGeometry(0, 0, 200, 100)
self.layoutH = QHBoxLayout(self.scrollAreaWidgetContents)
self.layoutH_Button = QHBoxLayout(self.scrollAreaWidgetContents)
self.gridLayout = QGridLayout()
self.layoutH.addLayout(self.gridLayout)
self.area.setWidget(self.scrollAreaWidgetContents)
self.left_spacer = QSpacerItem(50, 10, QSizePolicy.Minimum)
self.center_spacer = QSpacerItem(100, 10, QSizePolicy.Minimum)
self.submit_button = UVPush("Submit")
self.cancel_button = UVPush("Cancel")
# Log text
self.output = QPlainTextEdit()
self.output.setFixedHeight(150)
self.output.setPlaceholderText('output..')
self.layoutH_Button.addSpacerItem(self.left_spacer)
self.layoutH_Button.addWidget(self.submit_button)
self.layoutH_Button.addSpacerItem(self.center_spacer)
self.layoutH_Button.addWidget(self.cancel_button)
self.layoutV.addWidget(self.area)
self.layoutV.addLayout(self.layoutH_Button)
self.layoutV.addWidget(self.output)
self.widget = RenderWidget(self.toolname, self.process_queue)
self.gridLayout.addWidget(self.widget)
self.setGeometry(700, 200, 350, 300)
Process :
class ChildProc(Process):
def __init__(self, to_emitter, from_mother, daemon=True):
super(ChildProc, self).__init__()
self.daemon = daemon
self.to_emitter = to_emitter
self.data_from_mother = from_mother
self.maya_output = MayaOutput()
def run(self):
from python_library.maya_python import data_from_maya_scene
while True:
filename, count = self.data_from_mother.get()
print('+++ filename ', filename, count)
_cameras, _frames, _layers = data_from_maya_scene(filename)
self.maya_output.cameras = _cameras
self.maya_output.layers = _layers
self.maya_output.frames = _frames
self.maya_output.count = count
self.to_emitter.send(self.maya_output)
#TODO call signal slot to start stop loader
(ref: How to signal slots in a GUI from a different process?)
Emitter :
class Emitter(QThread):
ui_data_available = pyqtSignal(object) # Signal indicating new UI data is available.
def __init__(self, from_process):
super(Emitter, self).__init__()
self.data_from_process = from_process
def run(self):
while True:
try:
_object = self.data_from_process.recv()
except EOFError:
break
else:
self.ui_data_available.emit(_object)
MainWindow :
class CloudRenderView(QtWidgets.QMainWindow):
def __init__(self, toolname, child_process_queue, emitter):
QtWidgets.QMainWindow.__init__(self)
self.toolname = toolname
self.process_queue = child_process_queue
self.MyAppView = MyAppView(self.toolname, self.process_queue)
.
.
self.emitter = emitter
self.emitter.daemon = True
self.emitter.start()
# set window dimension
self.connections()
.
.
def connections(self):
.
.
self.emitter.ui_data_available.connect(self.update_ui)
.
.
def update_ui(self, maya_object):
count = maya_object.count
example_widget = self.MyAppView.gridLayout.itemAt(count).widget()
if 'Error' not in maya_object.cameras:
example_widget.scene_widget.textEdit_camera.setText('\n'.join([str(elem) for elem in maya_object.cameras]))
else:
example_widget.scene_widget.textEdit_camera.setHtml("<font color='red' size='2'><red>{}</font>".format('Error'))
if 'Error' not in maya_object.frames:
example_widget.scene_widget.lineEdit_frames.setText(maya_object.frames)
else:
example_widget.scene_widget.lineEdit_frames.setText('Error')
if 'Error' not in maya_object.layers:
example_widget.scene_widget.textEdit_render_layer.setText('\n'.join([str(elem) for elem in maya_object.layers]))
else:
example_widget.scene_widget.textEdit_render_layer.setHtml("<font color='red' size='2'><red>{}</font>".format('Error'))
Question :
A button to choose file from system is clicked. This selected file is send to a qprocess via queue and after processing is complete, emitter sends signal to main UI via a pipe.
Coming to the question, say data was entered for widget 3 or 4, After process, data gets send back to widget no 1 , always.
How to map it to same widget that it was selected from. ?