Beispiel #1
0
def _test_reorder():
    frame = wx.GetApp().GetTopWindow()
    grid = widgetgrid.WidgetGrid(frame)

    grid.SetGridSize(1, 10)

    labels = ['col {}'.format(i) for i in range(10)]
    cells = ['cell {}'.format(i) for i in range(10)]

    grid.SetColLabels(labels)
    grid.SetRowLabels(['row'])

    for i in range(10):
        grid.SetText(0, i, cells[i])

    grid.Refresh()
    realYield()
    for i in range(5):
        neworder = np.array(range(10))
        np.random.shuffle(neworder)
        grid.ReorderColumns(neworder)
        grid.Refresh()
        realYield()

        for i in range(10):

            assert grid.GetColLabel(i) == labels[neworder[i]]
            assert grid.GetWidget(0, i).GetLabel() == cells[neworder[i]]

        labels = [labels[i] for i in neworder]
        cells = [cells[i] for i in neworder]
Beispiel #2
0
    def __init__(self, parent, ftpanel, notes='right'):
        """Create a ``FileListPanel``.

        :arg parent:  ``wx`` parent object
        :arg ftpanel: The :class:`.FileTreePanel`
        :arg notes:   Location of the *Notes* column - one of:

                        - ``'right'`` - right-most column (default)
                        - ``'left'``  - left-most column, after varying
                          columns

        The *Notes* column location can be changed later via the
        :meth:`NotesColumn` method.
        """

        if notes not in ('left', 'right'):
            raise ValueError('Invalid value for notes: {}'.format(notes))

        wx.Panel.__init__(self, parent)

        self.__ftpanel = ftpanel
        self.__notes = notes
        self.__mgr = None
        self.__sizer = wx.BoxSizer(wx.VERTICAL)
        self.__grid = wgrid.WidgetGrid(
            self,
            style=(wx.HSCROLL | wx.VSCROLL | wgrid.WG_KEY_NAVIGATION
                   | wgrid.WG_SELECTABLE_ROWS | wgrid.WG_DRAGGABLE_COLUMNS))

        self.__sizer.Add(self.__grid, flag=wx.EXPAND, proportion=1)
        self.SetSizer(self.__sizer)

        self.__grid.Bind(wgrid.EVT_WG_SELECT, self.__onSelect)
        self.__grid.Bind(wgrid.EVT_WG_REORDER, self.__onReorder)
Beispiel #3
0
def _test_create():
    frame = wx.GetApp().GetTopWindow()
    grid = widgetgrid.WidgetGrid(frame)
    grid.SetGridSize(10, 10)
    grid.ShowRowLabels()
    grid.ShowColLabels()

    for i in range(10):
        grid.SetRowLabel(i, 'row {}'.format(i + 1))
        grid.SetColLabel(i, 'col {}'.format(i + 1))

    for i in range(10):
        for j in range(10):
            grid.SetText(i, j, 'cell [{}, {}]'.format(i + 1, j + 1))

    grid.Refresh()

    exprowlbls = ['row {}'.format(i + 1) for i in range(10)]
    expcollbls = ['col {}'.format(i + 1) for i in range(10)]

    assert grid.GetRowLabels() == exprowlbls
    assert grid.GetColLabels() == expcollbls

    for i in range(10):
        for j in range(10):
            exp = 'cell [{}, {}]'.format(i + 1, j + 1)
            assert grid.GetWidget(i, j).GetLabel() == exp
Beispiel #4
0
    def __init__(self, parent, overlayList, displayCtx, frame, lut):
        """Create a ``LabelGrid``.

        :arg parent:      The ``wx`` parent object.
        :arg overlayList: The :class:`.OverlayList`.
        :arg displayCtx:  The :class:`.DisplayContext`.
        :arg frame:       The :class:`.FSLeyesFrame` instance.
        :arg lut:         The :class:`.LookupTable` to be used to colour
                          component tags.
        """

        fslpanel.FSLeyesPanel.__init__(self, parent, overlayList, displayCtx,
                                       frame)

        self.__lut = lut
        self.__grid = widgetgrid.WidgetGrid(
            self,
            style=(wx.VSCROLL | widgetgrid.WG_SELECTABLE_ROWS
                   | widgetgrid.WG_KEY_NAVIGATION))

        # The LabelGrid displays one TextTagPanel
        # for each label that is currently displayed,
        # as:
        #
        #   { label_name : TextTagPanel }
        #
        # mappings.
        self.__labelTags = collections.OrderedDict()

        self.__sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.__sizer.Add(self.__grid, flag=wx.EXPAND, proportion=1)

        self.SetSizer(self.__sizer)

        self.__grid.Bind(widgetgrid.EVT_WG_SELECT, self.__onGridSelect)

        lut.register(self.name, self.__lutChanged, 'added')
        lut.register(self.name, self.__lutChanged, 'removed')
        lut.register(self.name, self.__lutChanged, 'label')

        self.__overlay = None
