Текст книги "Основы программирования в Linux"
Автор книги: Нейл Мэтью
Соавторы: Ричард Стоунс
Жанры:
Программирование
,сообщить о нарушении
Текущая страница: 63 (всего у книги 67 страниц)
LayoutWindow *window = new LayoutWindow();
app.setMainWidget(window);
window->show();
return app.exec();
}
Как и прежде, перед компиляцией нужно выполнить moc
для заголовочного файла:
$ moc LayoutWindow.h -о LayoutWindow.moc
$ g++ -о layout LayoutWindow.cpp -I$QTDIR/include -L$QTDIR/lib -lqui
Выполнив эту программу, вы получите схему размещения ваших меток QLabel (рис. 17.4). Попробуйте изменить величину окна и посмотрите, как расширяются и сжимаются метки, заполняя все доступное пространство.
Рис. 17.4
Как это работает
Программа LayoutWindow.cpp создает два виджета упаковочных контейнеров, горизонтальный и вертикальный контейнер для размещения виджетов. Вертикальный контейнер получает две метки, описанные, соответственно, как Top
и Bottom
. Горизонтальный контейнер также содержит два виджета, метку, обозначенную Right
, и вертикальный контейнер. Вы можете помещать компоновочные виджеты внутрь других компоновочных виджетов, как показано в данном примере.
Попробуйте изменить исходный текст программы в файле LayoutWindow.срр, чтобы поэкспериментировать и лучше понять, как работают компоновочные виджеты.
Мы рассмотрели основы применения Qt – сигналы и слоты, команду moc и средства компоновки. Теперь пора более внимательно изучить виджеты.
Виджеты Qt
Для каждого случая в Qt есть виджеты, и их подробное рассмотрение займет всю оставшуюся часть книги. В этом разделе мы познакомимся с виджетами Qt общего применения, включая виджеты для ввода данных, кнопки, обычные и раскрывающиеся списки.
QLineEditQLineEdit
– виджет для ввода однострочного текста. Применяйте его для ввода коротких фрагментов текста, таких как имя пользователя. В виджете QLineEdit
можно ограничить длину вводимого текста с помощью маски ввода, предлагающей заполнить шаблон, или для дополнительного контроля можно применить функцию проверки допустимости, например, чтобы убедиться в том, что пользователь вводит корректные дату, номер телефона или подобные величины. У виджета QLineEdit
есть функции редактирования, позволяющие выбирать части текста, вырезать и вставлять, отменять и повторять изменения, как командами пользователя, так и средствами API.
Далее перечислены конструкторы и наиболее полезные методы.
#include
QLineEdit::QLineEdit(QWidget *parent, const char* name = 0);
QLineEdit::QLineEdit(const QString& contents, QWidget *parent,
const char *name = 0);
QLineEdit::QLineEdit(const QString& contents, const QString& inputMask,
QWidget *parent, const char* name = 0);
void setInputMask(const QString& inputMask);
void insert(const QString& newText);
bool isModified(void);
void setMaxLength(int length);
void setReadOnly(bool read);
void setText(const QString &text);
QString text(void);
void setEchoMode(EchoMode mode);
В конструкторах вы задаете как обычно родительский виджет и имя виджета с помощью параметров parent
и name
.
Интересно свойство EchoMode
, определяющее способ отображения текста в виджете. Оно может принимать одно из трех значений:
□ QLineEdit::Normal
– отображать вводимые символы (по умолчанию);
□ QLineEdit::Password
– отображать звездочки на месте символов;
□ QLineEdit::NoEcho
– ничего не отображать. Задается режим отображения с помощью метода setEchoMode
:
lineEdit->setEchoMode(QLineEdit::Password);
Усовершенствование, внесенное в версию Qt 3.2, – свойство inputMask
, ограничивающее ввод в соответствии с правилом маски.
inputMask
– это строка, сформированная из символов, каждый из которых соответствует правилу, принимающему диапазон определенных символов. Если вы знакомы с регулярными выражениями, inputMask
использует во многом тот же самый принцип.
Есть два сорта символов, формирующих inputMask
: первые указывают на необходимость присутствия определенного символа, вторые при наличии символа добиваются его соответствия заданному правилу. В табл. 17.1 приведены примеры таких символов и их значения.
Таблица 17.1
A | a | Символы ASCII А–Z, а–z |
N | n | Символы ASCII A–Z, a–z, 0–9 |
X | x | Любой символ |
9 | 0 | Цифры 0–9 |
D | d | Цифры 1–9 |
Наша inputMask
– это строка, сформированная комбинацией этих символов и необязательно завершающаяся точкой с запятой. Существуют дополнительные специальные символы, у которых также есть значения (табл. 17.2).
Таблица 17.2
# | Разрешен, но не обязателен знак +/- |
> | Преобразует все последующие введенные символы в символы верхнего регистра. |
< | Преобразует все последующие введенные символы в символы нижнего регистра |
! | Останавливает преобразование регистра |
| Символ управляющей последовательности для применения специальных символов в качестве разделителей |
Все остальные символы в inputMask
действуют как разделители в поле ввода QLineEdit
.
В табл. 17.3 приведены примеры масок ввода и соответствующий им текст для ввода.
Таблица 17.3
«AAAAAA-999D» | Допустимо Athens-2004, но не Sydney-2000 или Atlanta-1996 |
«ААААnn-99-99;» | Допустимо March-03-12, но не Мау-03-12 или September-03-12 |
«000.000.000.000» | Допустим IP-адрес, например, 192.168.0.1 |
Выполните упражнение 17.4.
Упражнение 17.4. Виджет QLineEdit
Посмотрим, как действует виджет QLineEdit
.
1. Сначала – заголовочный файл LineEdit.h:
#include
#include
#include
class LineEdit : public QMainWindow {
Q_OBJECT
public:
LineEdit(QWidget *parent = 0, const char *name = 0);
QLineEdit *password_entry;
private slots:
void Clicked();
};
2. LineEdit.cpp – уже знакомый файл реализации класса:
#include «LineEdit.moc»
#include
#include
#include
#include
#include
LineEdit::LineEdit(QWidget *parent, const char *name) :
QMainWindow(parent, name) {
QWidget *widget = new QWidget(this);
setCentralWidget(widget);
3. Для компоновки виджетов примените QGridLayout
. Задайте число строк и столбцов, величины отступов и расстояния между виджетами:
QGridLayout *grid = new QGridLayout(widget, 3, 2, 10, 10, «grid»);
QLineEdit *username_entry = new QLineEdit(widget, «username_entry»);
password_entry = new QLineEdit(widget, «password_entry»);
password_entry->setEchoMode(QLineEdit::Password);
grid->addWidget(new QLabel(«Username», widget, «userlabel»), 0, 0, 0);
grid->addwidget(new QLabel(«Password», widget, «passwordlabel»), 1, 0, 0);
grid->addWidget(username_entry, 0, 1, 0);
grid->addWidget(password_entry, 1, 1, 0);
QPushButton *button = new QPushButton(«Ok», widget, «button»);
grid->addWidget(button, 2, 1, Qt::AlignRight);
resize(350, 200);
connect(button, SIGNAL(clicked()), this, SLOT(Clicked()));
}
void LineEdit::Clicked(void) {
std::cout << password_entry->text() << «n»;
}
int main(int argc, char **argv) {
QApplication app(argc, argv);
LineEdit *window = new LineEdit();
app.setMainWidget(window);
window->show();
return app.exec();
}
Выполнив эту программу, вы должны получить результат, показанный на рис. 17.5.
Рис. 17.5
Как это работает
Вы создали два виджета QLineEdit
, один подготовили для ввода пароля, задав EchoMode
, и заставили его выводить содержимое при щелчке мышью кнопки PushButton
. Обратите внимание на виджет QGridLayout
, который очень полезен для размещения виджетов в табличной сетке. Когда виджет вставляется в сетку таблицы, вы передаете номер строки и столбца, нумерация начинается с 0, нулевые номера строки и столбца у верхней левой ячейки.
Кнопки виджетов вездесущи и мало отличаются внешним видом, способом применения и API в разных комплектах инструментов. Неудивительно, что Qt предлагает стандартные кнопки PushButton
, флажки CheckBox
и радиокнопки (или зависимые переключатели) RadioButton
.
QButton: базовый класс кнопок
Все виджеты кнопок в комплекте Qt – потомки абстрактного класса QButton
. У этого класса есть методы для опроса и переключения включенного/выключенного состояния кнопки и задания текста кнопки или ее графического представления.
Вам никогда не придется обрабатывать виджет типа QButton
(не путайте с виджетом QPushButton
!), поэтому нет смысла приводить конструкторы. Далее перечислено несколько полезных функций-методов этого класса:
#include
virtual void QButton::setText(const QString&);
virtual void QButton::setPixmap(const QPixmap&);
bool QButton::isToggleButton() const;
virtual void QButton::setDown(bool);
bool QButton::isDown() const;
bool QButton::isOn() const;
enum QButton::ToggleState { Off, NoChange, On }
ToggleState QButton::state() const;
У функций isDown
и isOn
одно назначение. Обе они возвращают TRUE
, если кнопка была нажата или активизирована.
Часто вам нужно отключить или сделать серым вариант, если он недоступен в данный момент. Сделать недоступным любой виджет, включая QButton, можно с помощью вызова метода QWidget::setEnable(FALSE)
.
У QButton
есть три подкласса, заслуживающие внимания:
□ QPushButton
– виджет простой кнопки, выполняющий некоторое действие при щелчке кнопкой мыши;
□ QCheckBox
– виджет кнопки, способный изменять состояние с включенного на выключенное для обозначения некоторого выбора;
□ QRadioButton
– виджет кнопки, обычно применяемый в группе таких же кнопок, только одна из которых может быть активна в любой момент времени.
QPushButton
QPushButton
– стандартная кнопка общего вида, содержащая текст, такой как «OK» или «Cancel» и/или пиксельную пиктограмму. Как все кнопки класса QButton
, она порождает при активизации сигнал clicked
и обычно используется для связи со слотом и выполнения некоторого действия.
Вы уже применяли кнопку QPushButton
в примерах, и есть лишь еще одна интересная деталь, касающаяся этого простейшего из виджетов Qt. Кнопку QPushButton
можно превратить из кнопки, не помнящей своего состояния, в кнопку-выключатель (т.е. способную быть включенной и выключенной), вызвав метод setToggleButton
. (Если помните, у комплекта GTK+ из предыдущей главы есть для этих целей разные виджеты.)
Далее для полноты описания приведены конструкторы и полезные методы.
#include
QPushButton(QWidget *parent, const char *name = 0);
QPushButton(const QString& text, QWidget *parent, const char *name = 0);
QPushButton(const QIconSet& icon, const QString& text,
QWidget *parent, const char * name = 0);
void QPushButton::setToggleButton(bool);
QCheckBox
QCheckBox
– это кнопка, у которой есть состояние, ее можно включить и выключить (или установить и сбросить). Внешний вид QCheckBox
зависит от стиля отображения окон текущей системы (Motif, Windows и т.д.), но обычно она отображается как флажок с сопроводительным текстом справа.
Вы можете также перевести кнопку QCheckBox
в третье промежуточное состояние, которое означает «без изменения». Оно бывает полезно в редких случаях, когда вы не можете прочесть состояние выбора, который предоставляет кнопка QCheckBox
(и, следовательно, самостоятельно установить или сбросить флажок), но хотите дать пользователю возможность оставить выбор неизменным наряду с установкой и сбросом.
#include
QCheckBox(QWidget *parent, const char *name = 0);
QCheckBox(const QString& text, QWidget *parent, const char *name = 0);
bool QCheckBox::isChecked();
void QCheckBox::setTristate(bool y = TRUE);
bool QCheckBox::isTristate();
QRadioButton
Радиокнопки – кнопки-переключатели, применяемые для отображения исключающего выбора, когда можно выбрать только один вариант из группы представленных (вспомните снова старые автомобильные радиоприемники, в которых можно было нажать только одну кнопку блока). Сами по себе кнопки QRadioButton
не многим отличаются от кнопок QCheckBox
, поскольку группировка и исключительный выбор обрабатываются классом QButtonGroup
, главное же их отличие заключается в том, что они отображаются как круглые кнопки, а не как флажки.
QButtonGroup
– виджет, облегчающий обработку групп кнопок за счет предоставления удобных методов.
#include
QButtonGroup(QWidget *parent = 0, const char* name = 0);
QButtonGroup(const QString& title, QWidget* parent = 0,
const char * name = 0);
int insert (QButton *button, int id = -1);
void remove(QButton *button);
int id(QButton *button) const;
int count() const;
int selectedId() const;
Применять виджет QButtonGroup
проще простого: он даже предлагает необязательную рамку вокруг кнопок, если используется конструктор title
.
Добавить кнопку в QButtonGroup
можно с помощью метода insert
или заданием QButtonGroup
в качестве родительского виджета кнопки. Для уникального обозначения каждой кнопки в группе можно задать id
в методе insert
. Это особенно полезно при определении выбранной кнопки, т.к. функция selectedId
возвращает id
выбранной кнопки.
Все кнопки QRadioButton
, добавляемые в группу, автоматически становятся кнопками с исключающим выбором.
Далее приведены прототипы конструкторов QRadioButton
и одного уникального метода, который не вызовет большого удивления:
#include
QRadioButton(QWidget* parent, const char* name = 0);
QRadioButton(const QString& text, QWidget *parent, const char *name = 0);
bool QRadioButton::isChecked();
Выполните упражнение 17.5.
Упражнение 17.5. Виджет QButton
Теперь применим полученные знания в примере с кнопками Qt. Приведенная далее программа создает кнопки разных типов (радиокнопки, флажки и простые кнопки), чтобы показать, как использовать эти виджеты в ваших приложениях.
1. Введите файл Buttons.h:
#include
#include
#include
#include
class Buttons : public CMainWindow {
Q_OBJECT
public:
Buttons(QWidget *parent = 0, const char *name = 0);
2. Вы запросите состояние ваших кнопок позже, в функции слота, поэтому объявите указатели кнопок и вспомогательную функцию PrintActive
с атрибутом private в объявлении класса:
private:
void PrintActive(QButton *button);
QCheckBox *checkbox;
QRadioButton *radiobutton1, *radiobutton2;
private slots:
void Clicked();
}
3. Далее следует файл Buttons.срр:
#include «Buttons.moc»
#include
#include
#include
#include
#include
#include
Buttons::Buttons(QWidget *parent, const char *name) :
QMainWindow(parent, name) {
QWidget* widget = new QWidget(this);
setCentralWidget(widget);
QVBoxLayout *vbox = new QVBoxLayout(widget, 5, 10, «vbox»);
checkbox = new QCheckBox(«CheckButton», widget, «check»);
vbox->addWidget(checkbox);
4. Затем вы создаете QButtonGroup
для двух ваших радиокнопок (переключателей).
QButtonGroup *buttongroup = new QButtonGroup(0);
radiobutton1 = new QRadioButton(«RadioButton1», widget, «radio1»);
buttongroup->insert(radiobutton1);
vbox->addWidget(radiobutton1);
radiobutton2 = new QRadioButton(«RadioButton2», widget, «radio2»);
buttongroup->insert(radiobutton2);
vbox->addWidget(radiobutton2);
QPushButton* button = new QPushButton(«Ok», widget, «button»);
vbox->addWidget(button);
resize(350, 200);
connect(button, SIGNAL(clicked()), this, SLOT(Clicked()));
}
5. Затем приведен удобный метод для вывода состояния заданной кнопки QButton
:
void Buttons::PrintActive(QButton *button) {
if (button->isOn())
std::cout << button->name() << « is checkedn»;
else
std::cout" << button->name() << « is not checkedn»;
}
void Buttons::Clicked(void) {
PrintActive(checkbox);
PrintActive(radiobutton1);
PrintActive(radiobutton2);
std::cout << «n»;
}
int main(int argc, char **argv) {
QApplication app(argc, argv);
Buttons *window = new Buttons();
app.setMainWidget(window);
window->show();
return app.exec();
}
Как это работает
Этот простой пример показывает, как опрашивать виджеты кнопок Qt разных типов. После создания все они по большей части действуют одинаково. Например, функция PrintActive
демонстрирует, как получить состояние кнопки (включена или выключена). Обратите внимание на то, как она действует в случае запоминающих состояние кнопок разных типов, таких как флажки и переключатели (радиокнопки). В основном отличаются только вызовы для создания виджета кнопки. Радиокнопки, наиболее сложные (т.к. только одна в группе может быть включена), при создании требуют больше всего работы. В случае радиокнопок вы должны создать QButtonGroup
для того, чтобы гарантировать активность только одной радиокнопки в группе в любой момент времени.
Переключатели (радиокнопки) – отличный способ, позволяющий пользователю выбрать из небольшого числа вариантов, скажем шести или меньше. Если вариантов больше шести, ситуация начинает выходить из-под контроля и становится еще более напряженной, когда количество вариантов растет, что приводит к ощутимому увеличению размера окна. В этом случае прекрасным решением может быть использование поля ввода с раскрывающимся меню, также называемое раскрывающимся списком (combo box). Варианты выводятся, когда вы щелкаете кнопкой мыши и открываете меню и количество вариантов при этом ограничено только удобством поиска в списке.
В виджете QComboBox
сочетаются функциональные возможности виджетов QLineEdit
и QPushButton
и раскрывающихся меню, позволяя выбрать один вариант из неограниченного набора вариантов.
QComboBox
может быть открытым, как для чтения и записи, так и только для чтения. Если он позволяет читать и записывать, пользователь может ввести новый вариант в дополнение к предлагаемым; в противном случае пользователь ограничен выбором варианта из раскрывающегося списка.
При создании виджета QComboBox
можно указать, открыт ли он для чтения и записи или только для чтения, задавая логическое значение в конструкторе:
QComboBox *combo = new QComboBox(TRUE, parent, «widgetname»);
Передача значения TRUE
переводит QComboBox
в режим «чтение/запись». Остальные параметры – обычный указатель на родительский виджет и имя создаваемого виджета.
Как все виджеты Qt, QComboBox
обладает гибкостью и предлагает широкий набор функциональных возможностей.
Вы можете добавлять варианты по одному или набором, как тип QString
или в стандартном формате char*
.
Для вставки одного варианта вызовите функцию insertItem
:
combo->insertItem(QString(«An Item»), 1);
Приведенная функция принимает объект типа QString
и номер позиции в списке. В данном случае 1 вставляет вариант в список первым.
Для добавления в конец списка задайте любое отрицательное целое число.
Гораздо чаще вы будете вставлять несколько элементов списка одновременно, для этого можно применить класс QStrList
или, как показано далее, массив char*
:
char* weather[] = {"Thunder", «Lightning», «Rain», 0};
combo->insertStrList(weather, 3);
И снова вы можете задать номер позиции вставляемых в список элементов.
Если в виджете QComboBox
задан режим «чтение/запись», вводимые пользователем варианты могут автоматически вставляться в список. Это очень полезное, экономящее время свойство, избавляющее пользователя от повторного набора варианта, если он хочет уже введенный вариант использовать несколько раз.
Метод InsertionPolicy
управляет позицией вводимого в список элемента. Вы можете выбрать одно из значений, приведенных в табл. 17.4.
Таблица 17.4
QComboBox::AtTop | Вставляет вводимый в список элемент первым |
QComboBox::AtBottom | Вставляет вводимый в список элемент последним |
QComboBox::AtCurrent | Заменяет предварительно выбранный вариант в списке |
QComboBox::BeforeCurrent | Вставляет вводимый элемент перед предварительно выбранным вариантом из списка |
QComboBox::AfterCurrent | Вставляет вводимый элемент после предварительно выбранного варианта из списка |
QComboBox::NoInsertion | Новый элемент не вставляется в список вариантов |
Для задания политики вызовите метод InsertionPolicy
виджета QComboBox
:
combo->setInsertionPolicy(QComboBox::AtTop);
Давайте бросим взгляд на конструкторы и методы выбора варианта виджета QComboBox
:
#include
QComboBox(QWidget *parent = 0, const char *name = 0);
QComboBox(bool readwrite, QWidget *parent = 0, const char *name = 0);
int count();
void insertStringList(const QStringList& list, int index = -1);
void insertStrList(const QStrList& list, int index = -1);
void insertStrList(const QStrList *list, int index = -1);
void insertStrList (const char **strings, int numStrings = -1, int index = -1);
void insertItem(const QString &t, int index = -1);
void removeItem(int index);
virtual void setCurrentItem(int index);
QString currentText();
virtual void setCurrentText(const QString &);
void setEditable(bool);
Функция count
возвращает количество вариантов в списке. QStringList
и QStrList
– классы коллекций, которые можно применять для вставки вариантов. Удалить варианты можно с помощью метода removeItem, извлечь и задать текущий вариант можно, с помощью методов currentText
и setCurrentText
, а перейти в редактируемый режим – с помощью метода setEditable
.
QComboBox
порождает сигнал textChanged(QString&)
при каждом новом выборе варианта, передавая вновь выбранный элемент как аргумент.
Выполните упражнение 17.6.
Упражнение 17.6. Виджет QComboBox
В этом примере вы сделаете попытку применить виджет QComboBox
и посмотрите, как ведут себя сигналы и слоты с параметрами. Вы создадите класс ComboBox
, потомка QMainWindow
. В нем будут два виджета QComboBox
: один для чтения/записи, другой только для чтения. Вы установите связь с сигналом textChanged
для того, чтобы получать текущее значение при каждом его изменении.
1. Введите следующий программный код и назовите файл ComboBox.h:
#include
#include
class ComboBox : public QMainWindow {
Q_OBJECT
public:
ComboBox(QWidget* parent = 0, const char *name = 0);
private slots:
void Changed(const QString& s);
};
2. Интерфейс состоит из двух виджетов QComboBox
: один редактируемый, а другой предназначен только для чтения. Вы заполните оба списка одними и теми же вариантами:
#include «ComboBox.moс»
#include
#include
ComboBox::ComboBox(QWidget *parent, const char *name) :
QMainWindow(parent, name) {
QWidget *widget = new QWidget(this);
setCentralWidget(widget);
QVBoxLayout *vbox = new QVBoxLayout(widget, 5, 10, «vbox»);
QComboBox *editablecombo = new QComboBox(TRUE, widget, «editable»);
vbox->addWidget(editablecombo);
QComboBox *readonlycombo = new QComboBox(FALSE, widget, «readonly»);
vbox->addWidget(readonlycombo);
static const char* items[] = {"Macbeth", «Twelfth Night», «Othello», 0};
editablecombo->insertStrList(items);
readonlycombo->insertStrList(items);
connect(editablecombo, SIGNAL(textchanged(const QString&),
this, SLOT(Changed(const QString&)));
resize(350, 200);
}
3. Далее приведена функция слота. Обратите внимание на параметр s
типа QString
, передаваемый сигналом:
void ComboBox::Changed(const QString& s) {
std::cout << s << «n»;
}
int main(int argc, char **argv) {
QApplication app(argc, argv);
ComboBox* window = new ComboBox();
app.setMainWidget(window);
window->show();
return app.exec();
}
Вы сможете видеть вновь выбранные из редактируемого QComboBox
варианты в командной строке на рис. 17.6.
Рис. 17.6
Как это работает
Создаются виджеты раскрывающегося списка во многом так же, как и другие виджеты. Главная новая деталь – вызов функции insertStrList
для сохранения списка вариантов в виджете.
Как и в других содержащих текст виджетах, можно задать функцию, которая будет вызываться каждый раз при изменении значения или в общем случае текста раскрывающегося списка.