标签归档:QT

QVBoxLayout: 如何填充剩下的区域

大部分情况我们希望一个Layout中会放一些QWidget,其中一个QWidget填充剩下的区域,比如下面的代码,要求在一个Layout的顶端放置一个Title Bar、底端放置一个Status Bar、中间放一个填满剩余区域的QWidget:

AliceNetworkMonitor 构造函数:


AliceNetworkMonitor::AliceNetworkMonitor(QWidget* parent)
    : QMainWindow(parent)
{
    // 设置主布局
    m_mainLayout = new(std::nothrow) QVBoxLayout();
    m_mainLayout->setContentsMargins(0, 0, 0, 0);
    m_mainLayout->setSpacing(0);

    // 设置UI
    ui.setupUi(this);
    // Set mainLayout as the root layout
    ui.centralWidget->setObjectName("widget_main_window");
    ui.centralWidget->setLayout(m_mainLayout);

    // 设置windows图标
  setWindowIcon(QIcon(":/AliceNetworkMonitor/Resources/windowicon_alice.png"));  

    // 初始化菜单栏
    initTitleBar();

    // 初始化中间栏
    QHBoxLayout* centerLayout = new(std::nothrow) QHBoxLayout();
    centerLayout->setContentsMargins(0, 0, 0, 0);
    centerLayout->setSpacing(0);
    m_centerWidget = new(std::nothrow)QWidget();
    m_centerWidget->setObjectName("cld_border_widget");
    m_centerWidget->setLayout(centerLayout);

    // 初始化状态栏
    initStatusBar();

    // 添加到mainLayout
    m_mainLayout->addWidget(m_titleBar, 0, Qt::AlignTop);
    m_mainLayout->addWidget(m_centerWidget);
    m_mainLayout->addWidget(m_statusWidget, 0, Qt::AlignBottom);


    retranslateUi();
}

结果会是这个样子的:

预期的 m_centerWidge 并没有填充整个剩下的区域。

改进办法很简单, m_centerWidge 使用QSizePolicy::Expanding就行了:


    m_centerWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

完整代码如下:

AliceNetworkMonitor::AliceNetworkMonitor(QWidget* parent)
    : QMainWindow(parent)
{
    // 设置主布局
    m_mainLayout = new(std::nothrow) QVBoxLayout();
    m_mainLayout->setContentsMargins(0, 0, 0, 0);
    m_mainLayout->setSpacing(0);

    // 设置UI
    ui.setupUi(this);
    // Set mainLayout as the root layout
    ui.centralWidget->setObjectName("widget_main_window");
    ui.centralWidget->setLayout(m_mainLayout);

    // 设置windows图标
  setWindowIcon(QIcon(":/AliceNetworkMonitor/Resources/windowicon_alice.png"));  

    // 初始化菜单栏
    initTitleBar();

    // 初始化中间栏
    QHBoxLayout* centerLayout = new(std::nothrow) QHBoxLayout();
    centerLayout->setContentsMargins(0, 0, 0, 0);
    centerLayout->setSpacing(0);
    m_centerWidget = new(std::nothrow)QWidget();
    m_centerWidget->setObjectName("cld_border_widget");
    m_centerWidget->setLayout(centerLayout);
    m_centerWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);

    // 初始化状态栏
    initStatusBar();

    // 添加到mainLayout
    m_mainLayout->addWidget(m_titleBar, 0, Qt::AlignTop);
    m_mainLayout->addWidget(m_centerWidget);
    m_mainLayout->addWidget(m_statusWidget, 0, Qt::AlignBottom);


    retranslateUi();
}

结果如下:

【转】QT框架中快速应用OpenCV

  和MFC比较起来,QT的信号槽机制比MFC的信号机制慢,但是因为能很好的实现跨平台,所以我在这里总结一下可能对一些人有点用。OpenCV.China论坛上有一个帖子叫做《在MFC框架中快速应用OpenCV》看了后就想结合QT写一下。

0.搭建环境:OpenCV + QT 4.6

