Урок №10. Виджеты в Qt5

  Дмитрий Бушуев  | 

  |

  Обновл. 16 Сен 2021  | 

 37865

 ǀ   15 

Виджеты в Qt5 — это «строительные блоки» для создания пользовательского интерфейса. Визуальные объекты на форме, такие как кнопки, метки, поля, меню, раскрывающиеся списки и т.д. — всё это относится к виджетам.

На этом уроке мы рассмотрим следующие виджеты в Qt5:

   QLabel;

   QSlider;

   QComboBox;

   QSpinBox;

   QLineEdit;

   QMainWindow.

Виджет QLabel

Виджет QLabel используется для отображения текста или изображения. При этом стоит отметить, что у него не предусмотрено взаимодействие с пользователем. В следующем примере мы задействуем данный виджет для отображения в окне текстов песен.

Заголовочный файл — label.h:

Файл реализации — label.cpp:

Создаем виджет метки и устанавливаем для него определенный шрифт:

Основной файл программы — main.cpp:

Результат выполнения программы:


Виджет QSlider


Виджет QSlider представляет собой вертикальный или горизонтальный ползунок (слайдер). Он позволяет пользователю перемещать маркер ползунка вдоль горизонтальной или вертикальной линии и переводит положение ползунка в целочисленное значение в пределах допустимого диапазона.

В следующем примере у нас есть два виджета: слайдер и метка. Ползунок будет управлять числом, отображаемым в метке.

Заголовочный файл — slider.h:

Файл реализации — slider.cpp:

Создаем горизонтальный QSlider:

Далее подключаем сигнал valueChanged() к встроенному в метку слоту setNum(). Поскольку метод setNum() перегружен, то мы используем оператор static_cast для выбора корректного метода:

Основной файл программы — main.cpp:

Результат выполнения программы:


Виджет QComboBox

QComboBox — это виджет выбора, который отображает текущий элемент и может отображать выпадающий список выбираемых элементов. Список при этом может быть редактируемым, позволяя пользователю изменять каждый элемент в данном списке.

В следующем примере выбранный элемент из QComboBox будет отображаться в метке.

Заголовочный файл — combobox.h:

Файл реализации — combobox.cpp:

В QStringList хранятся данные QComboBox, а именно список названий дистрибутивов Linux:

Создаем QComboBox, а затем с помощью метода addItems() добавляем в него элементы:

Сигнал activated() нашего QComboBox подключается к слоту setText() метки. Поскольку сигнал перегружен, то мы делаем статическое преобразование данных при помощи оператора static_cast:

Основной файл программы — main.cpp:

Результат выполнения программы:


Виджет QSpinBox


QSpinBox — это виджет, который используется для обработки целых чисел и дискретных наборов значений. Данный виджет позволяет пользователю указать нужное значение либо вручную, либо кликая мышкой по кнопкам вверх/вниз, либо нажимая клавиши клавиатуры вверх/вниз для увеличения/уменьшения значения, отображаемого в текущий момент.

В следующей программе с помощью виджета QSpinBox мы можем выбирать число от 0 до 99. Выбранное в текущий момент значение отображается в метке.

Заголовочный файл — spinbox.h:

Файл реализации — spinbox.cpp:

Нам нужно выполнить конвертацию с помощью оператора static_cast дважды, потому что и сигнал, и слот перегружены:

Основной файл программы — main.cpp:

Результат выполнения программы:


Виджет QLineEdit

Виджет QLineEdit представляет собой редактор однострочного текста. Редактор строки позволяет пользователю вводить одну строку обычного текста и при этом использовать такие функции редактирования, как: отмена, повтор, вырезание, вставка, а также перетаскивание с помощью механизма drag-and-drop.

В следующем примере мы выведем три метки и три строки для редактирования, которые скомпонованы с помощью менеджера компоновки QGridLayout.

Заголовочный файл — ledit.h:

Файл реализации — ledit.cpp:

Основной файл программы — main.cpp:

Результат выполнения программы:


Строка состояния


Строка состояния (англ. «statusbar») — это панель, которая используется для отображения информации о состоянии приложения. Виджет Statusbar является частью виджета QMainWindow.

В следующем примере у нас есть две кнопки и одна строка состояния. При нажатии на кнопку будет отображаться соответствующее сообщение.

Заголовочный файл — statusbar.h:

Файл реализации — statusbar.cpp:

Виджет QFrame помещается в центральную область виджета QMainWindow. Центральную область может занимать только один виджет:

Мы создаем два виджета QPushButton и компонуем их вдоль горизонтальной линии. Родительским элементом кнопок является виджет frame:

