Skip to content

Commit 5d0dbcf

Browse files
author
David Stirling
authored
Fix Big Sur compatibility (#298)
* Test_rebuild * Run build * Keep status bar references * Manually generate status bar * Another test * Alt setup * Restore binds * Activate * Clear cache when switching properties * Fix Big Sur crash * Apply MPL monkey patch to Mac too * Reset Actions scripts
1 parent 798368c commit 5d0dbcf

7 files changed

Lines changed: 67 additions & 40 deletions

File tree

CellProfiler-Analyst.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77

88

99
import sys
10-
from io import StringIO
1110
import os
1211
import os.path
1312
import logging
1413

1514
from cpa.dimensionreduction import DimensionReduction
15+
from cpa.guiutils import create_status_bar
1616
from cpa.util.version import display_version
1717
from cpa.properties import Properties
1818
from cpa.dbconnect import DBConnect
@@ -95,7 +95,7 @@ def __init__(self, properties, parent, id=-1, **kwargs):
9595
self.tbicon = None
9696
self.SetName('CPA')
9797
self.Center(wx.HORIZONTAL)
98-
self.CreateStatusBar()
98+
self.status_bar = create_status_bar(self)
9999
self.log_io = True
100100

101101
#
@@ -174,7 +174,7 @@ def __init__(self, properties, parent, id=-1, **kwargs):
174174

175175
# Black background and white font
176176
self.console.SetDefaultStyle(wx.TextAttr(wx.WHITE,wx.BLACK))
177-
self.console.SetBackgroundColour('#000000')
177+
self.console.SetBackgroundColour('#000000')
178178

179179
log_level = logging.INFO # INFO is the default log level
180180
self.logr = logging.getLogger()
@@ -314,6 +314,8 @@ def on_load_properties(self, evt):
314314
p.clear()
315315
from cpa.datamodel import DataModel
316316
DataModel.forget()
317+
from cpa.trainingset import CellCache
318+
CellCache.forget()
317319
self.console.Clear()
318320

319321
if not p.is_initialized():

cpa/classifier.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# Encoding: utf-8
22

33
import matplotlib
4+
5+
from cpa.guiutils import create_status_bar
6+
47
matplotlib.use('WXAgg')
58

69
import matplotlib.pyplot as plt
@@ -131,11 +134,11 @@ def __init__(self, properties=None, parent=None, id=ID_CLASSIFIER, **kwargs):
131134
self.SetMenuBar(self.menuBar)
132135
self.CreateMenus()
133136

134-
self.CreateStatusBar()
135-
137+
self.status_bar = create_status_bar(self, force=True)
136138
#### Create GUI elements
137139
# Top level - three split windows
138140
self.splitter = wx.SplitterWindow(self, style=wx.NO_BORDER | wx.SP_3DSASH | wx.SP_LIVE_UPDATE)
141+
139142
self.fetch_and_rules_panel = wx.Panel(self.splitter)
140143
self.bins_splitter = wx.SplitterWindow(self.splitter, style=wx.NO_BORDER | wx.SP_3DSASH | wx.SP_LIVE_UPDATE)
141144

@@ -187,7 +190,7 @@ def __init__(self, properties=None, parent=None, id=ID_CLASSIFIER, **kwargs):
187190
self.scoreImageBtn = wx.Button(self.find_rules_panel, -1, 'Score Image')
188191

189192
# add sorting class
190-
self.addSortClassBtn = wx.Button(self.GetStatusBar(), -1, "Add new class", style=wx.BU_EXACTFIT)
193+
self.addSortClassBtn = wx.Button(self.status_bar, -1, "Add new class", style=wx.BU_EXACTFIT)
191194

192195
#### Create Sizers
193196
self.fetchSizer = wx.BoxSizer(wx.HORIZONTAL)
@@ -358,7 +361,7 @@ def __init__(self, properties=None, parent=None, id=ID_CLASSIFIER, **kwargs):
358361
self.nNeuronsTxt.Bind(wx.EVT_TEXT, self.ValidateNumberOfNeurons)
359362
self.nObjectsTxt.Bind(wx.EVT_TEXT_ENTER, self.OnFetch)
360363

361-
self.GetStatusBar().Bind(wx.EVT_SIZE, self.status_bar_onsize)
364+
self.status_bar.Bind(wx.EVT_SIZE, self.status_bar_onsize)
362365
wx.CallAfter(self.status_bar_onsize, None)
363366

364367
self.Bind(wx.EVT_MENU, self.OnClose, self.exitMenuItem)
@@ -391,7 +394,7 @@ def __init__(self, properties=None, parent=None, id=ID_CLASSIFIER, **kwargs):
391394
def status_bar_onsize(self, event):
392395
# draw the "add sort class..." button in the status bar
393396
button = self.addSortClassBtn
394-
width, height = self.GetStatusBar().GetClientSize()
397+
width, height = self.status_bar.GetClientSize()
395398
# diagonal lines drawn on mac, so move let by height.
396399
button.SetPosition((width - button.GetSize()[0] - 1 - height, button.GetPosition()[1]))
397400

cpa/datatable.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from cpa import dbconnect
44
from cpa.dbconnect import DBConnect
5+
from cpa.guiutils import create_status_bar
56
from .datamodel import DataModel
67
from .properties import Properties
78
from tempfile import gettempdir
@@ -381,7 +382,7 @@ def __init__(self, data=None, labels=None, grouping='Image',
381382
self.GetMenuBar().Append(self.dbmenu, 'Database')
382383
if self.grid:
383384
self.CreateColumnMenu()
384-
self.CreateStatusBar()
385+
self.status_bar = create_status_bar(self)
385386

386387
self.SetSize((800,500))
387388
if self.grid:

cpa/generalclassifier.py

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,35 +20,34 @@
2020
# MatPlotLib currently has a bug on Windows which crashes wx if you close an interactive plot window.
2121
# This should be fixed in MPL 3.4, but for now we'll monkey patch in the fix.
2222
# See MPL PR #19596 for more details. - dstirling Mar 2021
23-
if sys.platform == 'win32':
24-
import wx
25-
import matplotlib.backends.backend_wx
26-
from matplotlib._pylab_helpers import Gcf
27-
28-
def mp_onClose(self, event):
29-
self.canvas.close_event()
30-
self.canvas.stop_event_loop()
31-
self.figmgr.frame = None
32-
Gcf.destroy(self.figmgr)
33-
event.Skip()
34-
35-
def mp_Destroy(self, *args, **kwargs):
36-
try:
37-
self.canvas.mpl_disconnect(self.toolbar._id_drag)
38-
except AttributeError:
39-
pass
40-
if self and not self.IsBeingDeleted():
41-
wx.Frame.Destroy(self, *args, **kwargs)
42-
return True
43-
44-
def mp_mandestroy(self, *args):
45-
frame = self.frame
46-
if frame:
47-
wx.CallAfter(frame.Close)
48-
49-
matplotlib.backends.backend_wx.FigureFrameWx._onClose = mp_onClose
50-
matplotlib.backends.backend_wx.FigureFrameWx.Destroy = mp_Destroy
51-
matplotlib.backends.backend_wx.FigureManagerWx.destroy = mp_mandestroy
23+
import wx
24+
import matplotlib.backends.backend_wx
25+
from matplotlib._pylab_helpers import Gcf
26+
27+
def mp_onClose(self, event):
28+
self.canvas.close_event()
29+
self.canvas.stop_event_loop()
30+
self.figmgr.frame = None
31+
Gcf.destroy(self.figmgr)
32+
event.Skip()
33+
34+
def mp_Destroy(self, *args, **kwargs):
35+
try:
36+
self.canvas.mpl_disconnect(self.toolbar._id_drag)
37+
except AttributeError:
38+
pass
39+
if self and not self.IsBeingDeleted():
40+
wx.Frame.Destroy(self, *args, **kwargs)
41+
return True
42+
43+
def mp_mandestroy(self, *args):
44+
frame = self.frame
45+
if frame:
46+
wx.CallAfter(frame.Close)
47+
48+
matplotlib.backends.backend_wx.FigureFrameWx._onClose = mp_onClose
49+
matplotlib.backends.backend_wx.FigureFrameWx.Destroy = mp_Destroy
50+
matplotlib.backends.backend_wx.FigureManagerWx.destroy = mp_mandestroy
5251
##########
5352

5453
class GeneralClassifier(BaseEstimator, ClassifierMixin):

cpa/guiutils.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import logging
2+
import platform
23
import wx
34
import wx.adv
45
import os
@@ -837,3 +838,20 @@ def show_load_dialog():
837838
else:
838839
wx.CallAfter(dlg.Destroy)
839840
return False
841+
842+
def create_status_bar(parent, force=False):
843+
if platform.system() == "Darwin" and platform.mac_ver()[0].startswith('11'):
844+
# wx 4.1.0 crashes on Big Sur if you try to make a status bar.
845+
# Redirect messages to the log instead.
846+
# Provide a toolbar if we need to place buttons in the status bar.
847+
def log_status(text):
848+
logging.info(text)
849+
parent.SetStatusText = log_status
850+
if force:
851+
tb = wx.ToolBar(parent, style=wx.TB_BOTTOM)
852+
parent.SetToolBar(tb)
853+
return tb
854+
else:
855+
return None
856+
else:
857+
return parent.CreateStatusBar()

cpa/imagegallery.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33

44

55
import matplotlib
6+
7+
from cpa.guiutils import create_status_bar
8+
69
matplotlib.use('WXAgg')
710

811
import sys
@@ -77,7 +80,7 @@ def __init__(self, properties=None, parent=None, id=ID_IMAGE_GALLERY, **kwargs):
7780
self.SetMenuBar(self.menuBar)
7881
self.CreateMenus()
7982

80-
self.CreateStatusBar()
83+
self.status_bar = create_status_bar(self)
8184

8285
#### Create GUI elements
8386
# Top level - three split windows

cpa/tableviewer.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import wx
1818
import wx.grid as gridlib
1919
import cpa.helpmenu
20+
from cpa.guiutils import create_status_bar
2021
from .properties import Properties
2122
from . import dbconnect
2223
from .datamodel import DataModel
@@ -564,7 +565,7 @@ def __init__(self, parent, **kwargs):
564565

565566
self.GetMenuBar().Append(cpa.helpmenu.make_help_menu(self, manual_url="6_table_viewer.html"), 'Help')
566567

567-
self.CreateStatusBar()
568+
self.status_bar = create_status_bar(self)
568569

569570
self.Bind(wx.EVT_MENU, self.on_new_table, new_table_item)
570571
self.Bind(wx.EVT_MENU, self.on_load_csv, load_csv_menu_item)

0 commit comments

Comments
 (0)