How-To: Use Qt custom slots & generate Mocs in Visual Studio 2010

A while back I had a play with Qt in Linux and wrote-up how to auto-generate MOCs with a bash script… This time I needed to get Qt working in Visual Studio 2010, on machines which get wiped every time they boot, so I needed a standalone “base-project” with minimal installation requirements for students to work from. So I made one…

Simple Qt Text Editor screenshot

Project Properties

Linked below is a Visual Studio 2010 project which is an incredibly bare-bones text editor in Qt. You can enter text, you can save it (to a fixed filename), and you can quit! That’s it!

But the project does have some redeeming features in that:

  • It’s completely standalone, because it comes with the required Qt headers, libs and dlls to do its thing, and
  • It has a batch file that runs as a pre-build step which auto-generates the MOC files (using an included copy of moc.exe) – meaning you can change any headers in the same location as the main source and it’ll update the MOC(s) for you on build without having to dip into the commandline.

Download: 1-Standalone-Qt-Project.zip

Please note, this download is for Windows 7 64-bit, and it includes the libs/headers/dlls/moc.exe from Qt 4.8.0 (the most recent at time of writing).

If you just want the batch file to autogen the MOCs for you, then the script itself is simply:

@ECHO OFF
FOR %%f IN (*.h) DO moc.exe %%f -o moc_%%~nf.cpp

Place the batch file in the same location as your code, which is generally in the named project folder – so if I had a project called 2-QtTest, my code (and the batch file, and moc.exe) would live in 2-QtTest\2-QtTest. Finally, add executing the batch file as pre-build step like this (or just grab my project and use it as a base):

Visual Studio Qt Moc Prebuild-step settings

Additional

  • If you want a ton of Qt functionality you might need to copy more of the Qt headers into the include folder in the project (if you have the QtSDK installed, you can find these in C:\QtSDK\Desktop\Qt\4.8.0\msvc2010\include). I only put the QtCore and QtGui folders in to keep the project size down.
  • If you get a warning about being unable to delete a temporary file during build (generated by the genQtMoc batch file) – it could well be caused by AVG. For example:
    PreBuildEvent:
      Description: Generating Qt Mocs
    C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppCommon.targets(103,5): warning MSB5018: Failed to delete the temporary file "C:\Users\r3dux\AppData\Local\Temp\547660b1862d4d3491ed0d06e65f4a7a.exec.cmd". The process cannot access the file 'C:\Users\r3dux\AppData\Local\Temp\547660b1862d4d3491ed0d06e65f4a7a.exec.cmd' because it is being used by another process.

    I’ve seen the error once or twice during build, but it’s not consistent – really, it’s just a tempfile being locked – shouldn’t be a concern. AVG finger-pointing source: karmiistha.

Source code after the jump for those who want it…

Main.cpp

// Include QtGui, which pulls in any other Qt related headers which we need.
#include "QtGui\QtGui"
 
// Incude our Notepad.h header so we can create an object of our custom Notepad type!
#include "Notepad.h"
 
// Pull in the main Qt libraries
#pragma comment(lib, "QtMain")  // QtMaind
#pragma comment(lib, "QtCore4") // QtCored4
#pragma comment(lib, "QtGui4")  // QtGui4
 
int main(int argv, char **args)
{
	// Our QApplication instance, called "app"
	QApplication app(argv, args);
 
	// Create the window before you create the elements which
	// go inside the window! (or you'll get odd errors on exit!)
	QWidget window;
 
	// Create a QTextEdit object called textEdit
	Notepad n;
 
	// Create a layout object
	QVBoxLayout layout;
 
	// Add our QTextEdit and QPushButton objects to the layout
	layout.addWidget(&n);
 
	// Actually apply the layout to the window
	window.setLayout(&layout);
 
	// Set the window title
	window.setWindowTitle("Simple Qt Text Editor");
 
	// Display the window
	window.show();
 
	// And finally run the app!
	return app.exec();
}

Notepad.h

#ifndef NOTEPAD_H
#define NOTEPAD_H
 
#include <iostream>
#include <string>
#include <fstream>
 
#include "QtGui\QtGui"
 
class Notepad : public QWidget
{
	// Include the Q_OBJECT macro. All headers are "Moc"-ed by our genQtMoc batch file as a pre-build step
	Q_OBJECT 
 
	public:
		// We'll use our own constructor and destructors
		Notepad();
		~Notepad();
 
	// Each "slot" is a function we can bind to run when we click on a button
	private slots:
		void save(); // A function to save the text editor contents
		void quit(); // A function to quit the program
 
	private:
		QTextEdit   *textEdit;
		QPushButton *saveButton;
		QPushButton *quitButton;
		QVBoxLayout *layout;
};
 
#endif

Notepad.cpp

#include "Notepad.h"
 
Notepad::Notepad()
{
	// Actually create our text editor and buttons
	textEdit   = new QTextEdit;
	saveButton = new QPushButton("Save");
	quitButton = new QPushButton("Quit");
 
	// Connect our buttons to the functions we want to run when they're clicked
	connect( saveButton, SIGNAL( clicked() ), this, SLOT( save() ) );
	connect( quitButton, SIGNAL( clicked() ), this, SLOT( quit() ) );
 
	// Create our layout
	layout = new QVBoxLayout;
 
	// Add the text editor and quit button
	layout->addWidget(textEdit);
	layout->addWidget(saveButton);
	layout->addWidget(quitButton);
 
	// Apply the layout
	setLayout(layout);
}
 
// Destructor
Notepad::~Notepad()
{
	// Return resources taken by items
	delete quitButton;
	delete textEdit;
	delete layout;
}
 
void Notepad::quit()
{
	std::cout << "In quit function!" << endl;
	exit(0);
}
 
void Notepad::save()
{
	std::cout << "In save function!" << std::endl;
 
	// Create a file to write to called Test.txt
	std::ofstream ofs("Test.txt");
 
	// Get the contents of the text field as a QString
	QString qs = textEdit->toPlainText();
 
	std::string stdStringContents = qs.toUtf8().constData();
 
	std::cout << "--------- FILE CONTENTS WILL BE ---------" << std::endl;
	std::cout << stdStringContents << std::endl;
 
	// Convert to a standard string and write to fileConvert the
	ofs << stdStringContents << std::endl;
 
	// Close the file to save it
	ofs.close();
}

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.