Beispiel #5
0
    def __init__(self, parent, overlayList, displayCtx, frame, lut):
        """Create a ``ComponentGrid``.

        :arg parent:      The ``wx`` parent object.
        :arg overlayList: The :class:`.OverlayList`.
        :arg displayCtx:  The :class:`.DisplayContext`.
        :arg frame:       The :class:`.FSLeyesFrame` instance.
        :arg lut:         The :class:`.LookupTable` instance used to colour
                          each label tag.
        """

        fslpanel.FSLeyesPanel.__init__(
            self, parent, overlayList, displayCtx, frame)

        self.__lut  = lut
        self.__grid = widgetgrid.WidgetGrid(
            self,
            style=(wx.VSCROLL                    |
                   widgetgrid.WG_SELECTABLE_ROWS |
                   widgetgrid.WG_KEY_NAVIGATION))

        self.__grid.ShowRowLabels(False)
        self.__grid.ShowColLabels(True)

        self.__sizer = wx.BoxSizer(wx.HORIZONTAL)
        self.__sizer.Add(self.__grid, flag=wx.EXPAND, proportion=1)

        self.SetSizer(self.__sizer)

        self.__grid.Bind(widgetgrid.EVT_WG_SELECT, self.__onGridSelect)

        lut.register(self.name, self.__lutChanged, 'added')
        lut.register(self.name, self.__lutChanged, 'removed')
        lut.register(self.name, self.__lutChanged, 'label')

        self.__overlay   = None
        self.__volLabels = None
Beispiel #6
0
    def __init__(self, parent, dcmseries):
        """Create a ``BrowseDicomPanel``.

        :arg parent:    ``wx`` parent object
        :arg dcmseries: List of DICOM data series, as returned by the
                        :func:`fsl.data.dicom.scanDir` function.
        """

        wx.Panel.__init__(self, parent)

        # we assume that this metadata
        # is the same across all series
        date = dcmseries[0].get('AcquisitionDateTime', '')
        dcmdir = dcmseries[0].get('DicomDir', '')
        patient = dcmseries[0].get('PatientName', '')
        institution = dcmseries[0].get('InstitutionName', '')

        try:
            date = datetime.strptime(date, '%Y-%m-%dT%H:%M:%S.%f')
            date = '{:4d}-{:2d}-{:2d}'.format(date.year, date.month, date.day)
        except ValueError:
            date = ''

        self.__dcmdirLabel = wx.StaticText(self)
        self.__dateLabel = wx.StaticText(self)
        self.__patientLabel = wx.StaticText(self)
        self.__institutionLabel = wx.StaticText(self)

        self.__dcmdir = wx.StaticText(self, style=wx.ST_ELLIPSIZE_START)
        self.__date = wx.StaticText(self)
        self.__patient = wx.StaticText(self)
        self.__institution = wx.StaticText(self)
        self.__series = wg.WidgetGrid(self, style=0)

        self.__loadCheckboxes = [wx.CheckBox(self) for s in dcmseries]

        self.__dcmdirLabel.SetLabel(strings.labels[self, 'dicomdir'])
        self.__dateLabel.SetLabel(strings.labels[self, 'date'])
        self.__patientLabel.SetLabel(strings.labels[self, 'patient'])
        self.__institutionLabel.SetLabel(strings.labels[self, 'institution'])
        self.__dcmdir.SetLabel(dcmdir)
        self.__date.SetLabel(date)
        self.__patient.SetLabel(patient)
        self.__institution.SetLabel(institution)

        self.__mainSizer = wx.BoxSizer(wx.VERTICAL)
        self.__titleSizer = wx.FlexGridSizer(2, 5, 5)
        self.__titleSizer.AddGrowableCol(1)

        self.__titleSizer.Add(self.__dcmdirLabel, flag=wx.EXPAND)
        self.__titleSizer.Add(self.__dcmdir, flag=wx.EXPAND)
        self.__titleSizer.Add(self.__dateLabel, flag=wx.EXPAND)
        self.__titleSizer.Add(self.__date, flag=wx.EXPAND)
        self.__titleSizer.Add(self.__patientLabel, flag=wx.EXPAND)
        self.__titleSizer.Add(self.__patient, flag=wx.EXPAND)
        self.__titleSizer.Add(self.__institutionLabel, flag=wx.EXPAND)
        self.__titleSizer.Add(self.__institution, flag=wx.EXPAND)

        self.__mainSizer.Add(self.__titleSizer,
                             flag=wx.EXPAND | wx.ALL,
                             border=5)
        self.__mainSizer.Add(self.__series,
                             flag=wx.EXPAND | wx.ALL,
                             border=5,
                             proportion=1)

        self.SetSizer(self.__mainSizer)

        # columns:
        #   SeriesNumber
        #   SeriesDescription
        #   ReconMatrix
        #   Load (checkbox)
        # TODO For other useful information,
        #      you might need to look in the niftis

        # set up the grid
        self.__series.SetGridSize(len(dcmseries), 4, growCols=(0, 1))
        self.__series.ShowColLabels()
        self.__series.SetColLabel(0, strings.labels[self, 'SeriesNumber'])
        self.__series.SetColLabel(1, strings.labels[self, 'SeriesDescription'])
        self.__series.SetColLabel(2, strings.labels[self, 'Matrix'])
        self.__series.SetColLabel(3, strings.labels[self, 'Load'])

        for i, s in enumerate(dcmseries):

            num = s['SeriesNumber']
            desc = s['SeriesDescription']
            size = s['ReconMatrixPE']

            self.__series.SetText(i, 0, str(num))
            self.__series.SetText(i, 1, desc)
            self.__series.SetText(i, 2, '{}x{}'.format(size, size))
            self.__series.SetWidget(i, 3, self.__loadCheckboxes[i])

        self.__series.Refresh()
