Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 26fd914

Browse files
authored
Merge pull request #17391 from QuLogic/tk-cursor
tk/wx: Fix saving after the window is closed
2 parents 4a8aa8c + c0e7fbe commit 26fd914

File tree

3 files changed

+39
-14
lines changed

3 files changed

+39
-14
lines changed

lib/matplotlib/backends/_backend_tk.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -538,8 +538,12 @@ def release_zoom(self, event):
538538

539539
def set_cursor(self, cursor):
540540
window = self.canvas.get_tk_widget().master
541-
window.configure(cursor=cursord[cursor])
542-
window.update_idletasks()
541+
try:
542+
window.configure(cursor=cursord[cursor])
543+
except tkinter.TclError:
544+
pass
545+
else:
546+
window.update_idletasks()
543547

544548
def _Button(self, text, image_file, toggle, command):
545549
image = (tk.PhotoImage(master=self, file=image_file)

lib/matplotlib/backends/backend_wx.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,9 @@ def gui_repaint(self, drawDC=None, origin='WX'):
623623
The 'WXAgg' backend sets origin accordingly.
624624
"""
625625
_log.debug("%s - gui_repaint()", type(self))
626-
if self.IsShownOnScreen():
626+
# The "if self" check avoids a "wrapped C/C++ object has been deleted"
627+
# RuntimeError if doing things after window is closed.
628+
if self and self.IsShownOnScreen():
627629
if not drawDC:
628630
# not called from OnPaint use a ClientDC
629631
drawDC = wx.ClientDC(self)
@@ -881,14 +883,11 @@ def _print_image(self, filename, filetype, *args, **kwargs):
881883

882884
# Now that we have rendered into the bitmap, save it to the appropriate
883885
# file type and clean up.
884-
if isinstance(filename, str):
885-
if not image.SaveFile(filename, filetype):
886-
raise RuntimeError(f'Could not save figure to {filename}')
887-
elif cbook.is_writable_file_like(filename):
888-
if not isinstance(image, wx.Image):
889-
image = image.ConvertToImage()
890-
if not image.SaveStream(filename, filetype):
891-
raise RuntimeError(f'Could not save figure to {filename}')
886+
if (cbook.is_writable_file_like(filename) and
887+
not isinstance(image, wx.Image)):
888+
image = image.ConvertToImage()
889+
if not image.SaveFile(filename, filetype):
890+
raise RuntimeError(f'Could not save figure to {filename}')
892891

893892
# Restore everything to normal
894893
self.bitmap = origBitmap
@@ -900,7 +899,10 @@ def _print_image(self, filename, filetype, *args, **kwargs):
900899
# otherwise.
901900
if self._isDrawn:
902901
self.draw()
903-
self.Refresh()
902+
# The "if self" check avoids a "wrapped C/C++ object has been deleted"
903+
# RuntimeError if doing things after window is closed.
904+
if self:
905+
self.Refresh()
904906

905907

906908
class FigureFrameWx(wx.Frame):

lib/matplotlib/tests/test_backends_interactive.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ def _get_testable_interactive_backends():
6161
_test_script = """\
6262
import importlib
6363
import importlib.util
64+
import io
6465
import json
6566
import sys
6667
from unittest import TestCase
@@ -120,7 +121,23 @@ def check_alt_backend(alt_backend):
120121
fig.canvas.mpl_connect("draw_event", lambda event: timer.start())
121122
fig.canvas.mpl_connect("close_event", print)
122123
124+
result = io.BytesIO()
125+
fig.savefig(result, format='png')
126+
123127
plt.show()
128+
129+
# Ensure that the window is really closed.
130+
plt.pause(0.5)
131+
132+
# Test that saving works after interactive window is closed, but the figure is
133+
# not deleted.
134+
result_after = io.BytesIO()
135+
fig.savefig(result_after, format='png')
136+
137+
if not backend.startswith('qt5') and sys.platform == 'darwin':
138+
# FIXME: This should be enabled everywhere once Qt5 is fixed on macOS to
139+
# not resize incorrectly.
140+
assert_equal(result.getvalue(), result_after.getvalue())
124141
"""
125142
_test_timeout = 10 # Empirically, 1s is not enough on Travis.
126143

@@ -134,7 +151,8 @@ def test_interactive_backend(backend, toolbar):
134151
proc = subprocess.run(
135152
[sys.executable, "-c", _test_script,
136153
json.dumps({"toolbar": toolbar})],
137-
env={**os.environ, "MPLBACKEND": backend}, timeout=_test_timeout,
154+
env={**os.environ, "MPLBACKEND": backend, "SOURCE_DATE_EPOCH": "0"},
155+
timeout=_test_timeout,
138156
stdout=subprocess.PIPE, universal_newlines=True)
139157
if proc.returncode:
140158
pytest.fail("The subprocess returned with non-zero exit status "
@@ -148,7 +166,8 @@ def test_interactive_backend(backend, toolbar):
148166
def test_webagg():
149167
pytest.importorskip("tornado")
150168
proc = subprocess.Popen([sys.executable, "-c", _test_script],
151-
env={**os.environ, "MPLBACKEND": "webagg"})
169+
env={**os.environ, "MPLBACKEND": "webagg",
170+
"SOURCE_DATE_EPOCH": "0"})
152171
url = "http://{}:{}".format(
153172
mpl.rcParams["webagg.address"], mpl.rcParams["webagg.port"])
154173
timeout = time.perf_counter() + _test_timeout

0 commit comments

Comments
 (0)