Начало работы с QtДобро пожаловать в мир Qt - кроссплатформенного набора инструментов для разработки ГПИ (GUI). В данном руководстве мы изучим основы Qt, написав простое приложение Notepad. После прочтения данного руководства вы будете готовы к изучению наших обзоров и документации API, а также к поиску информации, необходимой для разработки ваших приложений. Hello NotepadВ качестве первого примера создадим и отобразим текстовый редактор. Это простейшее приложение на Qt, которое имеет ГПИ (GUI). Вот код: 1 #include <QApplication> 2 #include <QTextEdit> 3 4 int main(int argv, char **args) 5 { 6 QApplication app(argv, args); 7 8 QTextEdit textEdit; 9 textEdit.show(); 10 11 return app.exec(); 12 } Давайте рассмотрим каждую строку кода. В первых двух строчках мы подключаем заголовочные файлы для QApplication и QTextEdit – двух классов которые потребуются для этого примера. Все классы Qt имеют заголовочные файлы с соответствующим именем. На строке 6 создается экземпляр QApplication. Этот объект управляет ресурсами приложения и необходим для запуска любой программы с графическим интерфейсом на Qt. Ему необходимо передать argv и args, так как Qt может принимать некоторые параметры командной строки. На строке 8 создаётся экземпляр текстового редактора QTextEdit. Текстовый редактор – это графический элемент интерфейса пользователя. В Qt мы называем такие элементы виджетами. Примерами других виджетов являются линейки прокрутки (scroll bars), метки (labels) и переключатели (radio buttons). Виджет также может быть контейнером для других виджетов, например, диалог или главное окно приложения. На строке 9 текстовый редактор отображается на экране. Так как виджеты также служат контейнерами (например, QMainWindow, у которого есть панели инструментов (toolbars), меню, строка состояния (status bar) и другие виджеты), то можно показать отдельный виджет как полноценное окно. По умолчанию виджеты скрыты; метод show() делает их видимыми. В строке 11 QApplication входит в цикл событий (eventloop). Когда приложение Qt запущено, события генерируются и отправляются виджетам приложения. Примерами событий являются нажатия кнопок мыши и клавиш клавиатуры. Когда вы набираете текст в виджете редактора текста, он получает события нажатий кнопок и отвечает отображением введённого текста. Для запуска приложения откройте командную строку и зайдите в каталог, в котором находится файл .cpp вашей программы. Следующие команды соберут вашу программу. qmake -project
qmake
make
Это создаст исполняемый файл в текущем каталоге part1 (обратите внимание, что в Windows вы должны использовать nmake вместо make. Также исполняемый файл будет помещён в подкаталог part1\debug или part1\release (эти каталоги создаются при запуске make). qmake – это инструмент Qt для сборки приложения, использующий конфигурационный файл. qmake генерирует конфигурационный файл когда задан параметр -project. Используя заданный конфигурационный файл (файл с расширением .pro), qmake создаёт файл для утилиты make, которая будет собирать ваше приложение. Мы рассмотрим написание собственных файлов .pro позже. Дополнительная информация
Добавление кнопки выходаВ настоящем приложении обычно требуется более одного виджета. Добавим кнопку (QPushButton) под текстовым редактором. Кнопка будет закрывать приложение "Notepad", при нажатии на неё (т.е. при щелчке на ней левой кнопкой мыши). Давайте взглянем на код. 1 #include <QtGui> 2 3 int main(int argv, char **args) 4 { 5 QApplication app(argv, args); 6 7 QTextEdit textEdit; 8 QPushButton quitButton("Quit"); 9 10 QObject::connect(&quitButton, SIGNAL(clicked()), qApp, SLOT(quit())); 11 12 QVBoxLayout layout; 13 layout.addWidget(&textEdit); 14 layout.addWidget(&quitButton); 15 16 QWidget window; 17 window.setLayout(&layout); 18 19 window.show(); 20 21 return app.exec(); 22 } В первой строке мы включаем QtGui – заголовочный файл, содержащий все классы графического интерфейса пользователя Qt. В строке 10 используется механизм сигналов и слотов Qt для выхода из приложения при нажатии кнопки Quit. Слот это функция, которая может быть вызвана во время выполнения программы (runtime) по её имени (в виде строки символов). Сигнал это функция, которая вызывает связанные с ней слоты; мы называем это подключением слота к сигналу (connect) и посылкой сигнала (emit). quit() - это слот QApplication, который закрывает приложение. clicked() - это сигнал, посылаемый кнопкой (QPushButton) при нажатии. Статическая функция QObject::connect() соединяет сигнал со слотом. SIGNAL() и SLOT() это два макроса, которые принимают сигнатуры соединяемых функций сигнала и слота. Нам также необходимо предоставить указатели на объекты, посылающие и принимающие сигнал. В строке 12 создаётся вертикальный компоновщик (QVBoxLayout). Как было сказано выше, виджеты могут содержать другие виджеты. Можно непосредственно указать границы (расположение и размер) дочерних виджетов, но удобнее использовать компоновщик (layout). Компоновщик управляет границами дочерних виджетов. QVBoxLayout, например, размещает дочерние виджеты вертикально. В строках 13 и 14 текстовый редактор и кнопка добавляются в компоновщик. В строчке 17 мы устанавливаем компоновщик на виджет. Дополнительная информация
Наследование QWidgetКогда пользователь решит выйти из приложения, то, возможно, вы захотите вывести на экран диалог для подтверждения выхода. В этом примере мы наследуем QWidget и добавим слот, который соединим с кнопкой выхода Quit. Давайте взглянем на код: 5 class Notepad : public QWidget 6 { 7 Q_OBJECT 8 9 public: 10 Notepad(); 11 12 private slots: 13 void quit(); 14 15 private: 16 QTextEdit *textEdit; 17 QPushButton *quitButton; 18 }; Макрос Q_OBJECT должен быть первой инструкцией в объявлении класса. Этот макрос объявляет наш класс как QObject (естественно, класс должен быть унаследован от QObject). QObject добавляет несколько возможностей обычным классам C++. Например, имя класса и имена его слотов могут быть запрошены во время выполнения программы. Также можно вызывать слоты и узнавать типы их параметров. В строке 13 объявляется слот quit(). Это делается очень просто, используя макрос slots. Теперь слот quit() может быть соединён с сигналами. Мы проделаем это позже. Вместо настройки графического интерфейса пользователя и соединения слота в функции main() мы используем конструктор класса Notepad. 20 Notepad::Notepad() 21 { 22 textEdit = new QTextEdit; 23 quitButton = new QPushButton(tr("Quit")); 24 25 connect(quitButton, SIGNAL(clicked()), this, SLOT(quit())); 26 27 QVBoxLayout *layout = new QVBoxLayout; 28 layout->addWidget(textEdit); 29 layout->addWidget(quitButton); 30 31 setLayout(layout); 32 33 setWindowTitle(tr("Notepad")); 34 } Как видно из определения класса, мы используем указатели на экземпляры QObject (textEdit и quitButton). Как правило, вы всегда должны создавать экземпляры QObject в куче (heap) и никогда не должны копировать их. Также мы используем функцию tr() для видимых пользователю строк. Эта функция необходима, когда приложение должно быть более чем на одном языке (например, на китайском и английском). Сейчас мы не будем углубляться в подробности, но вы можете пройти по ссылке Qt Linguist из таблицы Узнать больше. Мы не будем рассматривать реализацию слота quit() и функции main(), но вы, если хотите, можете проверить исходный код. Дополнительная информация
Создание файла .proДля этого примера мы напишем собственный .pro файл вместо использования опции qmake -project. 1 HEADERS = notepad.h 2 SOURCES = notepad.cpp \ 3 main.cpp Следующие консольные команды соберут пример. qmake make Использование QMainWindowМногие приложения могут выиграть от использования QMainWindow, у которого есть собственный компоновщик куда вы можете добавить меню, прикрепляемые виджеты (dock widgets), панель инструментов (tool bars) и строку состояния (status bar). У QMainWindow есть центральная область где можно разместить любой виджет. В нашем случае мы разместим там наш текстовый редактор. Давайте взглянем на новое определение класса Notepad. 2 #include <QtGui> 3 4 class Notepad : public QMainWindow 5 { 6 Q_OBJECT 7 8 public: 9 Notepad(); 10 11 private slots: 12 void open(); 13 void save(); 14 void quit(); 15 16 private: 17 QTextEdit *textEdit; 18 19 QAction *openAction; 20 QAction *saveAction; 21 QAction *exitAction; 22 23 QMenu *fileMenu; 24 }; Мы добавили два слота, которые могут сохранять и открывать документ. Они будут реализованы в следующем разделе. Часто в главном окне один и тот же слот должен быть вызван сразу несколькими виджетами. Например, элементами меню и кнопками на панели инструментов. Для упрощения разработки Qt предоставляет QAction, который может быть использован несколькими виджетами и который может быть соединён со слотом. Например, и QMenu, и QToolBar могут создавать элементы меню и кнопки инструментов из одного QAction. Мы скоро увидим как это работает. Как и ранее, для настройки графического интерфейса пользователя мы используем конструктор Notepad. 25 Notepad::Notepad() 26 { 27 saveAction = new QAction(tr("&Open"), this); 28 saveAction = new QAction(tr("&Save"), this); 29 exitAction = new QAction(tr("E&xit"), this); 30 31 connect(openAction, SIGNAL(triggered()), this, SLOT(open())); 32 connect(saveAction, SIGNAL(triggered()), this, SLOT(save())); 33 connect(exitAction, SIGNAL(triggered()), qApp, SLOT(quit())); 34 35 fileMenu = menuBar()->addMenu(tr("&File")); 36 fileMenu->addAction(openAction); 37 fileMenu->addAction(saveAction); 38 fileMenu->addSeparator(); 39 fileMenu->addAction(exitAction); 40 41 textEdit = new QTextEdit; 42 setCentralWidget(textEdit); 43 44 setWindowTitle(tr("Notepad")); 45 } Экземпляры QAction создаются с указанием текста, который будет отображен на виджетах (в нашем случае, на элементах меню). Если мы хотим добавить их на панель инструментов, то мы могли бы задать действиям ещё и иконки. Когда происходит нажатие на элемент меню, элемент вызывает действие, которое выполняет соответствующий слот. Дополнительная информация
Сохранение и загрузкаВ этом примере мы реализуем слоты open() и save(), которые были добавлены в предыдущем примере. Начнем со слота open(): 48 void Notepad::open() 49 { 50 QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "", 51 tr("Text Files (*.txt);;C++ Files (*.cpp *.h)")); 52 53 if (fileName != "") { 54 QFile file(fileName); 55 if (!file.open(QIODevice::ReadOnly)) { 56 QMessageBox::critical(this, tr("Error"), tr("Could not open file")); 57 return; 58 } 59 QTextStream in(&file); 60 textEdit->setText(in.readAll()); 61 file.close(); 62 } 63 } Сначала у пользователя запрашивается имя открываемого файла. В Qt есть класс QFileDialog, который является диалогом выбора файла. Выше показан диалог в Kubuntu. Статическая функция getOpenFileName() отображает модальный диалог выбора файла. Он возвращает путь к выбранному файлу или пустую строку, если пользователь отменил диалог. Если у нас есть имя файла, то мы пытаемся открыть файл с помощью функции open(), которая возвращает true, если файл может быть открыт. Мы не будем углубляться в обработку ошибок, подробнее про них можно почитать в разделе дополнительной информации. Если файл не может быть открыт, то мы используем QMessageBox для отображения диалога с сообщением об ошибке (смотрите описание класса QMessageBox для получения дополнительных подробностей). Фактически, чтение данных выполняется с помощью одного класса QTextStream, который является обёрткой объекта QFile. Функция readAll() возвращает содержимое файла в виде строки QString. Затем содержимое отображается в текстовом редакторе. После этого вызывается функция close() для закрытия файла и возвращения файлового дескриптора операционной системе. Теперь давайте перейдем к слоту save(). 65 void Notepad::save() 66 { 67 QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "", 68 tr("Text Files (*.txt);;C++ Files (*.cpp *.h)")); 69 70 if (fileName != "") { 71 QFile file(fileName); 72 if (!file.open(QIODevice::WriteOnly)) { 73 // сообщение об ошибке 74 } else { 75 QTextStream stream(&file); 76 stream << textEdit->toPlainText(); 77 stream.flush(); 78 file.close(); 79 } 80 } 81 } Для записи данных в файл снова воспользуемся классом QTextStream. QTextStream может также записать строки QString в файл с помощью оператора <<. Дополнительная информация
|
Попытка перевода Qt документации. Если есть желание присоединиться, или если есть замечания или пожелания, то заходите на форум: Перевод Qt документации на русский язык... Люди внесшие вклад в перевод: Команда переводчиков |