Beispiel #7
0
    def __genClusterGrid(self, overlay, featImage, contrast, clusters):
        """Creates and returns a :class:`.WidgetGrid` which contains the given
        list of clusters, which are related to the given contrast.


        .. note:: This method assumes that the given ``overlay`` is an
                  :class:`.Image` which has the same voxel dimensions as,
                  and shares the the same world coordinate system as the
                  ``featImage``.


        :arg overlay:   The overlay for which clusters are currently being
                        displayed.

        :arg featImage: The :class:`.FEATImage` to which the clusters are
                        related.

        :arg contrast:  The (0-indexed) number of the contrast to which the
                        clusters are related.

        :arg clusters:  A sequence of objects, each representing one cluster.
                        See the :meth:`.FEATImage.clusterResults` method.
        """

        cols = {
            'index': 0,
            'nvoxels': 1,
            'p': 2,
            'logp': 3,
            'zmax': 4,
            'zmaxcoords': 5,
            'zcogcoords': 6,
            'copemax': 7,
            'copemaxcoords': 8,
            'copemean': 9
        }

        grid = widgetgrid.WidgetGrid(self)
        conName = featImage.contrastNames()[contrast]
        opts = self.displayCtx.getOpts(overlay)

        # We hide the grid and disable
        # this panle while the grid is
        # being created.
        grid.Hide()
        self.Disable()

        grid.SetGridSize(len(clusters), 10)

        grid.ShowRowLabels(False)
        grid.ShowColLabels(True)

        for col, i in cols.items():
            grid.SetColLabel(i, strings.labels[self, col])

        def makeCoordButton(coords):

            label = wx.StaticText(grid, label='[{} {} {}]'.format(*coords))
            btn = wx.Button(grid, label=six.u('\u2192'), style=wx.BU_EXACTFIT)

            sizer = wx.BoxSizer(wx.HORIZONTAL)
            sizer.Add(label, flag=wx.EXPAND, proportion=1)
            sizer.Add(btn)

            def onClick(ev):
                dloc = opts.transformCoords([coords], 'voxel', 'display')[0]
                self.displayCtx.location = dloc

            btn.Bind(wx.EVT_BUTTON, onClick)

            return sizer

        # Creating all of the widgets could
        # take a bit of time, so we'll
        # do it asynchronously via idle.idle
        # display a message while doing so.
        status.update(strings.messages[self, 'loadingCluster'].format(
            contrast + 1, conName),
                      timeout=None)

        def addCluster(i, clust):

            if not fwidgets.isalive(grid):
                return

            zmaxbtn = makeCoordButton((clust.zmaxx, clust.zmaxy, clust.zmaxz))
            zcogbtn = makeCoordButton((clust.zcogx, clust.zcogy, clust.zcogz))
            copemaxbtn = makeCoordButton(
                (clust.copemaxx, clust.copemaxy, clust.copemaxz))

            def fmt(v):
                return '{}'.format(v)

            grid.SetText(i, cols['index'], fmt(clust.index))
            grid.SetText(i, cols['nvoxels'], fmt(clust.nvoxels))
            grid.SetText(i, cols['p'], fmt(clust.p))
            grid.SetText(i, cols['logp'], fmt(clust.logp))
            grid.SetText(i, cols['zmax'], fmt(clust.zmax))
            grid.SetWidget(i, cols['zmaxcoords'], zmaxbtn)
            grid.SetWidget(i, cols['zcogcoords'], zcogbtn)
            grid.SetText(i, cols['copemax'], fmt(clust.copemax))
            grid.SetWidget(i, cols['copemaxcoords'], copemaxbtn)
            grid.SetText(i, cols['copemean'], fmt(clust.copemean))

        # Refresh the grid widget when all
        # clusters have been added.
        def onFinish():

            if not fwidgets.isalive(grid):
                return

            status.update('All clusters loaded.')
            self.Enable()
            grid.Show()
            grid.Refresh()

        for i, clust in enumerate(clusters):
            idle.idle(addCluster, i, clust)

        idle.idle(onFinish)

        return grid