我的实验是基于VS2008来做的,QT官方虽然提供了VS2008-add-in的插件,我没有用。直接下载器编译好的库文件进行配置,OpenCV的在VS2008下面的配置方法Google一下到处都是,这里不再补充。首先需要做的是在VS2008里面你需要使QT下和OpenCV的程序能分别跑起来。对于QT在VS的配置其实挺简单,有头文件和相应的链接库,保证调用的时候路径正确,一般就没有问题了。常用命令行make程序的人应该会很清楚那些IDE只不过是层画皮。

1.显示图像

QWidget是QObject下的第一个子类,使用它显示图像会减少不必要的开销。首先定制一个自己需要的QWidget:

class myWidget : public QWidget
{
  Q_OBJECT
  public:
    myWidget(const IplImage *img,QWidget *parent = 0);
    ~myWidget();
  protected:
    void paintEvent(QPaintEvent *e);
  private:
    IplImage* iplImg;
    QImage *qImg;
};
 

需要绘制一个图像,我重载paintEvent(QpaintEvent *e),我在这里面使用QPainter进行绘制。

void myWidget::paintEvent(QPaintEvent *e)
{
    QPainter painter(this);
    painter.drawImage(QPoint(5,5),*qImg);
}
 

drawImage(QPoint(5,5),qImg);的作用是将qImg绘制在左上顶点位于QPoint(5,5)处。

这里面有可能两个问题,第一个问题是要显示的图片太小,创建的Widget太大,最后显示比较丑陋。这时可以在此函数里面获得qImg的宽高,然后resize一下就好了。另外一个问题是:绘制的时候使用的是QImage,不是IplImage类型。关于这个问题论坛上有人专门写了IplImage <-> QImage的转换代码,我在这里不重复那个做法,一是有人已经做了,另外处于效率考虑,这里提供另一种方法。

通常同学们都是用cvLoadImage来读图片,保存在IplImage里面,在这里这个图片我们保存在img里面,然后通过img传进QWidget,然后我new一个QImage

qImg = new QImage(QSize(img->width,img->height),QImage::Format_RGB888);
 

我这里假设iplImg是RGB格式,且每个通道大小为8。然后创建一个IplImage 的文件头

iplImg = cvCreateImageHeader(cvSize(img.width(),img.height()),8,3);
 

此iplImage和QImage的不同之处在于QImage没有直接提供创建文件头的方法,可以通过如下方式创建只有文件头数据的QImage

qImg = new QImage(QSize(0,0),QImage::Format_RGB888);
 

另外两者的图像矩阵像素排列有点不同,比如IplImage中的BGR到了QImage中应该是RGB,当然单通道的灰度图是一样的,值得庆幸的是两者的像素矩阵都是形状相同的多维数组。这样我们可以通过指针共享这部分数据,一种方法如下:

iplImg->imageData = (char*)qImg.bits();
 

将iplImg的图像矩阵指到qImg那里,以后我们只需要对IplImage运用opencv里面的函数进行处理,其实就直接在处理qImg里面的数据了。但是现在的图像数据还在img里面,首先得把数据搞到手,然后放到iplImg和qImg的共享区中去,另外将颜色排列以QImage中的RGB顺序为标准。

if (img->origin == IPL_ORIGIN_TL)
{
	cvCopy(img,iplImg,0);
}
else
{
	cvFlip(img,iplImg,0);
}

cvCvtColor(iplImg,iplImg,CV_BGR2RGB);
 

实际上只要做到这里图片就能显示了。如下图所示

给出myWidget.cpp完整代码

#include "myWidget.h"
#include <QtGui\QPainter>
#include <QtCore\QPoint>

myWidget::myWidget(const IplImage *img,QWidget *parent /* = 0 */) : QWidget(parent)
{

 	qImg = new QImage(QSize(img->width,img->height),
 		QImage::Format_RGB888);
	iplImg = cvCreateImageHeader(cvSize(img->width,img->height),
		8,3);
	iplImg->imageData = (char*)qImg->bits();

	if (img->origin == IPL_ORIGIN_TL)
	{
		cvCopy(img,iplImg,0);
	}
	else
	{
		cvFlip(img,iplImg,0);
	}

	cvCvtColor(iplImg,iplImg,CV_BGR2RGB);

	this->resize(img->width,img->height);

}

