Pages

Connections between a line edit and a push button

I'm designing a simple window with the Qt Designer embedded in Qt Creator.

I have a QLineEdit and a QPushButton.

The push button should be initially disabled, and should get enabled if and only if at least a character is in the input line.

Clicking the push button should result in a slot execution, to do something with the text the user has input in the line edit.

When the focus is in the input line and the user enters the enter key, the slot for click on push button should be executed.

It's quite easy to do that visually.

I change the property "enabled" of the push button, setting it to false (check box unchecked).

I right click on the line edit, and select the menu item "go to slot". I want to react to the change on the text, so I select the signal textChanged(QString). I'm sent to the code of the slot, automatically created by the IDE, and I add a line of code, like this:

void MainWindow::on_lineEdit_textChanged(QString text)
{
ui->pushButton->setEnabled(text.size() == 0 ? false : true);
}

That means the button is enabled only if the text is not empty. As required.

Now I want to specify what happens when the user clicks on the push button. So I right click on the button, menu item "go to slot" and the signal is clicked(). And then I have to modify this generated function:

void MainWindow::on_pushButton_clicked()
{
// ...
}

Now I want to create an association between a line edit signal, the returnPressed() one that is called when the return key is pressed by the user, and a push button slot, the click() one that react at the user push.
So I go to the tabbed widget on bottom of the creator window, "Signals & Slots Editor" tab, I click on the green plus and I generate the connection:
Sender is lineEdit, Signal is returnPressed(), Receiver is pushButton, Slot is click().

This relation is saved in the xml for the ui, and recompiling we'll have the compiler generating the connection for us.

Go to the full post

for_each and functors

For some reasons, I had to write a test function to measure if the distribution of the rand() function is "flat" enough. The requirement for the test is that a number (ITERATIONS) of values have to be generated in the interval [0, ELEMENTS) and that we should ensure that all the possible elements are generated a number of times in a given interval (EXP_MIN, EXP_MAX).

The test function should return a boolean stating if it succeeded or failed, and a short message should be put on the standard console output in case a generated value is external to the expected interval, stating the value under or over represented, and the actual number of elements generated.

The idea is to use a vector of ELEMENTS elements, initialized to 0, then increasing the specific item when such a value is generated by rand(). Then using a functor to evaluate if the condition is respected for each element in the vector.

Here is the code for the functor:
class ValueTester
{
private:
bool success_;
int index_;

public:
ValueTester() : success_(true), index_(0) {}
bool succeeded() { return success_; }

void operator()(int value)
{
if(value < EXP_MIN || value > EXP_MAX)
{
success_ = false;
cout << "Bad random value [" << index_ << " = " << value << ']' << endl;
}

++index_;
};
};

The class should look quite intuitive. The constructor set its initial status, the operator() gets the value for the current element and check it. The member value index_ keeps track of the current iteration on the functor so, in case of error, we can display this information with the unexpected value to the user.

The test function is this one:
bool TestRand::testValue()
{
std::vector<int> vec(ELEMENTS, 0);

for(int i = 0; i < ITERATIONS; ++i)
{
int value = static_cast<int>((static_cast<double>(rand())/(RAND_MAX + 1)) * ELEMENTS); // 1.
++vec[value];
}
return for_each(vec.begin(), vec.end(), ValueTester()).succeeded(); // 2.
}

And maybe it requires a bit more of discussion.
1. rand() generates a pseudo-random number in the interval [0, RAND_MAX], casting it do double and dividing it by RAND_MAX + 1, we ensure we have a number in [0, 1). We multiply this for ELEMENTS and cast the result to integer, to get our value in [0, ELEMENTS).
Then we use this value as index in our vector, and increase the associated element.
2. In this compact line we instantiate an object of our functor, and use it in a for_each that works on all the elements in our vector; the for_each function returns the functor used internally, so we call on it the succeeded() function that returns its status, and return it to the caller.

Notice that for_each makes a copy of the third parameter, do not accept it by reference. That means it is not a good idea to make to write the last line of testValue() in this more explicit (but wrong) way:
ValueTester vt;
for_each(vec.begin(), vec.end(), vt);
return vt.succeeded(); // ERROR: this is always true!

The ValueTester object used internally by for_each is a copy of vt, the original vt is not modified by the for_each's execution so, in this doomed version, the caller would never be acknowledged of a failure - even though the user could see with his eyes the log for the failing elements.

Go to the full post

A good QMainWindow example

I found useful to understand how to work programmatically with QMainWindow the example "Application" provided by the official Qt documentation (doc/html/mainwindows-application.html).

It is a simple application, built around the QPlainTextEdit, a QtGui widget very similar to QTextEdit, but specifically aimed at the plain text management.

The project consists of a handful of files: mainwindow.h and .cpp for the QMainWindow subclass; main.cpp for the C++ main; application.qrc, a file containing the resource associated to the project: half a dozen images used for the buttons in the toolbar.

The application is so simple that misses a few useful standard features, but other examples are provided for them.

I suggest you to get the code, compile it, and get familiar with it, playing a bit around with it.

Let's have a close look at the code.

As we said, almost all the code in the application is in the MainWindow class, the QMainWindow subclass.

Its constructor create the QPlainTextEdit widget, stores it in the member textEdit and assigns it to the window central widget:

textEdit = new QPlainTextEdit();
setCentralWidget(textEdit);

