Как редактировать ui файл в qt

Обновлено: 05.07.2024

Если в двух предыдущих частях этого цикла было многовато абстрактных понятий, то теперь мы займемся вещами конкретными и красивыми. До сих пор наши программы-примеры обходились без одной важной вещи, без которой ни одна серьезная программа обойтись не может без главного окна. На этот раз мы создадим главное окно и для этого заново познакомимся с Qt Designer.

Qt Designer старый новый друг

Вы наверняка обратили внимание, что в Qt версии 3 Qt Designer выступал в роли своего рода полу-IDE. Помимо самого визуального редактора в нем присутствовал генератор проектов и собственный редактор кода, который позволял, например, редактировать текст методов-слотов. В Qt 4 разработчики решительно пересмотрели функции Qt Designer. Теперь этот инструмент предназначен исключительно для визуального редактирования. Редактор текста и генератор проектов из нового Qt Designer удалены. Объясняется это тем, что, по мнению разработчиков, генерация проектов и редактирование текстов программ должны целиком переместиться в IDE, такие, например, как KDevelop или Microsoft Visual Studio, а Qt Designer (который интегрируется c указанными IDE) будет выполнять функцию вспомогательного инструмента. Впрочем, версия KDevelop, поддерживающая Qt Designer 4, есть пока далеко не у всех, а продукт Microsoft нас и вовсе не касается, поэтому мы рассмотрим работу с Qt Designer 4, как с самостоятельным средством. Лично мне в новом дизайнере не понравилось то, что он представляет собой набор независимых друг от друга окон (наподобие Glade). Возможно, такая структура упрощает встраивание Qt Designer в другие программные среды, но при работе с самим дизайнером постоянно переключаться между окнами не очень удобно.

При запуске Qt Designer 4 нас встречает диалоговое окно выбора заготовки для формы, которую мы будем редактировать. Можно создать новую форму или открыть уже существующую. В списке заготовок форм всего 4 пункта, из которых мы выбираем пункт Main Window (рис. 1).

Qt Designer

Рисунок 1. Окно выбора формы Qt Designer

Само главное окно Qt-приложения (класс QMainWindow) также претерпело немало изменений. Теперь панели инструментов (объекты класса QToolBar) и стыкуемые окна (объекты класса QDockWidget) реализованы независимо друг от друга. Принципы работы с главным меню тоже несколько изменились (мы рассмотрим все это ниже). Пока что выберем в приветственном окне Qt Designer форму главного окна и щелкнем кнопку Create. Появится форма с заготовкой меню и строки состояния. Мы добавим в эту форму компонент QFrame, сделаем так, чтобы соответствующий объект заполнял всю форму (команда Lay Out Vertically контекстного меню) и сохраним форму в файле mainform.ui.

Для нашей первой программы с полноценным главным окном нам, разумеется, понадобится функция main(). Вот она:

Эта простенькая функция демонстрирует много не очень заметных, но существенных отличий Qt 4 от Qt 3. Мы начнем разбирать ее с заголовочных файлов. Включение заголовочных файлов QApplication и QMainWindow не должно вызывать вопросов. А вот откуда взялся файл ui_mainform.h? Этот файл должен описывать форму, созданную нами в визуальном редакторе, на языке C++. Иначе говоря, файл ui_mainform.h генерируется на основе данных, содержащихся в файле mainform.ui. Но чем его генерировать? В Qt3 нечто подобное создавалось автоматически программой Qt Designer (в Qt 3 этот файл назывался бы mainform.ui.h), но Qt Designer 4 не генерирует сам никаких исходных текстов. Мы можем возложить эту задачу на утилиту qmake. Тут возникает одна неуклюжесть. Обычно мы сначала пишем функцию main(), а затем вызываем такие инструменты как qmake. Но функция main() нуждается в файле ui_mainform.h, который только будет создан qmake. Я включил ссылку на файл ui_mainform.h в текст файла main.cpp, поскольку знал, что такой файл у нас появится (схему построения имен файлов с объявлением класса формы разгадать нетрудно имя состоит из префикса ui_, имени файла, в котором вы сохранили форму, и расширения .h). Если вы не уверены в том, как будет называться созданный автоматически заголовочный файл, можете сначала запустить qmake, а потом редактировать файл main.cpp. После этого qmake, конечно, придется запускать еще раз.

В файле ui_mainform.h определено пространство имен Ui, а в нем класс MainWindow (так по умолчанию назван класс, соответствующий форме главного окна). В функции main() мы создаем (статически) объект этого класса. Если вы думаете, что класс MainWindow происходит от QMainWindow, то ошибаетесь. На самом деле этот класс, описывающий интерфейс нашей программы, вообще не является потомком QWidget. Можно сказать, что класс MainWindow содержит инструкции по построению интерфейса, предназначенные для объекта класса QMainWindow. Объект этого класса мы и создаем далее в нашей программе. Метод mainWindow.setupUi() настраивает внешний вид объекта QMainWindow, в том числе, создает и настраивает дочерние элементы главного окна, которые мы определили в процессе редактирования формы.

Выполнив команды qmake project и qmake, мы можем собрать нашу программу с помощью make. В результате у нас получается главное окно с пустой формой в клиентской области. Конечно, на этом этапе наша программа выглядит не очень привлекательно, но она послужит холстом, на котором мы будем творить шедевры.

Графическая система Arthur