Для отображения строки состояния мы вызываем метод statusBar() виджета QMainWindow:

Метод showMessage() отображает сообщение в строке состояния. Последний параметр указывает количество миллисекунд, в течение которых сообщение отображается в строке состояния:

Основной файл программы — main.cpp:

Результат выполнения программы:


Заключение

Как вы уже могли заметить, виджеты являются простым, но в то же время довольно мощным инструментом построения графической части приложений, созданных при помощи Qt5. На следующем уроке мы продолжим тему виджетов.

Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (40 оценок, среднее: 4,70 из 5)
Загрузка...

Комментариев: 15

  1. Finchi:

    Для пользователей Qt6:
    В QComboBox сигнал activated больше не является перегруженным, он имеет только одну версию, возвращающую из параметров только тип int:

    Для корректной работы примера из урока можно использовать сигналы:

    Разница между ними в том, что первый будет генерировать сигнал только когда вы изменили значение ComboBox, а второй если вы выбрали даже то же самое значение, которое было установлено. На данном примере эта разница заметна не будет, но нужно иметь ее ввиду при создании приложений.

    P.S. Спасибо автору и сайту за отличные уроки.

  2. Alex:

    Приветствую!

    Не могу понять, что есть userData = QVariant().
    Возможно ли хранит нужные пользовательские данные в элементе меню QComboBox?
    Добавляю AddItem func(text string, userData core.QVariant_ITF), все отображается.
    Но вот незадача: нужно при выборе элемента меню получать ID (НЕ ИНДЕКС) этого элемента, который я хочу хранить в userData.
    Ситуация следующая: есть список городов из openweather:

    В QComboBox я добавляю список из городов и стран : Novyi Svit UA.
    При сигнале activated на Novyi Svit UA нужно получать 8224454.

  3. Дмитрий:

    Добрый день.
    Подскажите для чего делать преобразование:

    если можно сделать так:

    1. Фото аватара Дмитрий Бушуев:

      >>Подскажите для чего делать преобразование […] QComboBox::textActivated […]

      Я не вижу в статье такого преобразования. А вот преобразование для QComboBox::activated — вижу. Выполняется оно вот для чего (опять-таки, цитата из статьи):

      "Сигнал activated() нашего QComboBox подключается к слоту setText() метки. Поскольку сигнал перегружен, то мы делаем статическое преобразование данных при помощи оператора static_cast:

      connect(combo, static_cast<void(QComboBox::*)(const QString &)>(&QComboBox::activated),
      label, &QLabel::setText);
      "

      1. Дмитрий:

        Вам не нравится замена устаревшего в Вашем примере &QComboBox::activated на textActivated это Вас смутило ? Так QT указывает, что Ваш пример устарел и рекомендует его поменять на textActivated. Но по существу на вопрос Вы так и не ответили, ответьте пожалуйста на вопрос.

        1. Фото аватара Дмитрий Бушуев:

          Сигнал QComboBox::activated является перегруженным и имеет прототип activated(int index), т.е. работает с числами. Мы же хотим потребовать от него, чтобы он работал со строками, т.е. как activated(const QString &). Для этого компилятору явно даём понять, что нужно вызывать именно функцию activated(const QString &), выполняя приведение функции с прототипом activated(int index) к прототипу activated(const QString &) с помощью оператора static_cast:
          static_cast<void(QComboBox::*)(const QString &)>(&QComboBox::activated)

          Чтобы было понятнее, советую прочитать:
          Урок №56. Оператор static_cast
          https://ravesli.com/urok-56-yavnoe-preobrazovanie-tipov-dannyh-operatory-casts/#toc-3

          Урок №104. Указатели на функции
          https://ravesli.com/urok-104-ukazateli-na-funktsii/
          ———————————————————————

          Теперь касаемо вашего тезиса о том, что я "по существу на вопрос так и не ответил".
          Давайте разберем ситуацию по-порядку. Вы берете ежа (функцию QComboBox::textActivated, о которой в статье вообще ни слова не упоминается), скрещиваете его с ужом (оператором static_cast) и спрашиваете (почему-то)меня "для чего вы их только что скрестили?". Ответ — вы скрестили их потому, что отошли от излагаемого в уроке материала, при это слабо понимая суть своих действий.

          Ключевых момента здесь два, а именно:
          1. Да, действительно, на данный момент сигнал QComboBox::activated помечен как "устаревший" (deprecated) и что вместо него рекомендуется использовать QComboBox::textActivated. Но это не значит, что надо бросать всё и вот прям здесь и сейчас переписывать код с QComboBox::activated на QComboBox::textActivated.
          Вообще говоря, метка "deprecated" означает, что помечаемый ею объект (функция, класс, переменная, что угодно) из последующих версий компилятора может быть изъят. Но сейчас то он есть! Более того, в данный момент я вполне успешно откомпилировал и запустил проект с примером про QComboBox на своей машине (Qt 5.15.2, MSVC 2019 x64; Qt Creator 4.14.2).

          2. Рекомендуемая замена (которую вы использовали) в лице QComboBox::textActivated не является перегруженной, "из коробки" имеет нужный нам прототип textActivated(const QString &text) и не требует выполнение приведения типа через оператор static_cast.

          Резюме:
          QComboBox::аctivated — перегруженный сигнал => требуется приведение через static_cast.
          QComboBox::textActivated — НЕ перегруженный сигнал => можно использовать напрямую
          Если уж решили лепить франкенштейна, отходя от материалов урока, то нужно явно про это указывать в своём вопросе.

        2. Фото аватара Юрий:

          Ваши комментарии удаляю я. На ваш вопрос ответили и все ваши последующие комментарии, которые не несут в себе ни сути, ни пользы — будут удалены.

  4. Сергей:

    Для примера "Виджет QComboBox", в файле combobox.cpp не прошла "Сборка -> Запустить". Строки

    пришлось заменить на

    и тогда все получилось.
    Спасибо за Ваши материалы!

  5. Алексей:

    Здравствуйте , подскажите пожалуйста по поводу перегруженных сигналов и слотов.
    Насколько я понял из документации сейчас предпочтительнее использовать QOverload?
    Так же не совсем понятно, почему мы приводим к указателю на функцию?
    Сигнал подключается к указателю на функцию и мы передаём указатель слоту?
    Запутался, помогите)

  6. Александр:

    Теперь, кажется, понял.
    Видим, что нам нужен SetNum >>>>> смотрим его в документации и видим, что есть 2 варианта in и double а нам нужен int.

    Просто сама запись static_cast как-то ускользает. Понятно, когда вот так:
    int i = 49;
    char ch = static_cast<char>(i);
    А тут преобразовать в указатель на функцию..

  7. Александр:

    Добрый день!
    В примере с виджетом QSlider
    в файле slider.cpp
    нехватает мозга понять последнюю строку несмотря на разъяснения.

    отправитель, сигнал,получатель, и вот последний параметр в коннект
    static_cast<void (QLabel::*)(int)>(&QLabel::setNum) что он делает?
    Преобразует в "void (QLabel::*)(int)" значение "(&QLabel::setNum)"
    Т.е. сам static_cast тут непонятен..

    1. Фото аватара Дмитрий Бушуев:

      Добрый!
      Смотрите, в самой статье уже идет подсказка:
      >"Поскольку метод setNum() перегружен, мы используем оператор static_cast для выбора корректного метода"

      …ага, если метод перегружен, значит есть и другие? Тогда идем в оф. доки по Qt, смотрим описание класса QLabel (https://doc.qt.io/qt-5/qlabel.html) и видим там две функции setNum():
      >void setNum(double num)
      >void setNum(int num)

      …теперь возвращаемся к строчке с "connect…". Как она работает? Да очень просто — она связывает источник сигнала — slider, сам сигнал — &QSlider::valueChanged, приемник сигнала — label и метод, которым этот сигнала будет обработан (т.е. слот) — функция setNum()…. эмм… а…. а у нас же их две, какая из них должна вызываться? Вот чтобы явно указать, что нам нужен вот такой вариант функции — setNum(int num) — мы и используем вариант приведения к функции void (QLabel::*)(int) через static_cast.

      Ведь что такое — void (QLabel::*)(int)? Это указатель на функцию-элемент класса QLabel, которая принимает в качестве аргумента одну переменную типа int и возвращает void. А такому прототипу соответствует только функция void QLabel::setNum(int num). Тем самым мы ясно дали понять, что хотим использовать в качестве слота (или по-простому — обработчика события) именно её, а не похожую функцию void setNum(double num).
      🙂

      1. Jane:

        Добрый день. Можете дать ссылку, где в С++ рассказывается про подобное применение static_cast<>? Хотелось бы подробнее вникнуть.

        1. Фото аватара Дмитрий Бушуев:

          Добрый.
          Я пользовался этой темой:
          https://ravesli.com/urok-56-yavnoe-preobrazovanie-tipov-dannyh-operatory-casts/#toc-3

      2. Jane:

        Спасибо за ссылку на static_cast<>

Добавить комментарий для Alex Отменить ответ

Ваш E-mail не будет опубликован. Обязательные поля помечены *