Then calls a bunch of setup functions (more about them later), and makes an interesting connection:

connect(textEdit->document(), SIGNAL(contentsChanged()),
this, SLOT(documentWasModified()));

After this call, the signal contentsChanged() of the textEdit document is connected with the documentWasModified() slot of WinMain.

That means that any time the text is changed in the document available to the user, a call to documentWasModified() is performed:

void WinMain::documentWasModified()
{
setWindowModified(textEdit->document()->isModified());
}

In this way we keep the local windowModified flag aligned with the modified flag for the document. And this is going to reflect in the window title, where a star will be put (for Windows) near the file name when the window is marked as modified.

Then we call setCurrentFile() passing an empty string. If we have a look at this function we find out that:

void WinMain::setCurrentFile(const QString &fileName)
{
curFile = fileName; // 1.
textEdit->document()->setModified(false);
setWindowModified(false);

QString shownName = curFile; // 2.
if (curFile.isEmpty())
shownName = "untitled.txt";
setWindowFilePath(shownName);
}

1. the passed filename, in this case the empty string, is stored in the data member curFile, then the modify flag is set to false for both the document and the window.
2. the windows name is changed to show the name of the current file - in case of a new file (like here, in the constructor) a default name is showed instead.

Last line in the constructor, we call a specific method for Mac, setUnifiedTitleAndToolBarOnMac(), I didn't check what it is about, since I'm working on a windows machine.

Let see now the four setup function called by the constructor.

createActions(): as we can imaging from its name, it is about creating the actions associated with the menu items.

The first action is newAct, used to create a new file, and this is the related code:

newAct = new QAction(QIcon(":/images/new.png"), "&New", this); // 1.
newAct->setShortcuts(QKeySequence::New);
newAct->setStatusTip("Create a new file");
connect(newAct, SIGNAL(triggered()), this, SLOT(newFile())); // 2.

1. we create the action, passing an icon file name, the name of the action as showed to the user, and the owner of the action, responsible for its deletion. Notice that the icon file name starts with a colon (:) that means it is a resource path. We'll talk about it later.
2. through this connection, when the action is triggered, the relative function is executed. In this case the slot is newFile()

The rest of the code of createActions() is, more or less, all the same. There's a variation just at its end:

cutAct->setEnabled(false);
copyAct->setEnabled(false);
connect(textEdit, SIGNAL(copyAvailable(bool)), cutAct, SLOT(setEnabled(bool)));
connect(textEdit, SIGNAL(copyAvailable(bool)), copyAct, SLOT(setEnabled(bool)));

A couple of actions are marked as disabled - and this would reflect on the button associated to these actions, being showed as grayed.
Moreover the signal copyAvailable(bool) for the textEdit is connected with the slot setEnabled(bool) for both the action cut and copy. That means that these to actions will be active only when the text has some available for the copy.

createMenus(): it uses the actions created in createActions() to create the menu for the main window.

The structure is fairly easy, let's have a look a the first two lines of this function:

fileMenu = menuBar()->addMenu("&File");
fileMenu->addAction(newAct);

After creating a menu, delegating the job to the menu bar, we add an action that is displayed as an item in the menu.

createToolBars(): it's quite easy to add tool bars to a window, using the addToolBar() window method.

Here is the first two lines of this function, where we see how to create a tool bar, and how to add an action to it:

fileToolBar = addToolBar("File");
fileToolBar->addAction(newAct);


createStatusBar(): in a window, the status bar is always there, the fact is it is not showed. So creating it it's just a matter of displaying test in it, and that is what if done in this mono-line function:

statusBar()->showMessage("Ready");

Actually, if we had nothing to display, and we would just want to show the empty status bar, we could have call clearMessage().

Usually an application has a few values that we want to persist. And that is done here by the to functions readSettings() and writeSettings().

Another interesting point, is how to connect the application to a resource file. This is done in the main file for the application, with this line:
Q_INIT_RESOURCE(application);

That look for the application.qrc file. We should also put the qrc file name in the qt project (.pro) file, in the resources section.

Go to the full post

A simple QMainWindow subclass

In Qt's world, an application main window is a class derived from QMainWindow. I reckon it is usually better to create it through Qt Designer, since even a minimal main window should provide a number of widgets, and it is not much fun take care programmatically of all the details.

In any case, it is possible to do it just using C++, and we are about to show it now, creating a very rough main window.

Here is the include file:

#ifndef WINMAIN_H
#define WINMAIN_H

#include <QMainWindow>

class QCloseEvent;

class WinMain : public QMainWindow
{
Q_OBJECT
public:
explicit WinMain(QWidget* parent = 0);

private:
void closeEvent(QCloseEvent* event); // 1.
bool okToContinue(); // 2.
};
#endif // WINMAIN_H

1. this virtual function defined in QMainWindow allows us to say a last word before the application close. Here we'll just ask the user if he really wants to leave.
2. here we'll display a message box asking the required confirmation.

Let's see the implementation:

#include "WinMain.h"
#include <QtGui/QtGui>

WinMain::WinMain(QWidget* parent) : QMainWindow(parent)
{
setWindowTitle("My Title");
}

void WinMain::closeEvent(QCloseEvent* event) // 1.
{
if(okToContinue())
event->accept();
else
event->ignore();
}

bool WinMain::okToContinue()
{ // 2.
int res = QMessageBox::warning(this, windowTitle(), "Are you pretty sure?",
QMessageBox::Yes | QMessageBox::No);
if(res == QMessageBox::No)
return false;
return true;
}

