![]() |
Главная · Все классы · Основные классы · Классы по группам · Модули · Функции | ![]() |
[Предыдущий: Урок 6] [Учебное руководство] [Следующий: Урок 8]
Файлы:
Этот пример показывает, как связывать с помощью слотов и сигналов создаваемые вами виджеты в более сложных случаях. В этом примере мы разнесели наш код в несколько файлов, которые мы поместили в каталог examples/tutorial/t7.
Содержимое этого файла мы фактически взяли из файла main.cpp шестого урока; рассмотрим только существенные отличия.
#ifndef LCDRANGE_H #define LCDRANGE_H
Эти строчки вместе с #endif в конце файла являются стандартной конструкцией языка С++, позволяющей избежать ошибок, если вы пытаетесь подключить заголовочный файл несколько раз. Если в своих программах вы еще не использовали эту конструкцию, то мы настоятельно рекомендуем начать это делать.
#include <QWidget>
Подключаем класс <QWidget>, так как наш класс LCDRange унаследован от QWidget. Заголовочный файл родительского класса необходимо подключать всегда - мы немного хитрили в предыдущих частях, не подключая <QWidget> явно, а через другие заголовочные файлы.
class QSlider;
Это ещё один трюк с классами, он используется несколько реже. Так как мы не нуждаемся в полном интерфейсе класса QSlider, мы используем опережающее определение (forward declaration) класса в этом заголовочном файле, а полное описание QSlider подключаем в файле .cpp.
Использование данной конструкции позволит сократить время компиляции больших программ, так как обычно компилятор тратит большую часть времени на анализ заголовочных файлов, а не настоящего исходного кода. Один только этот приём позволяет сократить время компиляции в два-три раза.
class LCDRange : public QWidget { Q_OBJECT public: LCDRange(QWidget *parent = 0);
Обратите внимание на Q_OBJECT. Этот макрос должен быть включён во все классы, которые используют сигналы или слоты. Если вам интересно, он определяет функции, реализованные в мета-объектном файле.
int value() const; public slots: void setValue(int value); signals: void valueChanged(int newValue);
Эти три члена класса составляют интерфейс для взаимодействия с другими компонентами нашей программы. До сих пор LCDRange вообще не имел своего API.
value() - открытая функция для получения доступа к значению LCDRange, setValue() - наш первый слот, а valueChanged() - наш первый сигнал.
Слоты должны быть реализованы обычным способом (слот является также функцией-членом класса С++). Сигналы автоматически реализуются в мета-объектном файле. Сигналы следуют правилам доступа, которым подчиняются защищенные функции C++ (т.е., они могут испускаться только непосредственно самим классом или его потомком).
Сигнал valueChanged() используется тогда, когда изменилось значение LCDRange.
Содержимое этого файла мы также фактически взяли из файла main.cpp шестого урока, а здесь рассмотрим только его отличия.
connect(slider, SIGNAL(valueChanged(int)), lcd, SLOT(display(int))); connect(slider, SIGNAL(valueChanged(int)), this, SIGNAL(valueChanged(int)));
Этот код взят из конструктора LCDRange.
Первый вызов функции connect() ничем не отличается от примера, приведенного в предыдущем уроке. Второй вызов для нас новый; мы соединяем сигнал valueChanged() слайдера с сигналом valueChanged() объекта this. Да, именно так. Сигналы можно соединять. При испускании первого сигнала, второй сигнал также будет испускаться.
Давайте разберемся, что происходит когда пользователь управляет ползунком. Ползунок определяет, что его значение изменилось и испускает сигнал valueChanged(). Этот сигнал соединен и со слотом display() объекта QLCDNumber и с сигналом valueChanged() объекта LCDRange.
Таким образом, когда испускается сигнал, LCDRange испускает свой сигнал valueChanged(). Кроме того, вызывается QLCDNumber::display() и ЖК-индикатор показывает новое значение.
Обратите внимание на то, что очерёдность обработки сигналов не гарантируется; LCDRange::valueChanged() может быть испущен до или после вызова QLCDNumber::display().
int LCDRange::value() const { return slider->value(); }
Реализация value() очень проста. Этот метод просто возвращает значение ползунка.
void LCDRange::setValue(int value) { slider->setValue(value); }
Реализация setValue() примерно столь же проста. Обратите внимание на то, что поскольку ползунок и ЖК-индикатор соединены между собой, установка нового значения ползунка также автоматически обновляет значение ЖК-индикатора. Кроме того, ползунок автоматически корректирует значение, если оно выйдет за пределы диапазона допустимых значений.
LCDRange *previousRange = 0; for (int row = 0; row < 3; ++row) { for (int column = 0; column < 3; ++column) { LCDRange *lcdRange = new LCDRange; grid->addWidget(lcdRange, row, column); if (previousRange) connect(lcdRange, SIGNAL(valueChanged(int)), previousRange, SLOT(setValue(int))); previousRange = lcdRange; } }
Весь файл main.cpp целиком взят из предыдущего урока за исключением вызова конструктора MyWidget. Когда мы создаем девять объектов LCDRange, мы соединяем их используя механизм сигналов и слотов. У каждого из них (кроме первого) сигнал valueChanged() соединен со слотом setValue() предыдущего объекта. Так как LCDRange испускает сигнал valueChanged() когда изменяется значение, то получается цепочка сигналов и слотов.
Создание make-файла для программы, состоящей из нескольких файлов, ничем не отличается от случая приложения с одним файлом. Если вы сохранили все файлы данного примера в одном каталоге, то вам требуется только выполнить:
qmake -project qmake
Первой командой мы создаем с помощью qmake .pro-файл (файл проекта). Следующей командой мы создаем make-файл (платформозависимый), основанный на файле проекта. Теперь вы можете выполнить команду make (или nmake, если вы используете Visual Studio) для сборки приложения.
После запуска внешний вид приложения такой же как у программы, созданной нами в предыдущем уроке. Попробуйте подвигать нижний правый ползунок.
Используйте нижний правый ползунок для установки значения 50 на всех ЖК-индикаторах. Затем установите верхние 6 в значение 30, щелкая по ползунку на строке выше. Теперь используйте ползунок, расположенный слева от используемого до этого, для установки значения 50 на первых пяти ЖК-индикаторах.
Щелкните слева от рукоятки правого нижнего ползунка. Что произойдет? Почему такое поведение правильное?
[Предыдущий: Урок 6] [Учебное руководство] [Следующий: Урок 8]
Copyright © 2008 Trolltech | Торговые марки | Qt 4.3.5 |