myWidget::~myWidget()
{
	cvReleaseImage(&iplImg);
	delete qImg;
}

void myWidget::paintEvent(QPaintEvent *e)
{
	QPainter painter(this);
	painter.drawImage(QPoint(0,0),*qImg);
}

 

调用的代码很简单:

int main(int argc,char* argv[])
{
	QApplication app(argc,argv);

	IplImage *img = cvLoadImage("460.jpg",1);
	if (img)
	{
		myWidget *mw = new myWidget(img);
		mw->show();
	}
	int re = app.exec();
	cvReleaseImage(&img);
	return re;
}
 
 

2.播放视频

有些时候我们需要的是处理视频文件,比如AVI,当然也不过是图像序列。在由于QT运行时的多线程机制导致sleep函数不好使,可以通过其提供的QTimer来控制视频文件的播放。在给出例子之前要罗嗦两句QT的信号/槽机制。MFC里面的消息映射固然很快,但是让一个涉其未深的人阅读起来会觉得很晦涩,QT通过signal/slot机制实现了消息交换。用signal唤起slot,比如点击了button的clicked()事件是一个signal,当这个事件发生之后可以唤起其他的操作,只要你将clicked消息和那个实际操作的槽连接起来了。

opencv里面有函数可以方便的读取视频帧,如果使用Widget播放视频,如何控制帧率是一个很巧妙的地方,我使用一个QTimer控制时间(可以理解为帧率),并周期性的唤起读取视频帧的操作,然后在这个操作里面对widget进行重绘,或者模仿前面的方法,用一个QImage当作共享区域,让用来paintEvent用来显示。

有了上面显示图像的基础,我改一下上面的代码,给出一个例子:

myWidget.h

#ifndef MYWIDGET_H
#define MYWIDGET_H

#include <QtGui\QWidget>
#include <QtGui\QPaintEvent>
#include <QtGui\QImage>
#include <QtCore\QTimer>
#include <cv.h>
#include <highgui.h>
class myWidget : public QWidget
{
	Q_OBJECT
public:
	myWidget(const char *filename,QWidget *parent = 0);
	~myWidget();

protected:
	void paintEvent(QPaintEvent *e);
private slots:
	void nextFrame();
private:
	CvCapture *capture;
	IplImage *iplImg;
	IplImage *frame;
	QImage *qImg;
	QTimer *timer;
};
#endif
 

myWidget.cpp

#include "myWidget.h"
#include <QtGui\QPainter>
#include <QtCore\QPoint>

myWidget::myWidget(const char *filename,QWidget *parent /* = 0 */) : QWidget(parent)
{
	capture = cvCaptureFromFile(filename);
	if (capture)
	{
		frame = cvQueryFrame(capture);
		if (frame)
			this->resize(frame->width,frame->height);

		qImg = new QImage(QSize(frame->width,frame->height),
			QImage::Format_RGB888);
		iplImg = cvCreateImageHeader(cvSize(frame->width,frame->height),
			8,3);
		iplImg->imageData = (char*)qImg->bits();

		timer = new QTimer(this);
		timer->setInterval(30);
		connect(timer,SIGNAL(timeout()),this,SLOT(nextFrame()));
		timer->start();
	}

}

myWidget::~myWidget()
{
	cvReleaseImage(&iplImg);
	cvReleaseCapture(&capture);
	delete qImg;
	delete timer;

}

void myWidget::paintEvent(QPaintEvent *e)
{
	QPainter painter(this);
	painter.drawImage(QPoint(0,0),*qImg);
}

void myWidget::nextFrame()
{
	frame = cvQueryFrame(capture);
	if (frame)
	{

		if (frame->origin == IPL_ORIGIN_TL)
		{
			cvCopy(frame,iplImg,0);
		}
		else
		{
			cvFlip(frame,iplImg,0);
		}

		cvCvtColor(iplImg,iplImg,CV_BGR2RGB);

		this->update();

	}
}
 

主函数里面调用

int main(int argc,char* argv[])
{
	QApplication app(argc,argv);

	char *filename = "test.avi";
	myWidget *mw = new myWidget(filename);
	mw->show();

	int re = app.exec();
	return re;
}
 

由于接不截图都看不出来,所以就不截图。

后一个程序因为涉及到slots,所以添加了一个Q_OBJECT宏,编译之前需要将myWidget.h程序moc一下

比如:

moc myWidget.h –o moc_myWidget.cpp

这样会在目录下生成一个.cpp文件,make的时候加到源文件里一起make,或者编译的时候添加到源文件列表中去。

知道如何使用QT来显示图像和播放视频之后,在上述代码里面插入处理图像的代码就很简单了。显示图像的时候在构造函数里面就可以插入处理代码,当然也可以在paintEvent函数里面进行处理,播放视频的时候可以在nextFrame函数里面进行处理,有些预处理可以在构造函数里面完成。

相比于MFC的代码,QT的代码结构看上去,很明显,更加优美。

 原文:http://bugway.appspot.com/?p=469802

 

 

Qt Visual Studio Add-in: Frequently Asked Questions

Frequently Asked Questions

Why is code completion not working?

You’re implementing a slot…

Visual Studio can only provide code completion as long as it understands the code. Unfortunately, it does not know how to handle the Qt keyword slots in the header file. This means that the respective function body is foreign to the code model and no code completion will be provided. You can workaround the problem be placing a ';' after the colon of the slots keyword in the class declaration.

Note: Remember to remove the ';' when exporting the project as the code might not with older Unix compilers.

 class MyClass {
     Q_OBJECT

 public slots:;
     void doSomething();

   ...
 };

You are referencing objects from a .ui file…

The Visual Studio code model parser only parses C++ sources, meaning that widgets or objects defined in .ui files will not be accessible. To workaround the problem, the Qt Visual Studio Add-in automatically generates C++ code from the .ui file by saving the file and running uic on it. This step is done everytime the project is built. If the code completion does not work, try to rebuild the project. It is possible that you have to wait some time, before code completion fully works after updating an .ui file. For more information, you can refer to the Modifying Project Properties section.

It still does not work…

You should refresh the code model, Intellisense. This is done by opening the solution explorer, invoking the context menu of the project and activating the item Update Intellisense.

 

Qt Visual Studio Add-in: Creating Qt Translation Files for the Project

To add a new translation file to the project, select Qt|Create New Translation File. In the Add Translation dialog, you can choose the language to create a translation file. A suggested file name is provided, and will be created when you click OK. The translation file is placed in the Translation Files folder in Visual Studio’s Solution Explorer. Right-clicking on a translation file displays a menu that allows you to invoke lupdatelrelease, and Qt Linguist.

See the Qt Linguist manual for more information on Qt’s translation tools.

 

Qt Visual Studio Add-in:Managing Resources

Adding new resources to a Qt project is similar to adding resources to a normal C++ project, the main difference being that .qrc files (Qt resource files) are used instead of Windows .rc files. Unlike .rcfiles, .qrc files work on all platforms supported by Qt and are trivial to load from Qt code.

Screenshot of the .qrc editor

To add new resources, you must first create a new .qrc file. To do this, open the Add New Item dialog, select Qt Resource File from the Qt Project Items folder, and click Open. The newly created.qrc file will be displayed in the Qrc Editor, which is part of the Add-in installation.

At this point, the .qrc file only contains a prefix named after the project. You can add resources under that prefix by selecting it and clicking on the Add button on the right hand side. Then click Add File in the context menu. Now the Resource Editor will display a dialog that allows you to add an existing file.