Beispiel #8
0
    def __init__(self,
                 parent,
                 knownHosts=None,
                 knownAccounts=None,
                 filterType=None,
                 filters=None):
        """Create a ``XNATBrowserPanel``.

        :arg parent:        ``wx`` parent object.

        :arg knownHosts:    A sequence of hosts to be used as auto-complete
                            options in the host input field.

        :arg knownAccounts: A mapping of ``{ host : (username, password) }``,
                            which are used to automatically fill in the
                            login credentials when a particular host name
                            is entered.

        :arg filterType:    How the filter patterns should be applied -
                            either ``'regexp'`` for regular expressions, or
                            ``'glob'`` for shell-style wildcard patterns.
                            Defaults to ``'regexp'``.

        :arg filters:       Mapping containing initial filter values. Must
                            be of the form  ``{ level : pattern }``, where
                            ``level`` is the name of an XNAT hierarchy level
                            (e.g. ``'subject'``, ``'file'``, etc.).
        """

        if knownHosts    is None: knownHosts    = []
        if knownAccounts is None: knownAccounts = {}
        if filterType    is None: filterType    = 'regexp'
        if filters       is None: filters       = {}

        if filterType not in ('regexp', 'glob'):
            raise ValueError('Unrecognised value for filterType: '
                             '{}. May be one of \'regexp\' or '
                             '\'glob\''.format(filterType))

        # store hosts without
        # the http[s]:// prefix
        knownHosts    = [h.strip('https://')          for h in knownHosts]
        knownAccounts = {h.strip('https://') : (u, p) for h, (u, p)
                         in knownAccounts.items()}
        knownHosts   += [h for h in knownAccounts.keys()
                         if h not in knownHosts]

        wx.Panel.__init__(self, parent)

        self.__knownHosts    = knownHosts
        self.__knownAccounts = knownAccounts
        self.__filterType    = filterType
        self.__session       = None
        self.__filters = collections.OrderedDict([
            ('subject',    ''),
            ('experiment', ''),
            ('file',       ''),
        ])

        self.__filters.update(**filters)

        self.__host       = at.AutoTextCtrl(self)
        self.__username   = pt.PlaceholderTextCtrl(self,
                                                   placeholder='username')
        self.__password   = pt.PlaceholderTextCtrl(self,
                                                   placeholder='password',
                                                   style=wx.TE_PASSWORD)
        self.__connect    = wx.Button(self)
        self.__status     = wx.StaticText(self)
        self.__project    = wx.Choice(self)
        self.__refresh    = wx.Button(self)
        self.__filter     = wx.Choice(self)

        self.__filterText = pt.PlaceholderTextCtrl(self,
                                                   placeholder=filterType,
                                                   style=wx.TE_PROCESS_ENTER)
        self.__splitter   = wx.SplitterWindow(self,
                                              style=(wx.SP_LIVE_UPDATE |
                                                     wx.SP_BORDER))
        self.__info       = wgrid.WidgetGrid(self.__splitter)
        self.__browser    = wx.TreeCtrl(self.__splitter,
                                        style=(wx.TR_MULTIPLE    |
                                               wx.TR_NO_LINES    |
                                               wx.TR_HAS_BUTTONS |
                                               wx.TR_TWIST_BUTTONS))

        self.__splitter.SetMinimumPaneSize(50)
        self.__splitter.SplitHorizontally(self.__info, self.__browser)
        self.__splitter.SetSashPosition(50)
        self.__splitter.SetSashGravity(0.2)

        images = [icons.loadBitmap(icons.FILE_ICON),
                  icons.loadBitmap(icons.FOLDER_UNLOADED_ICON),
                  icons.loadBitmap(icons.FOLDER_LOADED_ICON)]

        self.__fileImageId           = 0
        self.__unloadedFolderImageId = 1
        self.__loadedFolderImageId   = 2

        imageList = wx.ImageList(16, 16)
        for i in images:
            imageList.Add(images[0])
            imageList.Add(images[1])
            imageList.Add(images[2])

        self.__browser.AssignImageList(imageList)

        self.__filter.SetItems([LABELS[f] for f in self.__filters.keys()])
        self.__filter.SetSelection(0)

        self.__hostLabel     = wx.StaticText(self)
        self.__usernameLabel = wx.StaticText(self)
        self.__passwordLabel = wx.StaticText(self)
        self.__projectLabel  = wx.StaticText(self)
        self.__filterLabel   = wx.StaticText(self)

        self.__status.SetFont(self.__status.GetFont().Larger().Larger())
        self.__info.SetColours(border=self.__info._defaultEvenColour)
        self.__host         .AutoComplete(knownHosts)
        self.__hostLabel    .SetLabel(LABELS['host'])
        self.__usernameLabel.SetLabel(LABELS['username'])
        self.__passwordLabel.SetLabel(LABELS['password'])
        self.__connect      .SetLabel(LABELS['connect'])
        self.__projectLabel .SetLabel(LABELS['project'])
        self.__filterLabel  .SetLabel(LABELS['filter'])
        self.__refresh      .SetLabel(LABELS['refresh'])

        filterTooltip = wx.ToolTip(TOOLTIPS['filter.{}'.format(filterType)])

        self.__filterLabel.SetToolTip(filterTooltip)
        self.__filter     .SetToolTip(filterTooltip)
        self.__filterText .SetToolTip(filterTooltip)

        self.__loginSizer  = wx.BoxSizer(wx.HORIZONTAL)
        self.__filterSizer = wx.BoxSizer(wx.HORIZONTAL)
        self.__mainSizer   = wx.BoxSizer(wx.VERTICAL)

        self.__loginSizer.Add((5, 1))
        self.__loginSizer.Add(self.__hostLabel)
        self.__loginSizer.Add((5, 1))
        self.__loginSizer.Add(self.__host, proportion=1)
        self.__loginSizer.Add((5, 1))
        self.__loginSizer.Add(self.__usernameLabel)
        self.__loginSizer.Add((5, 1))
        self.__loginSizer.Add(self.__username, proportion=1)
        self.__loginSizer.Add((5, 1))
        self.__loginSizer.Add(self.__passwordLabel)
        self.__loginSizer.Add((5, 1))
        self.__loginSizer.Add(self.__password, proportion=1)
        self.__loginSizer.Add((5, 1))
        self.__loginSizer.Add(self.__connect)
        self.__loginSizer.Add((5, 1))
        self.__loginSizer.Add(self.__status)
        self.__loginSizer.Add((5, 1))

        self.__filterSizer.Add((5, 1))
        self.__filterSizer.Add(self.__projectLabel)
        self.__filterSizer.Add((5, 1))
        self.__filterSizer.Add(self.__project, proportion=1)
        self.__filterSizer.Add((5, 1))
        self.__filterSizer.Add(self.__filterLabel)
        self.__filterSizer.Add((5, 1))
        self.__filterSizer.Add(self.__filter)
        self.__filterSizer.Add((5, 1))
        self.__filterSizer.Add(self.__filterText, proportion=1)
        self.__filterSizer.Add((5, 1))
        self.__filterSizer.Add(self.__refresh)
        self.__filterSizer.Add((5, 1))

        self.__mainSizer.Add(self.__loginSizer, flag=wx.EXPAND)
        self.__mainSizer.Add((1, 10))
        self.__mainSizer.Add(self.__filterSizer, flag=wx.EXPAND)
        self.__mainSizer.Add((1, 10))
        self.__mainSizer.Add(self.__splitter, flag=wx.EXPAND, proportion=1)

        self.SetSizer(self.__mainSizer)

        self.__host   .Bind(at.EVT_ATC_TEXT_ENTER,      self.__onHost)
        self.__connect.Bind(wx.EVT_BUTTON,              self.__onConnect)
        self.__project.Bind(wx.EVT_CHOICE,              self.__onProject)
        self.__refresh.Bind(wx.EVT_BUTTON,              self.__onRefresh)
        self.__filter .Bind(wx.EVT_CHOICE,              self.__onFilter)
        self.__browser.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.__onTreeActivate)
        self.__browser.Bind(wx.EVT_TREE_SEL_CHANGED,    self.__onTreeSelect)
        self.__filterText.Bind(wx.EVT_TEXT_ENTER,       self.__onFilterText)

        self.__updateFilter()
        self.EndSession()
