• Aucun résultat trouvé

Implementing Slots

Dans le document Qt 4 THE BOOK of THE BOOK of (Page 72-76)

The Tools Needed to Create Dialogs

2.1 What’s the Difference Between Dialogs and Widgets?Widgets?

2.1.4 Implementing Slots

Finally, we need to implement the functional connections that make the Quit but-ton work as expected and synchronize the three input fields with one another.

To ensure that clicking the Quit button will close the byte-converter dialog, we extend the ByteConverterDialog constructor to associate the clicked() signal of the

button with the accept() slot of the dialog. The slot is provided by QDialog, which the ByteConverterDialog class inherits from:

// byteConverter/ByteConverterDialog.cpp (continued) ...

connect(exitButton, SIGNAL(clicked()), this, SLOT(accept()));

...

The accept() method, when invoked, simply closes the dialog. Our use ofaccept() here follows a general convention: A large number of dialogs have an Ok and a Cancel button at the bottom; Ok corresponds to the accept() slot, Cancel to the reject() slot. Both slots close the dialog, the first exiting with a positive return value, the second with a negative one (see Chapter 6, page 161). In this example we only have one button and therefore are not interested in the return value, just the action.

However, the real event-processing logic of our byte converter application consists of augmenting the customary signals and slots with several custom-built connec-tions, specific to the functionality of our ByteConverterDialog class. These sig-nal/slot connections should come into action when any one of the QLineEdit ob-jects sends out the signal textChanged(), indicating that the text in that object’s input field has changed. For this purpose, we expand our class definition as fol-lows:

// byteConverter/ByteConverterDialog.h (continued) class ByteConverterDialog : public QDialog

{ ...

private slots:

void decChanged(const QString&);

void hexChanged(const QString&);

void binChanged(const QString&);

};

Slots are declared in the same way as normal functions, except that for access control we use the designators public slots:, protected slots:, and private slots:, instead of the usual public:, protected:, and private: protection modes.

Each of our three slots accepts an argument of the type const QString&. In this way the textChanged() signal of the function can pass the new text of the line edit.

As the argument type for the signals/slots to be, we do not choose simply QString, but a reference to a const QString. There are two reasons for this. First, by us-ing call-by-reference rather than call-by-value, the QStrus-ing object containus-ing the

updated input to be passed to the signals/slots will not be copied when the sig-nals and slots are invoked, and the code becomes more efficient. However, use of call-by-reference allows the function to modify the actual parameter, which the signals and slots should not do, so the parameter is also declared to be a reference to const data. This second step is a recommended “defensive programming” prac-tice whenever a function should not change an actual parameter that is passed by reference.

Even though the declaration of a slot differs slightly from that of other functions, it is still an ordinary function, which is implemented and can be called in the usual way. Here is the definition of the decChanged() slot in the file ByteConverterDia-log.cpp:

The function receives the new string displayed by the decimal line-edit widget as the actual value for its newValue parameter, and it updates the strings displayed by the hexadecimal and binary line-edit widgets. First, we need to determine the numeric value that corresponds to the input string. As an object of the QString class, newValue knows several functions that convert strings to numbers. We will use the toInt() function, as the input is a string representing an integer value.

toInt() accepts a bool pointer as an optional argument: If this argument is specified, the function sets the variable to which it points to true if the string is successfully converted to a numeric value, and to false if the conversion fails, that is, if the string does not represent an integer value.

If the conversion is successful, we set the texts displayed by the two other line edits (hexEdit and binEdit) to the hexadecimal and binary equivalents of the new value. To do this, we convert the number to a string that represents the new value in hexadecimal form and to a string that represents the new value in binary form.

For this purpose the QString class has the static function number(), which returns the representation of a number as a string. The number itself is its first argument.

As a second argument, number() expects the base for the number system used, in our case 16 for hexadecimal and 2 for binary. The second argument is optional,

and if it is not specified, number() assumes base 10 (the decimal system), which is the most common case.

If the toInt() function could not convert the string that was entered in the decimal line-edit widget into a number, we write an empty text to the other two line-edit widgets, with setText(). Thanks to the validator we used for the decEdit object, which ensures that only numbers in the range 0 to 255 can be entered, the con-version will only fail in one single case: if the user deletes the input completely.

We implement the two remaining slots in the same way:

// byteConverter/ByteConverterDialog.cpp (continued)

In these functions, when transforming the string to an integer value, we specify the base in an optional second argument to toInt(); like QString::number(), toInt() uses base 10 by default if this argument is omitted.

In order for these parts of our application to work together according to our design, we must connect the textChanged() signals of each of our QLineEdit objects with the corresponding slots. To do this, we extend the constructor for the last time:

// byteConverter/ByteConverterDialog.cpp (continued)

connect(binEdit, SIGNAL(textChanged(const QString&)), this, SLOT(binChanged(const QString&)));

}

The code for the constructor of our ByteConverterDialog class is now complete, and performs three different tasks:

It generates all the widgets of a dialog, incorporates them into the appropriate layouts, and sets up the object hierarchy of the dialog.

It restricts the user input to sensible values.

It sets up all the necessary signal/slot connections.

The entire logic of the application is contained in the code for slots and in their connections to the corresponding signals.

Dans le document Qt 4 THE BOOK of THE BOOK of (Page 72-76)