Help with design choices and code structure.
-
Hi, so I have this project to develop and image editor for thermal images. Thermal images are kind particular because they require some additional processing and features. So I started the project thinking on left and right panels as the main design in a .py file with nested widgets and, to organize the final layout in another .py like mainwindow, where I could have control of these panels in a macro way (really small simple file). I also have an external .py file with specific functions like an util file. As I was coding the panels, I realized there are some attributes there that I will need to reuse among classes. I reached a point where I'm afraid to continue and realized that I could mess the whole thing up in so many levels that I would need to refactor the whole thing. So I need opinions, critiques, suggestions, slaps or anything to enlighten me on this. Plus I really need help on how to deal these instances attributes among classes, how to share in a way that seems logical to me. I'm reading a lot of stuff about OOP, but nothing seems to works, aside from calling these attributes inside functions using parent().parent() Here are some snipets of the organization of my project. Does it makes sense for you guys? Thanks.
class LeftPanel(QWidget): def __init__(self): super().__init__() ##ATRIBUTES---------------------------------------------------------------------------------------------------------------------------------------------- self.pixmapitem = QGraphicsPixmapItem() self.exiftool_path = "exiftool" self.filename = None #will hold image address location self.tmp = None #will hold temporary image for display self.max_img_width = 640 self.max_img_height = 480 self.flir_raw = None self.pdkta_raw = None self.thermal_matrix = None **...other attributes bellow...** **...layout stuff...** #set horizontal layout for viewer/colorbar self.h_layout = QHBoxLayout() self.h_layout.setSpacing(3) self.h_layout.setContentsMargins(0, 0, 0, 0) #set Image Container self.viewer_groupbox = QGroupBox() self.viewer_layout = QVBoxLayout() self.pixmapitem = QGraphicsPixmapItem() self.pixmapitem.setPixmap(QPixmap("assets/placeholder.jpg")) self.scene = Scene() self.scene.addItem(self.pixmapitem) self.viewer = ImageViewer() self.viewer.setScene(self.scene) #Add viewer to layout self.viewer_layout.addWidget(self.viewer) self.viewer_groupbox.setLayout(self.viewer_layout) **...followed by a lot methods to process the image...** class ImageViewer(QGraphicsView): def __init__(self, parent=None): super().__init__(parent) self.setDragMode(QGraphicsView.ScrollHandDrag) self.setViewportMargins(-2, -2, -2, -2) self.setAlignment(Qt.AlignmentFlag.AlignCenter) self.setMinimumWidth(640) self.setMaximumHeight(480) self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.setAcceptDrops(True) ....more code def dropEvent(self, event): if event.mimeData().hasImage: try: event.setDropAction(Qt.CopyAction) **self.main_window_instance = self.parent().parent() // here is where I'm panicking** self.main_window_instance.filename = event.mimeData().urls()[0].toLocalFile() self.main_window_instance.set_image() event.accept() print(self.main_window_instance.pixmapitem)lass MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("Predikta Thermal Analyzer") self.setWindowIcon(QIcon("assets/logo.png")) layout = QHBoxLayout() layout.addWidget(LeftPanel(), alignment=Qt.AlignmentFlag.AlignLeft) #layout.addWidget(right_panel(), alignment=Qt.AlignmentFlag.AlignRight) widget = QWidget() widget.setLayout(layout) self.setCentralWidget(widget) if __name__ == "__main__": app = QApplication(sys.argv) window = MainWindow() window.show() app.exec()This is where I'm now. The first really struggle was to share attributes between the viewer and leftpanel Classes, because I'm planning and add ROis, Zoom, Pan and other stuff to it.

-
Hi, so I have this project to develop and image editor for thermal images. Thermal images are kind particular because they require some additional processing and features. So I started the project thinking on left and right panels as the main design in a .py file with nested widgets and, to organize the final layout in another .py like mainwindow, where I could have control of these panels in a macro way (really small simple file). I also have an external .py file with specific functions like an util file. As I was coding the panels, I realized there are some attributes there that I will need to reuse among classes. I reached a point where I'm afraid to continue and realized that I could mess the whole thing up in so many levels that I would need to refactor the whole thing. So I need opinions, critiques, suggestions, slaps or anything to enlighten me on this. Plus I really need help on how to deal these instances attributes among classes, how to share in a way that seems logical to me. I'm reading a lot of stuff about OOP, but nothing seems to works, aside from calling these attributes inside functions using parent().parent() Here are some snipets of the organization of my project. Does it makes sense for you guys? Thanks.
class LeftPanel(QWidget): def __init__(self): super().__init__() ##ATRIBUTES---------------------------------------------------------------------------------------------------------------------------------------------- self.pixmapitem = QGraphicsPixmapItem() self.exiftool_path = "exiftool" self.filename = None #will hold image address location self.tmp = None #will hold temporary image for display self.max_img_width = 640 self.max_img_height = 480 self.flir_raw = None self.pdkta_raw = None self.thermal_matrix = None **...other attributes bellow...** **...layout stuff...** #set horizontal layout for viewer/colorbar self.h_layout = QHBoxLayout() self.h_layout.setSpacing(3) self.h_layout.setContentsMargins(0, 0, 0, 0) #set Image Container self.viewer_groupbox = QGroupBox() self.viewer_layout = QVBoxLayout() self.pixmapitem = QGraphicsPixmapItem() self.pixmapitem.setPixmap(QPixmap("assets/placeholder.jpg")) self.scene = Scene() self.scene.addItem(self.pixmapitem) self.viewer = ImageViewer() self.viewer.setScene(self.scene) #Add viewer to layout self.viewer_layout.addWidget(self.viewer) self.viewer_groupbox.setLayout(self.viewer_layout) **...followed by a lot methods to process the image...** class ImageViewer(QGraphicsView): def __init__(self, parent=None): super().__init__(parent) self.setDragMode(QGraphicsView.ScrollHandDrag) self.setViewportMargins(-2, -2, -2, -2) self.setAlignment(Qt.AlignmentFlag.AlignCenter) self.setMinimumWidth(640) self.setMaximumHeight(480) self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.setAcceptDrops(True) ....more code def dropEvent(self, event): if event.mimeData().hasImage: try: event.setDropAction(Qt.CopyAction) **self.main_window_instance = self.parent().parent() // here is where I'm panicking** self.main_window_instance.filename = event.mimeData().urls()[0].toLocalFile() self.main_window_instance.set_image() event.accept() print(self.main_window_instance.pixmapitem)lass MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("Predikta Thermal Analyzer") self.setWindowIcon(QIcon("assets/logo.png")) layout = QHBoxLayout() layout.addWidget(LeftPanel(), alignment=Qt.AlignmentFlag.AlignLeft) #layout.addWidget(right_panel(), alignment=Qt.AlignmentFlag.AlignRight) widget = QWidget() widget.setLayout(layout) self.setCentralWidget(widget) if __name__ == "__main__": app = QApplication(sys.argv) window = MainWindow() window.show() app.exec()This is where I'm now. The first really struggle was to share attributes between the viewer and leftpanel Classes, because I'm planning and add ROis, Zoom, Pan and other stuff to it.

