今回は、前回やった「intSliderGrpモドキ」をベースに「floatSliderGrpモドキ」を作っていきたいと思います!まだ、みてないーって方は、昨日の記事も見てから読む事をオススメします!(`・ω・´)ゞ
簡単にできない理由
「intSliderGrpモドキ」をベースに作成しますが、、、
「QSpinBox」を「QDoubleSpinBox」に変えればいいんじゃない?
と思った方もいると思いますが、、、
スライダーを動かしても整数の部分しか変化しなくて、細かい調整ができない!!「QSlider」は「intでしか操作できない」ので、そのままじゃダメなんですね(´・ω・`)
今回は、「QSlider」とのやり取りにひと工夫して、「QDoubleSpinBox」と関連付けて行きたいと思います!!
作成の手順!
- クラスの骨格
- 「QSlider」とやりとりする考え方
- 「QDoubleSpinBox」の設定から「QSlider」の範囲を割り出す
- 「valueChangedCallback」の修正
- 「__updateSliderRange」を必要なところに追加する
クラスの骨格
まずは、クラスの骨格を用意します!「QSpinBox」を「QDoubleSpinBox」に変えるだけで、前回とかぶる部分は飛ばします!
from PySide import QtCore, QtGui class DoubleSlider(QtGui.QWidget): #floatに変更 valueChanged = QtCore.Signal(float) def __init__(self, *args, **kwargs): super(DoubleSlider, self).__init__(*args, **kwargs) layout = QtGui.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) # QDoubleSpinBoxに変更 self.__doubleSpinBox = QtGui.QDoubleSpinBox(self) self.__doubleSpinBox.setMinimumWidth(80) self.__doubleSpinBox.setButtonSymbols(QtGui.QAbstractSpinBox.NoButtons) layout.addWidget(self.__doubleSpinBox) self.__slider = QtGui.QSlider(QtCore.Qt.Horizontal, self) layout.addWidget(self.__slider) # floatに変更 self.__doubleSpinBox.valueChanged[float].connect(self.valueChangedCallback) self.__slider.valueChanged[int].connect(self.valueChangedCallback) def valueChangedCallback(self, value): sender = self.sender() if sender == self.__doubleSpinBox: self.__slider.blockSignals(True) self.__slider.setValue(value) self.__slider.blockSignals(False) elif sender == self.__slider: self.__doubleSpinBox.blockSignals(True) self.__doubleSpinBox.setValue(value) self.__doubleSpinBox.blockSignals(False) self.valueChanged.emit(value) def value(self): return self.__doubleSpinBox.value() def setValue(self, value): self.__doubleSpinBox.setValue(value) def setRange(self, min, max): self.__doubleSpinBox.setRange(min, max) self.__slider.setRange(min, max) # 新規追加 def setDecimals(self, prec): self.__doubleSpinBox.setDecimals(prec)
「QDoubleSpinBox」の、少数の桁を設定できるように「setDecimals」を追加で用意しました。
「QSlider」とやりとりする考え方
「QDoubleSpinBox」は、デフォルトの場合「0.00~99.99」まで数値が入力できるようになっていますが、「QSlider」で細かく設定できるようにするには「QSlider」の範囲を「100倍」して「0~9999」に設定してあげます!
でも、このまま「QDoubleSpinBox」に設定したらおかしくなるので、「100」で割り算して「0.00~99.99」の範囲に変更してから設定してあげます!
そう!QDoubleSpinBoxに設定された「少数の桁数(decimals)」を打ち消すように掛け算してあげればいいんですね(*´ω`*)
少数の桁数が1なら10倍、2なら100倍、3なら1000倍という具合です!
「QDoubleSpinBox」の設定から「QSlider」の範囲を割り出す
「QDoubleSpinBox」の設定から「QSlider」の範囲を割り出すために、メソッド「__updateSliderRange」を追加します。
from PySide import QtCore, QtGui class DoubleSlider(QtGui.QWidget): valueChanged = QtCore.Signal(float) def __init__(self, *args, **kwargs): ~中略~ def valueChangedCallback(self, value): ~中略~ def value(self): return self.__doubleSpinBox.value() def setValue(self, value): self.__doubleSpinBox.setValue(value) def setRange(self, min, max): ~中略~ def setDecimals(self, prec): self.__doubleSpinBox.setDecimals(prec) # 「QDoubleSpinBox」の設定から「QSlider」の範囲を割り出す def __updateSliderRange(self): # 少数の桁数を取得する decimals = self.__doubleSpinBox.decimals() # 設定できる最小値を取得する minimum = self.__doubleSpinBox.minimum() # 設定できる最大値を取得する maximum = self.__doubleSpinBox.maximum() # 少数の桁数を使って、倍率を文字列で求めてintに変換する。 # この値は、あとで使うので、インスタンス変数に代入します。 # # <decimalsが2の場合> # int('1'+('0'*2))は、int('1'+'00')→int('100')となります。 # # <decimalsが0の場合> # int('1'+('0'*0))は、int('1'+'')→int('1')となります。 # self.__boost = int('1'+('0'*decimals)) # QDoubleSpinBoxの範囲に、少数を打ち消す倍率を掛け算して設定する。 # # QDoubleSpinBoxの範囲が「0.00~99.99」の場合、 # QSliderの範囲は「0~9999」になる # self.__slider.setRange(minimum*self.__boost, maximum*self.__boost)
文字列に対して掛け算をするっというのは、Pythonならでは?という感じがしますが結構便利ですね!
同じ文字を繰り返したい時は、掛け算してしまえば文字が増殖してくれます(*´ω`*)b
「valueChangedCallback」の修正
少数の桁を打ち消す倍率を保存したインスタンス変数「self.__boost」を使って、相互の値のやり取りを修正します。
from PySide import QtCore, QtGui class DoubleSlider(QtGui.QWidget): valueChanged = QtCore.Signal(float) def __init__(self, *args, **kwargs): ~中略~ def valueChangedCallback(self, value): sender = self.sender() if sender == self.__doubleSpinBox: self.__slider.blockSignals(True) # 少数を打ち消す倍率を適用して、QSliderに値を設定する self.__slider.setValue(value*self.__boost) self.__slider.blockSignals(False) elif sender == self.__slider: # 少数を打ち消す倍率を適用して、変数の値を上書きする # 値を上書きするのは、カスタムのSignalをエミットする必要があるからです。 value = float(value)/self.__boost self.__doubleSpinBox.blockSignals(True) self.__doubleSpinBox.setValue(value) self.__doubleSpinBox.blockSignals(False) self.valueChanged.emit(value) def value(self): return self.__doubleSpinBox.value() def setValue(self, value): self.__doubleSpinBox.setValue(value) def setRange(self, min, max): ~中略~ def setDecimals(self, prec): ~中略~ def __updateSliderRange(self): ~中略~
「__updateSliderRange」を必要なところに追加する
最後に、「QDobuleSpinBox」の設定を後から変えられるようにしているので、各所にスライダーを更新するようにメソッド「__updateSliderRange」の呼び出しを追加します。
from PySide import QtCore, QtGui class DoubleSlider(QtGui.QWidget): valueChanged = QtCore.Signal(float) def __init__(self, *args, **kwargs): super(DoubleSlider, self).__init__(*args, **kwargs) layout = QtGui.QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) self.__doubleSpinBox = QtGui.QDoubleSpinBox(self) self.__doubleSpinBox.setMinimumWidth(80) self.__doubleSpinBox.setButtonSymbols(QtGui.QAbstractSpinBox.NoButtons) layout.addWidget(self.__doubleSpinBox) self.__slider = QtGui.QSlider(QtCore.Qt.Horizontal, self) self.__updateSliderRange()# QDoubleSpinBoxに合わせて、スライダーを初期化する layout.addWidget(self.__slider) self.__doubleSpinBox.valueChanged[float].connect(self.valueChangedCallback) self.__slider.valueChanged[int].connect(self.valueChangedCallback) def valueChangedCallback(self, value): sender = self.sender() if sender == self.__doubleSpinBox: self.__slider.blockSignals(True) self.__slider.setValue(value*self.__boost) self.__slider.blockSignals(False) elif sender == self.__slider: value = float(value)/self.__boost self.__doubleSpinBox.blockSignals(True) self.__doubleSpinBox.setValue(value) self.__doubleSpinBox.blockSignals(False) self.valueChanged.emit(value) def value(self): return self.__doubleSpinBox.value() def setValue(self, value): self.__doubleSpinBox.setValue(value) def setRange(self, min, max): self.__doubleSpinBox.setRange(min, max) self.__updateSliderRange()# 範囲が変更されたので、スライダーも更新する def setDecimals(self, prec): self.__doubleSpinBox.setDecimals(prec) self.__updateSliderRange()# 桁数が変更されたので、スライダーも更新する def __updateSliderRange(self): decimals = self.__doubleSpinBox.decimals() minimum = self.__doubleSpinBox.minimum() maximum = self.__doubleSpinBox.maximum() self.__boost = int('1'+('0'*decimals)) self.__slider.setRange(minimum*self.__boost, maximum*self.__boost)
以上、floatSliderGrpモドキの完成です!(`・ω・´)ゞ
そろそろAmazonプライムに加入しようか迷ってます。。。
みなさんは加入されていますか?