1. the point of closeEvent() is that we can set the "accepted" member of the passed event to false, that is, we can signal that we don't actually want the closing of the application to be performed. To do that we call the ignore() method on the event itself. It is not strictly a necessity to call accept() otherwise, since by default an event is accepted.
2. we create a warning message box owned by this window, with as title the same one of this window, asking a confirmation, and offering two options: yes or no.

The main is:

#include <QApplication>
#include "WinMain.h"

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

WinMain wm;
wm.show();

return app.exec();
}


I wrote this post while reading "C++ GUI Programming with Qt 4, Second Edition" by Jasmin Blanchette and Mark Summerfield.

Go to the full post

Connecting widget

In the paragraph Shape-Changing Dialogs, in chapter 2 of their book, Jasmin and Mark provide us an example a bit complicated and too boring to be reported here how to create a dialog that change its own size.

It's that kind of dialogs that have a mandatory part and an optional one. Usually only the first part is shown but, if we gently ask, we can have a look also at the second one.

The example is about a dialog for inputting the parameter for sorting our data. Only a primary key is mandatory, but we can set also a secondary and even a tertiary key.

The most interesting part of the example is where we connect widgets in the dialog. It's quite immediate to do that in Qt Designer. It's enough to click on the F4 key and we are ready to estabilish connections.

In past examples we have programmatically created the connection between the OK/Cancel buttons to the dialog accept() / dialog() slots. Actually we can do that also visually.

We click on a button an drag the generated line to the dialog background. When we leave it, the Designer knows we want to create a connection from the button to the dialog, now it needs to know from which signal to which slot. That what it asks us.

In this case we connect the clicked() slot from the button to the accept() or reject() slot of the dialog.

In a similar way we can do to make disappear a widget. We simply connect a checkable button (I mean, a button with the checkable property set) to the widget, and specify that the signal/slot relation is done by the button toggle() and widget setVisible().

I wrote this post as homework while reading "C++ GUI Programming with Qt 4, Second Edition" by Jasmin Blanchette and Mark Summerfield.

Go to the full post

Button Box

Different platforms have different conventions. This is true also for positioning OK and Cancel buttons. Luckly we can let to Qt to take care about this, that's the rason t'etre of the Button Box.

The disvantage of Button Box is that we can't set the buttons properties in the Designer, we have to do that programmatically.

We copy DlgGoToCell.ui to DlgGoToCell2.ui and modify the last one, removing buttons and spacer, and putting in a Button Box.

We recompile, so qmake could create ui_DlgGoToCell2.h that we will use instead. Then we modify the DlgGoToCell class. In the include file we refer to ui_DlgGoToCell2.h instead of ui_DlgGoToCell.h, and the class DlgGoToCell would extends QDialog, as before, but Ui::DlgGoToCell2 instead of Ui::DlgGoToCell.

The code of the constructor change in this way:

DlgGoToCell::DlgGoToCell(QWidget *parent) : QDialog(parent)
{
setupUi(this);
buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); // 1.

QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}");
where->setValidator(new QRegExpValidator(regExp, this));

connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept())); // 2.
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
}

1. we have to disable the button programmatically, as we said before
2. the button box provides the accepted() / rejected() signals that we use for connection to accept() / reject()

We have to change also on_where_textChanged(), to refer to the button box:

void DlgGoToCell::on_where_textChanged()
{
buttonBox->button(QDialogButtonBox::Ok)->
setEnabled(where->hasAcceptableInput());

}


I wrote this post as homework while reading "C++ GUI Programming with Qt 4, Second Edition" by Jasmin Blanchette and Mark Summerfield.

Go to the full post

From Qt Designer to Qt Creator

In the previous post we designed a custom dialog using Qt Designer, now we complete it using Qt Creator.

We had saved our dialog as DlgGoToCell.ui in the source folder of the project that we have previously created with Qt Creator, now we add it (as an existing file) to the project. Creator will put it in a specific "Forms" folder. Now it could be modified directly from Creator visually - through an embedded version of the Designer.

We immediately use this chance, since I forgot to do something: the OK button should be by default disabled. So, now we edit - visually - DlgGoToCell.ui to do this: after selecting the OK button, find among the property "enabled" and remove the tick from its check box. We see that now the OK button is showed grayed.

It is important to notice that, from the C++ point of view, what we have created with Qt Designer is not related in any way to QDialog, even after the conversion operated by qmake we have a class, Ui::DlgGoToCell, that is not part of the Qt class hierarchy.

What we are going to do, is to use what we have done to set the user interface of a standard QDialog. Something like that:

#include <QApplication>
#include <QDialog>

#include "ui_DlgGoToCell.h" // 1.

int b202(int argc, char** argv)
{
QApplication app(argc, argv);

Ui::DlgGoToCell ui; // 2.
QDialog* dialog = new QDialog();
ui.setupUi(dialog); // 3.
dialog->show();

return app.exec();
}

1. this is the file generated by qmake from DlgGoToCell.ui, basically a conversion from XML to C++ of what we had written.
2. that is the class containing the information of our dialog design.
3. in this way we create a connection between the UI and the QDialog.

That should work fine, but we want to add more meat to our dialog. To do that we use multiple inheritance to create a class that derives from both QDialog and Ui::DlgGoToCell, and add to it our required functionality:
  • the user can OK only after entering a valid cell address
  • we want to accept as valid cell address a letter (lower or uppercase) and a number in the range [1..999].
  • clicking on the buttons should work as expected (close the window and pass the status to the caller)

Here is the code for the include file:

#ifndef DLGGOTOCELL_H
#define DLGGOTOCELL_H

#include <QDialog>
#include "ui_DlgGoToCell.h"

class DlgGoToCell : public QDialog, public Ui::DlgGoToCell
{
Q_OBJECT
public:
explicit DlgGoToCell(QWidget* parent = 0);

private slots:
void on_where_textChanged(); // 1.
};

#endif // DLGGOTOCELL_H

// 1. why we create a function with such a name? Because we want to use a Qt functionality that generates signal-slot connection implicitly, if we use the correct names. In this case we are asking that this slot would be connected to the signal textChanged() for the member named "where".

And here is the implementation:

#include
#include "DlgGoToCell.h"

DlgGoToCell::DlgGoToCell(QWidget *parent) : QDialog(parent)
{
setupUi(this); // 1.

QRegExp regExp("[A-Za-z][1-9][0-9]{0,2}"); // 2.
where->setValidator(new QRegExpValidator(regExp, this));

connect(btnOK, SIGNAL(clicked()), this, SLOT(accept())); // 3.
connect(btnCancel, SIGNAL(clicked()), this, SLOT(reject()));
}

void DlgGoToCell::on_where_textChanged() // 4.
{
btnOK->setEnabled(where->hasAcceptableInput());
}

1. this call initialize the form and create the connection required for our on_where_textChanged()
2. that is the regular expression that satisfy our requirement on the input validation. We use it to create a QRegExpValidator that we'll pass to our line edit through the setValidator() method. Passing this to the QRegExpValidator constructor we ensure that the object will be removed when the dialog will be destroyed.
3. the connections between the clicked() signals of the buttons and the QDialog slot accept() and reject() make our buttons act as expected, closing the dialog and returning to the caller the expected status.
4. that's the slot that would be called for the signal textChanged() our line edit. It sets the button OK as enabled only if where has a valid string in it.

Now we have to rewrite the main, to use our new class:

#include <QApplication>
#include "DlgGoToCell.h"

int b202b(int argc, char** argv)
{
QApplication app(argc, argv);

DlgGoToCell* dialog = new DlgGoToCell();
dialog->show();

return app.exec();
}


I wrote this post as homework while reading "C++ GUI Programming with Qt 4, Second Edition" by Jasmin Blanchette and Mark Summerfield.

Go to the full post

A Dialog with Qt Designer

As we have seen in the previous post, to create a dialog we should go through these steps:
  1. create (and initialize) the contained widgets.
  2. organize the widgets in layouts.
  3. optionally set the tab order.
  4. set the signal-slot connections.
  5. implements the dialog custom slots, where provided.

We have done that programmatically, but we can do the same also using a visual tool, Qt Designer.

In this post we are about to create a dialog to get from the user a cell location, information that will be used from to application to move the current cell selection to the provided one. We need just a label-line edit pair and the usual ok-cancel buttons.

To do that, instead of Qt Creator we'll use Qt Designer. That means, we run designer.exe, found in our Qt bin directory. As we open the application a simple wizard is showed (until you decide to turn it off for good). Among the options there is what looks exactely what we are looking for: a dialog with buttons on the bottom. But let's so it by hand, and just start with a dialog without buttons.

The first step is just a matter of drag and drop from the panel Widget Box.

We put on the top of our dialog the label and line edit pair:
From the section "Display Widget" we grab a Label and put it in our dialog.
From "Input Widget" a Line Edit.

Then on the bottom the buttons. But on the left we put want to leave an empty space, so we put:
From section "Spacer" a Horizontal Spacer.
From "Buttons" two Push Buttons.

It's not worthy to spend much time in organizing the widget, since we'll use layout managers to do the job. But we should do some property setting for all our widgets.

Notice that we can access all available objects in the window through the Object Inspector window, and all the properties of any object through the Property Editor window.

Label: double clicking on it we can change the text property, setting it to "&Cell location", then we set its buddy to "where".

Line Edit: we set its objectName to "where".

First button: set its text to "OK" and its objectName to btnOK.
Second button: set its text to "Cancel" and its objectName to btnCancel.

Dialog: set its objectName to DlgGoToCell and its windowTitle to "Go To Cell".

Now the second step, we think about the layout.

We select both the label and the line edit and specify Lay Out Horizontally for them.

We select spacer and buttons and specify Lay Out Horizontally for them.

Click on the dialog background, to work on the dialog object, and click on Lay Out Vertically.

And that's it. We could now resize the window to specify our preferred size for it.

To have a preview of our job we can use the shortcut Ctrl-R, or call the menu item Form-Preview.

For the third step we click on the menu item Edit-Edit Tab Order. We see the numbers identifying it, and we can change it. We shouldn't have anything to modify in this case, but we could play around a bit with this feature. When we are done, F3 will bring us back to the "normal" edit state.

We are ready to save our dialog. Let's call it DlgGoToCell.ui and put it in the source folder of our project.

And that's it for this post. In the next one we are going to complete the functionality of this dialog using Qt Creator.

I wrote this post as homework while reading "C++ GUI Programming with Qt 4, Second Edition" by Jasmin Blanchette and Mark Summerfield.

Go to the full post

A QDialog subclass

Something more interesting in this post: we are about to create a dialog in a completely programmatic way.

What we should do is extending the Qt class named QDialog that provides the standard implementation for a dialog. In our dialog we what to show the user a line edit (aka: input line) with a relative label that shows what he should input there, a couple of check boxes to specify some options, a couple of button to act or cancel the action.

Given that, we see that the class definition is quite strightforward, the only nuisance here is that Qt uses a few pseudo-keyword to implement some basic Qt concepts. The easier thing is having a look at the code and figure out what is the sense ot it.

So, here is our new class, a dialog that allow the user to pass a few parameters required by the application to perform a search:

#include <QtGui/QDialog>

class QCheckBox;
class QLabel;
class QLineEdit;
class QPushButton;

class DlgFind : public QDialog
{
Q_OBJECT // 1.

public:
DlgFind(QWidget* parent = 0); // 2.

signals: // 3.
void findNext(const QString& str, Qt::CaseSensitivity cs);
void findPrev(const QString& str, Qt::CaseSensitivity cs);

private slots: // 4.
void findClicked();
void enableBtnFind(const QString& text);

private:
QHBoxLayout* createLayout(); // 5.

QLabel* label;
QLineEdit* what;
QCheckBox* cbCase;
QCheckBox* cbBack;
QPushButton* btnFind;
QPushButton* btnClose;
};

1. this macro is required by all the classes having signals or slots.
2. we could pass to the dialog constructor the pointer to another widget that will be considered as the parent. By default, no parent is assumed.
3. "signals" is a Qt macro, and it is used to identify the messages emitted by the dialog.
4. "slots" is another Qt macro, used to identify the member functions of this class that could be called in connection with the call to another function (that acts as a signal).
5. utility function to create the dialog layout. Not stricly a necessity, but I feel that it makes the code a bit clearer.

Let's have now a look at the code implementation for this class. Here is the complete source file, some notes follow:

#include <QtGui/QtGui> // 1.
#include "DlgFind.h"

DlgFind::DlgFind(QWidget* parent) : QDialog(parent)
{
label = new QLabel("Find &what:"); // 2.
what = new QLineEdit();
label->setBuddy(what); // 3.

cbCase = new QCheckBox("Match &case");
cbBack = new QCheckBox("Search &backward");

btnFind = new QPushButton("&Find"); // 4.
btnFind->setDefault(true);
btnFind->setEnabled(false);

btnClose = new QPushButton("Close");

// 5.
connect(what, SIGNAL(textChanged(const QString&)), this, SLOT(enableBtnFind(const QString&)));
connect(btnFind, SIGNAL(clicked()), this, SLOT(findClicked()));
connect(btnClose, SIGNAL(clicked()), this, SLOT(close()));

setLayout(createLayout());
setWindowTitle("Find");
setFixedHeight(sizeHint().height()); // 6.
}

QHBoxLayout* DlgFind::createLayout() // 7.
{
QHBoxLayout* topLeft = new QHBoxLayout();
topLeft->addWidget(label);
topLeft->addWidget(what);

QVBoxLayout* left = new QVBoxLayout();
left->addLayout(topLeft);
left->addWidget(cbCase);
left->addWidget(cbBack);

QVBoxLayout* right = new QVBoxLayout();
right->addWidget(btnFind);
right->addWidget(btnClose);
right->addStretch();

QHBoxLayout* main = new QHBoxLayout();
main->addLayout(left);
main->addLayout(right);

return main;
}

void DlgFind::findClicked() // 8.
{
QString text = what->text();
Qt::CaseSensitivity cs = cbCase->isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive;
if(cbBack->isChecked())
{
emit findPrev(text, cs);
}
else
{
emit findNext(text, cs);
}
}

void DlgFind::enableBtnFind(const QString& text) // 9.
{
btnFind->setEnabled(!text.isEmpty());
}

1. actually, this include is just laziness. It means "include any Qt core and GUI components", and usually this is a bit of overkilling.
2. Jasmin & Mark suggest that it is a good habit to use the function tr() for marking the strings that have to be translated. But I am quite sure I don't want to internationalize this application. Notice the ampersand to specify which letter is shortcut for the widget.
3. the label has a shortcut, the line edit is a buddy of the label so, when we press the key for the label we get in focus its buddy.
4. the Find button is the default one (selected when we press enter) and initially disable - so we can't give the order to find something before we specify what we want to find.
5. a delicate spot in the class: here we connect signals and slots. When textChanged() is called on what, we want enableBtnFind() to be called on this. When btnFind is clicked, findClicked() on this. And when btnClose is clicked we want to close the dialog.
6. our dialog has fixed height, but variable width. You can have (a limited) fun resizing it.
7. the idea of the layout for this dialog having a first box, topLeft, horizontally organized for the label and the line; a second box, left, that contains vertically the first one and the two check boxes; a third, right, for the buttons and a space to fill the gap, again vertically; and finally a big box in which we put left and right horizontally side by side. Quite boring to do this programmatically, isn't it? Luckly this is not the only way to do it.
8. that's the slot we call when the user click on the Find button. He could click it only if he has already put something in the line edit, so just have to check the other options the user has specified using the check boxes and emit the relative signal. Notice that currently there is no definition for our signals, so what happens is just nothing.
9. and this is the slot for the changes in the text of our line edit. We check the text passed and we enable or disable the button accordingly.

A good thing about using Qt Creator is that we can just compile this stuff and run it. If we are using another IDE that doesn't know enough about Qt we need an intermediate step before we can see the result of our job, since there is a bit of code that Qt should generate to manage all this signal-slot business and it is put in a "moc" file. So, that file has to be generated and added to the makefile for the project. If your IDE doesn't do that for you directly you should help it running by hand qmake. Otherwise you get some error like "unresolved external symbol" (for VC++) for a qt_metacall() guy.

I wrote this post as homework while reading "C++ GUI Programming with Qt 4, Second Edition" by Jasmin Blanchette and Mark Summerfield.

Go to the full post

Qt 4.7 and Qt Creator

Qt 4.6 doesn't work well with VC++ 2010. So I decided to install 4.7 (currently still in beta).

If you want to do that too, I suggest to have a look on what Chad Liu says on nabble.com. I found his post very useful.

Actually, the Chad's post is about installing CGAL, but that requires Qt 4.7, so I just skipped all but the relevant part - that is, point 5.

All worked fine and smoothly, with only a minor glitch: at 5.3 Chad forgot to nominate the name of the file to edit, Structure.cpp, but was easy to find it out.

In any case, till the binary for VC++ 2010 won't be available, be aware that you need to have some time available for the job.

After that, I've also downloaded Qt Creator and I started using it. Cool. I suggest you to try it too.

Go to the full post

Layout and widget synchronization

Another couple of Qt features and some widgets in this post.

We see how to use QHBoxLayout to nicely put the contained widgets in an horizontal box; how to set the title in a window; we get acquainted with the spin box and the slider widget, and we see how to connect them, so that changing the value of one automatically result in the adjustment of the value of the other.

All this stuff in such a short example:

#include <QtGui/QApplication>
#include <QtGui/QHBoxLayout>
#include <QtGui/QSlider>
#include <QtGui/QSpinBox>

namespace
{
const int MIN_AGE = 0;
const int MAX_AGE = 130;
const int DEF_AGE = 35;
}

int b103(int argc, char** argv)
{
QApplication app(argc, argv);

QSpinBox* sb = new QSpinBox(); // 1.
sb->setRange(MIN_AGE, MAX_AGE);

QSlider* sl = new QSlider(Qt::Horizontal); // 2.
sl->setRange(MIN_AGE, MAX_AGE);

QObject::connect(sb, SIGNAL(valueChanged(int)), sl, SLOT(setValue(int))); // 3.
QObject::connect(sl, SIGNAL(valueChanged(int)), sb, SLOT(setValue(int)));

// spin box and slider now are connected
sb->setValue(DEF_AGE); // 4.

QHBoxLayout* layout = new QHBoxLayout(); // 5.
layout->addWidget(sb);
layout->addWidget(sl);

QWidget* w = new QWidget(); // 6.
w->setWindowTitle("Enter Your Age");
w->setLayout(layout);
w->show();

return app.exec();
}

1. create and then specify a range for a spinbox widget.
2. create a (horizontal) slider and then specify its range.
3. the connection between two widgets is not different to the connection between a widget an the application. We just specify the object and the method for the emitting widget and then the object and method for the receiving one.
4. now that our two widget are connected we can set a default value for one of them relying on the signal-slot mechanism to let the other being consequentely adjusted.
5. we create a horizontal box and put in it our two widgets.
6. the widget w is the main (and only) window of our application, we set its title calling the setWindowTitle() method, then we set its layout using the one we have just created, and show the result to the user.

I wrote this post as homework while reading "C++ GUI Programming with Qt 4, Second Edition" by Jasmin Blanchette and Mark Summerfield.

Go to the full post

A button to quit

Here we are just getting started with Qt, so this post is not very clear. Is just a first look to how to write a button to close our application. It is not a complicated issue, but it is not such an easy task to be clarified in few lines.

The complication is in the fact that we should create a connection between the "signal" that is generated by the button when clicked and the "slot" (actually, a function) that we want to execute.

To to that we use a static method of the QObject class, connect(), and a couple of macros, SIGNAL and SLOT.

So, here is the code for our little application, a button that fill all our tiny window and that, when clicked, close it.

#include <QtGui/QApplication>
#include <QtGui/QPushButton>

int b102(int argc, char** argv)
{
QApplication app(argc, argv);
QPushButton* button = new QPushButton("Quit");
QObject::connect(button, SIGNAL(clicked()), &app, SLOT(quit()));
button->show();
return app.exec();
}

In our case, when the button is clicked - or the blank key is pressed - the quit() method of our QApplication is called.

I wrote this post as homework while reading "C++ GUI Programming with Qt 4, Second Edition" by Jasmin Blanchette and Mark Summerfield.

Go to the full post

Hello Qt with a color touch

Once installed both VC++ 2010 and Qt on my machine (not a top notch one, a lap top a couple of years old with the infamous Windows Vista on - but enough for having some fun), I started reading "C++ GUI Programming with Qt 4, Second Edition" by Jasmin Blanchette and Mark Summerfield. Looks like a good book on the matter.

I'm about to write down a few posts during my reading, hoping that that could be useful for someone else too. At least as an hint on wich book to buy to knowing more on Qt.

The first chapter of the book is all about writing an hello Qt program, so close to the one I wrote in the previous post on Qt that someone could even think it is just the same. Luckly it is shown also another variant, in which the label is set with a HTML formatted text. Quite cool, isn't it?

