отключить клавиши со стрелками в слайдере

При использовании scikit CollectionViewer (простой браузер изображений) я бы хотел, чтобы нажатие клавиш со стрелками не запускало переход к предыдущему/следующему изображению после того, как слайдер получил фокус. Я использовал 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' (см. инициализацию), клавиши со стрелками не вызывают изменение изображения, а изменяют положение ползунка. Подскажите, пожалуйста, как сделать так, чтобы нажатия стрелок полностью потреблялись фильтром?


person Gryphon    schedule 14.06.2020    source источник
comment
Не могли бы вы добавить импорт, чтобы ваш код был MRE?, и чтобы вы могли тестировать и анализировать свой код.   -  person eyllanesc    schedule 14.06.2020
comment
Добавил импорт.   -  person Gryphon    schedule 14.06.2020
comment
Вы много внимания уделяете фильтру вместо того, чтобы объяснить свою цель. Не могли бы вы объяснить мне, что происходит до использования фильтра, что происходит после использования фильтра и что вы хотите, чтобы произошло.   -  person eyllanesc    schedule 14.06.2020
comment
Я наблюдаю, что без фильтра, и если ползунок сфокусирован, и я нажимаю клавиши со стрелками, ползунок перемещается, и поэтому изображение изменяется после вызова обратного вызова. Вы хотите, чтобы то же самое происходило при переходе от переезда к релизу?   -  person eyllanesc    schedule 14.06.2020
comment
До (с использованием исходного CollectionViewer): когда ползунок получает фокус после щелчка, нажатие клавиш со стрелками вызывает смену изображения (вправо и вверх для следующего изображения в коллекции, влево и вниз для предыдущего). Изменение изображения также может быть выполнено перетаскиванием ползунка или нажатием на положение ползунка.   -  person Gryphon    schedule 14.06.2020
comment
Что я хочу: Изображение должно меняться только с помощью мыши (нажатие или перетаскивание ползунка). Клавиши со стрелками следует игнорировать   -  person Gryphon    schedule 14.06.2020
comment
Что у меня есть (с SilentViewer): с update_on='move' я получаю точно такое же поведение, как и при использовании исходного CollectionViewer. Однако кнопка со стрелкой игнорируется. Клавиши со стрелками update_on='release' не вызывают смену изображения (и это нормально), но они влияют на положение ползунка (это не нормально).   -  person Gryphon    schedule 14.06.2020


Ответы (1)


Анализ исходного кода Slider видно, что это контейнер, то есть виджет, у которого есть другие виджеты (QLabel, QSlider и QLineEdit), поэтому фильтр нужно устанавливать на внутренний 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()
person eyllanesc    schedule 14.06.2020
comment
Спасибо, ваш код делает именно то, что я хочу. Я надеялся, что мы сможем отфильтровать нежелательное событие на уровне контейнера, то есть evt.type() == 51 (ShortcutOverride). - person Gryphon; 14.06.2020