Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. ListView undefined reference to vtable for Custom Delegate (QStyledItemDelegate)
Forum Updated to NodeBB v4.3 + New Features

ListView undefined reference to vtable for Custom Delegate (QStyledItemDelegate)

Scheduled Pinned Locked Moved Solved General and Desktop
qt5.9qt5qlistviewqstyleditemdeledelegate
4 Posts 2 Posters 3.3k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • C Offline
    C Offline
    CybeX
    wrote on 11 Dec 2017, 07:49 last edited by CybeX 12 Nov 2017, 08:17
    #1

    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:

    • StackOverflow
    • StackOverflow
    • StackOverflow

    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"
    
    1 Reply Last reply
    0
    • C Offline
      C Offline
      CybeX
      wrote on 11 Dec 2017, 08:45 last edited by
      #3

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

      V 1 Reply Last reply 11 Dec 2017, 08:48
      0
      • V Offline
        V Offline
        VRonin
        wrote on 11 Dec 2017, 08:22 last edited by
        #2

        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

        "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
        ~Napoleon Bonaparte

        On a crusade to banish setIndexWidget() from the holy land of Qt

        1 Reply Last reply
        1
        • C Offline
          C Offline
          CybeX
          wrote on 11 Dec 2017, 08:45 last edited by
          #3

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

          V 1 Reply Last reply 11 Dec 2017, 08:48
          0
          • C CybeX
            11 Dec 2017, 08:45

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

            V Offline
            V Offline
            VRonin
            wrote on 11 Dec 2017, 08:48 last edited by
            #4

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

            "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
            ~Napoleon Bonaparte

            On a crusade to banish setIndexWidget() from the holy land of Qt

            1 Reply Last reply
            1

            2/4

            11 Dec 2017, 08:22

            • Login

            • Login or register to search.
            2 out of 4
            • First post
              2/4
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved