Recently I wrote a little application using Ruby and Qt. It was my first non-trivial project with qtruby. After some time I managed to translate C++ references and tutorials into working Ruby code, and got the hang of it.
Only when implementing my own drag and drop functionality in QTreeView
widgets, I got really stuck. I could isolate the problem to the Qt::AbstractItemModel::mimeData
method. After eliminating some other mistakes, I ended up with the following code which somehow caused the application to crash as soon as a drag action occured.
class TreeModel < Qt::AbstractItemModel
def mimeData(indexlist)
encodedData = Qt::ByteArray.new("")
stream = Qt::DataStream.new(encodedData, Qt::IODevice::WriteOnly)
indexlist.each do |index|
if index.column == 0
if index.isValid
stream << index.item.mime_data.to_json
end
end
end
mimeData = Qt::MimeData.new
mimeData.setData("application/x-tegi.json", encodedData)
mimeData
end
end
The crash appeared non-deterministic, a few times the code just worked. The error dump and backtrace did not give me a hint, only that the crash happened inside QApplication::exec
.
What is the issue and how can it be fixed?
The C++ prototype for mimeData
is :
QMimeData * QAbstractItemModel::mimeData
( const QModelIndexList & indexes ) const [virtual]
The method returns a pointer to a QMimeData
object. My implementation of mimeData
was returning a pointer to a local variable. Thus the non-deterministic crashes.
Once found, fixing the issue was easy. An instance variable would stay alive and keep its value until the next call of mimeData
:
@mimeData = Qt::MimeData.new
@mimeData.setData("application/x-tegi.json", encodedData)
@mimeData
end
Another possibility is to call super
and leave the construction and deconstruction to the superclass. This also inherits the default mime data ("application/x-qabstractitemmodeldatalist"):
mimeData = super
mimeData.setData("application/x-tegi.json", encodedData)
mimeData
end
After having found the issue, it appears trivial to me. Nevertheless I would like to share it, because I wasted too much time with it. The qtruby documentation warns about pointer arguments and mentions some unsupported functions returning uchar
pointers, but no word about functions returning pointers to Qt objects. Being lulled by qtruby seamlessly wrapping data types to and fro, I looked so many times over that little asterisk without spotting it.