When referring to the resources later on from Qt code, you must prepend the prefix, the file name, and a colon. For example, :/MyProject/print.bmp. Using the context menu, you can rename the predefined prefix or add other prefixes to the .qrc file.

See the Qt Resource System document for more information.

 

Qt Visual Studio Add-in:Adding Form Files to the Project

The Visual Studio Add-in lets you launch Qt Designer simply by double-clicking on a .ui file. See the Qt Designer manual} for more information.

To add a new .ui file to the project, select Project|Add New Item and then select the Qt Widget Form or the Qt Dialog Form template from the Qt Project Items folder.

Normally, you will need to wrap the code generated for the form file into a QWidget subclass to add signals or slots to it. A convenient way to do this is to select Project|Add Class and then selectQt4GuiClass from the Qt4Classes folder. This will create a .ui file, a .h file, and a .cpp file for you.

Creating Form Templates

You can add customized form templates by following these steps:

  • Create a form in the Qt Designer and save the .ui file (e.g. mydialog.ui).
  • Copy mydialog.ui to the uiItems\ directory within the Qt Visual Studio Add-in installation directory.
  • Create an icon file named mydialog.ico. It should have a size of 32×32 pixels.

After the next start of Visual Studio you can add new forms using your custom template.

 

 

Qt Visual Studio Add-in:Managing Projects

Creating New Qt Projects

Once you have installed the add-in, Visual Studio’s New Project dialog will contain a Qt Projects folder with the following project templates:

  1. Qt Application: A simple Qt GUI Application with one form.
  2. Qt Console Application: A basic Qt console application.
  3. Qt Library: A basic Qt-based dynamic library.
  4. Qt4 Designer Plugin: A Qt Designer custom widget plugin.
  5. ActiveQt Server: A simple ActiveX server.

If you have a Qt for Windows CE license, two additional project types are available:

  1. Qt WindowsCE Application: A simple Qt GUI Application for Windows CE with one form.
  2. Qt WindowsCE Library: A basic Qt-based dynamic library for Windows CE.

Each Qt project provides a wizard that allows you to specify the Qt modules required for your project. For some projects, the wizard will also generate a skeleton class that you can use to get started.

If you have used the installer for the binary version of Qt, you are now ready to write Qt code and build your projects. Alternatively, if you have built Qt from source, then you must tell Visual Studio where to find Qt. This step is further explained in the Basic Qt Version Management section.

Modifying Project Properties

Qt related project properties can be modified by opening the Qt Project Settings dialog. To display this dialog, select the respective Qt project in the solution explorer and select Qt|Qt Project Settings.

Screenshot of the property browser when selecting a Qt project

The following Qt project settings can be changed:

Property Description
Version The Qt version to use for this project (see Basic Qt Version Management).
MocDirectory The directory (relative to the project) where the generated moc files are put. This directory must include the $(ConfigurationName) variable, to ensure that the moc files for different configurations (e.g., debug or release) do not collide.
MocOptions Additional command line options for the moc build step.
UicDirectory The directory (relative to the project) where the uic generated header files are put.
RccDirectory The directory (relative to the project) where the rcc generated source files are put.

When a Qt project is created, these properties are initialized to default values based on the last entered information found in the the Qt|Qt Project Settings dialog.

Basic Qt Version Management

The Visual Studio Add-in offers its own simple Qt version management, enabling you to use multiple versions of Qt 4 in parallel, e.g., Qt 4.5.0 and 4.5.1. When you install the add-in, the information about Qt versions is added to the user registry hive. So, another user will have to add a new Qt version since no default version will be set.

To add or remove Qt versions, click Qt|Configure Qt Versions and select the Qt Versions page. Click Add, then enter a name for the Qt version and the path to Qt’s root directory, for example,C:\\Qt\\4.5.0". The first added Qt version is automatically the default version which will be used when creating new projects or importing a project from a .pro file. The default versions for Qt Windows or Windows CE projects can be changed using the combo boxes located under the Qt Builds list.

Screenshot of Qt versions configuration dialog

To specify which Qt version a project should use, select the project node of a Qt project (e.g., “Project1”) in the Solution Explorer, and set its Version property using the Qt Project Settings.

Changing the Qt version for all projects in the solution can be done by invoking the context menu of the solution and activating the Change Solutions’ Qt Version item. You can then select your desired Qt version in the dialog listing all available Qt versions.

Note: When you set a Qt version for the solution, this version becomes the default version if you add new projects to the solution.

Using the Qt Visual Studio Add-in does not require a globally set Qt environment variable. The Add-in will always overwrite the existing global Qt environment variable.

Note: If the build of your Qt projects fails with the error message The following environment variables were not found: $(QTDIR), then the project is probably referencing an invalid Qt build. This can happen after uninstalling an old Qt version. To correct this, change the Qt version of your project to a valid one.

Changing The Target Platform of Your Project

If you are developing on the Windows CE platform, Visual Studio Add-in enables you to switch between Windows and Windows CE easily. It is possible to create a standard Windows project, develop and test your application on your desktop PC, then later convert it into a Qt on Windows CE version.

To switch between platforms choose the appropriate Qt version in the Version property using the property browser, as described above.

Importing and Exporting Projects

Qt and Visual Studio use different file formats to save projects. If you build your application on multiple platforms, you probably already use Qt .pro files with qmake; otherwise, you might use .vcproj files and Visual Studio to build your project, usually convenient for Windows- only development.

Qt’s Visual Studio add-in provides a way to combine both approaches – you do not have to manually maintain .pro files and .vcproj files in parallel. You start by creating a .vcproj file as usual. When you want a qmake .pro file, select Qt|Create Basic .pro File to generate a .pro file where you can store Unix and/or Mac OS X specific settings.

Screenshot of export dialog

If you have multiple Qt projects in one Visual Studio solution, the basic .pro file generator can create a master .pro file of type subdirs that includes all of the projects.

The generated .pro file is not meant to be a complete file, but a simple starting point for porting to other platforms. Having said, these files should be sufficient for compiling the skeleton projects created by the predefined Qt project wizards. The .pro file includes a .pri file.

The .pri file contains the list of source files, header files, .ui files, and .qrc files in the project. To generate the .pri file, select Qt|Export Project to .pri File. Whenever you add or remove a file from the Visual Studio project file, you must regenerate the .pri file to ensure that the application can still be build on other platforms.

Also, ensure that the included .pri file in the .pro file points to the right file. If you saved the .pri file in the suggested path and name, this should be correct.

Developers on platforms other than Windows can add or remove files to the project by editing the .pri file. When this happens, Windows developers must select Qt|Import .pri File to Project to bring the Visual Studio project file in sync with the .pri file.

If your project contains platform-specific source files, these files should be listed in the .pro file so that they are not overwritten by the Visual Studio Add-in.

In summary, a cross-platform Qt project consists of the following files:

  • .vcproj file containing Windows-specific settings and listing the files in the project.
  • .pro file containing Unix and/or Mac OS X specific settings.
  • .pri file (a qmake include file) listing the files in the project.

If you already have a .pro file but not a .vcproj file, select Qt|Open Qt Project File (.pro)… to convert your .pro file to a .vcproj file. Be aware that the generated .vcproj only contains Windows-specific settings. Also, there is no way to convert a .vcproj file back to a .pro file format, apart from the basic .pro mechanism described above.

 

Qt Visual Studio Add-in: Getting Started

In this tutorial, we will create an address book application step-by-step using the Qt Visual Studio Add-in. We will also outline how to make a basic project using one of the project wizards and create a form with Qt Designer. In addition, we will also show you how to convert a Visual Studio project file into a qmake compatible .pro file.

Creating a Skeleton Qt Application

The first step is to create a trivial project. To do so, select the New Project dialog in Visual Studio and click the Qt Projects folder. Then select the Qt Application item and type “AddressBook” in theName field.

When you click OK, a project wizard will appear. This wizard has a page listing Qt modules you can link your project against, followed by a page that enables you to specify the name of a skeleton class that will be generated by the wizard as a starting point. For this Address Book example, we will use the default values.

