На этом уроке мы продолжим говорить о виджетах в Qt5 (первая часть о виджетах в Qt5). Рассматривать будем следующие виджеты:
QCheckBox
;
QListWidget
;
QProgressBar
;
QPixmap
;
QSplitter
;
QTableWidget
.
Виджет QCheckBox
QCheckBox — это виджет чекбокса (англ. «checkbox»), состоящий из ячейки и подписи к ней. QCheckBox
имеет 2 состояния: включено или выключено. При включенном состоянии, внутри ячейки отображается флажок (галочка или крестик), при выключенном — ничего.
В следующем примере мы выведем в окне виджет чекбокса. Если у чекбокса установлен флажок, то будет выводиться заголовок окна, в противном случае заголовок окна будет скрыт.
Заголовочный файл — checkbox.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#pragma once #include <QWidget> class CheckBox : public QWidget { Q_OBJECT public: CheckBox(QWidget *parent = 0); private slots: void showTitle(int); }; |
Выводим чекбокс в окне и подключаем его к слоту showTitle().
Файл реализации — checkbox.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
#include <QCheckBox> #include <QHBoxLayout> #include "checkbox.h" CheckBox::CheckBox(QWidget *parent) : QWidget(parent) { QHBoxLayout *hbox = new QHBoxLayout(this); QCheckBox *cb = new QCheckBox("Show Title", this); cb->setCheckState(Qt::Checked); hbox->addWidget(cb, 0, Qt::AlignLeft | Qt::AlignTop); connect(cb, &QCheckBox::stateChanged, this, &CheckBox::showTitle); } void CheckBox::showTitle(int state) { if (state == Qt::Checked) { setWindowTitle("QCheckBox"); } else { setWindowTitle(" "); } } |
Флажок устанавливается во время запуска программы:
1 |
cb->setCheckState(Qt::Checked); |
Определяем состояние флажка и вызываем метод setWindowTitle():
1 2 3 4 5 6 7 8 |
void CheckBox::showTitle(int state) { if (state == Qt::Checked) { setWindowTitle("QCheckBox"); } else { setWindowTitle(" "); } } |
Основной файл программы — main.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <QApplication> #include "checkbox.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); CheckBox window; window.resize(250, 150); window.setWindowTitle("QCheckBox"); window.show(); return app.exec(); } |
Результат выполнения программы:
Виджет QListWidget
QListWidget — это виджет, который используется для отображения списка элементов в Qt5. В нашем примере мы покажем, как добавлять, переименовывать и удалять элементы из данного виджета.
В следующем примере присутствуют виджет списка и четыре кнопки. Кнопки используются для добавления, переименования и удаления элементов из виджета списка.
Заголовочный файл — listwidget.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#pragma once #include <QWidget> #include <QPushButton> #include <QListWidget> class ListWidget : public QWidget { Q_OBJECT public: ListWidget(QWidget *parent = 0); private slots: void addItem(); void renameItem(); void removeItem(); void clearItems(); private: QListWidget *lw; QPushButton *add; QPushButton *rename; QPushButton *remove; QPushButton *removeAll; }; |
Файл реализации — listwidget.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
#include "listwidget.h" #include <QVBoxLayout> #include <QInputDialog> ListWidget::ListWidget(QWidget *parent) : QWidget(parent) { QVBoxLayout *vbox = new QVBoxLayout(); vbox->setSpacing(10); QHBoxLayout *hbox = new QHBoxLayout(this); lw = new QListWidget(this); lw->addItem("The Omen"); lw->addItem("The Exorcist"); lw->addItem("Notes on a scandal"); lw->addItem("Fargo"); lw->addItem("Capote"); add = new QPushButton("Add", this); rename = new QPushButton("Rename", this); remove = new QPushButton("Remove", this); removeAll = new QPushButton("Remove All", this); vbox->setSpacing(3); vbox->addStretch(1); vbox->addWidget(add); vbox->addWidget(rename); vbox->addWidget(remove); vbox->addWidget(removeAll); vbox->addStretch(1); hbox->addWidget(lw); hbox->addSpacing(15); hbox->addLayout(vbox); connect(add, &QPushButton::clicked, this, &ListWidget::addItem); connect(rename, &QPushButton::clicked, this, &ListWidget::renameItem); connect(remove, &QPushButton::clicked, this, &ListWidget::removeItem); connect(removeAll, &QPushButton::clicked, this, &ListWidget::clearItems); setLayout(hbox); } void ListWidget::addItem() { QString c_text = QInputDialog::getText(this, "Item", "Enter new item"); QString s_text = c_text.simplified(); if (!s_text.isEmpty()) { lw->addItem(s_text); int r = lw->count() - 1; lw->setCurrentRow(r); } } void ListWidget::renameItem() { QListWidgetItem *curitem = lw->currentItem(); int r = lw->row(curitem); QString c_text = curitem->text(); QString r_text = QInputDialog::getText(this, "Item", "Enter new item", QLineEdit::Normal, c_text); QString s_text = r_text.simplified(); if (!s_text.isEmpty()) { QListWidgetItem *item = lw->takeItem(r); delete item; lw->insertItem(r, s_text); lw->setCurrentRow(r); } } void ListWidget::removeItem() { int r = lw->currentRow(); if (r != -1) { QListWidgetItem *item = lw->takeItem(r); delete item; } } void ListWidget::clearItems(){ if (lw->count() != 0) { lw->clear(); } } |
Создаем QListWidget и заполняем его пятью элементами:
1 2 3 4 5 6 |
lw = new QListWidget(this); lw->addItem("The Omen"); lw->addItem("The Exorcist"); lw->addItem("Notes on a scandal"); lw->addItem("Fargo"); lw->addItem("Capote); |
Добавление нового элемента в виджет списка выполняется с помощью метода addItem():
данный метод открывает диалоговое окно ввода, которое возвращает строковое значение;
затем мы удаляем возможные символы пробела из строки с помощью метода simplified();
метод QString::simplified()
возвращает строку, в которой символы пробела удалены в начале и в конце, а все неодиночные пробелы, находящиеся внутри строки, заменены одиночными;
если возвращаемая строка не пуста, то мы добавляем её в конец виджета списка;
наконец, выделяем текущий добавленный элемент с помощью метода setCurrentRow().
Код:
1 2 3 4 5 6 7 8 9 10 11 12 |
void ListWidget::addItem() { QString c_text = QInputDialog::getText(this, "Item", "Enter new item"); QString s_text = c_text.simplified(); if (!s_text.isEmpty()) { lw->addItem(s_text); int r = lw->count() - 1; lw->setCurrentRow(r); } } |
Переименование элемента состоит из нескольких шагов:
сначала мы получаем текущий элемент списка и номер строки, в которой он находится, с помощью метода currentItem();
текст элемента отображается в диалоговом окне QInputDialog
. Строка, возвращаемая из диалогового окна, для удаления потенциальных символов пробела обрабатывается методом simplified();
затем мы извлекаем старый элемент с помощью метода takeItem() и заменяем его на другой элемент с помощью метода insertItem();
затем удаляем элемент, извлеченный методом takeItem() (поскольку извлеченные элементы больше не управляются Qt, то это нужно сделать «ручками»);
наконец, при помощи метода setCurrentRow(), устанавливаем новый текущий элемент.
Код:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
void ListWidget::renameItem() { QListWidgetItem *curitem = lw->currentItem(); int r = lw->row(curitem); QString c_text = curitem->text(); QString r_text = QInputDialog::getText(this, "Item", "Enter new item", QLineEdit::Normal, c_text); QString s_text = r_text.simplified(); if (!s_text.isEmpty()) { QListWidgetItem *item = lw->takeItem(r); delete item; lw->insertItem(r, s_text); lw->setCurrentRow(r); } } |
Удаление определенного элемента из списка осуществляется с помощью метода removeItem(). Сначала мы получаем текущую строку с помощью метода currentRow() (он возвращает -1
, если строк больше не осталось), затем текущий выбранный элемент извлекается с помощью метода takeItem():
1 2 3 4 5 6 7 8 9 10 |
void ListWidget::removeItem() { int r = lw->currentRow(); if (r != -1) { QListWidgetItem *item = lw->takeItem(r); delete item; } } |
Далее метод clear() удаляет все элементы из виджета списка:
1 2 3 4 5 6 |
void ListWidget::clearItems(){ if (lw->count() != 0) { lw->clear(); } } |
Основной файл программы — main.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <QApplication> #include "listwidget.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); ListWidget window; window.setWindowTitle("QListWidget"); window.show(); return app.exec(); } |
Результат выполнения программы:
Виджет QProgressBar
QProgressBar — это индикатор процесса (или «индикатор выполнения»), который используется для визуального представления пользователю хода выполнения определенного процесса/операции.
В следующем примере у нас присутствуют QProgressBar
и две кнопки. Одна из этих кнопок запускает таймер, который, в свою очередь, обновляет индикатор выполнения. Другая кнопка останавливает таймер.
Заголовочный файл — progressbar.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#pragma once #include <QWidget> #include <QProgressBar> #include <QPushButton> class ProgressBarEx : public QWidget { Q_OBJECT public: ProgressBarEx(QWidget *parent = 0); private: int progress; QTimer *timer; QProgressBar *pbar; QPushButton *startBtn; QPushButton *stopBtn; static const int DELAY = 200; static const int MAX_VALUE = 100; void updateBar(); void startMyTimer(); void stopMyTimer(); }; |
Файл реализации — progressbar.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
#include <QProgressBar> #include <QTimer> #include <QGridLayout> #include "progressbar.h" ProgressBarEx::ProgressBarEx(QWidget *parent) : QWidget(parent) { progress = 0; timer = new QTimer(this); connect(timer, &QTimer::timeout, this, &ProgressBarEx::updateBar); QGridLayout *grid = new QGridLayout(this); grid->setColumnStretch(2, 1); pbar = new QProgressBar(); grid->addWidget(pbar, 0, 0, 1, 3); startBtn = new QPushButton("Start", this); connect(startBtn, &QPushButton::clicked, this, &ProgressBarEx::startMyTimer); grid->addWidget(startBtn, 1, 0, 1, 1); stopBtn = new QPushButton("Stop", this); connect(stopBtn, &QPushButton::clicked, this, &ProgressBarEx::stopMyTimer); grid->addWidget(stopBtn, 1, 1); } void ProgressBarEx::startMyTimer() { if (progress >= MAX_VALUE) { progress = 0; pbar->setValue(0); } if (!timer->isActive()) { startBtn->setEnabled(false); stopBtn->setEnabled(true); timer->start(DELAY); } } void ProgressBarEx::stopMyTimer() { if (timer->isActive()) { startBtn->setEnabled(true); stopBtn->setEnabled(false); timer->stop(); } } void ProgressBarEx::updateBar() { progress++; if (progress <= MAX_VALUE) { pbar->setValue(progress); } else { timer->stop(); startBtn->setEnabled(true); stopBtn->setEnabled(false); } } |
QTimer
используется для управления виджетом QProgressBar
:
1 2 |
timer = new QTimer(this); connect(timer, &QTimer::timeout, this, &ProgressBarEx::updateBar); |
Создадим экземпляр QProgressBar
. Минимальное и максимальное значения по умолчанию указываются в диапазоне от 0
до 100
:
1 |
pbar = new QProgressBar(); |
В зависимости от состояния индикатора выполнения кнопки могут быть включены или выключены. Эта возможность реализуется с помощью метода setEnabled():
1 2 3 4 5 6 |
if (!timer->isActive()) { startBtn->setEnabled(false); stopBtn->setEnabled(true); timer->start(DELAY); } |
Ход выполнения операции сохраняется в переменной progress
. Метод setValue() обновляет текущее значение индикатора выполнения:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
void ProgressBarEx::updateBar() { progress++; if (progress <= MAX_VALUE) { pbar->setValue(progress); } else { timer->stop(); startBtn->setEnabled(true); stopBtn->setEnabled(false); } } |
Основной файл программы — main.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <QApplication> #include "progressbar.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); ProgressBarEx window; window.resize(250, 150); window.setWindowTitle("QProgressBar"); window.show(); return app.exec(); } |
Результат выполнения программы:
Виджет QPixmap
Виджет QPixmap используется для работы с изображениями. Он оптимизирован для показа изображений на экране.
В следующем примере мы выведем на экран изображение знаменитого Бойницкого замка, расположенного в центральной части Словакии.
Заголовочный файл — pixmap.h:
1 2 3 4 5 6 7 8 9 |
#pragma once #include <QWidget> class Pixmap : public QWidget { public: Pixmap(QWidget *parent = 0); }; |
Файл реализации — pixmap.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <QPixmap> #include <QLabel> #include <QHBoxLayout> #include "pixmap.h" Pixmap::Pixmap(QWidget *parent) : QWidget(parent) { QHBoxLayout *hbox = new QHBoxLayout(this); QPixmap pixmap("bojnice.jpg"); QLabel *label = new QLabel(this); label->setPixmap(pixmap); hbox->addWidget(label, 0, Qt::AlignTop); } |
Мы создаем pixmap
— пространство, в которое поместим наше растровое изображение. Затем созданный pixmap
мы помещаем в виджет метки:
1 2 3 4 |
QPixmap pixmap("bojnice.jpg"); QLabel *label = new QLabel(this); label->setPixmap(pixmap); |
Основной файл программы — main.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <QApplication> #include "pixmap.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); Pixmap window; window.setWindowTitle("QPixmap"); window.show(); return app.exec(); } |
Результат выполнения программы:
Виджет QSplitter
Виджет QSplitter позволяет пользователю управлять размером дочерних виджетов, перетаскивая границу между дочерними элементами.
В следующем примере мы рассмотрим три виджета QFrame
, организованных с помощью двух сплиттеров (или «разделителей»).
Заголовочный файл — splitter.h:
1 2 3 4 5 6 7 8 9 |
#pragma once #include <QWidget> class Splitter : public QWidget { public: Splitter(QWidget *parent = 0); }; |
Файл реализации — splitter.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#include <QFrame> #include <QSplitter> #include <QHBoxLayout> #include "splitter.h" Splitter::Splitter(QWidget *parent) : QWidget(parent) { QHBoxLayout *hbox = new QHBoxLayout(this); QFrame *topleft = new QFrame(this); topleft->setFrameShape(QFrame::StyledPanel); QFrame *topright = new QFrame(this); topright->setFrameShape(QFrame::StyledPanel); QSplitter *splitter1 = new QSplitter(Qt::Horizontal, this); splitter1->addWidget(topleft); splitter1->addWidget(topright); QFrame *bottom = new QFrame(this); bottom->setFrameShape(QFrame::StyledPanel); QSplitter *splitter2 = new QSplitter(Qt::Vertical, this); splitter2->addWidget(splitter1); splitter2->addWidget(bottom); QList<int> sizes({50, 100}); splitter2->setSizes(sizes); hbox->addWidget(splitter2); } |
Создаем виджет splitter1
и добавляем в него два виджета frame
:
1 2 3 |
QSplitter *splitter1 = new QSplitter(Qt::Horizontal, this); splitter1->addWidget(topleft); splitter1->addWidget(topright); |
Мы также можем добавить один сплиттер к другому сплиттеру:
1 2 |
QSplitter *splitter2 = new QSplitter(Qt::Vertical, this); splitter2->addWidget(splitter1); |
С помощью метода setSizes() устанавливаем размер дочерних виджетов сплиттера:
1 2 |
QList<int> sizes({50, 100}); splitter2->setSizes(sizes); |
Основной файл программы — main.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#include <QDesktopWidget> #include <QApplication> #include "splitter.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); Splitter window; window.resize(350, 300); window.setWindowTitle("QSplitter"); window.show(); return app.exec(); } |
Результат выполнения программы:
Примечание: В некоторых темах рабочего стола сплиттер может быть не очень хорошо виден.
Виджет QTableWidget
QTableWidget — это уникальный виджет, используемый в приложениях для работы с электронными таблицами (его еще называют «виджетом сетки»). Это один из самых сложных виджетов.
В следующем примере мы создадим таблицу с помощью виджета QTableWidget
и выведем её на экран.
Заголовочный файл — table.h:
1 2 3 4 5 6 7 8 9 |
#pragma once #include <QWidget> class Table : public QWidget { public: Table(QWidget *parent = 0); }; |
Файл реализации — table.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#include <QHBoxLayout> #include <QTableWidget> #include "table.h" Table::Table(QWidget *parent) : QWidget(parent) { QHBoxLayout *hbox = new QHBoxLayout(this); QTableWidget *table = new QTableWidget(25, 25, this); hbox->addWidget(table); } |
Создаем виджет таблицы с 25-ю строками и 25-ю столбцами:
1 |
QTableWidget *table = new QTableWidget(25, 25, this); |
Основной файл программы — main.cpp:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <QApplication> #include "table.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); Table window; window.resize(400, 250); window.setWindowTitle("QTableWidget"); window.show(); return app.exec(); } |
Результат выполнения программы:
Заключение
На следующих уроках мы познакомимся с возможностью рисования в Qt5, попробуем нарисовать примитивные фигуры такие, как линии, прямоугольники и т.п., а также другие геометрические фигуры, но уже со сложной произвольной формой. Также рассмотрим различные способы раскраски этих фигур (при помощи стандартного цвета, градиента или с использованием заданного шаблона).
при создании виджетов мы указываем предка (this). а при добавлении его в grid предком становится grid ? если так , зачем указывать this при создании?
>>при добавлении его в grid предком становится grid ?
Почти. При добавлении виджета в grid, предком становится тот виджет, в котором этот grid установлен. Более того, предком для виджета может быть только другой виджет, а не компоновка.
>>если так , зачем указывать this при создании?
Можно и не указывать. В данном случае вы полностью свободны в своём выборе 🙂
Спасибо. Очень интересные лекции.
Дмитрий, огромное Спасибо за помощь!
Все получилось, помог второй совет, с указанием полного пути к файлу в коде программы, и где надо было обязательно вставить двойные слэши (а у меня были одинарные).
Уточнение:
Qt Creator 3.5.1 (opensource)
Основан на Qt 5.5.1 (MSVC 2013, 32 бита)
Собрано Oct 13 2015 в 07:38:22
Ревизия e548635a24
Пробовал запустить Ваш проект "Виджет QPixmap", но картинка в метку не вставляется, т.е. все вроде работает но без картинки. Пробовал вывести разные jpg-файлы, но все без результата. Во время исполнения выдается сообщение "setGeometryDp: Unable to set geometry 27×35+640+282 on QWidgetWindow/'QWidgetClassWindow'. Resulting geometry: 137×35+640+282 (frame: 4, 40, 4, 4, custom margin: 0, 0, 0, 0, minimum size: 27×35, maximum size: 16777215×16777215)."
Работаю под Windows XP, в Qt Creator 3.5.1 (opensource).
Можете что-то посоветовать, бьюсь уже несколько дней с разными текстами программ из разных источников, все запускается, но результата вывода jpg-картинок нет. До этого работал с Qt3, там много графики, а сейчас хочу перейти на Qt5….
Ваша программа просто не находит файл с картинкой. Если вы запускаете ваше приложение из Qt Creator'а, то необходимо:
1.Откройте папку, в которой находится скомпилированная версия вашего приложения. У меня это "build-НАЗВАНИЕ_ПРОЕКТА-Desktop_Qt_5_15_0_MSVC2019_32bit-Debug". У вас скорее всего будет что-то похожее на… "build-НАЗВАНИЕ_ПРОЕКТА-Desktop_Qt_5_5_1_MSVC2013_32bit-Debug".
2. Скопировать в неё ваш файл с картинкой (проверьте, чтобы имя файла совпадало с именем, прописанным в коде программы).
Либо же можете напрямую задать путь к вашему файлу с картинкой непосредственно в коде программы. В моём случае это выглядит вот так (не забудьте про двойные слэши):
"C:\\Coding\\C++\\Qt\\build-untitled4-Desktop_Qt_5_15_0_MSVC2019_32bit-Debug\\bojnice.jpg"