Using TQtWidget with PyQt Application

Hello, I am trying to embed a simple TF1 object in my PyQt application. I’ve configured qt with ROOT installation and it seemed to install successfully. I tried to follow the example given under ROOT-based Qt Applications in the ROOT documentation, but I get an error. I’ve included my code below

MyWidget = TQtWidget(0, "MyWidget")
MyWidget.show()
MyWidget.GetCanvas().cd()
f1 = TF1("f1","sin(x)/x",0,10)
f1.Draw()
MyWidget.GetCanvas().Update()
self._layout.addWidget(MyWidget)

where self._layout is a QVBoxLayout object. I get the folllowing error.

TypeError: none of the 2 overloaded methods succeeded. Full details:
  TQtWidget::TQtWidget(QWidget* parent, const char* name, QFlags<Qt::WindowType> f = 0, bool embedded = true) =>
    problem in C++; program state has been reset
  TQtWidget::TQtWidget(QWidget* parent = 0, QFlags<Qt::WindowType> f = 0, bool embedded = true) =>
    could not convert argument 2

Any help with this would be greatly appreciated.

On the first line, you pass a parent pointer of null, leading to a segfault …

To solve, create a parent for the widget (e.g. a QMainWindow). Example in tutorials/pyroot/qtexample.py

From the experience of our KDE5 work, there are other problems with dictionary generation for Qt and so I presume for TQt as well (e.g. that QFlags typedef). Some fixes have made it upstream, not all.

Thanks for the response. I tried following what is in the qtexample but was unsuccessful. I still get a segfault.
I also tried to run qtexample.py but it failed with wrapped C/C++ object of type QApplication has been deleted.
I have a QVBoxLayout that I want to have a button and a TF1 object. What kind of object would I set for the parent? I tried making the parent a new QWidget object and self._layout but both didn’t work. I don’t think QMainWindow is applicable in my situation given this is for one QVBoxLayout among many.

Ownership issue: you may have a widget replacing another one, while keeping a reference to the old widget (make sure that the series of parents is strictly hierarchical). Or you may have a local reference to a widget going out of scope, with it thinking it holds ownership (release ownership when passing).

See the qtexample.py: you need to set up a TQtWidget with as parent the frame that the layout is for. Then add the TQtWidget to the layout. The TF1 draws on the TQtWidget.

Thanks for the response.

The qtexample.py in tutorials/pyroot will not run itself. I’ve tried to mock what’s in the script but everytime I include self.Canvas = ROOT.TQtWidget(sip.voidptr(self.Address).ascobject()) I get the segfault.

self.f1 = ROOT.TF1("f1","sin(x)/x",0,10)
self._widget = QtGui.QWidget()
self.Address = sip.unwrapinstance(self._widget)
self.Canvas = ROOT.TQtWidget(sip.voidptr(self.Address).ascobject())
ROOT.SetOwnership( self.Canvas, False )

Again, you need to have a parent that is not nullptr. If you use the default ctor for QWidget, the default value of parent is 0. (In the example code, the main window is passed as the parent of the QWidget.)

I understand that I need a parent that is not nullptr. But I don’t understand what I’m supposed to use for the parent (I can’t use Main Window in this case). Again, the example code (qtexample.py) doesn’t work.

The parent should be whatever you want to put the QWidget on. As per your earlier posting above, the parent you want is the widget that the layout is associated with (i.e. the parent provided when creating the layout). And if your code did not create the layout, you can call parentWidget() to retrieve the parent.

Okay so I have the following code now.
gui is my main QWidget object that I put everything else on and call show(). I pass it to view_manager object as parent and create a QWidget object with parent parent.

class gui(QtGui.QWidget):

        def __init__(self):
                super(gui, self).__init__()
                self._view_manager = view_manager(self)