Now, we have a small working Qt application. Press F5 to try it out. The result is an empty window. You can close it by clicking the X button on the title bar.

Designing the Main Dialog

Next, we will design the application’s main dialog using Qt Designer. See the Qt Designer Manual for more information.

We begin by adding the widgets and setting their properties. These widgets are then put into layouts. The result is shown below.

Screenshot of the AddressBook's main dialog

Adding the Widgets

We launch Qt Designer by double-clicking on the Form Files\addressbook.ui file in Visual Studio’s Solution Explorer.

First, we add the QListWidget. Expand the Item-Based Widgets group in the Widget Box, then click on the List Widget subitem and drag it to the top-left corner of the form. The Property Editor will now display the properties for the QListWidget object. Using this editor, set the ObjectName property to “addressList”.

Next, we insert the Add and Delete buttons. Expand the Buttons group in the Widget Box and drag two Push Buttons to the top-right corner of the form. Rename the buttons to “addButton” and “deleteButton”, and their Text property to “Add” and “Delete”.

Finally, we add two QLabel objects to display the selected item in the list by dragging the Label item from the Display Widgets group onto the form, once for each label.

Rename the first label to “nameLabel” and change its Text property to “<No item selected>”; rename the second label to “emailLabel” and leave its Text property empty.

Try to position the widgets as they appear in the screenshot above.

Adding the Layouts

In order to properly position the widgets and ensure that they resize accordingly when the form is resized, we need to add layouts to the form.

We require a vertical layout for the buttons as well as a spacer to push the buttons to the top of the layout. To add a spacer, drag the Vertical Spacer item from the Spacers group onto the form, located below the push buttons. Then, select the buttons and the spacer (click on each widget while holding Shift) and click Form|Layout Vertically.

The window also needs a layout to manage the positioning of other widgets as well as the button layout. So, we add another layout by selecting the list widget, the two labels and the button layout, and then clicking Form|Layout in a Grid.

Hint: Make sure that the labels are almost as wide as the form; otherwise the grid layout will make them only as wide as the address list.

To preview your form without compiling it, click Form|Preview…. To build and run the application save the form, leave the Qt Designer and press F5 in Visual Studio.

Adding an “Add Address” Dialog

Now that the main dialog is done, we move on to add functionality to our address book application. We would like to have an application that pops up a dialog when the user clicks the Add button. Hence, we require an “Add Address” dialog.

Designing the Dialog

We start by designing the dialog. This time, there is no ready-made .ui file available in the project. So, we select Project|Add Class…|Qt4 Classes|Qt4GuiClass. This will invoke a wizard requesting for a class name. Enter “AddDialog” as the name and “QDialog” as the base class. Then, check the “Multiple Inheritance” checkbox and click on the Finish button.

You will now have an adddialog.ui file in the project’s Form Files folder.

Screenshot of the Add Address Dialog

To set the properties of the dialog, double-click on adddialog.ui to open the form in Qt Designer. Then, click on the form and set its WindowTitle property to “Add Address”. Next, create the following widgets and set their ObjectName and Text properties according to values listed in the table below.

Widget ObjectName Text
QLabel “nameText” “Name:”
QLabel “emailText” “Email:”
QLineEdit “nameEdit” “”
QLineEdit “emailEdit” “”
QPushButton “okButton” “OK”

Now you can layout your widgets. Hint: Use a grid layout for the labels and line edits.

Connecting to the Dialog’s OK Button

We want the OK button to invoke the QDialog::accept() slot, and we do this by clicking on the Edit Signals/Slots toolbar button. You will then enter Qt Designer‘s Signals and Slots Editing Mode.

Click on the OK button and drag the mouse cursor to an empty area of the form and release the mouse button. The Configure Connection dialog will pop up, allowing you to establish a signal-slot connection between the OK button and the form. Connect the button’s clicked() signal to the form’s accept() slot.

Displaying the “Add Address” Dialog from the Application

