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. one model, two proxies, two views - Argg!
Forum Updated to NodeBB v4.3 + New Features

one model, two proxies, two views - Argg!

Scheduled Pinned Locked Moved Solved Qt for Python
3 Posts 2 Posters 381 Views 1 Watching
  • 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.
  • R Offline
    R Offline
    Raoul
    wrote on last edited by
    #1

    I'm trying to apply MVC in Pyside6. The problem for a hobbyist working alone like me, is that Pyside6 is so large it is very hard to get the correct model and philosophy of how it works in mind. The use case is a custom photo manager, with folders only in a treeview, and folders and thumbnails in a list view, sharing a selection model.
    My code is producing just the top level in both views; it is not starting at the desired subfolder; the folder view also contains filenames, which is shouldn't, and the listview only contains folders, when it should contain filenames.

    6802e771-fd73-42b5-83e9-fc80d15f4a87-image.png

    and expanding the treeview to show files when it shouldn't:
    42fd09cf-ba6b-4dd8-83f7-74446e45e0c4-image.png

    Here's a simplified example which runs and shows the problem.

    """
    Pycasa is intended to replicate the functionality of Google's Picasa image management utility.
    Google abandoned Picasa in 2016.  Pycasa is entirely in Python3, using PySide6 for the user interface, and
    Sqlite3 for storage of data.
    
    CODE CONVERTER:  Many examples for Qt are in C++.  Use https://www.codeconvert.ai/c++-to-python-converter to convert.
    
    DESIGN OF THE MAIN WINDOW
    Picasa's key feature for me was the display of the first line of caption underneath the thumbnail.  Then, upon
    displaying the photo, editing the caption, copying the caption, and easily moving to the next photo and pasting
    the caption.
    
    The essence of the design is to construct a widget containing the thumbnail and the caption, then displaying that
    widget in a list.  There are two choices of list, either a list view or a list widget.  This file uses the list view.
    
    Constructing the thumbnails pane is hard.
    Based on my research, there appear to be these ways to approach this problem.
    First, use a QListWidget instead of a QListView.
        Create the desired display widget, namely CaptionedThumbnail
        Create QListItems
        Bind the thumbnail to the list item with item.setItemWidget()
    Or, Use a QListView instead of a QListWidget
        Create a QStandardItemModel
        Create the desired display widget, namely CaptionedThumbnail
        Create a QStandardItem to hold the widget
        Add the item to the model
        Bind the widget to the model with setIndexWidget()
    Or, use a QStyledItemDelegate
        Subclass QStyledItemDelegate
        Define a paint function paint(self, painter, option, index)
        Use paint.drawControl(element, option, ...)
        I have read on the web that this should be used to edit data, so I may be forced to this more complex way.
    """
    import sys
    from pathlib import Path
    
    from PySide6.QtCore import (QItemSelection, QSortFilterProxyModel, QItemSelectionModel)
    from PySide6.QtCore import (QSize, Qt)
    from PySide6.QtWidgets import (QAbstractItemView, QAbstractScrollArea, QApplication, QFrame, QHBoxLayout, QLayout,
                                   QListView, QMainWindow, QSizePolicy, QTreeView, QVBoxLayout, QWidget)
    from PySide6.QtWidgets import (QFileSystemModel, QFileIconProvider)
    
    VALID_EXTENSIONS = (".jpg", ".jpeg", '.tif', '.tiff', '.png', ".raw", ".rw2", '.bmp', '.webp', '.heic')
    
    
    class CustomSortFilterProxyModel(QSortFilterProxyModel):
        """Filter for folders of any name, and files in VALID_EXTENSIONS, or just for folders"""
    
        def __init__(self, parent=None, filter_option: str = 'dir'):
            super().__init__(parent)
            self.filter_option = filter_option
    
        def filterAcceptsRow(self, row, parent):
            # The doc says to return False to filter out.  Returning True accepts the row.
            model = self.sourceModel()  # The underlying model
            index = model.index(row, 0)
            filepath = model.filePath(index)
            if self.filter_option.lower() == 'dir':
                if not Path(filepath).is_dir():
                    return False
            elif self.filter_option.lower() == 'files':
                if Path(filepath).is_dir() or Path(filepath).suffix in VALID_EXTENSIONS:
                    return True
                else:
                    return False
            else:
                return True
    
    
    class MainWindow(QMainWindow):
        def __init__(self, root_path: str | Path = None, test_run=False):
            super().__init__()
            self.root_path = root_path
    
            # ****** Code generated by Designer, but copied here for the bug demo
            self.centralwidget = QWidget(self)
            self.centralwidget.setObjectName(u"centralwidget")
            self.horizontalLayout = QHBoxLayout(self.centralwidget)
            self.horizontalLayout.setObjectName(u"horizontalLayout")
            self.fldrView = QTreeView(self.centralwidget)
            self.fldrView.setObjectName(u"fldrView")
            sizePolicy = QSizePolicy(QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Expanding)
            sizePolicy.setHorizontalStretch(0)
            sizePolicy.setVerticalStretch(0)
            sizePolicy.setHeightForWidth(self.fldrView.sizePolicy().hasHeightForWidth())
            self.fldrView.setSizePolicy(sizePolicy)
            self.fldrView.setMaximumSize(QSize(300, 16777215))
            self.fldrView.setLayoutDirection(Qt.LayoutDirection.LeftToRight)
            self.fldrView.setSizeAdjustPolicy(QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents)
            self.fldrView.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
            self.fldrView.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectItems)
            self.fldrView.setSortingEnabled(True)
            self.fldrView.setAnimated(True)
            self.fldrView.setWordWrap(True)
    
            self.horizontalLayout.addWidget(self.fldrView)
    
            self.verticalLayout_3 = QVBoxLayout()
            self.verticalLayout_3.setSpacing(0)
            self.verticalLayout_3.setObjectName(u"verticalLayout_3")
            self.verticalLayout_3.setSizeConstraint(QLayout.SizeConstraint.SetFixedSize)
            self.thumbnails = QListView(self.centralwidget)
            self.thumbnails.setObjectName(u"thumbnails")
            sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum)
            sizePolicy1.setHorizontalStretch(0)
            sizePolicy1.setVerticalStretch(0)
            sizePolicy1.setHeightForWidth(self.thumbnails.sizePolicy().hasHeightForWidth())
            self.thumbnails.setSizePolicy(sizePolicy1)
            self.thumbnails.setAutoFillBackground(True)
            self.thumbnails.setFrameShape(QFrame.Shape.StyledPanel)
            self.thumbnails.setSizeAdjustPolicy(QAbstractScrollArea.SizeAdjustPolicy.AdjustToContentsOnFirstShow)
            self.thumbnails.setTabKeyNavigation(True)
            self.thumbnails.setDragEnabled(True)
            self.thumbnails.setAlternatingRowColors(True)
            self.thumbnails.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection)
            self.thumbnails.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectColumns)
            self.thumbnails.setMovement(QListView.Movement.Snap)
            self.thumbnails.setFlow(QListView.Flow.LeftToRight)
            self.thumbnails.setResizeMode(QListView.ResizeMode.Adjust)
            self.thumbnails.setSpacing(12)
            self.thumbnails.setViewMode(QListView.ViewMode.IconMode)
            self.thumbnails.setUniformItemSizes(True)
            self.thumbnails.setBatchSize(98)
            self.thumbnails.setWordWrap(True)
            self.thumbnails.setSelectionRectVisible(True)
            self.thumbnails.setItemAlignment(Qt.AlignmentFlag.AlignLeading)
    
            self.verticalLayout_3.addWidget(self.thumbnails)
    
            self.horizontalLayout.addLayout(self.verticalLayout_3)
    
            self.setCentralWidget(self.centralwidget)
            # ************ end of code copied from Designer
            self.resize(1076, 708)
    
            # In the spirit of the MVC pattern, set up one model for both views.
            # Use QProxyModel to provide different filtering
            # For the thumbnails view, customize to display a widget constructed from the model's filename
            # But first, just get a list of the filespecs displayed
            model = QFileSystemModel()
            self.model = model
            model.directoryLoaded.connect(self.on_directoryLoaded)
            icon_provider = QFileIconProvider()
            model.setIconProvider(icon_provider)
            model.setReadOnly(False)  # True is the default
    
            # Create the proxy models, one for each view, but each sharing the same model
            self.folder_proxy = CustomSortFilterProxyModel(filter_option='dirs')
            self.folder_proxy.setSourceModel(model)
    
            self.thumbs_proxy = CustomSortFilterProxyModel(filter_option='files')
            self.thumbs_proxy.setSourceModel(model)
    
            # Set up the file directory pane.
            model.setRootPath(root_path)
    
            # ToDo: set the selection for the fldrView from the saved configuration
            # Set up the list view.  The view is created in Designer, but was copied into this bug demo
            # Attach the model to the view.  This must be done before setting root index and sorting.
            self.fldrView.setModel(self.folder_proxy)
            self.fldrView.setRootIndex(self.model.index(self.root_path))
            self.fldrView.sortByColumn(0, Qt.AscendingOrder)
            self.fldrView.setIconSize(QSize(0, 0))  # Get rid of the folder icon
            self.fldrView.setExpanded(self.fldrView.rootIndex(), True)
    
            # Hide some columns, all but the first 
            for i in range(1, self.model.columnCount()):
                self.fldrView.hideColumn(i)
    
            # Set up the thumbnails view
            # TODO: Set the style for the listview to have border = none.
            # Share the selection model with the folder view  (https://doc.qt.io/qt-5/model-view-programming.html)
            self.thumbnails.setSelectionModel(self.fldrView.selectionModel())
            self.thumbnails.setModel(self.thumbs_proxy)
            self.thumbnails.setRootIndex(self.model.index(self.root_path))
            self.thumbnails.setIconSize(QSize(0, 0))  # Get rid of the folder icon
    
            self.thumbnails.show()
            self.show()
    
            # define the connections of signals to slots
            # Below should be unnecessary because of sharing of the selection model between the views
            # self.fldrView.selectionModel().selectionChanged.connect(self.fldrView_current_changed)
    
        def on_directoryLoaded(self):
            print('on_directoryLoaded fired')
            self.fldrView.setModel(self.folder_proxy)
            self.thumbnails.setModel(self.thumbs_proxy)
            self.thumbnails.show()
    
        def fldrView_current_changed(self, selected: QItemSelection, deselected: QItemSelection):
            # Obsolete - sharing the selection model should make this unnecessary
            # Synchronize selection in the thumbnails view
            selection_index = self.fldrView.selectionModel().selectedIndexes()[0]
            self.thumbnails.selectionModel().select(selection_index, QItemSelectionModel.Select)
    
    
    def main():
        # Configure User Interface
        global APP
        APP = QApplication(sys.argv)
        APP.setStyle('default')
        global START_PATH
        START_PATH = "C:/Photographs/Misc"
        w = MainWindow(START_PATH)
        w.show()
        APP.exec()
    
    
    if __name__ == '__main__':
        main()
    
    
    jeremy_kJ 1 Reply Last reply
    0
    • R Raoul

      I'm trying to apply MVC in Pyside6. The problem for a hobbyist working alone like me, is that Pyside6 is so large it is very hard to get the correct model and philosophy of how it works in mind. The use case is a custom photo manager, with folders only in a treeview, and folders and thumbnails in a list view, sharing a selection model.
      My code is producing just the top level in both views; it is not starting at the desired subfolder; the folder view also contains filenames, which is shouldn't, and the listview only contains folders, when it should contain filenames.

      6802e771-fd73-42b5-83e9-fc80d15f4a87-image.png

      and expanding the treeview to show files when it shouldn't:
      42fd09cf-ba6b-4dd8-83f7-74446e45e0c4-image.png

      Here's a simplified example which runs and shows the problem.

      """
      Pycasa is intended to replicate the functionality of Google's Picasa image management utility.
      Google abandoned Picasa in 2016.  Pycasa is entirely in Python3, using PySide6 for the user interface, and
      Sqlite3 for storage of data.
      
      CODE CONVERTER:  Many examples for Qt are in C++.  Use https://www.codeconvert.ai/c++-to-python-converter to convert.
      
      DESIGN OF THE MAIN WINDOW
      Picasa's key feature for me was the display of the first line of caption underneath the thumbnail.  Then, upon
      displaying the photo, editing the caption, copying the caption, and easily moving to the next photo and pasting
      the caption.
      
      The essence of the design is to construct a widget containing the thumbnail and the caption, then displaying that
      widget in a list.  There are two choices of list, either a list view or a list widget.  This file uses the list view.
      
      Constructing the thumbnails pane is hard.
      Based on my research, there appear to be these ways to approach this problem.
      First, use a QListWidget instead of a QListView.
          Create the desired display widget, namely CaptionedThumbnail
          Create QListItems
          Bind the thumbnail to the list item with item.setItemWidget()
      Or, Use a QListView instead of a QListWidget
          Create a QStandardItemModel
          Create the desired display widget, namely CaptionedThumbnail
          Create a QStandardItem to hold the widget
          Add the item to the model
          Bind the widget to the model with setIndexWidget()
      Or, use a QStyledItemDelegate
          Subclass QStyledItemDelegate
          Define a paint function paint(self, painter, option, index)
          Use paint.drawControl(element, option, ...)
          I have read on the web that this should be used to edit data, so I may be forced to this more complex way.
      """
      import sys
      from pathlib import Path
      
      from PySide6.QtCore import (QItemSelection, QSortFilterProxyModel, QItemSelectionModel)
      from PySide6.QtCore import (QSize, Qt)
      from PySide6.QtWidgets import (QAbstractItemView, QAbstractScrollArea, QApplication, QFrame, QHBoxLayout, QLayout,
                                     QListView, QMainWindow, QSizePolicy, QTreeView, QVBoxLayout, QWidget)
      from PySide6.QtWidgets import (QFileSystemModel, QFileIconProvider)
      
      VALID_EXTENSIONS = (".jpg", ".jpeg", '.tif', '.tiff', '.png', ".raw", ".rw2", '.bmp', '.webp', '.heic')
      
      
      class CustomSortFilterProxyModel(QSortFilterProxyModel):
          """Filter for folders of any name, and files in VALID_EXTENSIONS, or just for folders"""
      
          def __init__(self, parent=None, filter_option: str = 'dir'):
              super().__init__(parent)
              self.filter_option = filter_option
      
          def filterAcceptsRow(self, row, parent):
              # The doc says to return False to filter out.  Returning True accepts the row.
              model = self.sourceModel()  # The underlying model
              index = model.index(row, 0)
              filepath = model.filePath(index)
              if self.filter_option.lower() == 'dir':
                  if not Path(filepath).is_dir():
                      return False
              elif self.filter_option.lower() == 'files':
                  if Path(filepath).is_dir() or Path(filepath).suffix in VALID_EXTENSIONS:
                      return True
                  else:
                      return False
              else:
                  return True
      
      
      class MainWindow(QMainWindow):
          def __init__(self, root_path: str | Path = None, test_run=False):
              super().__init__()
              self.root_path = root_path
      
              # ****** Code generated by Designer, but copied here for the bug demo
              self.centralwidget = QWidget(self)
              self.centralwidget.setObjectName(u"centralwidget")
              self.horizontalLayout = QHBoxLayout(self.centralwidget)
              self.horizontalLayout.setObjectName(u"horizontalLayout")
              self.fldrView = QTreeView(self.centralwidget)
              self.fldrView.setObjectName(u"fldrView")
              sizePolicy = QSizePolicy(QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Expanding)
              sizePolicy.setHorizontalStretch(0)
              sizePolicy.setVerticalStretch(0)
              sizePolicy.setHeightForWidth(self.fldrView.sizePolicy().hasHeightForWidth())
              self.fldrView.setSizePolicy(sizePolicy)
              self.fldrView.setMaximumSize(QSize(300, 16777215))
              self.fldrView.setLayoutDirection(Qt.LayoutDirection.LeftToRight)
              self.fldrView.setSizeAdjustPolicy(QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents)
              self.fldrView.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
              self.fldrView.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectItems)
              self.fldrView.setSortingEnabled(True)
              self.fldrView.setAnimated(True)
              self.fldrView.setWordWrap(True)
      
              self.horizontalLayout.addWidget(self.fldrView)
      
              self.verticalLayout_3 = QVBoxLayout()
              self.verticalLayout_3.setSpacing(0)
              self.verticalLayout_3.setObjectName(u"verticalLayout_3")
              self.verticalLayout_3.setSizeConstraint(QLayout.SizeConstraint.SetFixedSize)
              self.thumbnails = QListView(self.centralwidget)
              self.thumbnails.setObjectName(u"thumbnails")
              sizePolicy1 = QSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum)
              sizePolicy1.setHorizontalStretch(0)
              sizePolicy1.setVerticalStretch(0)
              sizePolicy1.setHeightForWidth(self.thumbnails.sizePolicy().hasHeightForWidth())
              self.thumbnails.setSizePolicy(sizePolicy1)
              self.thumbnails.setAutoFillBackground(True)
              self.thumbnails.setFrameShape(QFrame.Shape.StyledPanel)
              self.thumbnails.setSizeAdjustPolicy(QAbstractScrollArea.SizeAdjustPolicy.AdjustToContentsOnFirstShow)
              self.thumbnails.setTabKeyNavigation(True)
              self.thumbnails.setDragEnabled(True)
              self.thumbnails.setAlternatingRowColors(True)
              self.thumbnails.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection)
              self.thumbnails.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectColumns)
              self.thumbnails.setMovement(QListView.Movement.Snap)
              self.thumbnails.setFlow(QListView.Flow.LeftToRight)
              self.thumbnails.setResizeMode(QListView.ResizeMode.Adjust)
              self.thumbnails.setSpacing(12)
              self.thumbnails.setViewMode(QListView.ViewMode.IconMode)
              self.thumbnails.setUniformItemSizes(True)
              self.thumbnails.setBatchSize(98)
              self.thumbnails.setWordWrap(True)
              self.thumbnails.setSelectionRectVisible(True)
              self.thumbnails.setItemAlignment(Qt.AlignmentFlag.AlignLeading)
      
              self.verticalLayout_3.addWidget(self.thumbnails)
      
              self.horizontalLayout.addLayout(self.verticalLayout_3)
      
              self.setCentralWidget(self.centralwidget)
              # ************ end of code copied from Designer
              self.resize(1076, 708)
      
              # In the spirit of the MVC pattern, set up one model for both views.
              # Use QProxyModel to provide different filtering
              # For the thumbnails view, customize to display a widget constructed from the model's filename
              # But first, just get a list of the filespecs displayed
              model = QFileSystemModel()
              self.model = model
              model.directoryLoaded.connect(self.on_directoryLoaded)
              icon_provider = QFileIconProvider()
              model.setIconProvider(icon_provider)
              model.setReadOnly(False)  # True is the default
      
              # Create the proxy models, one for each view, but each sharing the same model
              self.folder_proxy = CustomSortFilterProxyModel(filter_option='dirs')
              self.folder_proxy.setSourceModel(model)
      
              self.thumbs_proxy = CustomSortFilterProxyModel(filter_option='files')
              self.thumbs_proxy.setSourceModel(model)
      
              # Set up the file directory pane.
              model.setRootPath(root_path)
      
              # ToDo: set the selection for the fldrView from the saved configuration
              # Set up the list view.  The view is created in Designer, but was copied into this bug demo
              # Attach the model to the view.  This must be done before setting root index and sorting.
              self.fldrView.setModel(self.folder_proxy)
              self.fldrView.setRootIndex(self.model.index(self.root_path))
              self.fldrView.sortByColumn(0, Qt.AscendingOrder)
              self.fldrView.setIconSize(QSize(0, 0))  # Get rid of the folder icon
              self.fldrView.setExpanded(self.fldrView.rootIndex(), True)
      
              # Hide some columns, all but the first 
              for i in range(1, self.model.columnCount()):
                  self.fldrView.hideColumn(i)
      
              # Set up the thumbnails view
              # TODO: Set the style for the listview to have border = none.
              # Share the selection model with the folder view  (https://doc.qt.io/qt-5/model-view-programming.html)
              self.thumbnails.setSelectionModel(self.fldrView.selectionModel())
              self.thumbnails.setModel(self.thumbs_proxy)
              self.thumbnails.setRootIndex(self.model.index(self.root_path))
              self.thumbnails.setIconSize(QSize(0, 0))  # Get rid of the folder icon
      
              self.thumbnails.show()
              self.show()
      
              # define the connections of signals to slots
              # Below should be unnecessary because of sharing of the selection model between the views
              # self.fldrView.selectionModel().selectionChanged.connect(self.fldrView_current_changed)
      
          def on_directoryLoaded(self):
              print('on_directoryLoaded fired')
              self.fldrView.setModel(self.folder_proxy)
              self.thumbnails.setModel(self.thumbs_proxy)
              self.thumbnails.show()
      
          def fldrView_current_changed(self, selected: QItemSelection, deselected: QItemSelection):
              # Obsolete - sharing the selection model should make this unnecessary
              # Synchronize selection in the thumbnails view
              selection_index = self.fldrView.selectionModel().selectedIndexes()[0]
              self.thumbnails.selectionModel().select(selection_index, QItemSelectionModel.Select)
      
      
      def main():
          # Configure User Interface
          global APP
          APP = QApplication(sys.argv)
          APP.setStyle('default')
          global START_PATH
          START_PATH = "C:/Photographs/Misc"
          w = MainWindow(START_PATH)
          w.show()
          APP.exec()
      
      
      if __name__ == '__main__':
          main()
      
      
      jeremy_kJ Offline
      jeremy_kJ Offline
      jeremy_k
      wrote on last edited by jeremy_k
      #2

      @Raoul said in one model, two proxies, two views - Argg!:

      I'm trying to apply MVC in Pyside6. The problem for a hobbyist working alone like me, is that Pyside6 is so large it is very hard to get the correct model and philosophy of how it works in mind.

      https://doc.qt.io/qtforpython-6/examples/index.html is a good place to start.

      Here's a simplified example which runs and shows the problem.

      That's too much code to work as a simple example, at least for me. Comments and unrelated UI setup code get in the way of understanding the core issue.

      This is a demonstration of a tree view and list view into the same filesystem model. It uses PyQt5, but translating to PySide 6 should be trivial.

      from PyQt5 import QtCore, QtWidgets
      
      class FilterModel(QtCore.QSortFilterProxyModel):
          def filterAcceptsRow(self, source_row: int, source_parent: QtCore.QModelIndex):
              index = self.sourceModel().index(source_row, 0 , source_parent)
              if self.sourceModel().isDir(index):
                  return True
              return False
      
      app = QtWidgets.QApplication([])
      
      model = QtWidgets.QFileSystemModel()
      model.setRootPath(app.applicationDirPath())
      filterModel = FilterModel()
      filterModel.setSourceModel(model)
      
      treeView = QtWidgets.QTreeView()
      listView = QtWidgets.QListView()
      treeView.setModel(filterModel)
      listView.setModel(model)
      treeView.clicked.connect(lambda index: listView.setRootIndex(filterModel.mapToSource(index)))
      
      splitter = QtWidgets.QSplitter()
      splitter.addWidget(treeView)
      splitter.addWidget(listView)
      splitter.show()
      app.exec()
      

      Asking a question about code? http://eel.is/iso-c++/testcase/

      1 Reply Last reply
      1
      • R Raoul has marked this topic as solved on
      • R Offline
        R Offline
        Raoul
        wrote on last edited by
        #3

        Thank you, this helped a lot. Your example works. I discovered a problem when I added in a second proxy model, but I will post that in a second topic.

        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