Хотя изменения графической системы Qt 4 по сравнению с Qt 3 не очень заметны на первый взгляд, новая система предоставляет весьма широкие возможности. Напомню, что основные функции работы с графикой в Qt 3 были реализованы в классе QPainter, который изначально предназначался для вывода графики в растровые массивы. Для поддержки подсистем вывода, не основанных на растровых массивах (например, принтеров PostScript) специальные объекты-потомки класса QPaintDevice эмулировали растровое устройство. В Qt 4 разработчики пошли более простым и логичным путем. Классы QPainter и QPaintDevice остались, но к ним добавился абстрактный класс QPaintEngine. Теперь все функции, реализующие специфику графического вывода на разных устройствах, собраны в классах-потомках QPaintEngine, соответствующих этим устройствам. Классы QPainter и QPaintDevice используют методы QPaintEngine для доступа к графическим устройствам, а не обращаются к этим устройствам напрямую, как раньше. Вам же, наоборот, не придется иметь дела с потомками QPaintEngine, если только вы не захотите расширить функциональность Qt 4, реализовав графический вывод на каком-нибудь неподдерживаемом устройстве. На практике это означает, что сладкая парочка QPainter и QPaintDevice теперь может рисовать практически на всех графических устройствах, доступных на данной платформе, причем работа с разными устройствами, будь то принтер или окно OpenGL, в значительной степени унифицирована. Еще одно преимущество новой системы заключается в том, что многие графические операции, которые раньше были реализованы чисто программными средствами, теперь могут использовать аппаратное ускорение и другие функции, поддерживаемые железом (раньше это было невозможно потому, что между QPainter и устройством лежала прослойка эмулятора растрового массива).

Посмотрим, как все это работает на практике. В качестве примера рассмотрим визуальный компонент QGLWidget. Благодаря новой архитектуре мы можем создавать изображения средствами QPainter в рабочем окне QGLWidget точно так же, как и на поверхности любого другого виджета. Не могу не отметить некоторую диалектичность процесса: когда-то я демонстрировал, как выводить графику OpenGL на поверхности объекта-потомка QWidget. Теперь мы воспользуемся QGLWidget для вывода обычных изображений, которые не являются частью трехмерных сцен. Такое использование OpenGL не по назначению отражает популярную в последнее время тенденцию задействовать мощь 3D-ускорителей в традиционно не-трехмерных задачах, например при отрисовке окон или работе с растровыми картинками.

Вернемся к программе с главным окном. Для того чтобы заставить наше главное окно что-то делать, нам следует создать его потомка. Посмотрим на объявление класса OGLWindow, который представляет собой главное окно программы arthur-demo (полный текст программы вы, как всегда, найдетепо ссылке в коце страницы).