#include <QtGui/QApplication>
#include <QtGui/QLabel>

int main(int argc, char** argv)
{
QApplication app(argc, argv);
QLabel* label = new QLabel(("<h2><i>Hello</i><font color=red>Qt!</font></h2>"));
label->show();

return app.exec();
}

Actually, there is another difference in this hello Qt program, compared to the one in the previous post. Here we have a memory leak, since we put the label on the heap, and not on the stack, without deleting it when done with it. Is that a major problem? Well, no, it isn't, since we are just about to leave the main.

Go to the full post

Hello Qt

To use Qt with VC++ 2010 you should set a few prerequisite.

In Project Properties - Configuration Properties

add C:\Qt\4.6.2\lib; (or your actual Qt lib directory) to Linker - General - Additional Library Directories
add QtCore4.lib;QtGui4.lib to Linker - Input - Additional Dependencies
add C:\Qt\4.6.2\include; (or your actual Qt include directory) to C/C++ - General - Additional Include Directories

Done that, it is quite easy to develop an hello Qt program:

#include <QtGui/QApplication>
#include <QtGui/QLabel>

int main(int argc, char** argv)
{
QApplication app(argc, argv);
QLabel label("Hello Qt!");
label.show();

return app.exec();
}

As any hello program, it is not doing much, just showing in a minimal window a greeting text. But we have created a real window that could be moved, resized, and even closed.

Go to the full post

System::IO

To access a file it is possible to use the System::IO::FileStream that provides access to the low level details of a file.

As example, we write a function, readFile(), that access a file and put its content in a managed array:

void readFile(System::String^ filename)
{
using System::IO::FileStream;
using System::IO::FileMode;

FileStream^ fs = gcnew FileStream(filename, FileMode::Open); // 1.

long long len = fs->Length;

System::Console::WriteLine("File length is {0}", len);

int size = static_cast(len); // 2.
array^ content = gcnew array(size);
fs->Read(content, 0, size);
fs->Close();
}

1. since we specify the mode FileMode::Open, if the file does not exists, an exception is thrown.
2. the length of a FileStream is defined as a long long, but the size of an array in just an int. Instead of simply casting to int, as we did here, we should add a bit of logic, to properly read all the file.

If we expect the file to be a text one, we could use StreamReader and TextWriter:

void readTextFile(System::String^ filename)
{
using System::IO::StreamReader;
using System::IO::TextWriter;

StreamReader^ sr = gcnew StreamReader(filename);
TextWriter^ tw = System::Console::Out;
tw->WriteLine("File {0}:", filename);

System::String^ line;
for(int i = 0; (line = sr->ReadLine()) != nullptr; ++i)
tw->WriteLine("Line {0}: {1}", i, line);

sr->Close();
}

This post is based on my reading on the book "Expert C++/CLI: .NET for Visual C++ Programmers" by Marcus Heege, APress.

Go to the full post

Command line arguments

It is commonly known that to output the command line arguments for a standard C++ program we could write a piece of code like that:

int main(int argc, char** argv)
{
for (int i = 0; i < argc; ++i)
std::cout << "Argument " << i << ": " << argv[i] << std::endl;

system("pause");
}

Where the first argument is the name of the program itself.

To achieve something similar in C++/CLI we write this:

int main(cli::array^ args)
{
for (int i = 0; i < args->Length; ++i)
System::Console::WriteLine("Argument {0}: {1}", i, args[i]);

system("pause");
}

I wrote "similar" not for the fact that we deal with System::Strings instead of raw arrays of chars - this is just an implementation details, after all - but because the program name is not in the argument lists.

To be a bit more pedantic, the managed version of the main function for a C++/CLI program accepts in input a managed array of managed System::String. The environment puts in this array any argument passed to the program.
This post is based on my reading on the book "Expert C++/CLI: .NET for Visual C++ Programmers" by Marcus Heege, APress.

Go to the full post

Using .NET classes

To use .NET classes that are defined in a specific dll we have to use a Microsoft extension to the preprocessor: the directive using.

The exception is the core library, mscorlib.dll, that requires no using directive to be available to our code. In this way we can use Console, Object, and many other basic stuff without explicit preprocessor using.

In this short example we use the class System::Uri that is defined in the System.dll:

#using

void exp03()
{
System::Uri^ uri = gcnew System::Uri("http://www.heege.net");
System::Console::WriteLine(uri->Host);
}

This post is based on my reading on the book "Expert C++/CLI: .NET for Visual C++ Programmers" by Marcus Heege, APress.

Go to the full post

Managed array

To create a manged array we should just specify the type and the number of dimensions. The default is a dimension of one. The array keyword, not a standard C++ keyword, is defined in the pseudo namespace cli, that could be used to avoid conflicts.

A managed array is initialized like a standard C++ array:

cli::array^ square = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};

cli::array^ square2 = gcnew array(3, 3);
for(int i = 0; i < 3; ++i)
for(int j = 0; j < 3; ++j)
square2[i, j] = (i * 3) + (j + 1) ;

The dimension of the array is not part of the array type specification, and, as for the other .NET object, once created an array can't change its size. The System::Array::Resize function does not actually resize the passed array, but just create a new one with the new dimensions and then copy the data from the original one.

The initialization of a managed array differs from the one of a standard C++ one in the way that all the element are always initialized to zero and then its default constructor is called, if available.