@IvanDesuo said in Help with design choices and code structure.:
**self.main_window_instance = self.parent().parent() // here is where I'm panicking** self.main_window_instance.filename = event.mimeData().urls()[0].toLocalFile() self.main_window_instance.set_image()I don't claim to analyse the whole of what you say/your structure. But all of this is "yucky". You really don't want to go
parent()anything, parents can know about children but children should normally know nothing about parents: it ties your image viewer to the main window, and (as far as possible) you want to avoid that. Further, you then "poke" values into the main page and call it to set an image, that's also yucky. The Qt way is to send a signal (with parameters as required), the main window starts up by placing a slot on that signal so it "listens" to it, when it gets that signal let it do whatever to do with setting its filename, pixmap, etc. -
@IvanDesuo said in Help with design choices and code structure.:
**self.main_window_instance = self.parent().parent() // here is where I'm panicking** self.main_window_instance.filename = event.mimeData().urls()[0].toLocalFile() self.main_window_instance.set_image()I don't claim to analyse the whole of what you say/your structure. But all of this is "yucky". You really don't want to go
parent()anything, parents can know about children but children should normally know nothing about parents: it ties your image viewer to the main window, and (as far as possible) you want to avoid that. Further, you then "poke" values into the main page and call it to set an image, that's also yucky. The Qt way is to send a signal (with parameters as required), the main window starts up by placing a slot on that signal so it "listens" to it, when it gets that signal let it do whatever to do with setting its filename, pixmap, etc.@JonB thanks! I will check and study about the signals (already saw some articles on that), if you have any source that you could share or recommend about this subject, I would be grateful. Other than that, I was using Qlabel to the viewer and it seemed more straightforward for me, but once I intend to implement Rois, zoom, pan and other functions to the image I read from multiple places that I should use Qgraphicsview, and there I hit the first wall. I'm struggling to understand the framework, but I'm getting there. I think as the process of passing attributes among classes is more logical and clear to me, I can pass for the next level. Indeed, when I used parent () i felt some strange feeling in my stomach. Thanks again.
-
@JonB thanks! I will check and study about the signals (already saw some articles on that), if you have any source that you could share or recommend about this subject, I would be grateful. Other than that, I was using Qlabel to the viewer and it seemed more straightforward for me, but once I intend to implement Rois, zoom, pan and other functions to the image I read from multiple places that I should use Qgraphicsview, and there I hit the first wall. I'm struggling to understand the framework, but I'm getting there. I think as the process of passing attributes among classes is more logical and clear to me, I can pass for the next level. Indeed, when I used parent () i felt some strange feeling in my stomach. Thanks again.
@IvanDesuo said in Help with design choices and code structure.:
, I would be grateful. Other than that, I was using Qlabel to the viewer and it seemed more straightforw
-
@JonB thanks! I will check and study about the signals (already saw some articles on that), if you have any source that you could share or recommend about this subject, I would be grateful. Other than that, I was using Qlabel to the viewer and it seemed more straightforward for me, but once I intend to implement Rois, zoom, pan and other functions to the image I read from multiple places that I should use Qgraphicsview, and there I hit the first wall. I'm struggling to understand the framework, but I'm getting there. I think as the process of passing attributes among classes is more logical and clear to me, I can pass for the next level. Indeed, when I used parent () i felt some strange feeling in my stomach. Thanks again.
@IvanDesuo
For Python (PySide6) read https://doc.qt.io/qtforpython-6/tutorials/basictutorial/signals_and_slots.html. You will need to understand this for Qt programming. You would define your own signal for use withemit(), perhaps passing it a parameter ofevent.mimeData().urls()[0].toLocalFile()to be received in your slot. -
@IvanDesuo
For Python (PySide6) read https://doc.qt.io/qtforpython-6/tutorials/basictutorial/signals_and_slots.html. You will need to understand this for Qt programming. You would define your own signal for use withemit(), perhaps passing it a parameter ofevent.mimeData().urls()[0].toLocalFile()to be received in your slot.