在 Slider 中禁用箭头键

disable arrow keys in Slider

当使用 scikit CollectionViewer(简单图像浏览器)时,我希望在滑块获得焦点后按下箭头键不会触发转到 prev/next 图像。我为此使用了 eventFilter

from skimage.viewer import ImageViewer
from skimage.viewer.qt import Qt
from skimage.viewer.widgets import Slider

class SilentViewer(ImageViewer): #CollectionViewer with some modifications

    def __init__(self, image_collection, update_on='move', **kwargs):
        self.image_collection = image_collection
        self.index = 0
        self.num_images = len(self.image_collection)

        first_image = image_collection[0]
        super(SilentViewer, self).__init__(first_image)

        slider_kws = dict(value=0, low=0, high=self.num_images - 1)
        slider_kws['update_on'] = update_on
        slider_kws['callback'] = self.update_index
        slider_kws['value_type'] = 'int'
        self.slider = Slider('frame', **slider_kws)
        self.layout.addWidget(self.slider)
        self.installEventFilter(self) #Modification to CollectionViewer №1

    def update_index(self, name, index):
        index = int(round(index))

        if index == self.index:
            return

        index = max(index, 0)
        index = min(index, self.num_images - 1)

        self.index = index
        self.slider.val = index
        self.update_image(self.image_collection[index])

    def eventFilter(self,obj,evt): #Modification to CollectionViewer №2
        try:
            print(evt.type(), evt.key(), evt.text())
            if (evt.key() == Qt.Key_Left or
                evt.key() == Qt.Key_Right or
                evt.key() == Qt.Key_Up or
                evt.key() == Qt.Key_Down):

                print("Ignored arrow button")
                return True
            else:
                return False
        except:
            print("Smth went wrong")
            return False

#for testing reasons
from skimage import data
from skimage.transform import pyramid_gaussian

img = data.coins()
img_pyr = pyramid_gaussian(img, downscale=2, multichannel=False)
img_collection = tuple(img_pyr)
viewer = SilentViewer(img_collection)
viewer.show()

事件过滤器似乎在工作:按键和其他事件触发控制台输出。但是,箭头键会触发图像更改。如果我更改为 update_on='release'(请参阅 init),箭头键不会触发图像更改,但会更改滑块位置。 你能告诉我怎样才能让箭头按下被过滤器完全消耗吗?

分析the Slider source code,可以看出它是一个容器,也就是一个widget里面有其他的widget(QLabel,QSlider和QLineEdit),所以filter必须安装在内部的QSlider和不在容器上。

from skimage.viewer import ImageViewer
from skimage.viewer.qt import QtCore
from skimage.viewer.widgets import Slider


class SilentViewer(ImageViewer):  # CollectionViewer with some modifications
    def __init__(self, image_collection, update_on="move", **kwargs):
        self.image_collection = image_collection
        self.index = 0
        self.num_images = len(self.image_collection)

        print(self.num_images)

        first_image = image_collection[0]
        super(SilentViewer, self).__init__(first_image)

        slider_kws = dict(value=0, low=0, high=self.num_images - 1)
        slider_kws["update_on"] = update_on
        slider_kws["callback"] = self.update_index
        slider_kws["value_type"] = "int"
        self.slider = Slider("frame", **slider_kws)
        self.layout.addWidget(self.slider)

        self.slider.slider.installEventFilter(self)

    def update_index(self, name, index):
        if index == self.index:
            return
        index = max(index, 0)
        index = min(index, self.num_images - 1)
        self.index = index
        self.update_image(self.image_collection[index])

    def eventFilter(self, obj, evt):
        if obj is self.slider.slider and evt.type() == QtCore.QEvent.KeyPress:
            if evt.key() in (
                QtCore.Qt.Key_Left,
                QtCore.Qt.Key_Right,
                QtCore.Qt.Key_Up,
                QtCore.Qt.Key_Down,
            ):
                return True
        return super(SilentViewer, self).eventFilter(obj, evt)


def main():
    # for testing reasons
    from skimage import data
    from skimage.transform import pyramid_gaussian

    img = data.coins()
    img_pyr = pyramid_gaussian(img, downscale=2, multichannel=False)
    img_collection = tuple(img_pyr)
    viewer = SilentViewer(img_collection)
    viewer.show()


if __name__ == "__main__":
    main()