class view_manager(QtCore.QObject):
        def __init__(self, parent):
                super(view_manager, self).__init__()
                self._layout = QtGui.QVBoxLayout()

                # Create widget with parent
                self._parent = parent
                self._hist_plot = None
                self._Address = sip.unwrapinstance(parent)
                self._Canvas = None

     def some_other_method(self):

               # ROOT STUFF
                if self._hist_plot is not None:
                        self._hist_plot = None
                self._hist_plot = ROOT.TH1F("pipo","pipo", 100,0,100)
            
                if self._Canvas is not None:
                        self._Canvas = None
                self._Canvas = ROOT.TQtWidget(sip.voidptr(self._Address).ascobject())

                ROOT.SetOwnership( self._Canvas, False )

                self._layout.addWidget(sip.wrapinstance(ROOT.AddressOf(self._Canvas)[0],QWidget), 0, 0)
                self._hist_plot.Draw()

I’ve checked to make sure that parent and self._Address are not nullptr. This still gives a segfault, particularly when I add self._Canvas = ROOT.TQtWidget(sip.voidptr(self._Address).ascobject()).

I don’t see anything obvious, other than those checks for ‘None’ in some_other_method: is this method being called multiple times, i.e. is the TQtWidget created more than once?

If not that, can you post the actual stack trace?

So I’ll give an example here. I’m just creating a simple application with two buttons and a ROOT histogram.
This script works if all ROOT code is commented out, and if I comment out all Qt code the histogram will draw. But I get a segfault otherwise.

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *

import ROOT
import sip
import time

app = QApplication(sys.argv)
win = QWidget()
win.resize(1000,500)

b1 = QPushButton("Button 1")
b2 = QPushButton("Button 2")
master = QHBoxLayout()

vbox1 = QVBoxLayout()
vbox1.addStretch(1)
vbox1.addWidget(b1)
vbox1.addStretch(1)
master.addLayout(vbox1)
	
vbox2 = QVBoxLayout()
vbox2.addWidget(b2)

# ROOT 
c1 = ROOT.TCanvas("c1", "c1", 800, 800)
hist = ROOT.TH1F("pipo","pipo", 100, 0, 100)

Address = sip.unwrapinstance(win)
Canvas = ROOT.TQtWidget(sip.voidptr(Address).ascobject())
ROOT.SetOwnership( Canvas, False )

vbox2.addWidget(sip.wrapinstance(ROOT.AddressOf(Canvas)[0],QWidget), 0, 0)
hist.Draw()
c1.Update()

master.addLayout(vbox2)
win.setLayout(master)

win.setWindowTitle("ROOT Test")
win.show()
#time.sleep(5)
sys.exit(app.exec_())

Sure, but I’m not about to install ROOT. :slight_smile:

If you print the stack trace, I can maybe reason something out. Are you e.g. sure that the version for PyQt and the one for ROOT matched?

I am not sure how to check if they match. I have PyQt4 and ROOT version 6.08.

Here is my stack trace…

Traceback (most recent call last):
  File "pyqtEx.py", line 31, in <module>
    Canvas = ROOT.TQtWidget(sip.voidptr(Address).ascobject())
TypeError: none of the 2 overloaded methods succeeded. Full details:
  TQtWidget::TQtWidget(QWidget* parent, const char* name, QFlags<Qt::WindowType> f = 0, bool embedded = true) =>
    takes at least 2 arguments (1 given)
  TQtWidget::TQtWidget(QWidget* parent = 0, QFlags<Qt::WindowType> f = 0, bool embedded = true) =>
    problem in C++; program state has been reset

For checking I meant purely which Qt versions. Qt4 is old, so perhaps ROOT found Qt5 on your system (then again PyQt4 can build with Qt5, so that would be system dependent).

The relevant stack trace should be part of this (ROOT generated):

If there’s nothing there, then you’ll have to run it under a debugger to get a trace ("$ gdb --args python your_script.py" then “run” and “where”). Among other things, it’ll hopefully show the libraries that were loaded and from where the calls came, allowing version check. (By default ROOT builds with debug info.)

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.