Beispiel #9
0
def _test_reorder_events_draglimit():
    realYield()
    frame = wx.GetApp().GetTopWindow()
    frame.SetSize((800, 600))
    sim = wx.UIActionSimulator()
    grid = widgetgrid.WidgetGrid(frame, style=widgetgrid.WG_DRAGGABLE_COLUMNS)
    sizer = wx.BoxSizer(wx.VERTICAL)
    frame.SetSizer(sizer)
    sizer.Add(grid, flag=wx.EXPAND, proportion=1)

    grid.ShowColLabels()
    grid.SetGridSize(1, 5)
    grid.SetDragLimit(2)

    labels = ['col {}'.format(i) for i in range(5)]
    cells = ['cell {}'.format(i) for i in range(5)]

    for i in range(5):
        grid.SetColLabel(i, labels[i])
    for i in range(5):
        grid.SetText(0, i, cells[i])

    grid.Refresh()
    frame.Layout()

    # (clicked column, drop column, drop pos, expected order)
    tests = [
        (0, 1, 0.75, [1, 0, 2, 3, 4]),
        (1, 2, 0.75, [0, 2, 1, 3, 4]),
        (1, 0, 0.25, [1, 0, 2, 3, 4]),
        (2, 1, 0.25, [0, 2, 1, 3, 4]),

        # drop is past drag limit -> clamp
        (0, 3, 0.75, [1, 2, 0, 3, 4]),
        (0, 4, 0.75, [1, 2, 0, 3, 4]),

        # past drag limit -> no-ops
        (3, 1, 0.25, [0, 1, 2, 3, 4]),
        (3, 4, 0.75, [0, 1, 2, 3, 4]),
        (4, 3, 0.25, [0, 1, 2, 3, 4]),
    ]

    realYield()
    for clickcol, dropcol, droppos, exporder in tests:

        fakestate = FakeMouseState()

        with mock.patch('wx.GetMouseState', return_value=fakestate):

            cwidget = grid.colLabels[clickcol].GetParent()
            dwidget = grid.colLabels[dropcol].GetParent()

            ev = FakeEV(cwidget)
            grid._WidgetGrid__onColumnLabelMouseDown(ev)
            realYield()

            fakestate.pos = wx.Point(*cxy(dwidget, (droppos, 0.5)))
            with mock.patch('wx.FindWindowAtPointer', return_value=[dwidget]):
                grid._WidgetGrid__onColumnLabelMouseDrag(ev)
                realYield()
                ev.evo = dwidget
                grid._WidgetGrid__onColumnLabelMouseUp(ev)
                realYield()

            explabels = [labels[i] for i in exporder]
            gotlabels = grid.GetColLabels()

            assert explabels == gotlabels

            labels = gotlabels