GOOGLE ADS

Samstag, 16. April 2022

pyqt5 - aktualisiert ein dynamisch erstelltes Widget mit seinen entsprechenden Daten

Ich habe ein Tool mit Hilfe eines benutzerdefinierten Widgets erstellt.

benutzerdefiniertes Widget

Dieses Widget passt so in das Hauptfenster
Hauptfenster
. Widget hinzufügenDer Benutzer kann mit einem Klick auf eine Schaltfläche neue Instanzen eines benutzerdefinierten Widgets erstellen.

Geben Sie hier die Bildbeschreibung ein

benutzerdefiniertes 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"))

Haupt-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)

Verfahren:

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

(Referenz: Wie signalisiert man Slots in einer GUI von einem anderen Prozess? )

Sender:

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)

Hauptfenster:

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'))

Frage:
Eine Schaltfläche Datei wählenzur Auswahl einer Datei aus dem System wurde angeklickt. Diese ausgewählte Datei wird über eine Warteschlange an einen qprocess gesendet, und nach Abschluss der Verarbeitung sendet der Emitter über eine Pipe ein Signal an die Hauptbenutzeroberfläche.

Kommen wir zu der Frage, sagen wir, dass Daten für Widget 3 oder 4 eingegeben wurden. Nach dem Prozess werden die Daten immer an Widget Nr. 1 zurückgesendet.

So ordnen Sie es demselben Widget zu, aus dem es ausgewählt wurde.?


Lösung des Problems

Der Versuch, eine Antwort zu finden, die hilft, aber ohne Code und wenn Sie Ihren speziellen Ansatz kennen, ist es schwierig.

Ich gehe davon aus, dass Sie die Daten nicht an das richtige Widget senden, da Ihr Verweis auf dieses Widget falsch ist. Sie brauchen eine Möglichkeit, auf das neu erstellte Widget zu verweisen, und dafür gibt es im Allgemeinen zwei Möglichkeiten.

  • Speichern Sie einen Verweis auf das neue Widget an einem Ort, an dem Sie leicht darauf zugreifen können, z. B. eine self._second_widgetVariable oder eine Liste oder ein Wörterbuch von Variablen. Wenn Sie dann Daten an Ihr Widget senden, verwenden Sie diese Referenz.


  • Finden Sie das Widget im QGridLayout mit entsprechenden Aufrufen, die so etwas wie sein könnten.itemAtPosition(x,y).widget()


  • Hoffentlich hilft das - wenn Sie eine bessere Antwort wünschen, ist es eine gute Idee, Code zu posten.

    Keine Kommentare:

    Kommentar veröffentlichen

    Warum werden SCHED_FIFO-Threads derselben physischen CPU zugewiesen, obwohl CPUs im Leerlauf verfügbar sind?

    Lösung des Problems Wenn ich das richtig verstehe, versuchen Sie, SCHED_FIFO mit aktiviertem Hyperthreading ("HT") zu verwenden, ...