I am trying to encapsulate table view behavior and I am starting with connecting the table view header signals to table view slots defined in the subclass. I can get the behavior I'm looking for without subclassing, but that defeats the purpose. When I do try to subclassing, I get the dreaded "No matching function call to connect. All components are ultimately QObjects, so I don't think that's the problem. (But, then again, maybe that IS the problem.) Right now I'm connecting to 'hideColumn()', but I would eventually like to connect to my own slots (such as 'my_sectionClicked(int)'.
The code below was drawn from the source for "C++ GUI Programming with Qt 4" by Jasmin Blanchette and Mark Summerfield with the exception of the "MyTableView" addition that I made.
MyTableView.h
#ifndef MYTABLEVIEW_HPP
#define MYTABLEVIEW_HPP
#include <QTableView>
class MyTableView : public QTableView
{
Q_OBJECT
public:
explicit MyTableView(QWidget *parent = 0);
public slots:
void my_sectionClicked(int logicalIndex);
private slots:
public:
private:
QHeaderView *m_rowHeader;
};
#endif // MYTABLEVIEW_HPP
MyTableView.cpp
// Qt Includes
#include <QDebug>
#include <QMenu>
// Local Includes
#include "MyTableView.h"
MyTableView::MyTableView(QWidget *parent) : QTableView(parent)
{
m_rowHeader = horizontalHeader();
connect(m_rowHeader, SIGNAL(sectionClicked(int)), this, SLOT(hideColumn(int)));
}
void MyTableView::my_sectionClicked(int logicalIndex)
{
qDebug().nospace() << "Column " << logicalIndex << " selected." << "\n";
}
currencymodel.h
#ifndef CURRENCYMODEL_H
#define CURRENCYMODEL_H
#include <QAbstractTableModel>
#include <QMap>
class CurrencyModel : public QAbstractTableModel
{
public:
CurrencyModel(QObject *parent = 0);
void setCurrencyMap(const QMap<QString, double> &map);
int rowCount(const QModelIndex &parent) const;
int columnCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
QVariant headerData(int section, Qt::Orientation orientation,
int role) const;
private:
QString currencyAt(int offset) const;
QMap<QString, double> currencyMap;
};
#endif
currencymodel.cpp
#include <QtCore>
#include "currencymodel.h"
CurrencyModel::CurrencyModel(QObject *parent)
: QAbstractTableModel(parent)
{
}
void CurrencyModel::setCurrencyMap(const QMap<QString, double> &map)
{
currencyMap = map;
reset(); // Forces views to refresh data
}
int CurrencyModel::rowCount(const QModelIndex & /* parent */) const
{
return currencyMap.count();
}
int CurrencyModel::columnCount(const QModelIndex & /* parent */) const
{
return currencyMap.count();
}
QVariant CurrencyModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (role == Qt::TextAlignmentRole)
{
return int(Qt::AlignRight | Qt::AlignVCenter);
}
else if (role == Qt::DisplayRole)
{
QString rowCurrency = currencyAt(index.row());
QString columnCurrency = currencyAt(index.column());
if (currencyMap.value(rowCurrency) == 0.0)
return "####";
double amount = currencyMap.value(columnCurrency)
/ currencyMap.value(rowCurrency);
return QString("%1").arg(amount, 0, 'f', 4);
}
return QVariant();
}
QVariant CurrencyModel::headerData(int section,
Qt::Orientation /* orientation */,
int role) const
{
if (role != Qt::DisplayRole)
return QVariant();
return currencyAt(section);
}
QString CurrencyModel::currencyAt(int offset) const
{
return (currencyMap.begin() + offset).key();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtGui>
#include "MyTableView.h"
#include "currencymodel.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
protected:
private slots:
void on_sectionClicked(int locicalIndex);
private:
QMap<QString, double> currencyMap;
CurrencyModel currencyModel;
QTableView tableView;
QHeaderView *m_rowHeader;
};
#endif
mainwindow.cpp
#include <iostream>
#include "mainwindow.h"
MainWindow::MainWindow()
{
currencyMap.insert("AUD", 1.3259);
currencyMap.insert("CHF", 1.2970);
currencyMap.insert("CZK", 24.510);
currencyMap.insert("DKK", 6.2168);
currencyMap.insert("EUR", 0.8333);
currencyMap.insert("GBP", 0.5661);
currencyMap.insert("HKD", 7.7562);
currencyMap.insert("JPY", 112.92);
currencyMap.insert("NOK", 6.5200);
currencyMap.insert("NZD", 1.4697);
currencyMap.insert("SEK", 7.8180);
currencyMap.insert("SGD", 1.6901);
currencyMap.insert("USD", 1.0000);
currencyModel.setCurrencyMap(currencyMap);
/*
THIS WORKS!!!
m_rowHeader = tableView.horizontalHeader();
connect(m_rowHeader, SIGNAL(sectionClicked(int)),
&(tableView), SLOT(hideColumn(int)));
*/
tableView.setModel(¤cyModel);
tableView.setAlternatingRowColors(true);
tableView.setWindowTitle(QObject::tr("Currencies"));
tableView.show();
}
void MainWindow::on_sectionClicked(int logicalIndex)
{
qDebug().nospace() << "Column " << logicalIndex << " selected." << "\n";
}
main.cpp
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow mainWin;
return app.exec();
}
The error I get is:
g++ -c -pipe -O2 -Wall -W -D_REENTRANT -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED -I/opt/QtSDK/Desktop/Qt/4.8.1/gcc/mkspecs/default -I. -I/opt/QtSDK/Desktop/Qt/4.8.1/gcc/include/QtCore -I/opt/QtSDK/Desktop/Qt/4.8.1/gcc/include/QtGui -I/opt/QtSDK/Desktop/Qt/4.8.1/gcc/include -I. -I. -o MyTableView.o MyTableView.cpp
MyTableView.cpp: In constructor ‘MyTableView::MyTableView(QWidget*)’:
MyTableView.cpp:11: error: no matching function for call to ‘MyTableView::connect(QHeaderView*&, const char [21], MyTableView* const, const char [17])’
/opt/QtSDK/Desktop/Qt/4.8.1/gcc/include/QtCore/qobject.h:204: note: candidates are: static bool QObject::connect(const QObject*, const char*, const QObject*, const char*, Qt::ConnectionType)
/opt/QtSDK/Desktop/Qt/4.8.1/gcc/include/QtCore/qobject.h:217: note: static bool QObject::connect(const QObject*, const QMetaMethod&, const QObject*, const QMetaMethod&, Qt::ConnectionType)
/opt/QtSDK/Desktop/Qt/4.8.1/gcc/include/QtCore/qobject.h:337: note: bool QObject::connect(const QObject*, const char*, const char*, Qt::ConnectionType) const
make: *** [MyTableView.o] Error 1
This kind of problem is usually caused when you're passing a class that has been forward declared, but not #include
'd
In your case it looks like you probably need a #include <QHeaderView>
in your MyTableView.cpp file.
The issue is that you can pass around pointers to objects that have been forward declared, but the compiler doesn't know that your class is ultimately derived from QObject
, so it isn't allowed to use your subclass pointer as a QObject
pointer when calling the connect()
function.