Issue is resolved. I explained it to myself in the reply below. Maybe it will help someone else too.
Thanks for the feedback. I still had to figure it out for myself, but a few of the supplied links provided new ideas when I looked at them the second (or third) time.
I am running Visual Studio 2013 Express, so to get MOC to work, I had to do manually adjust the command line that built the VS project. In case any other confused person discovers this, I'll just post all my demo code and give myself a thorough explanation.
Misc Note: The following two additional include directories were specified in project properties->Configuration Properties->C/C++->Addition Include Directories:
C:\Qt\4.8.5\include
$(ProjectDir)
C:\Qt\4.8.5\include
$(ProjectDir)
To copy to clipboard, switch view to plain text mode
Explanation:
In order to use SLOT or SIGNAL in Visual Studio without the Qt plugin, such as if you are using VS Express as I am, you need to invoke the MOC system yourself. Examine the header file below for details on how SLOT is used, but SIGNAL, Q_INVOKABLE, and other meta-system tags are used in the same way.
The MOC system will generate .cpp files (they appear to be C-based files, so they may actually be C files that can work without a fuss in a C++ compiler (??is this correct??)), not binary files, so they cannot be linked in later and must be run through the compiler from the beginning. Therefore, the files in need of the meta system tags need to be run through MOC before the rest of the compilation begins.
(1) Right-click your project (NOT the solution) that contains the file that needs the MOC tags (in my case, the project that contained my_TCP_socket.h, shown below), select properties.
(2) Configuration Properties->Custom Build Step->General
(3) Leave "Execute After" blank.
(4) Under "Execute Before", select "PreBuildEvent" from the drop down menu. This tells Visual Studio to attempt to execute the text in "Command Line" before the pre-build event, which is the earliest build phase in the Visual Studio program builder (http://msdn.microsoft.com/en-us/library/e85wte0k.aspx).
(5) In "Command Line", follow this outline: *location of moc executable* *path of file to run through MOC* -o *path of where you want the output file to go (hence the "-o" option)
In my case, this was as follows:
C:\Qt\4.8.5\bin\moc.exe $(ProjectDir)\my_TCP_socket.h -o $(ProjectDir)\tmp\moc_my_TCP_socket.cpp
C:\Qt\4.8.5\bin\moc.exe $(ProjectDir)\my_TCP_socket.h -o $(ProjectDir)\tmp\moc_my_TCP_socket.cpp
To copy to clipboard, switch view to plain text mode
Note: It is necessary to include the MOC-generated .cpp files from a source file. It is generally shenaniganry to #include a source file (.c or .cpp) at all because it will cause "X is already defined" errors if it happens to get included more than once. It is perfectly fine to declare things more than once, but it is not ok to define them more than once. Class method definitions in a header file can get away with it because they are special. Each compilation unit (that is, source file) is compiled once on its own into an object file, along with all the stuff that was dumped into it via #includes, and then all the resulting object files are linked together. If there is a function definition that appears more than once during this linking stage, such as non-class functions generated by MOC that were included in more than one compilation unit, then there will be "X is already defined" errors during linking.
Here is my custom TCP socket class declared in "my_TCP_socket.h":
#pragma once
#include <QtCore\QObject>
#include <QtNetwork\QTcpSocket>
#include <QtCore\QDebug>
// if this header file gets included by more than one source file, then there will be an "X is already defined" error, so it is a very bad plan to include the MOC-generated code here
// Note: The commented out #include was kept in expressly for this comment.
//#include "tmp\moc_my_TCP_socket.cpp"
class my_TCP_socket
: public QObject{
public:
explicit my_TCP_socket
(QObject *parent
= 0);
~my_TCP_socket();
private:
// http://qt-project.org/doc/qt-4.8/qobject.htm#Q_OBJECT
// "The Q_OBJECT macro must appear in the private section of a class definition
// that declares its own signals and slots or that uses other services provided
// by Qt's meta-object system."
Q_OBJECT
// http://qt-project.org/doc/qt-4.8/qobject.html#Q_INVOKABLE
// "Apply this macro to definitions of member functions to allow them to be
// invoked via the meta-object system. The macro is written before the return
// type..."
// Note: This applies to Q_SLOT and Q_SIGNAL as well, even though the
// documentation at the link does not expressly say so (as far as I saw).
Q_SLOT void read_it();
};
#pragma once
#include <QtCore\QObject>
#include <QtNetwork\QTcpSocket>
#include <QtCore\QDebug>
// if this header file gets included by more than one source file, then there will be an "X is already defined" error, so it is a very bad plan to include the MOC-generated code here
// Note: The commented out #include was kept in expressly for this comment.
//#include "tmp\moc_my_TCP_socket.cpp"
class my_TCP_socket : public QObject
{
public:
explicit my_TCP_socket(QObject *parent = 0);
~my_TCP_socket();
private:
// http://qt-project.org/doc/qt-4.8/qobject.htm#Q_OBJECT
// "The Q_OBJECT macro must appear in the private section of a class definition
// that declares its own signals and slots or that uses other services provided
// by Qt's meta-object system."
Q_OBJECT
QTcpSocket *m_socket_ptr;
// http://qt-project.org/doc/qt-4.8/qobject.html#Q_INVOKABLE
// "Apply this macro to definitions of member functions to allow them to be
// invoked via the meta-object system. The macro is written before the return
// type..."
// Note: This applies to Q_SLOT and Q_SIGNAL as well, even though the
// documentation at the link does not expressly say so (as far as I saw).
Q_SLOT void read_it();
};
To copy to clipboard, switch view to plain text mode
Here is my_TCP_socket.cpp:
#include "my_TCP_socket.h"
#include <iostream>
using std::cout;
using std::endl;
#include <QtCore\QMetaMethod>
#include "tmp\moc_my_TCP_socket.cpp"
my_TCP_socket
::my_TCP_socket(QObject *parent
) :{
m_socket_ptr->connectToHost("10.10.10.126", 5);
if (!(m_socket_ptr->waitForConnected(5000)))
{
qDebug() << "Not connected!";
m_socket_ptr = NULL;
}
else
{
qDebug() << "Connected!";
}
// just showing that the file exists
int method_index = this->metaObject()->indexOfMethod("read_it()");
cout << "index of method read_it() is '" << method_index << "'" << endl;
QObject::connect(m_socket_ptr,
SIGNAL(readyRead
()),
this,
SLOT(read_it
()));
}
my_TCP_socket::~my_TCP_socket()
{
if (NULL != m_socket_ptr)
{
m_socket_ptr->close();
}
}
void my_TCP_socket::read_it()
{
//QDataStream in(m_socket_ptr);
if (m_socket_ptr->waitForReadyRead(3000))
{
qint64 bytes_available = m_socket_ptr->bytesAvailable();
if (bytes_available > 0)
{
qDebug() << "Reading '" << bytes_available << "' bytes";
qDebug() << m_socket_ptr->readAll();
//QString in_data;
//in >> in_data;
//qDebug() << in_data;
}
else
{
qDebug() << "no data";
}
}
}
#include "my_TCP_socket.h"
#include <iostream>
using std::cout;
using std::endl;
#include <QtCore\QMetaMethod>
#include "tmp\moc_my_TCP_socket.cpp"
my_TCP_socket::my_TCP_socket(QObject *parent) :
QObject(parent)
{
m_socket_ptr = new QTcpSocket(this);
m_socket_ptr->connectToHost("10.10.10.126", 5);
if (!(m_socket_ptr->waitForConnected(5000)))
{
qDebug() << "Not connected!";
m_socket_ptr = NULL;
}
else
{
qDebug() << "Connected!";
}
// just showing that the file exists
int method_index = this->metaObject()->indexOfMethod("read_it()");
cout << "index of method read_it() is '" << method_index << "'" << endl;
QObject::connect(m_socket_ptr, SIGNAL(readyRead()), this, SLOT(read_it()));
}
my_TCP_socket::~my_TCP_socket()
{
if (NULL != m_socket_ptr)
{
m_socket_ptr->close();
}
}
void my_TCP_socket::read_it()
{
//QDataStream in(m_socket_ptr);
if (m_socket_ptr->waitForReadyRead(3000))
{
qint64 bytes_available = m_socket_ptr->bytesAvailable();
if (bytes_available > 0)
{
qDebug() << "Reading '" << bytes_available << "' bytes";
qDebug() << m_socket_ptr->readAll();
//QString in_data;
//in >> in_data;
//qDebug() << in_data;
}
else
{
qDebug() << "no data";
}
}
}
To copy to clipboard, switch view to plain text mode
Lastly, here is main.cpp:
#include "my_TCP_socket.h"
#include <QtCore/QCoreApplication>
#pragma comment (lib, "C:/Qt/4.8.5/lib/QtCored4.lib")
#pragma comment (lib, "C:/Qt/4.8.5/lib/QtNetworkd4.lib")
int main(int argc, char **argv)
{
int app_ret_val = 0;
my_TCP_socket S;
app_ret_val = app.exec();
return app_ret_val;
}
#include "my_TCP_socket.h"
#include <QtCore/QCoreApplication>
#pragma comment (lib, "C:/Qt/4.8.5/lib/QtCored4.lib")
#pragma comment (lib, "C:/Qt/4.8.5/lib/QtNetworkd4.lib")
int main(int argc, char **argv)
{
int app_ret_val = 0;
QCoreApplication app(argc, argv);
my_TCP_socket S;
app_ret_val = app.exec();
return app_ret_val;
}
To copy to clipboard, switch view to plain text mode
Bookmarks