def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) bg_color = 'green' # changes the background of the scrollbars self.SetBackgroundColour(bg_color) sizer = wx.BoxSizer(wx.VERTICAL) panel = ScrolledPanel(self) panel.SetBackgroundColour(bg_color) panel.SetupScrolling(scroll_y=True) panelsizer = wx.BoxSizer(wx.VERTICAL) for _ in range(4): p = wx.Panel(panel, size=(400, 300)) p.SetBackgroundColour(bg_color) panelsizer.Add(p, 0, flag=wx.EXPAND) panelsizer.Add((-1, 10)) panel.SetSizer(panelsizer) for child in panel.GetChildren(): print(type(child)) # there is no scrollbar sizer.Add(panel, 1, flag=wx.EXPAND) self.SetSizer(sizer) self.Layout()
class ExportAnalysisEvents(wx.Frame): def __init__(self, parent, analysis, ext="ext", non_scalars=[]): self.parent = parent self.analysis = analysis self.ext = ext self.toggled_event_features = True # Get the window positioning correctly pos = self.parent.GetPosition() pos = (pos[0] + 100, pos[1] + 100) wx.Frame.__init__(self, parent=self.parent, title="Export all event data", pos=pos, style=wx.DEFAULT_FRAME_STYLE | wx.FRAME_FLOAT_ON_PARENT) ## panel self.panel = ScrolledPanel(self) self.panel.SetupScrolling() self.topSizer = wx.BoxSizer(wx.VERTICAL) # init textinit = wx.StaticText( self.panel, label="Export all event data as *.{} files.".format(ext)) self.topSizer.Add(textinit) # Chechbox asking for Mono-Model horsizer = wx.BoxSizer(wx.HORIZONTAL) self.WXCheckFilter = wx.CheckBox(self.panel, label="export filtered data only") self.WXCheckFilter.SetValue(True) horsizer.Add(self.WXCheckFilter, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) horsizer.AddStretchSpacer() # Button to (de)select all variables btnselect = wx.Button(self.panel, wx.ID_ANY, "(De-)select all") self.Bind(wx.EVT_BUTTON, self.OnToggleAllEventFeatures, btnselect) horsizer.Add(btnselect, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL) self.topSizer.Add(horsizer, 0, wx.EXPAND) ## Add checkboxes checks = [] # find out which are actually used in the analysis for cc in dclab.dfn.scalar_feature_names: for mm in self.analysis.measurements: if cc in mm: checks.append(cc) checks = non_scalars + sorted(list(set(checks))) self.box = wx.StaticBox(self.panel, label="Axes") self.sizerin = wx.StaticBoxSizer(self.box, wx.VERTICAL) # get longest text of checks dc = wx.ScreenDC() tl = np.max([dc.GetTextExtent(c)[0] for c in checks]) sp = dc.GetTextExtent(" ")[0] for c in checks: # label id (b/c of sorting) lid = c + ":" + " " * ((tl - dc.GetTextExtent(c)[0]) // sp) + "\t" label = dclab.dfn.feature_name2label[c] cb = wx.CheckBox(self.panel, label=lid + label, name=c) self.sizerin.Add(cb) if c in self.analysis.GetPlotAxes(): cb.SetValue(True) self.topSizer.Add(self.sizerin) btnbrws = wx.Button(self.panel, wx.ID_ANY, "Save to directory") # Binds the button to the function - close the tool self.Bind(wx.EVT_BUTTON, self.OnBrowse, btnbrws) self.topSizer.Add(btnbrws, 0, wx.EXPAND) self.panel.SetSizer(self.topSizer) self.topSizer.Fit(self) self.SetMinSize((self.topSizer.GetMinSizeTuple()[0], 500)) #Icon if parent.MainIcon is not None: wx.Frame.SetIcon(self, parent.MainIcon) self.Show(True) def OnBrowse(self, e=None): """ Let the user select a directory and save everything in that directory. """ # warn the user, if there are measurements that # have the same name. names = [m.title for m in self.analysis.measurements] dupl = list(set([n for n in names if names.count(n) > 1])) if len(dupl) != 0: dlg1 = wx.MessageDialog(self, message="Cannot export plots with duplicate titles: {}".format( ", ".join(dupl))\ +"\nPlot titles can be edited in the 'Contour Plot' tab.", style=wx.OK|wx.ICON_ERROR) if dlg1.ShowModal() == wx.ID_OK: return # make directory dialog dlg2 = wx.DirDialog( self, message="Select directory for data export", defaultPath=self.parent.config.get_path("ExportData"), style=wx.DD_DEFAULT_STYLE) if dlg2.ShowModal() == wx.ID_OK: outdir = dlg2.GetPath().encode("utf-8") self.parent.config.set_path(outdir, "ExportData") # determine if user wants filtered data filtered = self.WXCheckFilter.IsChecked() # search all children for checkboxes that have # the names in dclab.dfn.feature_names names = dclab.dfn.feature_names features = [] for ch in self.panel.GetChildren(): if (isinstance(ch, wx._controls.CheckBox) and ch.IsChecked()): name = ch.GetName() if name in names: features.append(name) # Call the export function of dclab.rtdc_dataset # Check if the files already exist for m in self.analysis.measurements: if os.path.exists( os.path.join(outdir, m.title + "." + self.ext)): msg = "Override existing .{} files in '{}'?".format( self.ext, outdir) dlg3 = wx.MessageDialog(self, message=msg, style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION) if dlg3.ShowModal() == wx.ID_YES: # ok, leave loop break else: # do not continue return wx.BeginBusyCursor() self.export(out_dir=outdir, features=features, filtered=filtered) wx.EndBusyCursor() def OnToggleAllEventFeatures(self, e=None): """Set all values of the event features to `self.toggled_event_features` and invert `self.toggled_event_features`. """ panel = self.panel names = dclab.dfn.feature_names for ch in panel.GetChildren(): if (isinstance(ch, wx._controls.CheckBox) and ch.GetName() in names): ch.SetValue(self.toggled_event_features) # Invert for next execution self.toggled_event_features = not self.toggled_event_features @staticmethod def get_dataset_features(data_set, features): out_feat = [] for feat in features: if feat in data_set: out_feat.append(feat) return out_feat def export(self, out_dir, features, filtered): raise NotImplementedError("Please subclass and rewrite this function.")
class BatchFilterFolder(wx.Frame): def __init__(self, parent, analysis): self.parent = parent self.analysis = analysis self.out_tsv_file = None self.data_files = None self.axes_panel_sizer = None # Features checks self.toggled_event_features = True # Statistical parameters checks self.toggled_stat_parms = False # Get the window positioning correctly wx.Frame.__init__(self, parent=self.parent, title="Batch filtering", style=wx.DEFAULT_FRAME_STYLE | wx.FRAME_FLOAT_ON_PARENT) ## panel panel = self.panel = wx.Panel(self) self.topSizer = wx.BoxSizer(wx.VERTICAL) # init self.topSizer.Add( wx.StaticText(panel, label="Apply the filter setting of one measurement\n"+\ "to all measurements within a folder and\n"+\ "save selected statistical parameters.") ) self.topSizer.AddSpacer(10) ## Filter source selection boxleft = wx.StaticBox(panel, label="Filter settings") self.rbtnhere = wx.RadioButton(panel, -1, 'Current session', style=wx.RB_GROUP) self.rbtnhere.SetValue(True) self.rbtnthere = wx.RadioButton(panel, -1, 'Other source') self.rbtnthere.Disable() self.dropdown = wx.ComboBox(panel, -1, "", (15, 30), wx.DefaultSize, [], wx.CB_DROPDOWN | wx.CB_READONLY) # Create the dropdownlist self.Bind(wx.EVT_RADIOBUTTON, self.OnRadioHere, self.rbtnhere) self.Bind(wx.EVT_RADIOBUTTON, self.OnRadioThere, self.rbtnthere) self.Bind(wx.EVT_COMBOBOX, self.OnSelectMeasurement, self.dropdown) leftSizer = wx.StaticBoxSizer(boxleft, wx.VERTICAL) leftSizer.Add(self.rbtnhere) leftSizer.Add(self.rbtnthere) leftSizer.AddSpacer(5) leftSizer.Add(self.dropdown) leftSizer.AddSpacer(5) self.topSizer.Add(leftSizer, 0, wx.EXPAND) self.topSizer.AddSpacer(10) ## Folder selection boxfold = wx.StaticBox(panel, label="Input folder") foldSizer = wx.StaticBoxSizer(boxfold, wx.VERTICAL) btnbrws = wx.Button(panel, wx.ID_ANY, "Browse") # Binds the button to the function - close the tool self.Bind(wx.EVT_BUTTON, self.OnBrowse, btnbrws) self.WXfold_text1 = wx.StaticText( panel, label="Folder containing RT-DC measurements") self.WXdropdown_flowrate = wx.ComboBox(panel, -1, "All measurements", (15, 30), wx.DefaultSize, ["All measurements"], wx.CB_DROPDOWN | wx.CB_READONLY) self.WXdropdown_flowrate.Disable() self.WXdropdown_region = wx.ComboBox( panel, -1, "Channel and Reservoir", (15, 30), wx.DefaultSize, ["Channel and Reservoir", "Channel only", "Reservoir only"], wx.CB_DROPDOWN | wx.CB_READONLY) fold2sizer = wx.BoxSizer(wx.HORIZONTAL) fold2sizer.Add(btnbrws) fold2sizer.Add(self.WXfold_text1, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) foldSizer.AddSpacer(5) foldSizer.Add(fold2sizer, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL) foldSizer.Add(self.WXdropdown_flowrate, 0, wx.EXPAND | wx.ALL) foldSizer.Add(self.WXdropdown_region, 0, wx.EXPAND | wx.ALL) foldSizer.AddSpacer(5) self.topSizer.Add(foldSizer, 0, wx.EXPAND) self.topSizer.AddSpacer(10) ## Axes checkboxes self.axes_panel = ScrolledPanel(panel, -1, size=(-1, 200)) self.axes_panel.SetupScrolling() self.topSizer.Add(self.axes_panel, 1, wx.EXPAND) self.topSizer.AddSpacer(10) ## Statistical parameters self.stat_panel = ScrolledPanel(panel, -1, size=(-1, 200)) self.stat_panel.SetupScrolling() self.topSizer.Add(self.stat_panel, 1, wx.EXPAND) self.topSizer.AddSpacer(10) self.SetupStatisticalParameters() ## Output selection boxtsv = wx.StaticBox(panel, label="Output file") tsvSizer = wx.StaticBoxSizer(boxtsv, wx.VERTICAL) btnbrwstsv = wx.Button(panel, wx.ID_ANY, "Browse") # Binds the button to the function - close the tool self.Bind(wx.EVT_BUTTON, self.OnBrowseTSV, btnbrwstsv) self.WXtsv_text1 = wx.StaticText( panel, label="Results of statistical analysis") tsv2sizer = wx.BoxSizer(wx.HORIZONTAL) tsv2sizer.Add(btnbrwstsv) tsv2sizer.Add(self.WXtsv_text1, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5) tsvSizer.AddSpacer(5) tsvSizer.Add(tsv2sizer, 0, wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL) self.topSizer.Add(tsvSizer, 0, wx.EXPAND) ## Batch button btnbatch = wx.Button(self.panel, wx.ID_ANY, "Perform batch filtering") # Binds the button to the function - close the tool self.Bind(wx.EVT_BUTTON, self.OnBatch, btnbatch) self.topSizer.Add(btnbatch, 0, wx.EXPAND) btnbatch.Disable() self.btnbatch = btnbatch panel.SetSizer(self.topSizer) self.topSizer.Fit(self.panel) self.SetMinSize(self.topSizer.GetMinSizeTuple()) self.OnRadioHere() #Icon if parent.MainIcon is not None: wx.Frame.SetIcon(self, parent.MainIcon) self.Show(True) def OnBatch(self, e=None): wx.BeginBusyCursor() # Get selected axes features = [] for ch in self.axes_panel.GetChildren(): if (isinstance(ch, wx._controls.CheckBox) and ch.IsChecked()): name = ch.GetName() if name in dclab.dfn.scalar_feature_names: features.append(name) # Get selected features col_dict = dclab.statistics.Statistics.available_methods methods = [] for ch in self.stat_panel.GetChildren(): if (isinstance(ch, wx._controls.CheckBox) and ch.IsChecked()): name = ch.GetName() if name in col_dict: methods.append(name) # Get filter configuration of selected measurement if self.rbtnhere.GetValue(): mhere = self.analysis.measurements[self.dropdown.GetSelection()] f_config = mhere.config # Compute statistics head = None rows = [] # Determine which flow rates to use idflow = self.WXdropdown_flowrate.GetSelection() - 1 if idflow < 0: files = self.data_files else: files = self.flow_dict[self.flow_rates[idflow]] # Filter regions regid = self.WXdropdown_region.GetSelection() if regid > 0: if regid == 1: reg = "channel" elif regid == 2: reg = "reservoir" newfiles = [] for tt in files: if meta_tool.get_chip_region(tt) == reg: newfiles.append(tt) files = newfiles if not files: raise ValueError("No valid measurements with current selection!") # Process each data file separately to reduce memory usage for data in files: # Make analysis from data file anal = analysis.Analysis([data], config=f_config) mm = anal.measurements[0] # Apply filters mm.apply_filter() # Get statistics h, v = dclab.statistics.get_statistics(rtdc_ds=mm, methods=methods, features=features) if head is None: head = h else: assert h == head, "Problem with available methods/features!" rows.append([mm.path, mm.title] + v) head = ["data file", "Title"] + head with io.open(self.out_tsv_file, "w") as fd: header = u"\t".join([h for h in head]) fd.write("# " + header + "\n") with open(self.out_tsv_file, "ab") as fd: for row in rows: fmt = ["{:s}"] * 2 + ["{:.10e}"] * len(v) line = "\t".join(fmt).format(*row) fd.write(line + "\n") wx.EndBusyCursor() def OnBrowse(self, e=None): """ Let the user select a directory and search that directory for RT-DC data sets. """ # make directory dialog dlg2 = wx.DirDialog( self, message="Please select directory containing measurements", defaultPath=self.parent.config.get_path("BatchFD"), style=wx.DD_DEFAULT_STYLE) if dlg2.ShowModal() == wx.ID_OK: thepath = dlg2.GetPath().encode("utf-8") else: thepath = None dlg2.Destroy() wx.Yield() if thepath is not None: wx.BeginBusyCursor() self.WXfold_text1.SetLabel(thepath) self.parent.config.set_path(thepath, "BatchFD") # Search directory tree, _cols = meta_tool.collect_data_tree(thepath) self.data_files = [t[1][1] for t in tree] if self.out_tsv_file is not None: self.btnbatch.Enable() wx.EndBusyCursor() # Update WXdropdown_flowrate and self.flow_rates # Determine flow rates flow_dict = {} for tt in self.data_files: fr = meta_tool.get_flow_rate(tt) if fr not in flow_dict: flow_dict[fr] = [] flow_dict[fr].append(tt) selections = ["All measurements ({})".format(len(self.data_files))] self.flow_rates = list(flow_dict.keys()) self.flow_rates.sort() for fr in self.flow_rates: num = len(flow_dict[fr]) selections += ["Flow rate {} µl/s ({})".format(fr, num)] self.WXdropdown_flowrate.SetItems(selections) self.WXdropdown_flowrate.SetSelection(0) self.WXdropdown_flowrate.Enable() self.flow_dict = flow_dict def OnBrowseTSV(self, e=None): dlg2 = wx.FileDialog( self, message="Please select an output file.", defaultDir=self.parent.config.get_path("BatchOut"), style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT, wildcard="TSV files" + " (*.tsv)|*.tsv") if dlg2.ShowModal() == wx.ID_OK: thepath = dlg2.GetPath().encode("utf-8") if not thepath.endswith(".tsv"): thepath += ".tsv" self.WXtsv_text1.SetLabel(thepath) thedir = os.path.dirname(thepath) self.parent.config.set_path(thedir, "BatchOut") self.out_tsv_file = thepath if self.data_files is not None: self.btnbatch.Enable() def OnRadioHere(self, e=None): meas = [mm.title for mm in self.analysis.measurements] self.dropdown.SetItems(meas) self.dropdown.SetSelection(0) self.OnSelectMeasurement() def OnRadioThere(self, e=None): self.OnUpdateAxes() self.filter_config = None def OnSelectMeasurement(self, e=None): ## Remove initial stuff sizer = self.axes_panel_sizer panel = self.axes_panel if sizer is not None: for child in sizer.GetChildren(): window = child.GetWindow() panel.RemoveChild(window) sizer.RemoveWindow(window) window.Destroy() sizerin = sizer else: box = wx.StaticBox(self.axes_panel, label="Event features") sizerbox = wx.StaticBoxSizer(box, wx.HORIZONTAL) sizerin = wx.BoxSizer(orient=wx.VERTICAL) sizerbox.Add(sizerin) sizersel = wx.BoxSizer(orient=wx.VERTICAL) btnselect = wx.Button(self.axes_panel, wx.ID_ANY, "(De-)select all") sizersel.Add(btnselect, 0, wx.ALIGN_RIGHT) sizerbox.Add(sizersel, 1, wx.EXPAND | wx.ALIGN_RIGHT) self.Bind(wx.EVT_BUTTON, self.OnToggleAllEventFeatures, btnselect) sizerbox.AddSpacer(5) self.axes_panel_sizer = sizerin checks = [] if self.rbtnhere.Value: sel = self.dropdown.GetSelection() mm = self.analysis.measurements[sel] for c in dclab.dfn.scalar_feature_names: if c in mm: checks.append(c) else: for c in dclab.dfn.scalar_feature_names: checks.append(c) checks = list(set(checks)) labels = [dclab.dfn.feature_name2label[c] for c in checks] # Sort checks according to labels checks = [x for (_y, x) in sorted(zip(labels, checks))] labels.sort() for c, l in zip(checks, labels): # label id (b/c of sorting) label = l cb = wx.CheckBox(self.axes_panel, label=label, name=c) sizerin.Add(cb) if c in self.analysis.GetPlotAxes(): cb.SetValue(True) self.axes_panel.SetupScrolling() self.axes_panel.SetSizer(sizerbox) sizerbox.Fit(self.axes_panel) self.topSizer.Fit(self.panel) size = self.topSizer.GetMinSizeTuple() self.SetSize((size[0] + 1, -1)) self.SetSize((size[0] - 1, -1)) def OnToggleAllEventFeatures(self, e=None): """Set all values of the event features to `self.toggled_event_features` and invert `self.toggled_event_features`. """ panel = self.axes_panel for ch in panel.GetChildren(): if isinstance(ch, wx._controls.CheckBox): ch.SetValue(self.toggled_event_features) # Invert for next execution self.toggled_event_features = not self.toggled_event_features def OnToggleAllStatParms(self, e=None): """Set all values of the statistical parameters to `self.toggled_stat_parms` and invert `self.toggled_stat_parms`. """ panel = self.stat_panel for ch in panel.GetChildren(): if isinstance(ch, wx._controls.CheckBox): ch.SetValue(self.toggled_stat_parms) # Invert for next execution self.toggled_stat_parms = not self.toggled_stat_parms def SetupStatisticalParameters(self, e=None): ## Remove initial stuff box = wx.StaticBox(self.stat_panel, label="Statistical parameters") sizerbox = wx.StaticBoxSizer(box, wx.HORIZONTAL) sizerin = wx.BoxSizer(orient=wx.VERTICAL) sizerbox.Add(sizerin) sizersel = wx.BoxSizer(orient=wx.VERTICAL) btnselect = wx.Button(self.stat_panel, wx.ID_ANY, "(De-)select all") sizersel.Add(btnselect, 0, wx.ALIGN_RIGHT) sizerbox.Add(sizersel, 1, wx.EXPAND | wx.ALIGN_RIGHT) self.Bind(wx.EVT_BUTTON, self.OnToggleAllStatParms, btnselect) sizerbox.AddSpacer(5) checks = list(dclab.statistics.Statistics.available_methods.keys()) checks.sort() for c in checks: # label id (b/c of sorting) cb = wx.CheckBox(self.stat_panel, label=c, name=c) sizerin.Add(cb) cb.SetValue(True) self.stat_panel.SetupScrolling() self.stat_panel.SetSizer(sizerbox) sizerbox.Fit(self.stat_panel)
def __init__(self, parent, workspace): self.frame = CPFigureFrame( parent, title = "CellProfiler Workspace") self.workspace = workspace self.ignore_redraw = False self.image_rows = [] self.object_rows = [] self.measurement_rows = [] self.frame.set_subplots((1, 1)) self.axes = self.frame.subplot(0, 0) self.image = None panel = ScrolledPanel(self.frame.secret_panel) self.frame.secret_panel.Sizer = wx.BoxSizer() self.frame.secret_panel.Sizer.Add(panel, 0, wx.EXPAND) panel.Sizer = wx.BoxSizer(wx.VERTICAL) self.panel = panel # # Make a grid of image controls # panel.Sizer.AddSpacer(4) self.image_grid = wx.GridBagSizer(vgap = 3, hgap = 3) sub_sizer = wx.BoxSizer(wx.VERTICAL) panel.Sizer.Add( sub_sizer, 0, wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT, 3) sub_sizer.Add(self.image_grid, 0, wx.ALIGN_LEFT) self.image_grid.Add( wx.StaticText(panel, label="Images"), (0, self.C_CHOOSER), flag = wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_BOTTOM) self.image_grid.Add( wx.StaticText(panel, label="Color"), (0, self.C_COLOR), flag = wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_BOTTOM) self.image_grid.Add( wx.StaticText(panel, label="Show"), (0, self.C_SHOW), flag = wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_BOTTOM) self.image_grid.Add( wx.StaticText(panel, label="Remove"), (0, self.C_REMOVE), flag = wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_BOTTOM) self.add_image_row(can_delete = False) add_image_button = wx.Button(panel, label = "Add image") sub_sizer.Add(add_image_button, 0, wx.ALIGN_RIGHT) add_image_button.Bind( wx.EVT_BUTTON, lambda event:self.add_image_row()) panel.Sizer.AddSpacer(4) panel.Sizer.Add(wx.StaticLine(panel, style = wx.LI_HORIZONTAL), 0, wx.EXPAND) panel.Sizer.AddSpacer(4) # # Make a grid of object controls # self.object_grid = wx.GridBagSizer(vgap = 3, hgap = 3) sub_sizer = wx.BoxSizer(wx.VERTICAL) panel.Sizer.Add(sub_sizer, 0, wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT, 3) sub_sizer.Add(self.object_grid, 0, wx.ALIGN_LEFT) self.object_grid.Add( wx.StaticText(panel, label="Objects"), (0, self.C_CHOOSER), flag = wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_BOTTOM) self.object_grid.Add( wx.StaticText(panel, label="Color"), (0, self.C_COLOR), flag = wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_BOTTOM) self.object_grid.Add( wx.StaticText(panel, label="Show"), (0, self.C_SHOW), flag = wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_BOTTOM) self.object_grid.Add( wx.StaticText(panel, label="Remove"), (0, self.C_REMOVE), flag = wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_BOTTOM) self.add_objects_row(can_delete = False) add_object_button = wx.Button(panel, label = "Add objects") sub_sizer.Add(add_object_button, 0, wx.ALIGN_RIGHT) add_object_button.Bind( wx.EVT_BUTTON, lambda event:self.add_objects_row()) panel.Sizer.AddSpacer(4) panel.Sizer.Add(wx.StaticLine(panel, style = wx.LI_HORIZONTAL), 0, wx.EXPAND) panel.Sizer.AddSpacer(4) # # Make a grid of measurements to display # self.m_grid = wx.GridBagSizer(vgap = 3, hgap = 3) sub_sizer = wx.BoxSizer(wx.VERTICAL) panel.Sizer.Add(sub_sizer, 0, wx.ALIGN_LEFT | wx.LEFT | wx.RIGHT, 3) sub_sizer.Add(self.m_grid, 0, wx.ALIGN_LEFT) self.m_grid.Add( wx.StaticText(panel, label="Measurement"), (0, self.C_CHOOSER), flag = wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_BOTTOM) self.m_grid.Add( wx.StaticText(panel, label="Font"), (0, self.C_COLOR), flag = wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_BOTTOM) self.m_grid.Add( wx.StaticText(panel, label="Show"), (0, self.C_SHOW), flag = wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_BOTTOM) self.m_grid.Add( wx.StaticText(panel, label="Remove"), (0, self.C_REMOVE), flag = wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_BOTTOM) self.add_measurement_row(can_delete = False) add_measurement_button = wx.Button(panel, label = "Add Measurement") sub_sizer.Add(add_measurement_button, 0, wx.ALIGN_RIGHT) add_measurement_button.Bind( wx.EVT_BUTTON, self.on_add_measurement_row) self.frame.Bind(wx.EVT_CLOSE, self.on_frame_close) self.set_workspace(workspace) self.frame.secret_panel.Show() self.layout() for child in panel.GetChildren(): child.Refresh() panel.Refresh()