Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Help with design choices and code structure.
Qt 6.11 is out! See what's new in the release blog

Help with design choices and code structure.

Scheduled Pinned Locked Moved Unsolved Qt for Python
6 Posts 3 Posters 1.7k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • I Offline
    I Offline
    IvanDesuo
    wrote on last edited by IvanDesuo
    #1

    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.

    mainpanels.py

    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)
    

    mainwindow.py

    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.

    fc4f8144-6e34-4e30-a7ae-4caada7b5cc9-image.png

    JonBJ 1 Reply Last reply
    0
    • I IvanDesuo

      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.

      mainpanels.py

      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)
      

      mainwindow.py

      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.

      fc4f8144-6e34-4e30-a7ae-4caada7b5cc9-image.png

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by
      #2

      @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.

      I 1 Reply Last reply
      3
      • JonBJ JonB

        @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.

        I Offline
        I Offline
        IvanDesuo
        wrote on last edited by
        #3

        @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.

        jsulmJ JonBJ 2 Replies Last reply
        0
        • I IvanDesuo

          @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.

          jsulmJ Offline
          jsulmJ Offline
          jsulm
          Lifetime Qt Champion
          wrote on last edited by
          #4

          @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

          https://doc.qt.io/qt-6/signalsandslots.html

          https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          1
          • I IvanDesuo

            @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.

            JonBJ Offline
            JonBJ Offline
            JonB
            wrote on last edited by
            #5

            @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 with emit(), perhaps passing it a parameter of event.mimeData().urls()[0].toLocalFile() to be received in your slot.

            I 1 Reply Last reply
            2
            • JonBJ JonB

              @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 with emit(), perhaps passing it a parameter of event.mimeData().urls()[0].toLocalFile() to be received in your slot.

              I Offline
              I Offline
              IvanDesuo
              wrote on last edited by
              #6

              @JonB awesome! Thx a lot!

              1 Reply Last reply
              0

              • Login

              • Login or register to search.
              • First post
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • Users
              • Groups
              • Search
              • Get Qt Extensions
              • Unsolved