Виджет PySide не обновляется QDataWidgetMapper при отображении - PullRequest
0 голосов
/ 24 января 2020

Я пытаюсь использовать QDataWidgetMapper для управления пользовательским QComboBox с использованием Enum.

I Нахожусь на Windows 10, используя Python 2.7.13, PySide 1.2.4 (Qt 4.8.7), вот код:

from PySide.QtCore import Qt, Property
from PySide.QtGui import (
    QApplication,
    QComboBox,
    QDataWidgetMapper,
    QFormLayout,
    QLineEdit,
    QMainWindow,
    QPushButton,
    QStandardItem,
    QStandardItemModel,
    QWidget,
)
from enum import Enum


class State(Enum):

    foo = 1
    bar = 2
    baz = 3


class StateEdit(QComboBox):

    def __init__(self, parent=None):
        super(StateEdit, self).__init__(parent)
        self.addItems(State._member_names_)

    def state(self):
        text = self.currentText()
        return State[text] if text else None

    def setState(self, value):
        if value is None:
            index = -1
        else:
            index = self.findText(value.name, Qt.MatchExactly)
        self.setCurrentIndex(index)

    state = Property(State, state, setState, user=True)


class Window(QMainWindow):

    def __init__(self, parent=None):
        super(Window, self).__init__(parent)

        self._name_edit = QLineEdit()
        self._state_edit = StateEdit()
        self._state_button = QPushButton('Change State')

        self._content = QWidget()
        self.setCentralWidget(self._content)

        self._form = QFormLayout()
        self._content.setLayout(self._form)

        self._form.addRow('Name', self._name_edit)
        self._form.addRow('State', self._state_edit)
        self._form.addRow('Action', self._state_button)

        self._state_button.released.connect(self._on_state_button_clicked)

        self._model = QStandardItemModel()
        name_item = QStandardItem()
        state_item = QStandardItem()
        name_item.setText('My Name')
        state_item.setData(State.bar)
        self._model.appendRow([name_item, state_item])

        self._mapper = QDataWidgetMapper()
        self._mapper.setModel(self._model)
        self._mapper.addMapping(self._name_edit, 0)
        self._mapper.addMapping(self._state_edit, 1, 'state')
        self._mapper.toFirst()

    def _on_state_button_clicked(self):
        self._state_edit.state = State.baz

    def data(self):
        return {
            'name': self._name_edit.text(),
            'state': self._state_edit.state,
        }



if __name__ == "__main__":
    import sys
    from pprint import pprint

    app = QApplication(sys.argv)
    win = Window()
    win.show()
    app.exec_()
    pprint(win.data())

Проблема в том, что виджет enum всегда всплывает показывая свой первый индекс.

Кажется, нет никаких проблем с самим свойством, так как установка его с помощью кнопки работает.

Состояние также обновляется при выборе другого индекса с помощью поля со списком, о чем свидетельствуют данные, напечатанные при закрытии окна.

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

Я также изучил это руководство , но, похоже, это обычные проблемы с QComboBox и QDataWidgetMapper на самом деле не применимы к моему случаю.

Единственное решение, которое я вижу, это использовать обычный рабочий процесс с QComboBox и просто использовать простые старые индексы вместо значений enum, но это было бы позором, мне просто нужно, чтобы начальное отображение было правильно запущено, и все работало бы отлично.

Я действительно не знаю, где искать, может быть, это проблема PySide Speci c, поэтому любые указатели помогут!

Ответы [ 2 ]

0 голосов
/ 02 мая 2020

Я проверяю твой код. И я нашел простое решение.

# At line 68
name_item.setText('My Name')
state_item.setText('')
state_item.setData(State.bar)

Реализуйте метод setText, тогда все будет работать правильно.

0 голосов
/ 30 января 2020

Так что в итоге я для простоты развернул свой собственный картограф данных.

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

Вот реализация, если это может кому-то помочь:

from Qt import QtCore, QtWidgets  # pylint: disable=no-name-in-module


class ModelWidgetMapper(QtCore.QObject):
    """
    :type model: Qt.QtCore.QAbstractItemModel
    :type parent: Qt.QtWidget.QWidget
    """

    class MappingEntry(object):
        """
        :type widget: Qt.QtWidget.QWidget
        :type section: int
        :type property_name: str
        :type getter: callable
        :type setter: callable
        """

        def __init__(self, widget, section, property_name, getter, setter):
            self.widget = widget
            self.section = section
            self.property_name = property_name
            self.getter = getter
            self.setter = setter

    def __init__(self, model, parent=None):
        super(ModelWidgetMapper, self).__init__(parent)
        self._model = model
        self._mapping = []
        self._current_index = None

    def model(self):
        """
        :rtype: Qt.QtCore.QAbstractItemModel
        """
        return self._model

    def add_mapping(self, widget, section, property_name=None, getter=None, setter=None):
        """
        :type widget: Qt.QtWidget.QWidget
        :type section: int
        :type proerty_name: str
        :type getter: callable
        :type setter: callable
        :rtype: ModelWidgetMapper.MappingEntry
        """
        entry = ModelWidgetMapper.MappingEntry(
            widget,
            section,
            property_name,
            getter,
            setter
        )
        self._mapping.append(entry)
        if self._current_index and self._current_index.isValid():
            self._update_widget_from_model(entry)
        return entry

    def submit(self):
        """
        :rtype: bool
        """
        res = True
        for entry in self._mapping:
            res = res & self._update_model_from_widget(entry)
        res & self._model.submit()
        return res

    def revert(self):
        self._model.revert()
        for entry in self._mapping:
            self._update_widget_from_model(entry)

    def set_current_index(self, index):
        """
        :type index: Qt.QtCore.QModelIndex
        """
        self._current_index = index
        for entry in self._mapping:
            self._update_widget_from_model(entry)

    def current_index(self):
        """
        :rtype: Qt.QtCore.QModelIndex
        """
        return self._current_index

    def edits(self):
        """
        :rtype: Dict[int, Any]
        """
        res = {}
        for entry in self._mapping:
            model_value = self._model_value(entry)
            widget_value = self._get_widget_property(entry)
            try:
                widget_value = type(model_value)(widget_value)
            except TypeError:
                pass
            if widget_value != model_value:
                res[entry.section] = widget_value
        return res

    def _model_value(self, entry):
        row = self._current_index.row()
        index = self._model.index(row, entry.section)
        value = self._model.data(index)
        return value

    def _update_widget_from_model(self, entry):
        value = self._model_value(entry)
        self._set_widget_property(entry, value)

    def _update_model_from_widget(self, entry):
        value = self._get_widget_property(entry)
        row = self._current_index.row()
        index = self._model.index(row, entry.section)
        return self._model.setData(index, value)

    def _get_widget_property(self, entry):
        if entry.getter:
            return entry.getter()
        elif not entry.property_name:
            return self._get_widget_user_property(entry.widget)
        return entry.widget.property(entry.property_name)

    def _get_widget_user_property(self, widget):
        return widget.metaObject().userProperty().read(widget)

    def _set_widget_property(self, entry, value):
        if entry.setter:
            return entry.setter(value)
        elif not entry.property_name:
            return self._set_widget_user_property(entry.widget, value)
        return entry.widget.setProperty(entry.property_name, value)

    def _set_widget_user_property(self, widget, value):
        return widget.metaObject().userProperty().write(widget, value)

Используется Qt.py Обертка для совместимости.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...