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)

ListView undefined reference to vtable for Custom Delegate (QStyledItemDelegate)

Scheduled Pinned Locked Moved Solved General and Desktop
qt5.9qt5qlistviewqstyleditemdeledelegate
4 Posts 2 Posters 3.2k 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

            4/4

            11 Dec 2017, 08:48

            • Login

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