Класс OGLWindow наследует сразу двум классам QMainWindow и Ui::MainWindow (второй из этих классов объявлен в файле ui_mainform.h. Что дает нам двойное наследование? Вернемся к функции main(), приведенной выше. Нам пришлось создать объект класса Ui::MainWindow для того, чтобы настроить внешний вид объекта QMainWindow. Для объекта класса OGLWindow дополнительных объектов создавать не придется, так как этот объект уже знает все, что нужно для построения его графического интерфейса. Ниже приводится текст конструктора OGLWindow:

Поскольку класс OGLWindow наследует классу Ui::MainWindow, метод setupUi() становится доступен в конструкторе OGLWindow. Мы вызываем этот метод и передаем ему в качестве параметра указатель this. Таким образом, объект класса OGLWindow сам настраивает свой интерфейс, а программисту, который захочет работать с нашим классом, не придется беспокоиться о вызове setupUi(). С классом GLWidget, производным от QGLWidget, мы познакомимся ниже. Объект frame представляет собой панель QFrame, которую мы добавили в форму главного окна в процессе визуального редактирования. Мы делаем объект класса GLWidget дочерним объектом этой панели.

Как вы, конечно, догадались, объект glWidget это визуальный компонент, предназначенный для вывода графики средствами OpenGL. Мы хотим, чтобы он занимал все пространство панели frame. Для этого мы создаем новый объект-менеджер компоновки класса QHBoxLayout, назначаем его в качестве текущего менеджера компоновки объекту frame (с помощью метода setLayout()) и добавляем в коллекцию менеджера объект glWidget. Самый простой способ заставить виджет QGLWidget выводить графическое изображение заключается в том, чтобы перекрыть метод paintEvent() в классе потомке QGLWidget. Именно для этого нам и нужен класс GLWidget. Наш вариант метода paintEvent() приводится ниже:

Рисование начинается с вызова метода begin() объекта painter() класса QPainter. Аргументом этого метода должен быть указатель на объект QPaintDevice, к каковому типу теперь приводится и объект класса QGLWidget (и, естественно, его потомки). Останавливаться на каждой инструкции вывода графики мы не будем. Обращу внимание читателей на поддержку сглаживания контуров, которую мы включаем с помощью вызова метода setRenderHint() и смешивания цветов alpha blending (обратите внимание на четвертый аргумент конструктора QColor()). Сглаживание и смешивание являются новыми возможностями QPainter и могут выполняться с использованием аппаратной поддержки (например, поддержки 3D-ускорителя), если аппаратная поддержка включена в вашей системе.

В приведенном выше примере я специально не использовал функции OpenGL (например, воспользовался методом eraseRect() вместо glClearColor()), чтобы показать, что в графической системе Arthur можно задействовать возможности OpenGL, не используя сами команды OpenGL. В результате один и тот же код может использоваться для вывода графики в окне с помощью 3D-ускорителя, для записи графики в растровое изображения или для вывода изображений на принтер PostScript.

Рассмотрим теперь функцию main() нашей программы. Наследование класса главного окна сразу от двух предков (QMainWindow и UI::MainWindow) позволило упростить код и этой функции:

Для того чтобы собрать программу успешно, в файле pro нужно включить поддержку модуля QtOpenGL:

Наиболее полно мощь OpenGL проявляется (помимо собственно 3D-графики), в тех приложениях, которым приходится выполнять различные преобразования изображений на экране. Возможность работы с QGLWidget как с обычным компонентом для вывода графики, позволяет, например, создать программу просмотра электронных фотографий, которая будет использовать аппаратно-ускоренные спецэффекты при показе изображений. При этом тот же самый код может быть использован, например, для сохранения результатов преобразований в растровом формате.


Рисунок 2. Arthur: не-трехмерная графика с помощью OpenGL

В заключение обзора этой программы (первой нашей программы, использующей главное окно) позволю себе дать вам один совет. Готовьтесь к тому, что при работе с главным окном (и другими окнами, спроектированными в Qt Designer 4) вам все время придется создавать их потомков. В Qt Designer 3 мы могли редактировать код обработчиков сигналов в процессе визуального редактирования. Qt Designer 4 тоже позволяет нам связывать сигналы и слоты и даже определять новые слоты, но, поскольку редактировать код в дизайнере все равно нельзя, лучше определять все новые слоты и связывать их с сигналами в классе-потомке того класса, который сгенерирован Qt Designer 4.

Пишем красиво

Система вывода форматированного текста претерпела в Qt 4 не меньше, а, пожалуй, даже больше изменений, чем система вывода графики. Основой для работы с текстовыми документами в новой системе вывода текста, получившей название Scribe, служит класс QTextDocument. Объект этого класса хранит всю информацию о структуре форматированного документа, а также предоставляет функции для его редактирования. Вы можете использовать класс QTextEdit для ручного редактирования текста, содержащегося в QTextDocument, и класс QTextBrowser для просмотра. Любопытно отметить, что хотя в документации к Qt 4 разработчики советуют использовать повсеместно объекты QTextDocument (а не QTextString) для хранения текста, у класса QTextEdit нет конструктора, которому можно было бы передать ссылку на объект QTextDocument, а вот конструктор со ссылкой на объект QString - есть. Для того чтобы назначить объекту класса QTextEdit объект класса QTextDocument, необходимо вызвать метод setDocument().

Важную роль в редактировании содержимого QTextDocument играет класс QTextCursor. Объекты QTextCursor используются как для указания текущей позиции в документе, так и для обозначения выбранных фрагментов текста. Кроме этого объекты QTextCursor предоставляют в распоряжение программиста ряд методов, предназначенных для редактирования текста и изменения форматирования, начиная с выбранной позиции.

Высшей единицей логической структуры документа QTextDocument является фрейм, представленный классом QTextFrame. Весь документ содержится в корневом фрейме (получить доступ к корневому фрейму можно с помощью метода rootFrame()). Перейти от корневого фрейма к дочерним фреймам можно с помощью метода childFrames() объекта QTextFrame (собственные фреймы положены таким элементам документа как таблица или изображение). На более низком уровне элементы документа представлены текстовыми блоками (объекты класса QTextBlock). Текстовым блоком в форматированном документе является любой массив текста, к символам которого применены одинаковые элементы форматирования (это может быть абзац, фраза или отдельное слово). Обычно программа получает доступ к текстовым блокам тогда, когда пользователь выделяет фрагмент текст или когда сама программа выделяет текстовый фрагмент по какому-либо признаку.

Работа со сложными документами не единственный козырь Scribe. Помимо прочего эта система позволяет выполнять фигурный вывод текста. Если вы хотите, чтобы вместо ровных полей слева и права выводимый вами текст был выровнен по контуру какой-нибудь сложной фигуры, воспользуйтесь классом QTextLayout. Класс QTextLayout управляет компоновкой неформатированного текста, то есть, текста, который выводится одним шрифтом. Объекты класса QTextLayout позволяют нам сделать две вещи: разбить текст на строки с учетом параметров выбранного шрифта и ширины каждой строки и задать расположение каждой строки относительно левого края виртуального листа. После этого вывести фигурно расположенный текст на экран (на принтер, или на другое устройство) можно одной командой.

В качестве демонстрации сложного расположения текста мы рассмотрим программу scribe-demo, полный исходный текст которой вы найдете на диске. Как и программа arthur-demo, наша новая программа добавляет в главное окно свой собственный виджет. На этот раз наш фирменный виджет реализуется классом Label. Класс Label происходит не от класса QLabel, а непосредственно от класса QWidget, ведь мы собираемся выводить текст нашими собственными средствами и функциональность класса QLabel нам ни к чему. Объявление класса Label выглядит просто:

В классе Label, как и в классе GLWidget, мы перекрываем метод paintEvent() класса-предка. Кроме того мы водим вспомогательный метод makeLayout(). Рассмотрим определения всех трех методов класса Label (конструктора, makeLayout() и paintEvent()).

В конструкторе Label мы создаем объект класса QTextLayout. Конструктору объекта textLayout передаются два аргумента ссылка на строку теста и ссылка на объект QFont, который определяет используемый шрифт. Все самое интересное сосредоточено в методе makeLayout(). Мы начинаем работу с компоновщиком текста с вызова метода beginLayout(). Для каждой строки выводимого текста мы создаем объект класса QTextLine с помощью метода createLine() объекта textLayout. Этот метод будет возвращать объекты QTextLine со значением isValid(), равным true, до тех пор, пока весь текст не будет распределен на строки (общее количество строк, разумеется, зависит от размеров шрифта и ширины каждой строки). Ширина строки устанавливается с помощью метода setLineWidth(), а ее позиция методом setPosition(). Для того, чтобы строки не наезжали друг на друга, мы смещаем отступ очередной строки от верхнего края на значение, равное высоте строки. В этом нам помогает метод height() объекта класса QTextLine. После того как создание и расположение строк закончены, мы вызываем метод endLayout().

Метод makeLayout создает своего рода шаблон, содержащий текст. Для вывода этого текста в виджет достаточно вызвать метод draw() объекта textLayout. Первым аргументом метода draw() должна быть ссылка на объект класса QPainter, вторым аргументом ссылка на объект QPoint, определяющий расположение левого верхнего угла той области, в которой выводится текст (фактическое расположение строк, заданное в методе makeLayout(), при выводе текста будет отсчитываться относительно этой точки).


Рисунок 3. Текст с полями в форме треугольника.

Обратите внимание на важную особенность QTextLayout. Каждый раз, когда мы вызываем метод beginLayout() информация о предыдущей компоновке текста (и всех созданных объектах QTextLine) теряется. Эта особенность может стать источником труднообъяснимых ошибок для новичка, но нам на позволяет создать объект класса QTextLayout один раз (в конструкторе Label), а затем использовать его многократно для генерации компоновок текста, зависящих от ширины виджета, в методе makeLayout(). В связи с этим любопытно отметь, что в релизе Qt 4.4 (на момент написания статьи он находился на стадии бета) у класса QTextLayout появился метод clearLayout (), который очищает список строк компоновщика текста. Лично я большой пользы от этого метода не вижу (разве что кому-то понадобится обнулить список строк между вызовами beginLayout() и endLayout()), а, учитывая то, что этот метод поддерживается не всеми релизами Qt 4, пользоваться им не советую.

На этом наше знакомство с изобразительными средствами Qt 4 не закончилось. В следующий раз мы познакомимся с системой Graphics View, которая появилась в Qt 4.2 и была серьезно дополнена и переработана в Qt 4.3 и Qt 4.4.

«Руководство разработчика Qt 5.9 C ++» Раздел 2.1. Дизайн и работа с UI-файлом [Полная версия]

2.1 Дизайн файла пользовательского интерфейса и механизм работы

2.1.1 Состав проектной документации

Создайте новый проект приложения виджетов samp2_1 в Qt Creator,На странице выбора базового класса окна (рисунок 1-8)Выберите QWidget в качестве базового класса формы и установите флажок «Создать форму». Созданное дерево каталогов файлов проекта показано на рисунке 2-1.


Рисунок 2-1 Дерево каталогов файлов проекта

Этот проект содержит следующие файлы:

● Файл организации проекта samp2_1.pro, в котором хранится файл настроек проекта.

● Основной файл записи программы main.cpp, программный файл, реализующий функцию main ().

● Файл интерфейса окна widget.ui, файл компонентов и их расположение в окне, хранящийся в формате XML.

● widget.h - это файл заголовка спроектированного класса окна, а widget.cpp - файл реализации определенного класса в widget.h. В C ++ любая форма или компонент интерфейса инкапсулируется классом.Класс обычно имеет файл заголовка (файл .h) и исходный файл (файл .cpp).

2.1.2 Документы по управлению проектом

Файл с суффиксом «.pro» - это файл управления проектом, а имя файла - это имя проекта, например samp2_1.pro в этом проекте. Ниже приводится содержимое файла samp2_1.pro.

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

«Qt + = core gui» означает, что в проект добавлен модуль coregui. Core gui - это модуль библиотеки классов, используемый Qt для проектирования графического интерфейса пользователя.Если вы создаете консольное приложение, вам не нужно добавлять основной графический интерфейс.

Библиотека классов Qt организует классы различных функций в виде модулей и добавляет в проект соответствующую поддержку модуля библиотеки классов в соответствии с функциональными требованиями, задействованными в проекте. Например, если в проекте используется класс, связанный с операциями с базой данных, необходимо использовать модуль sql и добавить в файл pro следующую строку:

Вторая строка в samp2_1.pro:

Это оператор условного выполнения, что означает, что модуль виджетов будет добавлен только тогда, когда основная версия Qt больше 4.

«TARGET = samp2_1» представляет имя сгенерированного целевого исполняемого файла, то есть исполняемого файла, созданного после компиляции, является samp2_1.exe.

«TEMPLATE = app» означает, что в проекте используется шаблон app, который является общим приложением.

Следующие ниже ИСТОЧНИКИ, ЗАГОЛОВКИ, ФОРМЫ записывают имена исходных файлов, файлов заголовков и файлов форм (файлов .ui), содержащихся в проекте. Эти списки файлов автоматически добавляются в файлы управления проектом Qt Creator, и пользователям не нужно изменять их вручную. При добавлении файла в проект или удалении файла из проекта запись в файле управления проектом будет автоматически изменена.

2.1.3 Интерфейсный файл

Файл с расширением «.ui» - это файл определения визуально оформленного окна, например widget.ui. Дважды щелкните файл widget.ui в дереве каталогов файлов проекта, чтобы открыть Qt Designer, интегрированный в Qt Creator, для визуального проектирования формы, как показано на рисунке 2-2.


Рисунок 2-2 UI-дизайнер, интегрированный в QtCreator

[Соглашение] Позже в этой книге этот Qt Designer, интегрированный в Qt Creator, будет называться «UI дизайнер», чтобы отличать его от автономного Qt Designer.

Дизайнер пользовательского интерфейса на рис. 2-2 имеет следующие функциональные области:

● Панель компонентов. В левой части окна находится панель компонентов дизайна интерфейса, которая разделена на несколько групп, таких как макеты, кнопки, виджеты дисплея и т. Д. Общие компоненты дизайна интерфейса можно найти на панели компонентов.

● Основная область посередине - это окно, которое нужно спроектировать. Если вы хотите разместить компонент на форме, перетащите компонент с панели компонентов на форму. Например, сначала поместите в форму метку и кнопку.

● Редактор сигналов и слотов и редактор действий - это два редактора, расположенные под формой, которую необходимо разработать. Редактор сигналов и слотов используется для визуального связывания сигналов и слотов, а редактор действий используется для визуального проектирования действий.

● Панель инструментов макета и дизайна интерфейса. Панель инструментов в верхней части окна. Кнопки на панели инструментов в основном реализуют макет и дизайн интерфейса.

● Инспектор объектов (обозреватель объектов). В правом верхнем углу окна находится инспектор объектов, который использует древовидное представление для отображения взаимосвязи включения макета между компонентами в форме.Представление имеет два столбца, в которых отображается ObjectName (имя объекта) и имя класса каждого компонента.

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

На рис. 2-3 показано содержимое редактора свойств после выбора компонента метки, помещенного в форму. Текст «LabDemo: QLabel», отображаемый вверху, указывает, что этот компонент является компонентом QLabel, а имя объекта - LabDemo. Содержимое редактора свойств разделено на два столбца: столбец «Свойство» - это имя свойства, а столбец «Значение» - это значение свойства. Атрибуты разделены на несколько групп, которые фактически представляют отношение наследования класса.Например, на рисунке 2-3 можно увидеть, что отношение наследования QLabel - это QObject -> QWidget -> QFrame -> QLabel.


Рисунок 2-3 Редактор свойств компонентов интерфейса

objectName представляет имя объекта компонента, и каждому компоненту в интерфейсе необходимо уникальное имя объекта, чтобы на него можно было ссылаться. Именование компонентов в интерфейсе должно соответствовать определенным правилам. Конкретные используемые правила именования зависят от личных привычек. Основная цель - облегчить различение и запоминание, а также отличить его от обычных переменных.

Вам нужно только установить значения других атрибутов в редакторе атрибутов.Например, чтобы установить текстовый атрибут LabDemo на «Hello, World», вам нужно только изменить значение текстового атрибута, как показано на рисунке 2-3.

[Подсказка] В стандартном языке C ++ ключевого слова свойства нет .. Свойство - это расширение Qt до стандартного C ++, которое позволяет визуально устанавливать данные класса в Qt Designer.

На форме дизайна на Рисунке 2-2 разместите компоненты Label и Push Button, значения основных атрибутов которых показаны в Таблице 2-1.

Таблица 2-1 Настройки свойств компонентов интерфейса

Установить текст и шрифт отображения метки

Установите текст кнопки

После редактирования свойств добавьте к кнопке btnClose функцию, которая должна закрыть окно и выйти из программы при нажатии этой кнопки. Используйте редактор сигналов и слотов для выполнения этой функции, как показано на рисунке 2-4.


Рисунок 2-4 Связь проектных сигналов и слотов в редакторе сигналов и слотов


Рисунок 2-5 Программа «Hello World» с кнопкой «Закрыть»

2.1.4 Главный файл функций

main.cpp - это файл, который реализует функцию main (). Ниже показано содержимое файла main.cpp.

QApplication - это стандартный класс приложения Qt.В первой строке кода определяется экземпляр a класса QApplication, который является объектом приложения.

Затем определяется переменная w класса Widget. Widget - это имя класса окна, созданного в этом примере. После определения этого окна используйте w.show () для отображения этого окна.

2.1.5 Файлы, связанные с формами

Чтобы уточнить определение класса формы и принцип реализации интерфейсной функции, скомпилируйте проект. После компиляции в каталоге проекта будет автоматически сгенерирован файл ui_widget.h, поэтому для окна имеется 4 файла, а описание функции каждого файла показано в таблице 2-2.

Таблица 2-2 4 файла, связанных с формой

Заголовочный файл, который определяет класс окна, определяет класс Widget

Исходный программный файл реализации функции класса виджета

Файл интерфейса формы, который автоматически создается дизайнером пользовательского интерфейса, хранит настройки атрибутов и макет каждого компонента в форме.

После компиляции автоматически создается файл определения класса на основе компонентов и их атрибутов в форме, ассоциации сигналов и слотов и т. Д. Имя класса - Ui_Widget

Далее анализируется содержимое и функции каждого файла, а также то, как они работают вместе для создания и отображения интерфейса.

1. файл widget.h

Файл widget.h - это файл заголовка класса формы. При создании проекта базовым классом выбранной формы является QWidget, а класс Widget, унаследованный от QWidget, определяется в widget.h. Ниже приводится содержимое файла widget.h.


Файл widget.h состоит из нескольких важных частей.

(1) объявление пространства имен

В коде есть объявление пространства имен, как показано ниже:

Это необходимо для объявления пространства имен с именем Ui, которое содержит класс Widget. Но этот класс Widget не является классом Widget, определенным в этом файле, а классом, определенным в файле ui_widget.h, который используется для описания компонентов интерфейса. Это объявление эквивалентно объявлению внешнего типа (в частности, вы можете понять его, прочитав объяснение в файле ui_widget.h).

(2) Определение класса Widget. Основная часть файла widget.h - это определение класса Widget, унаследованного от QWidget, который является классом формы в этом примере.

Макрос Q_OBJECT используется в классе Widget, который является макросом, который должен быть добавлен к классам, которые используют механизм сигналов и слотов Qt (сигналы и слоты подробно описаны позже).

Определите конструктор и деструктор класса Widget в публичной части 。

Указатель определяется в закрытом разделе.

Этот указатель определяется классом Widget в объявленном ранее пространстве имен Ui, поэтому указатель ui указывает на визуально разработанный интерфейс. Позже вы увидите, что вам необходимо получить доступ к компонентам интерфейса через этот указатель ui.

2. файл widget.cpp

Файл widget.cpp - это код реализации класса Widget. Ниже приведено содержимое файла widget.cpp.

Обратите внимание, что следующая строка автоматически добавляется в раздел включаемого файла этого файла:

Это файл определения класса, соответствующий файлу пользовательского интерфейса widget.ui, сгенерированному компиляцией Qt.

На данный момент есть только конструкторы и деструкторы. Глава конструктора:

Его значение: выполнить конструктор родительского класса QWidget для создания объекта ui класса Ui :: Widget. Этот ui является переменной-указателем ui, определенной в частной части виджета.

В конструкторе есть только одно строковое выражение:

Он выполняет функцию setupUi () класса Ui :: Widget.Эта функция реализует создание окна, установку различных атрибутов и ассоциацию сигналов и слотов (описано ниже).

Деструктор просто удаляет указатель ui, созданный с помощью new.

Следовательно, существует пространство имен с именем Ui в файле ui_widget.h и есть класс Widget, который используется для описания визуального дизайна формы и имеет то же имя, что и класс, определенный в widget.h. Для доступа к переменным-членам или функциям класса Ui :: Widget в классе Widget необходимо передать указатель ui в классе Widget, точно так же, как при выполнении функции ui-> setupUi (this) в конструкторе.

3. файл widget.ui

widget.ui - файл определения интерфейса окна. Это XML-файл, который определяет настройки атрибутов, макет и ассоциацию сигналов и функций слотов всех компонентов в окне. Интерфейсы, визуально разработанные с помощью UI-дизайнера, автоматически анализируются Qt и сохраняются в виде файлов XML. При разработке интерфейса вам нужно только визуально оформить дизайн в UI-дизайнере, независимо от того, как создается файл widget.ui.

Ниже представлено содержимое файла widget.ui.

4. Файл ui_widget.h

ui_widget.h - это файл, созданный после компиляции файла widget.ui. ui_widget.h появится в скомпилированном каталоге или в том же каталоге, что и widget.ui (связанный с настройками компиляции теневой сборки проекта).

Файл ui_widget.h не появляется в дереве каталогов файлов проекта Qt Creator.Конечно, вы можете вручную добавить ui_widget.h в проект. Метод состоит в том, чтобы щелкнуть правой кнопкой мыши узел имени проекта в дереве каталогов файлов проекта, выбрать «Добавить существующие файлы . » в появившемся контекстном меню, найти и добавить файл ui_widget.h.

[Примечание] ui_widget.h автоматически создается после компиляции файла widget.ui, а widget.ui создается с помощью визуального дизайна дизайнера пользовательского интерфейса. Поэтому нет особого смысла изменять ui_widget.h вручную - все изменения, связанные с интерфейсом, должны выполняться непосредственно в дизайнере пользовательского интерфейса. Следовательно, ui_widget.h не нужно добавлять в проект.

Ниже приводится содержимое файла ui_widget.h.

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

(1) Класс Ui_Widget определен для инкапсуляции интерфейса визуального дизайна.

(2) Автоматически создается определение переменной-члена класса для каждого компонента интерфейса. В общедоступной части переменная-указатель определяется для каждого компонента интерфейса, а имя переменной - это set objectName. Например, после размещения QLabel и QPushButton в форме и присвоения им имени автоматически сгенерированное определение:

(3) Определена функция setupUi (), которая используется для создания каждого компонента интерфейса и установки его положения, размера, текстового содержимого, шрифта и других атрибутов, а также для установки связи между сигналом и слотом.

setupUi () Первая часть тела функции В соответствии с визуально разработанным содержимым интерфейса используйте код C ++ для создания каждого компонента интерфейса и установки его свойств.

Далее setupUi () вызывает функцию retranslateUi ( Widget ) , Используется для установки свойств текстового содержимого каждого компонента интерфейса, таких как текст метки, текст кнопки, заголовок окна и т. Д. Разделите содержимое текстовых настроек интерфейса как функцию retranslateUi (), которая будет использоваться при разработке многоязычного интерфейса.

Третья часть функции setupUi () - установить связь между сигналом и слотом. В этом файле есть следующие две строки:

Первая строка - это вызов функции connect (), будет UI Связь между сигналом и набором слотов в конструкторе преобразуется в предложение . Здесь необходимо связать сигнал clicked () кнопки btnClose с функцией слота close () оконного виджета, который показан на рисунке 2-4. Реализуется связанный программный оператор установленного сигнала и слота. Таким образом, при нажатии кнопки btnClose выполняется функция слота close () виджета, а функция функции слота close () заключается в закрытии окна.

Вторая строка предназначена для установки метода связывания функции слота, который используется для связывания функции слота компонентного сигнала, автоматически сгенерированного разработчиком пользовательского интерфейса, с компонентным сигналом.

Следовательно, вызывая ui-> setupUI (this) в конструкторе виджета, реализуется создание компонентов в форме, настройка свойств и ассоциация сигналов и слотов.

(4) Определите namespaceUi и определите класс Widget, унаследованный от Ui_Widget.

Задавал вопрос по объяснению с PyQt5 & Qt Designer .
Ответ был дан, но так же такое замечания:

введите сюда описание изображения

По этому поводу создаю отдельно эту тему, чтобы спросить следующие:

Правильно ли я создал структуру своей программы? Ведь раньше я всё делал в одном файле, и без функции __init__ и super().__init__()

Как правильно редактировать интерфейс? Смотрим по примеру из файлов ниже. Мне нужно добавить ещё одну кнопку или же переименовать старую. Разве не правильно и легче зайти в файл ресурсов (fromqt.py) и там например строчку:

  1. Так же есть вариант, раз у нас файл ресурсов это отдельный файл, то просто зайти в qt designer , предварительно сохранив старую версию в .ui и просто добавить новые изменения, сохранить файл и просто заменить старый файл ресурсов на новый?

Но если учитывать заметку наведенную от автора ответа, получается что это не правильный метод изменения интерфейса.

Просьба помочь разобраться с этим. (Буду очень благодарен за наведенный пример).

main.py:

fromqt.py:


50.9k 46 46 золотых знаков 29 29 серебряных знаков 46 46 бронзовых знаков


Разве не правильно и легче зайти в файл ресурсов (fromqt.py) правильно если у вас нет ui файла, от которого вы этого скрипт сгенерировали. Т.е. лучше открыть ui файл в дизайнере qt и поменять там, после перегенерировать ui в py . Кст, названия полей относятся к значениям objectName из ui . Еще вы можете поменять значения прям в __init__ у MainWindow , но я бы советовал все-таки вариант с ui или fromqt.py:

Правильный вариант, у нас в третьем вопросе.

зайти в qt designer , сделать изменения в .ui ;

сконвертировать .ui в fromqt.py ; Обратите внимание на строку в fromqt.py -

запускайте main.py с новым дизайном.

Но если вдруг вы потеряли файл .ui и у вас сейчас нет времени его нарусовать, а надо срочно что-то добавит ли изменить, тогда смотрим ниже:

main.py

fromqt.py

введите сюда описание изображения

UPDATE

Ещё не большой вопрос, не хочу уже создавать для него отдельную тему. Подскажите пожалуйста, что значит. Он как то влияет на расположения виджетов? Центрирует. Вы использовали его в строчке, где создавали новую кнопку, а точнее:

class MainWindow(..)

.

self.newButton = QtWidgets.QPushButton("Новая кнопка", self.centralwidget)

Это не не большой вопрос, отдельная тема для большого разговора.

виджет без родителя - это окно. Попробуйте пример ниже. Поэтому все что мы хотим показать в главном окне должно иметь родителя основного виджета приложения.

В нашем случае Класс QMainWindow предоставляет главное окно приложения. QMainWindow - это особый класс. QMainWindow имеет свой собственный layout , к которому вы можете добавить QToolBars , QDockWidgets , QMenuBar и QStatusBar . Макет имеет центральную область, которая может быть занята любым виджетом.

У нас этот 'любой виджет' - это:

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

этот способ не практичный.

Вам надо изучить классы QBoxLayout , QFormLayout , QGridLayout , . для дальнейшего разговора.


Многие из тех кто занимаются разработкой на C++/Qt знакомы с такой средой как Qt Creator, создатели которой потрудились над дизайном не меньше чем над функциональностью. Но меня, как любителя темных цветовых схем и плоского минимализма, всегда не устраивали светлый фон панелек и градиентные заголовки.

Казалось бы, открытый исходный код — бери да меняй, но неопытность и лень останавливали меня, пока я не узнал про такую вещь как Qt Style Sheets, позволяющюю описать вид виджетов в формате css.

Заранее предупреждаю: Приведенное ниже пускай и не очень грязный, но хак. Конечно он наврятли откроет дыру в безопасности, украдет ваши пароли и отошлет их Пражским хакерам, но возможны разнообразные артефакты в интерфейсе.

UPD: Ничего патчить ненадо Вместо этого по совету cyberbobs достаточно запускать QtCreator с параметром -stylesheet=stylesheet.css, поэтому сразу переходим к перерисовке, но если очень хочется

Для начала берем исходный код среды. Распаковываем и добавляем в конструктор MainWindow::MainWindow() расположенный примерно в ./src/plugins/coreplugin/mainwindow.cpp:199 свой костыль, снабдив его опознавательными знаками, чтоб в случае чего можно было быстро найти и уничтожить:

ленивые могут взять измененный файл для последней стабильной версии 2.5.0
затем
qmake && make && ./bin/qtcreator
если все прошло гладко на выходе получаем
NOTE: stylesheet not found in <путь-к-таблице-стилей>/stylesheet.css

теперь создаем этот самый stylesheet.css и пишем туда для проверки


перезапускаем qtcreator (для экономии нервов следовало бы настроить редактор на запуск qtcreator одним нажатием) и видим такую феерию:

Как и следовало, setStyle покрасил все в синий, но появилось два отщепенца: список классов и методов текущего документа и переключатели панелей вывода. У меня есть два предположения почему так: либо эти элементы не являются потомками QWidget, что врятли, либо они используют свой способ отрисовки обходящий систему стилей Qt, что вполне возможно, учитывая их нестандартный вид.

Как известно таблица стилей представляет собой набор записей вида:

Если вы никогда раньше не писали ничего подобного, несколько уроков из любого тьюторала дадут вам представление о том что будет происходить ниже. Позже стоит прочесть документацию по Qt Style Sheet и примеры.

Селекторы

В демонологии чтобы вызвать демона нужно знать его имя, в нашем случае для составления селектора нужно знать название класса, objectName или значение любого свойства, заданного с использованием Q_PROPERTY() и setProperty().
Qt потдерживает все СSS2-селекторы. Самые полезные согласно документации:


Теперь давайте поиграем в дизайнеров.

Напомню, мы хотели сделать темный фон у панелей. Для этого нам нужно выбрать селектор. Что мы обычно видим в этих панельках? Деревья в «Проекты», «Обзор Классов», «Иерархия типов» и «Контур» (в девичестве «Outline»), списки в «Файловая Система», «Открытые Документы» и «Закладки» и таблицы в панелях отладки, т.е. стандартные QListView, QTreeView и QTableVeiw имя которым QAbstractItemView.
Поэтому напишем в наш stylesheet.css следующее:


Запускаем, уменьшаем размеры окна до минимума чтоб вылезло побольше всяких элементов и видим:

Мы получили что хотели, но наши (пусть и нелюбимые) панельки потеряли свой вид, и причем без нашей команды. Если кто пробегался глазами по MainWindow::MainWindow() возможно заметил неприметную строчку qApp->setStyle(new ManhattanStyle(baseName)); , особо настойчивые могли щелкнуть по ManhattanStyle и заметить что он наследуеться от QProxyStyle т.е. именно он переопределяет рисовку у наших панелек. И именно он уходит за кулисы как только мы задаем стиль.
Предчуствуя кучу мелкой работы по наведению красоты в этих поблекших кнопках я решил не мелочиться, и вбухал помимо QAbstractItemView еще и QMainWindow — отца всех виджетов:


Запускаем:

Почти то что надо. Остается омрачить белые пятна табов, хедеров и скролбаров.

Субэлементы и состояния

Как и СCS2, Qt Style Sheet поддерживает субэлементы и состояния, т.е. запись селектора в виде:

Например QScrollBar::left-arrow:horizontal выбирает все левые стрелки гоизонтальных полос прокрутки.
Рассмотрим как это работает на наших белых пятнах.

Оформляем QTreeView и QAbstractItemView

Для начала изменим облик выделенного элемента в QAbstractItemView на более темный с помощью:


Сравниваем:

Теперь разберемся с QTreeView.
Каждая его строчка состоит из одного субэлемента ::item и одного или нескольких ::branch:


::branch помимо стандартных состояний поддерживает еще 4:
* Синие — элементы с искомым состоянием





:open :adjoins-item :has-children :has-subling

Подумав, я решил забыть про надоевшие стрелочки и сделать напротив сгрупированных элементов маленькую серенькую точку. Стало быть нам нужны :closed:adjoins-item:has-children . Подергав параметры получаем чтото вроде:


Если же вы любите стрелочки, вам должна понравиться конструкция url(filename), которая переданная в image: или border-image: установит в качестве фона или границы изображение, хранящееся на жестком диске либо в системе ресурсов Qt.

Изменяем QScrollBar


В глазах Qt Style Sheets, стандартная полоса прокрутки состоит из следующих субэлементов:

Цинично превращаем это трехмерное великолепие в унылую серо-серую полоску, а кнопки вместе со стрелочками отправляем на награждение премии «Ненужно 2012» следующими строками:


Получаем:

Модифицируем QTabBar

  • Субэлементы: ::tear (разделитель вкладок) и ::scroller (кнопка прокрутки)
  • Целая россыпь дополнительных состояний вкладок: :only-one, :first, :last, :middle, :previous--selected, :next-selected, :selected, назначения которых я надеюсь понятны из названий.
  • Псевдо-состояния :top, :left, :right, :bottom зависимые от ориентации панели.
  • Отрицательные поля которые можно использовать для создания перекрытий


Изменяем QHeaderView

Для тех кто не знал, все эти заголовки таблиц в Qt это и есть QHeaderView. У него один субэлемент ::section который обладает теми же состояниями что и QTabBar::tab.

На этот раз я решил отступиться от традиции и сделать градиентную заливку (да здесь и так можно). Для этого используются конструкции qlineargradient, qradialgradient, qconicalgradient. Градиенты указываются в режиме ограничивающего прямоугольника объекта (Object Bounding Mode). Представьте себе прямоугольник, в котором визуализируется градиент, верхний левый угол которого находится в (0, 0), а нижний правый угол — в (1, 1). Параметры градиента в этом случае указываются как доля между 0 и 1. Эти значения экстраполируются на реальные координаты прямоугольника во время выполнения. Возможно задание значений, которые лежат вне ограничивающего прямоугольника (например, -0.6 или 1.8).
Я использовал следующее оформление:



То чего мы и добивались.

Уговариваем упрямую панельку


Осталась только одна маленькая проблемка:

Этот отщепеныш остался абсолютно равнодушен к нашим стараниям, более того он оставался равнодушен даже когда мы в качестве селектора указали прадедушку QWidget'а. Несмотря на это, я все же перебирал разные селекторы. Впервые удалось пронять ее селекторами с QComboBox и QLabel:


Минусы на лицо. Мало неумолимой никакими border-style рамки вокруг отщепеныша, так еще и тяжелая наследственнасть просочилась везде куда ненадо.

Тут как кстати, проявились капли здравого смысла. Дети, что такое тоненькое, в верху окна с кнопочками в ряд? Конечно же это QToolBar!
Пробуем:


Бинго! Пропали все следы тяжелой болезни и отщепенец послушно влился в общий вид.



stylesheet.css

Читайте также: