From 10:00 CET Friday 22nd November we will adjust how the server works to deal with some recently reported problems. Therefore there may be a load problem, if you experience more problems than usual trying to access the forum then please PM AndyS or any of the moderators so they can inform me.


ListView undefined reference to vtable for Custom Delegate (QStyledItemDelegate)



  • Good day

    I required a QListView to display information in a readable fashion to a user. After much searching, I came across this post made in 2010.

    What I tried:
    Following the code provided had me creating a custom delegate, a QStyledItemDelegate.

    A delegate is required to allow a developer to 'customize' how they want data to be displayed. e.g. Display 2 icons on a ListView item/entry with text inbetween.

    Using this understanding which I derived from the paint() and sizeHint() methods, I proceeded to edit it for my own use. See below for code example.

    The Problem:

    The issue I have is simple. Undefined reference to 'vtable for ServerDelegate'.

    serverdelegate.o: In function `ServerDelegate::ServerDelegate()':
    /../../../serverdelegate.cpp:3: undefined reference to `vtable for ServerDelegate'
    collect2: error: ld returned 1 exit status
    make: *** [Makefile:291: VPNSumo] Error 1
    09:32:22: The process "/usr/bin/make" exited with code 2.
    Error while building/deploying project VPNSumo (kit: Desktop Qt 5.9.3 GCC 64bit)
    When executing step "Make"
    

    Out of experience (and lots of Google'ing), I have found that this is very often a case where the Q_OBJECT macro is not defined/declared in the header file, since methods defined in the Q_OBJECT macro are used within this class.

    See for reference:

    What I tried v2

    I then proceeded to append the Q_OBJECT macro to the ServerDelegate class, also adding a constructor argument to the ServerDelegate constructor:

    ServerDelegate(QStyledItemDelegate* parent = 0);
    

    and implemented by:

    ServerDelegate::ServerDelegate(QStyledItemDelegate *parent)
        : QStyledItemDelegate(parent)
    {
    //...
    }
    

    but the error persisted. I added a default constructor as a last resort taking no arguments, and as expected, it also did not work.

    Error after adding parent argument and default constructor:

    serverdelegate.o: In function `ServerDelegate::ServerDelegate()':
    /../../../serverdelegate.cpp:3: undefined reference to `vtable for ServerDelegate'
    serverdelegate.o: In function `ServerDelegate::ServerDelegate(QStyledItemDelegate*)':
    /../../../serverdelegate.cpp:15: undefined reference to `vtable for ServerDelegate'
    collect2: error: ld returned 1 exit status
    make: *** [Makefile:291: VPNSumo] Error 1
    09:40:52: The process "/usr/bin/make" exited with code 2.
    Error while building/deploying project VPNSumo (kit: Desktop Qt 5.9.3 GCC 64bit)
    When executing step "Make"
    

    I am out of ideas, and at Google Results page 5

    Help would be very much appreciated


    Code for class ServerDelegate

    ServerDelegate.h

    #ifndef SERVERDELEGATE_H
    #define SERVERDELEGATE_H
    
    #include <QApplication>
    #include <QtGui>
    #include <QStyledItemDelegate>
    #include <QtWidgets>
    
    class ServerDelegate : public QStyledItemDelegate
    {
    
    public:
        ServerDelegate();
        virtual ~ServerDelegate();
    
        enum DataRole{
            CountryText = Qt::UserRole + 100,
            CityText = Qt::UserRole+101,
            CountryFlag = Qt::UserRole+102,
            PremiumFlag = Qt::UserRole+103,
            ListIndex = Qt::UserRole+104
        };
    
        void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    
        QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
    
    private:
        QFont fontCountry, fontCity;
    };
    
    #endif // SERVERDELEGATE_H
    

    and the implementation serverdelegate.cpp

    **Please note: the implementation is untested due to the error below

    #include "serverdelegate.h"
    
    ServerDelegate::ServerDelegate()
    {
        fontCountry = QApplication::font();
        fontCountry.setBold(true);
        fontCountry.setPointSize(QApplication::font().pointSize() + 3);
    
        fontCity = QApplication::font();
        fontCity.setItalic(true);
        fontCity.setPointSize(QApplication::font().pointSize() - 1);
    }
    
    QSize ServerDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const{
        QIcon countryFlag = qvariant_cast<QIcon>(index.data(CountryFlag));
        QIcon premiumFlag = qvariant_cast<QIcon>(index.data(PremiumFlag));
    
        QSize totalCountrySize = countryFlag.actualSize(option.decorationSize);
        QSize totalPremiumSize = premiumFlag.actualSize(option.decorationSize);
    
        QFontMetrics fmCountry(fontCountry);
        QFontMetrics fmCity(fontCity);
    
        int fontHeight = 4 + fmCountry.height() + 2 + fmCity.height() + 4;
        int iconHeight = 4 + (totalCountrySize.height() > totalPremiumSize.height() ? totalCountrySize.height() : totalPremiumSize.height()) + 4;
    
        return QSize(totalCountrySize.width() + totalPremiumSize.width(), (fontHeight > iconHeight ? fontHeight : iconHeight));
    }
    
    void ServerDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const{
        QStyledItemDelegate::paint(painter, option, index);
        painter->save();
    
    
        QString countryText = index.data(DataRole::CountryText).toString();
        QString cityText = index.data(DataRole::CityText).toString();
        QFontMetrics fmCountry(fontCountry);
        QFontMetrics fmCity(fontCity);
    
        QPixmap cF, pF;
        cF.loadFromData(index.data(DataRole::CountryFlag).toByteArray(), "PNG");
        pF.loadFromData(index.data(DataRole::PremiumFlag).toByteArray(), "PNG");
        QIcon countryFlag = QIcon(cF);
        QIcon premiumFlag = QIcon(pF);
        QSize totalCountrySize = countryFlag.actualSize(option.decorationSize);
        QSize totalPremiumSize = premiumFlag.actualSize(option.decorationSize);
    
        QRect rectSeperator = option.rect;
        QRect rectCountryText = option.rect;
        QRect rectCityText = option.rect;
        QRect rectCountryFlag = option.rect;
        QRect rectPremiumFlag = option.rect;
    
        rectSeperator.setTop(0);
        rectSeperator.setLeft(0);
        rectSeperator.setBottom(2);
        rectSeperator.setRight(option.rect.width());
    
        rectCountryFlag.setRight(totalCountrySize.width()+20);
        rectCountryFlag.setTop(totalCountrySize.height()+4);
    
        rectCountryText.setLeft(rectCountryFlag.right());
        rectCountryText.setTop(fmCountry.height()+4);
    
        rectCityText.setLeft(rectCountryFlag.right());
        rectCityText.setTop(fmCity.height()+2);
    
        rectPremiumFlag.setLeft(rectCountryFlag.right());
        rectCountryFlag.setTop(totalCountrySize.height());
    
    
        painter->drawRect(rectSeperator);
        painter->drawPixmap(QPoint(rectCountryFlag.left()+totalCountrySize.width()/2+2,rectCountryFlag.top()+totalCountrySize.height()/2+3),countryFlag.pixmap(totalCountrySize.width(),totalCountrySize.height()));
        painter->setFont(fontCountry);
        painter->drawText(rectCountryText, countryText);
        painter->setFont(fontCity);
        painter->drawText(rectCityText, cityText);
        painter->drawPixmap(QPoint(rectPremiumFlag.left()+totalPremiumSize.width()/2+2,rectPremiumFlag.top()+totalPremiumSize.height()/2+3),premiumFlag.pixmap(totalPremiumSize.width(),totalPremiumSize.height()));
        painter->restore();
    }
    

    Update v1

    According to a suggestion on StackOverflow, it was mentioned that I did not Run qMake after adding the macro. I did so, resulting in further errors. I took the following steps when I built the application:

    1. clean
    2. run qmake
    3. rebuild

    The resulting error indicates and issue with the moc* output. To my knowledge, this results from an old build with classes not all including the required macros.

    However, this error points to the virtual destructor of the ServerDelegate class.

    In the tutorial I followed, it required one to create the virtual destructor to allow the parent to handle deleting the object.

    and here is the error output:

    moc_serverdelegate.o:(.data.rel.ro._ZTV14ServerDelegate[_ZTV14ServerDelegate]+0x28): undefined reference to `ServerDelegate::~ServerDelegate()'
    moc_serverdelegate.o:(.data.rel.ro._ZTV14ServerDelegate[_ZTV14ServerDelegate]+0x30): undefined reference to `ServerDelegate::~ServerDelegate()'
    collect2: error: ld returned 1 exit status
    make: *** [Makefile:293: VPNSumo] Error 1
    10:09:41: The process "/usr/bin/make" exited with code 2.
    Error while building/deploying project VPNSumo (kit: Desktop Qt 5.9.3 GCC 64bit)
    When executing step "Make"


  • It turns out that all that was required is an implementation for the ~virtual() method. A bare implementation of the destructor is required.


  • Qt Champions 2018

    you have to just combine the 2 solutions you already have.
    Add Q_OBJECT (good thing to have the QObject* parent =Q_NULLPTR constructor too) and re-run qmake



  • It turns out that all that was required is an implementation for the ~virtual() method. A bare implementation of the destructor is required.


  • Qt Champions 2018

    Actually, since the base class already has a virtual destructor you can just remove the destructor of your derived altogether