From 415bd38ce9f5ab3199f44f132d7da9b8f8f715a3 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Wed, 15 Apr 2020 10:17:32 +0200 Subject: [PATCH 1/3] Shorten comment & update link re: Qt focus policy. --- lib/matplotlib/backends/_backend_tk.py | 2 +- lib/matplotlib/backends/backend_qt5.py | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/lib/matplotlib/backends/_backend_tk.py b/lib/matplotlib/backends/_backend_tk.py index 30f4a801cd19..57935f660f94 100644 --- a/lib/matplotlib/backends/_backend_tk.py +++ b/lib/matplotlib/backends/_backend_tk.py @@ -405,8 +405,8 @@ class FigureManagerTk(FigureManagerBase): The tk.Toolbar window : tk.Window The tk.Window - """ + def __init__(self, canvas, num, window): FigureManagerBase.__init__(self, canvas, num) self.window = window diff --git a/lib/matplotlib/backends/backend_qt5.py b/lib/matplotlib/backends/backend_qt5.py index 64a127994aec..51c031a95b3f 100644 --- a/lib/matplotlib/backends/backend_qt5.py +++ b/lib/matplotlib/backends/backend_qt5.py @@ -512,7 +512,6 @@ class FigureManagerQT(FigureManagerBase): The qt.QToolBar window : qt.QMainWindow The qt.QMainWindow - """ def __init__(self, canvas, num): @@ -526,13 +525,10 @@ def __init__(self, canvas, num): image = str(cbook._get_data_path('images/matplotlib.svg')) self.window.setWindowIcon(QtGui.QIcon(image)) - # Give the keyboard focus to the figure instead of the - # manager; StrongFocus accepts both tab and click to focus and - # will enable the canvas to process event w/o clicking. - # ClickFocus only takes the focus is the window has been - # clicked - # on. http://qt-project.org/doc/qt-4.8/qt.html#FocusPolicy-enum or - # http://doc.qt.digia.com/qt/qt.html#FocusPolicy-enum + # Give the keyboard focus to the figure instead of the manager: + # StrongFocus accepts both tab and click to focus and will enable the + # canvas to process event without clicking. + # https://doc.qt.io/qt-5/qt.html#FocusPolicy-enum self.canvas.setFocusPolicy(QtCore.Qt.StrongFocus) self.canvas.setFocus() From ca2640871a6e06451ed7a25d0d9b5b496b9dd2f9 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Wed, 15 Apr 2020 10:17:51 +0200 Subject: [PATCH 2/3] Remove duplicate canvas assignments. These `self.canvas = canvas` are already being done by the base class init. --- lib/matplotlib/backends/_backend_tk.py | 2 -- lib/matplotlib/backends/backend_qt5.py | 1 - lib/matplotlib/backends/backend_wx.py | 1 - 3 files changed, 4 deletions(-) diff --git a/lib/matplotlib/backends/_backend_tk.py b/lib/matplotlib/backends/_backend_tk.py index 57935f660f94..e7def29b7716 100644 --- a/lib/matplotlib/backends/_backend_tk.py +++ b/lib/matplotlib/backends/_backend_tk.py @@ -412,7 +412,6 @@ def __init__(self, canvas, num, window): self.window = window self.window.withdraw() self.set_window_title("Figure %d" % num) - self.canvas = canvas # If using toolmanager it has to be present when initializing the # toolbar self.toolmanager = self._get_toolmanager() @@ -502,7 +501,6 @@ class NavigationToolbar2Tk(NavigationToolbar2, tk.Frame): ``pack_toolbar=False``. """ def __init__(self, canvas, window, *, pack_toolbar=True): - self.canvas = canvas # Avoid using self.window (prefer self.canvas.get_tk_widget().master), # so that Tool implementations can reuse the methods. self.window = window diff --git a/lib/matplotlib/backends/backend_qt5.py b/lib/matplotlib/backends/backend_qt5.py index 51c031a95b3f..2702ef23dcb9 100644 --- a/lib/matplotlib/backends/backend_qt5.py +++ b/lib/matplotlib/backends/backend_qt5.py @@ -516,7 +516,6 @@ class FigureManagerQT(FigureManagerBase): def __init__(self, canvas, num): FigureManagerBase.__init__(self, canvas, num) - self.canvas = canvas self.window = MainWindow() self.window.closing.connect(canvas.close_event) self.window.closing.connect(self._widgetclosed) diff --git a/lib/matplotlib/backends/backend_wx.py b/lib/matplotlib/backends/backend_wx.py index 4114be06d16e..091fece535f5 100644 --- a/lib/matplotlib/backends/backend_wx.py +++ b/lib/matplotlib/backends/backend_wx.py @@ -1110,7 +1110,6 @@ class NavigationToolbar2Wx(NavigationToolbar2, wx.ToolBar): def __init__(self, canvas): wx.ToolBar.__init__(self, canvas.GetParent(), -1) NavigationToolbar2.__init__(self, canvas) - self.canvas = canvas self._idle = True self.prevZoomRect = None # for now, use alternate zoom-rectangle drawing on all From a19495c35202f7b40ff2b105131006fcec417392 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Wed, 15 Apr 2020 10:23:09 +0200 Subject: [PATCH 3/3] Dedupe _get_toolmanager and move it to base class init. It's mostly simple, except specifically for the wx backend which for some reason previously attached the toolmanager to the Frame (aka "Window" in other toolkits parlance) so needs some properties to redirect things to the right place. --- lib/matplotlib/backend_bases.py | 5 ++++- lib/matplotlib/backends/_backend_tk.py | 11 ---------- lib/matplotlib/backends/backend_gtk3.py | 10 --------- lib/matplotlib/backends/backend_qt5.py | 9 -------- lib/matplotlib/backends/backend_wx.py | 28 ++++++++++++++----------- 5 files changed, 20 insertions(+), 43 deletions(-) diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index f494ee167975..00ea846bb970 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -46,6 +46,7 @@ backend_tools as tools, cbook, colors, textpath, tight_bbox, transforms, widgets, get_backend, is_interactive, rcParams) from matplotlib._pylab_helpers import Gcf +from matplotlib.backend_managers import ToolManager from matplotlib.transforms import Affine2D from matplotlib.path import Path @@ -2590,7 +2591,9 @@ def __init__(self, canvas, num): 'button_press_event', self.button_press) - self.toolmanager = None + self.toolmanager = (ToolManager(canvas.figure) + if mpl.rcParams['toolbar'] == 'toolmanager' + else None) self.toolbar = None @self.canvas.figure.add_axobserver diff --git a/lib/matplotlib/backends/_backend_tk.py b/lib/matplotlib/backends/_backend_tk.py index e7def29b7716..bbe94cd48195 100644 --- a/lib/matplotlib/backends/_backend_tk.py +++ b/lib/matplotlib/backends/_backend_tk.py @@ -15,7 +15,6 @@ from matplotlib.backend_bases import ( _Backend, FigureCanvasBase, FigureManagerBase, NavigationToolbar2, StatusbarBase, TimerBase, ToolContainerBase, cursors) -from matplotlib.backend_managers import ToolManager from matplotlib._pylab_helpers import Gcf from matplotlib.figure import Figure from matplotlib.widgets import SubplotTool @@ -412,9 +411,6 @@ def __init__(self, canvas, num, window): self.window = window self.window.withdraw() self.set_window_title("Figure %d" % num) - # If using toolmanager it has to be present when initializing the - # toolbar - self.toolmanager = self._get_toolmanager() # packing toolbar first, because if space is getting low, last packed # widget is getting shrunk first (-> the canvas) self.toolbar = self._get_toolbar() @@ -439,13 +435,6 @@ def _get_toolbar(self): toolbar = None return toolbar - def _get_toolmanager(self): - if mpl.rcParams['toolbar'] == 'toolmanager': - toolmanager = ToolManager(self.canvas.figure) - else: - toolmanager = None - return toolmanager - def resize(self, width, height): self.canvas._tkcanvas.configure(width=width, height=height) diff --git a/lib/matplotlib/backends/backend_gtk3.py b/lib/matplotlib/backends/backend_gtk3.py index d565818e07e5..7fdc6070b9d4 100644 --- a/lib/matplotlib/backends/backend_gtk3.py +++ b/lib/matplotlib/backends/backend_gtk3.py @@ -10,7 +10,6 @@ from matplotlib.backend_bases import ( _Backend, FigureCanvasBase, FigureManagerBase, NavigationToolbar2, StatusbarBase, TimerBase, ToolContainerBase, cursors) -from matplotlib.backend_managers import ToolManager from matplotlib.figure import Figure from matplotlib.widgets import SubplotTool @@ -343,7 +342,6 @@ def __init__(self, canvas, num): w = int(self.canvas.figure.bbox.width) h = int(self.canvas.figure.bbox.height) - self.toolmanager = self._get_toolmanager() self.toolbar = self._get_toolbar() self.statusbar = None @@ -420,14 +418,6 @@ def _get_toolbar(self): toolbar = None return toolbar - def _get_toolmanager(self): - # must be initialised after toolbar has been set - if mpl.rcParams['toolbar'] == 'toolmanager': - toolmanager = ToolManager(self.canvas.figure) - else: - toolmanager = None - return toolmanager - def get_window_title(self): return self.window.get_title() diff --git a/lib/matplotlib/backends/backend_qt5.py b/lib/matplotlib/backends/backend_qt5.py index 2702ef23dcb9..1bb4f55e5397 100644 --- a/lib/matplotlib/backends/backend_qt5.py +++ b/lib/matplotlib/backends/backend_qt5.py @@ -15,7 +15,6 @@ TimerBase, cursors, ToolContainerBase, StatusbarBase, MouseButton) import matplotlib.backends.qt_editor.figureoptions as figureoptions from matplotlib.backends.qt_editor.formsubplottool import UiSubplotTool -from matplotlib.backend_managers import ToolManager from . import qt_compat from .qt_compat import ( QtCore, QtGui, QtWidgets, _isdeleted, is_pyqt5, __version__, QT_API) @@ -533,7 +532,6 @@ def __init__(self, canvas, num): self.window._destroying = False - self.toolmanager = self._get_toolmanager() self.toolbar = self._get_toolbar(self.canvas, self.window) self.statusbar = None @@ -598,13 +596,6 @@ def _get_toolbar(self, canvas, parent): toolbar = None return toolbar - def _get_toolmanager(self): - if matplotlib.rcParams['toolbar'] == 'toolmanager': - toolmanager = ToolManager(self.canvas.figure) - else: - toolmanager = None - return toolmanager - def resize(self, width, height): # these are Qt methods so they return sizes in 'virtual' pixels # so we do not need to worry about dpi scaling here. diff --git a/lib/matplotlib/backends/backend_wx.py b/lib/matplotlib/backends/backend_wx.py index 091fece535f5..7edfe233a230 100644 --- a/lib/matplotlib/backends/backend_wx.py +++ b/lib/matplotlib/backends/backend_wx.py @@ -935,7 +935,8 @@ def __init__(self, num, fig): # By adding toolbar in sizer, we are able to put it at the bottom # of the frame - so appearance is closer to GTK version - self.toolmanager = self._get_toolmanager() + self.figmgr = FigureManagerWx(self.canvas, num, self) + statusbar = (StatusbarWx(self, self.toolmanager) if self.toolmanager else StatusBarWx(self)) self.SetStatusBar(statusbar) @@ -961,8 +962,6 @@ def __init__(self, num, fig): self.canvas.SetMinSize((2, 2)) - self.figmgr = FigureManagerWx(self.canvas, num, self) - self.Bind(wx.EVT_CLOSE, self._onClose) @cbook.deprecated("3.2", alternative="self.GetStatusBar()") @@ -970,6 +969,10 @@ def __init__(self, num, fig): def statusbar(self): return self.GetStatusBar() + @property + def toolmanager(self): + return self.figmgr.toolmanager + def _get_toolbar(self): if mpl.rcParams['toolbar'] == 'toolbar2': toolbar = NavigationToolbar2Wx(self.canvas) @@ -979,13 +982,6 @@ def _get_toolbar(self): toolbar = None return toolbar - def _get_toolmanager(self): - if mpl.rcParams['toolbar'] == 'toolmanager': - toolmanager = ToolManager(self.canvas.figure) - else: - toolmanager = None - return toolmanager - def get_canvas(self, fig): return FigureCanvasWx(self, -1, fig) @@ -1045,8 +1041,16 @@ def __init__(self, canvas, num, frame): self.frame = frame self.window = frame - self.toolmanager = getattr(frame, "toolmanager", None) - self.toolbar = frame.GetToolBar() + @property + def toolbar(self): + return self.frame.GetToolBar() + + @toolbar.setter + def toolbar(self, value): + # Never allow this, except that base class inits this to None before + # the frame is set up. + if value is not None or hasattr(self, "frame"): + raise AttributeError("can't set attribute") def show(self): # docstring inherited