sciapp / python-gr

Python wrapper for the GR framework
https://gr-framework.org
Other
30 stars 8 forks source link

QTabWidget with embedded InteractiveGRWidget rasies a Division by Zero Error #8

Closed BoxWizard000000 closed 5 years ago

BoxWizard000000 commented 5 years ago

I've been toying around with getting graphs to work in a tab view so I can easily add, remove, and view many graphs simultaneously.

Here's my code below. I try to do the example live plotter in a QTabWidget.

import sys
from gr.pygr import Plot, PlotAxes, PlotCurve
from qtgr.backend import QtCore, QtGui, QtWidgets
from qtgr import InteractiveGRWidget

from numpy import arange, sin, pi

class ScaledPlotAxes(PlotAxes):

    def doAutoScale(self, curvechanged=None):
        xmin, xmax, ymin, ymax = PlotAxes.doAutoScale(self, curvechanged)
        bxmin, _bxmax, _bymin, _bymax = self.getBoundingBox()
        if xmin < bxmin:
            xmin = bxmin
        self.setWindow(xmin, xmax, ymin, ymax)
        return self.getWindow()

class GRTab(QtWidgets.QTabWidget):
    def __init__(self, *args, **kwargs):
        QtWidgets.QTabWidget.__init__(self)
        self._tabDict = {"Tab 1": InteractiveGRWidget()}

        viewport = [0.1, 0.88, 0.1, 0.88]
        x = arange(0, 2 * pi, 0.01)
        y = sin(x)

        self.curve = PlotCurve(x, y)
        axes = ScaledPlotAxes(viewport)
        axes.addCurves(self.curve)
        plot = Plot(viewport).addAxes(axes)
        plot.title = "QtGR Timer example"
        plot.subTitle = "Plotting Live-Data"
        plot.xlabel = "t"
        plot.ylabel = "sin(t)"

        self._tabDict["Tab 1"].addPlot(plot)

        self.addTab(self._tabDict["Tab 1"], "Tab 1")

    def updateData(self):
        self.curve.x += 0.05
        self.curve.y = sin(self.curve.x)
        self.update()

class TabWindow(QtWidgets.QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        layout = QtWidgets.QGridLayout()
        self._grtab = GRTab()

        layout.addWidget(self._grtab, 0, 0)
        self.setLayout(layout)

def main():
    app = QtWidgets.QApplication(sys.argv)
    mainWindow = TabWindow()
    mainWindow.show()
    sys.exit(app.exec_())

if (__name__ == '__main__'):
    main()

And here is the error:

Traceback (most recent call last):
  File "/home/emdash00/.local/lib/python3.7/site-packages/qtgr/__init__.py", line 93, in resizeEvent
    self._sizex = self._mwidth / self._mheight
ZeroDivisionError: float division by zero
[1]    19857 abort (core dumped)  python3 grtabview.py

I'm not entirely sure what to make this being new to Qt and GR still.

My OS is Ubuntu 19.04 and I'm running this on an Intel Core i7.

FlorianRhiem commented 5 years ago

The QTabWidget seems to resize the GRWidget to 0x0 temporarily, causing this division by zero. I've added a check against this in ff8c6ef097f3cce3d9914e524c47914081d98341 in the develop branch. This fix will be part of the next release.

BoxWizard000000 commented 5 years ago

What can I do in the meantime to fix this?

BoxWizard000000 commented 5 years ago
Details
FlorianRhiem commented 5 years ago

You can either replicate the change I madein that commit in your local installation of gr, or set the keepRatio attribute of the widget to True until the widget has been properly sized by Qt.

BoxWizard000000 commented 5 years ago

I'm a bit wary about breaking my installation when editing it. I think I'll simply subclass and override it and let you know how it goes.

BoxWizard000000 commented 5 years ago

I decided to simply use introspection for now so I don't have to worry about messy inheritance rules. This seems to get it to display. I'm going to see if I can patch it at runtime rather than by a per object basis as well.

from types import MethodType

def _patchWidget(self, widget):
    def _resizeEvent(self, event):
        self._dwidth, self._dheight = self.width(), self.height()
        self._mwidth = self.widthMM() * 0.001
        self._mheight = self.heightMM() * 0.001
        if self._mwidth > self._mheight:
            self._sizex = 1.
            if self.keepRatio:
                self._sizey = 1.
                self._mwidth = self._mheight
                self._dwidth = self._dheight
            elif self._mwidth > 0:
                 self._sizey = self._mheight / self._mwidth
            else:
                 self._sizey = 1.
            else:
                 if self.keepRatio:
                    self._sizex = 1.
                    self._mheight = self._mwidth
                    self._dheight = self._dwidth
                 elif self._mheight > 0:
                    self._sizex = self._mwidth / self._mheight
                 else:
                    self._sizex = 1.
                 self._sizey = 1.

    setattr(widget, 'resizeEvent', MethodType(_resizeEvent, widget))
FlorianRhiem commented 5 years ago

The fix is included in version 1.11.1.