0

前のウィジェットで動的に設定されたプロパティに従って、動的に作成されたウィジェット(削除可能)内にあるラベルを更新する方法を見つけようとしています。

pyqtオブジェクトを他のウィジェットのプロパティに自動的かつ動的にリンクして、どこかで値を変更すると、そのオブジェクトが自動的に更新されるようにする方法はありますか?

例:オブジェクト'a'にはプロパティstartbarsあり、end; barsが与えられ、start前のオブジェクト(またはNoneの場合endは1)によって取得され、計算されます。オブジェクト'b'はstartfroma.endなどを取得します。

class myclass(object):
  def __init__(self, referrer=None, value=1):
    self.referrer=referrer
    self.value=value

  def _get_start(self):
    if not self.referrer:
      return 1
    else:
      return self.referrer.end+1

  def _get_end(self):
    return self.start+self.value-1

  start=property(_get_start)
  end=property(_get_end)

def create(value=1):
  if not vList:
    ref=None
  else:
    ref=vList[-1]
  val=myclass(ref, value)
  vList.append(val)

def showList():
  for i in vList:
    print 'item: %d\tstart: %d\tend: %d' % (vList.index(i),i.start, i.end)

vList=[]

create()を3回呼び出すと、showList()は次のように表示されます。

item: 0 start: 1        end: 1
item: 1 start: 2        end: 2
item: 2 start: 3        end: 3

vList [0] .valueを3に変更した場合:

item: 0 start: 1        end: 3
item: 1 start: 4        end: 4
item: 2 start: 5        end: 5

これらの値をGUIで更新し続ける必要がある場合(このようなインターフェイスと考えてください)、問題が発生します。すべての水平ウィジェットには、のプロパティを示すラベルstart、のスピンボックス、およびbarsラベルがありend、スピンボックスの値が変更されると、後続のすべてのウィジェットは、前のウィジェットに従ってプロパティとプロパティを更新し、相対ラベルに表示する必要があります。さらに、ウィジェットが削除されると、後続のすべてのウィジェットはすべてのプロパティを再計算する必要があります。startend

getter / setterを使用してウィジェットの次のインスタンスのラベルに値を設定することは、必要に応じて明らかに機能しません。これx.valueは、次のインスタンスstartを変更すると、end実際にはリコールされたときにのみ更新されるためです。すべての新しいウィジェットを以前のウィジェットに接続するvalueChanged()か(を使用して)、後続のウィジェットを検索してそれらのプロパティを更新する関数を作成することもできますが、それは良い解決策ではありません。

私はPythonにほとんど慣れていないので(最も重要です:私はプログラマーではありません)、変数をより適切でクリーンな方法で「接続」することについて何かを無視していると思います(おそらくシグナルやスレッドに関連していますか?)。

これらのウィジェットは、実際には別の「メイン」ウィジェットの子ウィジェットであり、同様のプロパティを持つことを考慮してください。start以前のメインウィジェット(存在する場合)から取得されます。これは、すべての子ウィジェットbarsのすべての合計です。barsendstart+bars-a

ありがとう!

(私が何を意味するのか理解していただければ幸いです。私の英語は完璧ではありません。私はプログラマーではないので、私の用語は必ずしも正しいとは限りません)

4

1 に答える 1

2

あなたの質問のユースケースは見つかりませんが、Qt Signals-Slots を使用した可能な解決策は次のとおりです。

# -*- coding: utf-8 -*-
import functools

from PyQt4 import QtGui, QtCore


class ObservableVariable(QtCore.QObject):
    """ Represents variable with value, when value changes it emits
    signal: changed(new_value)
    """
    changed = QtCore.pyqtSignal(object)

    def __init__(self, initial_value=0):
        super(ObservableVariable, self).__init__()
        self._value = initial_value

    def get_value(self):
        return self._value

    def set_value(self, new_val):
        self._value = new_val
        self.changed.emit(new_val)

    value = property(get_value, set_value)

    def __str__(self):
        return str(self.value)

    # it can support more operators if needed
    def __iadd__(self, other):
        self.value += other
        return self

    def __isub__(self, other):
        self.value -= other
        return self


class MyClass(object):
    def __init__(self, referrer=None, value=1):
        self.referrer = referrer
        self.value = ObservableVariable(value)
        self._initial_value = value
        if referrer:
            # propagate referrer changes to subscribers
            referrer.value.changed.connect(
                lambda x: self.value.changed.emit(self.value.value)
            )

    @property
    def start(self):
        if not self.referrer:
            return self.value.value
        return self.referrer.end + 1

    @property
    def end(self):
        return self.start + self.value.value - 1


class GuiExample(QtGui.QWidget):
    def __init__(self):
        super(GuiExample, self).__init__()
        self.values = []
        layout = QtGui.QVBoxLayout(self)
        obj = None
        for i in range(5):
            obj = MyClass(obj, i)
            self.values.append(obj)
            # create gui elements
            hlayout = QtGui.QHBoxLayout()
            spinbox = QtGui.QSpinBox()
            spinbox.setValue(obj.value.value)
            start_label = QtGui.QLabel()
            end_label = QtGui.QLabel()
            hlayout.addWidget(start_label)
            hlayout.addWidget(spinbox)
            hlayout.addWidget(end_label)
            layout.addLayout(hlayout)

            # function called on value change
            def update_start_end(instance, start_label, end_label):
                start_label.setText(str(instance.start))
                end_label.setText(str(instance.end))

            action = functools.partial(update_start_end, obj, start_label,
                                       end_label)
            action()  # set initial start end text to labels
            # connect signals to gui elements
            obj.value.changed.connect(action)
            spinbox.valueChanged.connect(obj.value.set_value)
            obj.value.changed.connect(spinbox.setValue)
        layout.addWidget(QtGui.QPushButton('test',
                                           clicked=self.test_modification))

    def test_modification(self):
        self.values[1].value += 1


app = QtGui.QApplication([])
gui = GuiExample()
gui.show()

app.exec_()
于 2013-02-04T05:28:58.340 に答える