1

I'm trying to capture a "changed tab" event from a traitsui view. I've been circling for a while now searching, googling, and reading library source code trying to see if there's a signal/event that occurs when users change which tab has focus in the UI, but I've come up with nothing so far.

The issue I currently have is that each tab holds a Chaco plot. I noticed that the Chaco plots do not initialize the plots width/height values until it renders on screen. I've given up on trying to have the plots initialize these values and opt'ed to simply pull the values once the plots are displayed. Which leads me to trying to capture the event of "tabs have changed".

I'm still open to somebody telling me how I can initialize the width/height values of the Chaco plot, but being able to capture a "changed tab" event would be fantastic as well.

Here some code to go along with my problem. Here is the traits view for my widget:

traits_view = View(
            Tabbed(
            Group(
                Item('FFT_Container',editor=ComponentEditor(), show_label=False),
            label='Fourier Spectrum', id='FFTPlot'),
            Group(
                VGroup(
                    Item('TS_Container',editor=ComponentEditor(), show_label=False),
                    Item('NAV_Container', editor=ComponentEditor(), show_label=False, height=100)
                ),
            label='Time Series', id='TSPlot')
            ),
            spring,
            HGroup(
            Item('SonicationUI', show_label=True, label='Sonication:'),
            Item('BurstNumberUI', show_label=True, label = 'Burst:'),
            Item('PeakNumberUI', show_label=True, label = 'Peak:'),
            Item('FrequencyRange', show_label=True, label = 'Freq. range'),
            Item("triggerPDB", show_label=False)),
            resizable=True)

The event I'm trying to capture is when users switch between the the two Tabbed views.

Alternatively, if we are able to initialize the width/height parameters of the plots, that would work as well. The plots are built in the following code:

        self.FFT_Container = OverlayPlotContainer(  padding = 50,
                                                    valign='center',
                                                    halgin='right',
                                                    use_backbuffer = True)

        self.TS_Container  = OverlayPlotContainer(  padding = 50,
                                                    valign='center',
                                                    halgin='right',
                                                    use_backbuffer = True)

        self.NAV_Container = OverlayPlotContainer(  padding = 10,
                                                    valign='bottom',
                                                    halign='center',
                                                    use_backbuffer = True)


        self.data_fft       = np.zeros(1)
        self.data_fft_freq  = np.zeros(1)

        self.data_time      = np.zeros(1)
        self.data_voltage   = np.zeros(1)

        self.data_nav_time  = np.zeros(1)
        self.data_nav_volts = np.zeros(1)

        #2019-01-24 CK: a dictionary to reference the plot data.
        self.dataPointers           = {}
        self.dataPointers['FFT']    = {'frequency':self.data_fft_freq,'spectrum':self.data_fft}
        self.dataPointers['Time']   = {'timeVector':self.data_time,'voltageVector':self.data_voltage}
        self.dataPointers['NAV']    = {'navTime':self.data_nav_time,'navVoltage':self.data_nav_volts}
        self.dataPointers['Index']  = {'Start':self.StartIndex,'Stop':self.StopIndex}

        self.plot_fft                   = create_line_plot((self.data_fft_freq, self.data_fft), color=self.ColorsPlot[0], bgcolor="black", add_grid = True, add_axis = True)
        self.plot_ts                    = create_line_plot((self.data_time, self.data_voltage), color=self.ColorsPlot[0], bgcolor="black", add_grid = True, add_axis = True)
        self.plot_nav_ts                = create_line_plot((self.data_nav_time, self.data_nav_volts), color=self.ColorsPlot[0], bgcolor="black")

        self.plot_fft.use_downsampling      = True
        self.plot_ts.use_downsampling       = True
        self.plot_nav_ts.use_downsampling   = True

        self.plot_fft.x_axis.title      = 'Frequency (Hz)'
        self.plot_fft.y_axis.title      = 'Volts (V)'

        self.plot_ts.x_axis.title       = 'Time ('+unichr(956)+'s)'
        self.plot_ts.y_axis.title       = 'Volts (mV)'

        self.listener                   = PlotListener( pUpdatePlot = self.updatePlot,
                                                        pBounds = self.plot_nav_ts.index.get_bounds(),
                                                        data=self.dataPointers)
        self.plot_nav_ts.active_tool    = RangeSelection(self.plot_nav_ts, left_button_selects=True)

        self.plot_nav_ts.active_tool.listeners.append(self.listener)
        self.plot_nav_ts.overlays.append(RangeSelectionOverlay(component=self.plot_nav_ts))

        self.pan_fft                    = PanTool(component=self.plot_fft,drag_button='left')
        self.pan_ts                     = PanTool(component=self.plot_ts, drag_button='left')

        self.zoom_fft                   = BetterSelectingZoom(component=self.plot_fft, tool_mode="box", always_on=False)
        self.zoom_ts                    = BetterSelectingZoom(component=self.plot_ts, tool_mode="range", axis='index', always_on=False)

        self.plot_fft.tools.append(self.pan_fft)
        self.plot_fft.overlays.append(self.zoom_fft)

        self.plot_ts.tools.append(self.pan_ts)
        self.plot_ts.overlays.append(self.zoom_ts)

where the self.plot_nav_ts.width is the parameter I'm truly interested in. But it simply returns 0.0 unless the plot has been rendered into the display.

Any help or insight will be appreciated!

BaleineBoy
  • 41
  • 5

1 Answers1

2

Because I have a hard time giving up, I've answered my own question.

I knew that Traitsui was generating a QWidget to be displayed in the interface. I also knew that I wanted to find some child QTabWidget that is "somewhere" inside the top-level QWidget. by using the "inspect" python library (pretty helpful!) and the PySide documentation I was able to produce the following line of code that allowed me to connect the "currentChanged" QTabWidget signal to a method so I can perform what I wanted to do. Here is that code:

self.ShowAnalysis.OwnWidget.findChild(QtGui.QTabWidget).currentChanged.connect(self.ShowAnalysis.handleTabChange, QtCore.Qt.QueuedConnection)

For those who want to know what's going on here:

self.ShowAnalysis.OwnWidget is the QWidget that traitsui produces. By using the QWidget method findChild we can search for the child QTabWidget instance that we're interested in. After that we're simply connecting the signal to the method call for handling the rest of the actions we want to perform upon the "Tab Changed" event.

BaleineBoy
  • 41
  • 5