PyQt GUI: как хранить данные (объекты классов)? - PullRequest
0 голосов
/ 26 сентября 2018

Я недавно начал программировать на python и написал свой первый графический интерфейс для пост-обработки и оценки данных ЯМР с использованием PyQt.Текущая версия приложения выглядит следующим образом: screenshot of the pyqt app

Типичный рабочий процесс:

  1. чтение данных различных экспериментов (обычно 3D или 4D (2D / 3D + время / частота) стеки изображений)
  2. выполнить некоторую постобработку, такую ​​как определение областей интереса (ROI), подбор спектров с разрешением по времени / частоте, расчет контрастов и т. Д.
  3. визуализация результатов в графическом интерфейсе
  4. экспорт результатов в виде изображений / графиков / таблиц с результатами подгонки (xml)
  5. сохранение рабочей области для возможности ее перезагрузки

Стеки изображений 4d хранятся вместе с экспериментальными настройками, настройками восстановления изображений, результатами подгонки и т. Д. Как объекты класса моего собственного класса MriData:

class MriData:
   def __init__(self, path='', exp_num=0, exp_name=''):
       self.path = path
       self.exp_num = exp_num
       self.exp_name = exp_name    
       self.img_stack = np.array([])
       self.ROIs = []  # list of ROIs  
       self.settings= {}
       self.lmfit = {}
       ...

В настоящее время у моего MainWindow есть атрибут "mri_data "типа списка, где я храню все объекты данных / класса.Если я выбираю (несколько) экспериментов и / или областей интереса в QTreeWidget слева, я всегда проверяю, является ли элемент элементом верхнего уровня или нет, получаю индекс эксперимента (и индекс области интереса, если он один)и затем получить доступ к соответствующей записи списка в списке «mri_data»:

list_items: = self.QTreeWidget.selectedItems()
list_idx = self.QTreeWidget.selectedIndexes()
list_zipped = zip(list_idx, list_items)
for (index, item) in list_zipped:
    if not item.parent():  # if current item is exp
        data = self.mri_data[index.row()]
    else:  # if current item is ROI
        idx_parent = self.QTreeWidget.indexFromItem(item.parent())
        data = self.QTreeWidget[idx_parent.row()].ROIs[index.row()]

Это работает, но это, очевидно, не так здорово, и я совершенно уверен, что это очень неэффективно.Вот почему я пишу этот пост.Я прочитал, что могу хранить данные в QTreeWidgetItems, но прежде чем переписать весь код, я хотел спросить экспертов, хорошая ли это идея.Я не смог найти никакой информации о производительности, если хранимые данные достаточно велики (4d стеки размером до 256x256x32x2500 и у меня одновременно до нескольких сотен экспериментов в QTreeWidget).Или, может быть, лучше использовать совершенно другой подход к базе данных?К сожалению, (по крайней мере, для меня) очень трудно найти учебники или сообщения о похожих проблемах ... может быть, потому что я использую неправильные ключевые слова ?!

Заранее спасибо за ваши ответы / советы / ссылки и т. Д.

1 Ответ

0 голосов
/ 16 июля 2019

Я тестировал реализацию, где я храню данные в QTreeWidgetItems в течение достаточно долгого времени, и, по крайней мере, в моем случае это работает как чудо.Например, добавление новых элементов очень удобно:

def add_dataset(self, _obj):
    """adds new QTreeWidgetItem when 'addItemSignal' is emitted from ImportDataDialog"""
    tree_obj = QtWidgets.QTreeWidgetItem([_obj.name])
    tree_obj.setData(1, QtCore.Qt.UserRole, _obj)
    self.treeWidget.addTopLevelItem(tree_obj)

Однако лучше всего для меня это очень простой и элегантный способ сохранения / загрузки рабочих пространств с использованием QDataStream:

def action_saveworkspace_triggered(self, filename):
    """Saves current workspace to the selected file"""
    file = QtCore.QFile(filename)
    file.open(QtCore.QIODevice.WriteOnly)
    datastream = QtCore.QDataStream(file)
    root_item = self.treeWidget.invisibleRootItem()

    # write the total number of items to be stored
    datastream.writeUInt32(root_item.childCount())

    # write all data (= all elements of the TreeWidget) to the file
    for n in range(root_item.childCount()):
        item = root_item.child(n)
        item.write(datastream)

Я до сих пор не уверен, что это самый эффективный способ, но, по крайней мере, для моего приложения у меня не возникает проблем с производительностью и т. Д.

...