是否必须以不同的方式处理键盘事件才能在 Matplotlib/PyQt5 中选择事件? [复制]

Posted

技术标签:

【中文标题】是否必须以不同的方式处理键盘事件才能在 Matplotlib/PyQt5 中选择事件? [复制]【英文标题】:Do keyboard events have to be handled in a different manner to pick events in Matplotlib/PyQt5? [duplicate] 【发布时间】:2018-07-06 11:47:32 【问题描述】:

我不知道我做错了什么,或者这是否是 Matplotlib 中的错误。我有一个主要人物,里面有各种物品。当用户点击一个对象/艺术家时,应该会弹出一个单独的窗口以显示一个包含该对象信息的表格。表格可能非常大,因此窗口需要可滚动。我还希望两个窗口都处理拾取事件和键盘按下事件,最好使用相同的事件处理函数,尽管这并不重要。

我从 PyQt5 版本 here 改编了可滚动窗口的实现。下面是一些说明问题的虚拟代码:

import matplotlib

matplotlib.use('Qt5Agg')
import matplotlib.pyplot as plt
from PyQt5 import QtWidgets
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from matplotlib.figure import Figure
from matplotlib.lines import Line2D

class ScrollableWindow(QtWidgets.QMainWindow):

    def __init__(self, fig, windowTitle="Matplotlib"):
        QtWidgets.QMainWindow.__init__(self)
        self.widget = QtWidgets.QWidget()
        self.setCentralWidget(self.widget)
        self.widget.setLayout(QtWidgets.QVBoxLayout())
        self.widget.layout().setContentsMargins(0, 0, 0, 0)
        self.widget.layout().setSpacing(0)
        self.fig = fig
        self.canvas = FigureCanvasQTAgg(self.fig)
        self.canvas.draw()
        self.scroll = QtWidgets.QScrollArea(self.widget)
        self.scroll.setWidget(self.canvas)
        self.widget.layout().addWidget(self.scroll)
        self.setWindowTitle(windowTitle)

class MainClass(object):

    def __init__(self):
        self.scrollWindow = None
        self.tableFig = None

        lines = plt.plot([1, 2, 3], 'go-')
        lines[0].set_picker(True)

        canvas = plt.gcf().canvas
        canvas.mpl_connect('pick_event', self.onPick)
        canvas.mpl_connect('key_press_event', self.onKeyPress)

    def onPick(self, event):
        print("onPick called! Artist: %s" % event.artist)

        if isinstance(event.artist, Line2D):
            self.tableFig = self.createTableFigure()
            self.scrollWindow = ScrollableWindow(self.tableFig, "Table")
            canvas = self.tableFig.canvas
            canvas.mpl_connect('pick_event', self.onPick)
            canvas.mpl_connect('key_press_event', self.onKeyPress)
            self.scrollWindow.show()

    def onKeyPress(self, event):
        print('onKeyPress called! Key: ' + event.key)

    def createTableFigure(self):
        columnLabels = ('Length', 'Width', 'Height', 'Sold?')
        rowLabels = ['Jeep', 'Ferrari', 'Porsche']
        data = [[2.2, 1.6, 1.2, True],
                [2.1, 1.5, 1.4, False],
                [2.0, 1.4, 1.5, False]]

        tableFig = Figure(figsize=(6, 1))
        ax = tableFig.gca()
        ax.set_axis_off()
        table = matplotlib.table.table(ax, cellText=data, colLabels=columnLabels, rowLabels=rowLabels, cellLoc='center', loc='center')
        table.set_picker(True)
        return tableFig

m = MainClass()
plt.show()

主窗口显示一行。如果我单击该行,则会出现带有表格的可滚动窗口。如果我点击表格,您可以看到 onPick 方法按预期调用。

但是,onKeyPress 方法只有在我将主窗口设为当前窗口时才会被调用。选择表窗口时,将忽略按键,请忽略事件。为什么??这是 Matplotlib 中的错误还是应该以不同的方式处理按键事件以选择事件?如何让表格窗口响应按键事件?我已经看到了PyQt特定的答案,如this one关于处理键盘事件,但在选择事件与您预期的完全相同时,必须这样做似乎是奇数。也许这是鼠标与键盘事件的事情。我对 PyQt 很陌生。

使用 Python 2.7 和 Matplotlib 2.2.2。

【问题讨论】:

解决方案在this question中给出。一旦有人对答案投了赞成票,它就会被标记为重复。 谢谢!我出去了几天,但当我回来时,我会检查一下。 【参考方案1】:

@ImportanceOfBeingErnest 是对的。如果我将其中一条导入行更改为:

from PyQt5 import QtWidgets, QtCore

并在可滚动窗口的构造函数中的self.canvas = FigureCanvasQTAgg(self.fig) 之后立即添加这两行...

self.canvas.setFocusPolicy(QtCore.Qt.ClickFocus)
self.canvas.setFocus()

...那么表格窗口也会响应按键事件。

【讨论】:

以上是关于是否必须以不同的方式处理键盘事件才能在 Matplotlib/PyQt5 中选择事件? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

Java 系统范围的键盘快捷键

如何以编程方式生成按键事件? [复制]

如何以正确的方式检测 Android 设备?

setCapture只能作用于鼠标不可作用于键盘等其它事件

是否必须以调试方式编译 Tensorflow C++ DLL 才能根据它调试/运行代码?

(转)KeyDownKeyUpKeyPress区别