This post is based on my reading on the book "Expert C++/CLI: .NET for Visual C++ Programmers" by Marcus Heege, APress.

Go to the full post

CTS System::String and System::Text::StringBuilder

Any System::String object is immutable. That means, for instance, that calling String::Concat() does not change the passed object, but return a newly allocated System::String.

Here is a short example that should clarify how System::String works:

System::String^ str1 = System::String::Empty; // 1.
str1 += "a";
str1 = str1 + "a";
str1 = System::String::Concat(str1, "a");
System::Console::WriteLine(str1); // 2.
System::String^ str2 = str1->ToUpper();
System::Console::WriteLine(str2); // 3.

1. overkilling, Concat() is smart enough to manage nullptr System::String in input
2. the three lines before have the same effect, so now we have "aaa" in str1
3. notice that ToUpper() does not change str1, it just creates a new System::String

To avoid the creation of many unncecessary temporary strings is often useful using System::Text::StringBuilder, a sort of mutable string. It coulb be used in this way:

using System::Text::StringBuilder;
StringBuilder^ sb = gcnew StringBuilder(1024);
sb->Append("Rows: \n");
for (int i = 0; i < 100; ++i)
sb->AppendFormat("Row {0}\n", i);
System::String^ str3 = sb->ToString();
System::Console::WriteLine(str3);


This post is based on my reading on the book "Expert C++/CLI: .NET for Visual C++ Programmers" by Marcus Heege, APress.

Go to the full post

Managed Heap

The heap memory management in .NET is based on the concept of garbage collection, this has many advantages but a huge problem: it doesn't match with the standard C++ model.

So, C++/CLI introduces a specific operator, gcnew, to allocate memory on the managed heap. This operator returns something like a pointer to the managed memory, that is called tracking handle to stress the fact that it is not a native C++ pointer, and is denotated by ^ (caret) instead of * (asterisk). Instead of NULL, the invalid value for a tracking handle is nullptr. To access members through a tracking handle is used the same arrow operator used to access members through a standard C++ pointer. Curiously enough, to dereference a tracking handle a * (asterisk) is used.

Here is piece of code that should clarify the matter:

int^ i; // 1.

if(i == nullptr)
std::cout << "i is initialized to nullptr" << std::endl;

i = gcnew int(42); // 2.
if(i != nullptr)
{
System::Console::WriteLine(i->GetType()); // 3.
System::Console::WriteLine(i->ToString()); // 4.

std::cout << "i has value " << *i << std::endl; // 5.
}

1. define a tracking handle, implicitly initialized to nullptr.
2. an int object is created on the managed heap, its tracking handle is returned, and stored in the local variable
3. the tracking handle is dereferenced to call the GetType() method. System.Int32 should be printed, since int is converted to that type on the managed memory.
4. this instruction would print the value of the int object on the managed heap, that means 42.
5. here we print the derefenced value of i, again 42.

This post is based on my reading on the book "Expert C++/CLI: .NET for Visual C++ Programmers" by Marcus Heege, APress.

Go to the full post

CTS and primitive types

There is a hierarchy of classes that should be used to help language interoperability in .NET, it is called CTS (Common Type System) and it is based on the System::Object class. So, anything in CTS is a System::Object.

That means that we can call on any CTS object the System::Object method:
  • ToString;
  • GetType, provides RunTime Type Information (RTTI) in .NET;
  • GetHashCode;
  • Equals.

C++/CLI it is smart enough to use primitive types as managed types, so having a way to work on them as System::Objects.

So this code would output to console System.Int32:

System::Console::WriteLine((42).GetType()); // System.Int32

Here is the mapping the primitive C++ type and the CTS classes that wrap each of them, and some examples of its literal values:

bool System::Boolean (true)
unsigned char System::Byte
signed char System::SByte ('a')
short System::Int16
unsigned short System::UInt16
int System::Int32
unsigned int System::UInt32 (1U)
long long System::Int64 (1LL)
unsigned long long System::UInt64 (1ULL)
float System::Single (1.0f)
double System::Double (1.0)
wchar_t System::Char (L'a')
void System::Void

Even cooler, C++/CLI could use a CTS object as a primitive, when required so, this piece of code works properly:

System::Double PI = 3.14159265358979;
std::cout << PI << std:: endl;

PI is passed to cout as if it were declared as double.

This post is based on my reading on the book "Expert C++/CLI: .NET for Visual C++ Programmers" by Marcus Heege, APress. I suggest you to read it too, to have more details on the matter

Go to the full post

Hello CLI

The code we are talking about here is not proper C++, it is C++/CLI, where CLI stands for Common Language Infrastructure, and that means .NET, so we are basically talking about the C++ twisted by Microsoft to fit in its propertary architecture.

The cool thing about C++/CLI is that it is a superset of the standard C++, so we could, in principle, just avoid CLI and developing (more or less) pure C++ for our Windows platform.

Here is the usual hello program written in a way to show how C++/CLI could use C, C++ and CLI features:

#include <stdio.h>
#include <iostream>

int main()
{
printf("hello"); // C
std::cout << ", "; // C++
System::Console::WriteLine("world"); // CLI

system("pause");
}

Isn't that too bad, is it?

This post is based on my reading on the book "Expert C++/CLI: .NET for Visual C++ Programmers" by Marcus Heege, APress. I suggest you to read it too, to have more details on the matter

Go to the full post