Once we have completed designing the dialog, we have to invoke it when the user clicks the main dialog’s Add button. To achieve this behavior, we add a slot to the AddressBook class and invoke theAddDialog from this slot.

Forms created using Qt Designer call QMetaObject::connectSlotsByName() to establish connections between signals emitted by the form’s child widgets and slots that follow the naming conventionon_<sender>_<signal>(). To react on clicking the add button you must implement a slot called on_addButton_clicked(). Type in the following lines of code in the slot’s body:

 AddDialog dialog(this);
 dialog.exec();

If we want to connect to another signal, instead of clicked(), we have to add another signal to the AddressBook class. This requires editing both the header file (addressbook.h) and the implementation file (addressbook.cpp).

Next, we include adddialog.h to addressbook.cpp:

 #include "adddialog.h"

Build and run the program now. If you click on the Add button, the Add Address dialog will pop up. If you click on OK, the dialog will disappear.

Adding Items to the List Widget

When the user clicks OK, we would like to add an item to the QListWidget. To do so, modify the code in the on_addButton_clicked() slot to the following:

 AddDialog dialog(this);

 if (dialog.exec()) {
             QString name = dialog.nameEdit->text();
             QString email = dialog.emailEdit->text();

             if (!name.isEmpty() && !email.isEmpty()) {
                     QListWidgetItem *item = new QListWidgetItem(name, ui.addressList);
                     item->setData(Qt::UserRole, email);
                     ui.addressList->setCurrentItem(item);
             }
     }

We execute the dialog. If the dialog is accepted, e.g., OK is clicked, we extract the Name an Email fields and create a QListWidgetItem with the given information.

Try out the application. Click Add, enter “John Doe” for the name and “john@johndoe.de” for the email. Click OK. The list widget should now contain the new item.

Displaying the Selected Item

When the user selects an item in the list widget, we would like to update the nameLabel and emailLabel at the bottom of the form. This behavior requires another slot to be added to the AddressBookclass.

In the addressbook.h file, add the following code in the private slots section of the class:

 void on_addressList_currentItemChanged();

Then, add the block of code below to addressbook.cpp:

 void AddressBook::on_addressList_currentItemChanged()
 {
     QListWidgetItem *curItem = ui.addressList->currentItem();

         if (curItem) {
                 ui.nameLabel->setText("Name: " + curItem->text());
                 ui.emailLabel->setText("Email: " +
                     curItem->data(Qt::UserRole).toString());
         } else {
                 ui.nameLabel->setText("<No item selected>");
                 ui.emailLabel->clear();
         }
 }

Thanks to the naming convention, this slot will automatically be connected to addressList‘s currentItemChanged() signal, and will be invoked whenever the selected item in the list changes.

Adding Functionality for the Delete Button

Similar to the Add button, we implement a slot for the Delete button. Open the addressbook.h file and add a new slot declaration on_deleteButton_clicked(). Then open addressbook.cpp and add the slot definition for on_deleteButton_clicked(). Type the following code in the slot’s boy:

 QListWidgetItem *curItem = ui.addressList->currentItem();

     if (curItem) {
             int row = ui.addressList->row(curItem);
             ui.addressList->takeItem(row);
             delete curItem;

             if (ui.addressList->count() > 0)
                     ui.addressList->setCurrentRow(0);
             else
                     on_addressList_currentItemChanged();
     }

Your application is now complete!

Creating Qt Project File

If you want to build this application on other platforms, you need to create a .pro file for the project. A simple way to do this is to let the Visual Studio Add-in create a basic .pro file for you by clickingQt|Create Basic .pro File. When the Export Project dialog shows up, ensure that the Create .pri File option is checked, then click OK. Visual Studio will then ask you where to save the .pri file. The default location and name is usually sufficient, so just click Save. For more information about .pro files and their associated .pri files, see Managing Projects.

That’s it! You should now have a working .pro file and .pri file for your project. For more complex projects, manually editing the .pro file is required to make it work on all plaforms; however, for our simple project the generated .pro file is sufficient.