GettingStartedWithQtRussian: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
 
(Remove non-functioning "toc" command)
 
(6 intermediate revisions by 2 users not shown)
Line 1: Line 1:
=Начало работы с Qt=
{{Cleanup | reason=Auto-imported from ExpressionEngine.}}


Добро пожаловать в мир Qt — кроссплатформенного набора инструментов (''toolkit'') для разработки графического интерфейса пользователя (''<span class="caps">GUI</span>''). В данном руководстве мы изучим основы Qt, написав простое приложение “Блокнот”. После прочтения этого руководства вы сможете лучше ориентироваться в документации и найти там всю необходимую информацию для разработки своих приложений.


==Привет, Блокнот!==
= Начало работы с Qt =


В качестве первого примера создадим и отобразим текстовый редактор ([http://doc.qt.nokia.com/4.7/qtextedit.html QTextEdit] ''[doc.qt.nokia.com]''). Это, пожалуй, самая простая программа на Qt с графическим интерфейсом пользователя, которая только может существовать.
Добро пожаловать в мир Qt — кроссплатформенного набора инструментов (''toolkit'') для разработки графического интерфейса пользователя (''GUI''). В данном руководстве мы изучим основы Qt, написав простое приложение "Блокнот". После прочтения этого руководства вы сможете лучше ориентироваться в документации и найти там всю необходимую информацию для разработки своих приложений.


[[Image:gs1.png|Самое простое приложение на Qt]]
== Привет, Блокнот! ==


Исходный код:<br /> Давайте рассмотрим каждую строку кода. На первых двух строках мы подключаем заголовочные файлы для [http://doc.qt.nokia.com/4.7/qapplication.html QApplication] ''[doc.qt.nokia.com]'' и [http://doc.qt.nokia.com/4.7/qtextedit.html QTextEdit] ''[doc.qt.nokia.com]'' – двух классов которые потребуются для этого примера. Для каждого класса Qt есть заголовочный файл с соответствующим именем.
В качестве первого примера создадим и отобразим текстовый редактор ([http://doc.qt.nokia.com/4.7/qtextedit.html QTextEdit]). Это, пожалуй, самая простая программа на Qt с графическим интерфейсом пользователя, которая только может существовать.


На строке 6 создается экземпляр [http://doc.qt.nokia.com/4.7/qapplication.html QApplication] ''[doc.qt.nokia.com]''. Этот объект управляет ресурсами уровня приложения и необходим для запуска любой программы на Qt с графическим интерфейсом. Ему необходимо передать ''argv'' и ''args'', так как Qt может принимать некоторые параметры командной строки.
p=. [[Image:http://doc.qt.nokia.com/4.7/images/gs1.png|Самое простое приложение на Qt]]


На строке 8 создаётся экземпляр текстового редактора [http://doc.qt.nokia.com/4.7/qtextedit.html QTextEdit] ''[doc.qt.nokia.com]''. Текстовый редактор – это графический элемент интерфейса пользователя. В Qt мы называем такие элементы виджетами. Примерами других виджетов являются полосы прокрутки (''scroll bars''), метки (''labels'') и переключатели (''radio buttons''). Виджет также может быть контейнером для других виджетов, например, диалог или главное окно приложения.
Исходный код:
<code>
#include <QApplication>
#include <QTextEdit>


На строке 9 текстовый редактор отображается на экране. Так как виджеты также служат контейнерами (например, [http://doc.qt.nokia.com/4.7/qmainwindow.html QMainWindow] ''[doc.qt.nokia.com]'', у которого есть панели инструментов (''toolbars''), меню, строка состояния (''status bar'') и другие виджеты), то можно показать отдельный виджет как полноценное окно. По умолчанию виджеты скрыты; метод [http://doc.qt.nokia.com/4.7/qwidget.html#show show()] ''[doc.qt.nokia.com]'' делает их видимыми.
int main(int argv, char **args)
{
QApplication app(argv, args);


На строке 11 [http://doc.qt.nokia.com/4.7/qapplication.html QApplication] ''[doc.qt.nokia.com]'' входит в цикл событий (''eventloop''). Во время работы приложения на Qt события генерируются и отправляются виджетам. Примерами событий могут служить нажатия кнопок мыши или ввод с клавиатуры. Когда пользователь вводит текст в текстовый редактор, этот виджет получает события нажатий клавиш и отображает набранный текст на экране.
QTextEdit textEdit;
textEdit.show();


Чтобы запустить приложение нужно в командной строке перейти в каталог с .cpp-файлом и выполнить следующие команды:<br />
return app.exec();;
}
</code>
Давайте рассмотрим каждую строку кода. На первых двух строках мы подключаем заголовочные файлы для [http://doc.qt.nokia.com/4.7/qapplication.html QApplication] и [http://doc.qt.nokia.com/4.7/qtextedit.html QTextEdit] – двух классов которые потребуются для этого примера. Для каждого класса Qt есть заголовочный файл с соответствующим именем.


Так как утилита qmake может работать в двух режимах для создания Makefile или для создания .pro файла, мы должны импользовать ее два раза.
На строке 6 создается экземпляр [http://doc.qt.nokia.com/4.7/qapplication.html QApplication]. Этот объект управляет ресурсами уровня приложения и необходим для запуска любой программы на Qt с графическим интерфейсом. Ему необходимо передать ''argv'' и ''args'', так как Qt может принимать некоторые параметры командной строки.
 
На строке 8 создаётся экземпляр текстового редактора [http://doc.qt.nokia.com/4.7/qtextedit.html QTextEdit]. Текстовый редактор – это графический элемент интерфейса пользователя. В Qt мы называем такие элементы виджетами. Примерами других виджетов являются полосы прокрутки (''scroll bars''), метки (''labels'') и переключатели (''radio buttons''). Виджет также может быть контейнером для других виджетов, например, диалог или главное окно приложения.
 
На строке 9 текстовый редактор отображается на экране. Так как виджеты также служат контейнерами (например, [http://doc.qt.nokia.com/4.7/qmainwindow.html QMainWindow], у которого есть панели инструментов (''toolbars''), меню, строка состояния (''status bar'') и другие виджеты), то можно показать отдельный виджет как полноценное окно. По умолчанию виджеты скрыты; метод [http://doc.qt.nokia.com/4.7/qwidget.html#show show()] делает их видимыми.
 
На строке 11 [http://doc.qt.nokia.com/4.7/qapplication.html QApplication] входит в цикл событий (''eventloop''). Во время работы приложения на Qt события генерируются и отправляются виджетам. Примерами событий могут служить нажатия кнопок мыши или ввод с клавиатуры. Когда пользователь вводит текст в текстовый редактор, этот виджет получает события нажатий клавиш и отображает набранный текст на экране.
 
Чтобы запустить приложение нужно в командной строке перейти в каталог с .cpp-файлом и выполнить следующие команды:
<code>
qmake -project
qmake
make
</code>
 
Так как утилита qmake может работать в двух режимах- для создания Makefile или для создания .pro файла, мы должны импользовать ее два раза.


После этого в каталоге появится исполняемый файл (обратите внимание, что в Windows вместо ''make'' необходимо выполнить ''nmake'' и исполняемый файл будет в подкаталоге ''debug'' или ''release''). ''qmake'' – это инструмент Qt для сборки приложения, использующий конфигурационный файл, который создается при запуске ''qmake'' с ключом -project. Используя заданный конфигурационный файл (файл с расширением .pro), ''qmake'' создаёт файл для утилиты ''make'', которая будет собирать ваше приложение. Мы рассмотрим написание собственных .pro файлов позже.
После этого в каталоге появится исполняемый файл (обратите внимание, что в Windows вместо ''make'' необходимо выполнить ''nmake'' и исполняемый файл будет в подкаталоге ''debug'' или ''release''). ''qmake'' – это инструмент Qt для сборки приложения, использующий конфигурационный файл, который создается при запуске ''qmake'' с ключом -project. Используя заданный конфигурационный файл (файл с расширением .pro), ''qmake'' создаёт файл для утилиты ''make'', которая будет собирать ваше приложение. Мы рассмотрим написание собственных .pro файлов позже.


===Дополнительная информация===
=== Дополнительная информация ===
|Тема|Статья|
|Виджеты и геометрия окна|[http://doc.qt.nokia.com/4.7/application-windows.html| Window and Dialog Widgets]
|События и их обработка|[http://doc.qt.nokia.com/4.7/eventsandfilters.html| The Event System]
 
 
== Добавление кнопки выхода ==
В настоящем приложении обычно требуется более одного виджета. Добавим кнопку ([http://doc.qt.nokia.com/4.7/qpushbutton.html QPushButton]) под текстовым редактором. Кнопка будет закрывать Блокнот при нажатии на неё.
 
p=. [[Image:http://doc.qt.nokia.com/4.7/images/gs2.png|Кнопка выход]]
 
Давайте взглянем на код.
<code>
#include <QtGui>
 
int main(int argv, char **args)
{
QApplication app(argv, args);


{| class="infotable line"
QTextEdit textEdit;
| Тема
QPushButton quitButton("Quit");
| Статья
 
|-
QObject::connect(&quitButton, SIGNAL (clicked()), qApp, SLOT (quit()));
| Виджеты и геометрия окна
|
[http://doc.qt.nokia.com/4.7/application-windows.html Window and Dialog Widgets] ''[doc.qt.nokia.com]''
|-
| События и их обработка
|
[http://doc.qt.nokia.com/4.7/eventsandfilters.html The Event System] ''[doc.qt.nokia.com]''
|}


==Добавление кнопки выхода==
QVBoxLayout layout;
layout.addWidget(&textEdit);
layout.addWidget(&quitButton);


В настоящем приложении обычно требуется более одного виджета. Добавим кнопку ([http://doc.qt.nokia.com/4.7/qpushbutton.html QPushButton] ''[doc.qt.nokia.com]'') под текстовым редактором. Кнопка будет закрывать Блокнот при нажатии на неё.
QWidget window;
window.setLayout(&layout);


[[Image:gs2.png|Кнопка выход]]
window.show();


Давайте взглянем на код.<br />
return app.exec();
}
</code>


На первой строке мы включаем [http://doc.qt.nokia.com/4.7/qtgui.html QtGui] ''[doc.qt.nokia.com]'' – заголовочный файл, содержащий все классы графического интерфейса пользователя Qt.
На первой строке мы включаем [http://doc.qt.nokia.com/4.7/qtgui.html QtGui] – заголовочный файл, содержащий все классы графического интерфейса пользователя Qt.


На строке 10 используется механизм сигналов и слотов Qt для выхода из приложения при нажатии кнопки '''Quit'''. Слот это функция, которая может быть вызвана во время выполнения программы (''runtime'') с помощью её имени (в виде строки). Сигнал это функция, которая вызывает связанные с ней слоты; мы называем это подключением слота к сигналу (''connect'') и отправкой сигнала (''emit'').
На строке 10 используется механизм сигналов и слотов Qt для выхода из приложения при нажатии кнопки '''Quit'''. Слот это функция, которая может быть вызвана во время выполнения программы (''runtime'') с помощью её имени (в виде строки). Сигнал это функция, которая вызывает связанные с ней слоты; мы называем это подключением слота к сигналу (''connect'') и отправкой сигнала (''emit'').


[http://doc.qt.nokia.com/4.7/qcoreapplication.html#quit quit()] ''[doc.qt.nokia.com]'' — это слот [http://doc.qt.nokia.com/4.7/qapplication.html QApplication] ''[doc.qt.nokia.com]'', который закрывает приложение. [http://doc.qt.nokia.com/4.7/qabstractbutton.html#clicked clicked()] ''[doc.qt.nokia.com]'' – это сигнал, посылаемый кнопкой ([http://doc.qt.nokia.com/4.7/qpushbutton.html QPushButton] ''[doc.qt.nokia.com]'') при нажатии. Статическая функция [http://doc.qt.nokia.com/4.7/qobject.html#connect QObject::connect()] ''[doc.qt.nokia.com]'' соединяет сигнал со слотом. ''<span class="caps">SIGNAL</span>'' и ''<span class="caps">SLOT</span>'' это два макроса, которые принимают сигнатуры соединяемых функций сигнала и слота. Также необходимо передать указатели на соединяемые объекты.
[http://doc.qt.nokia.com/4.7/qcoreapplication.html#quit quit()] — это слот [http://doc.qt.nokia.com/4.7/qapplication.html QApplication], который закрывает приложение. [http://doc.qt.nokia.com/4.7/qabstractbutton.html#clicked clicked()] – это сигнал, посылаемый кнопкой ([http://doc.qt.nokia.com/4.7/qpushbutton.html QPushButton]) при нажатии. Статическая функция [http://doc.qt.nokia.com/4.7/qobject.html#connect QObject::connect()] соединяет сигнал со слотом. ''SIGNAL'' и ''SLOT'' это два макроса, которые принимают сигнатуры соединяемых функций сигнала и слота. Также необходимо передать указатели на соединяемые объекты.


На строке 12 создаётся вертикальный компоновщик ([http://doc.qt.nokia.com/4.7/qvboxlayout.html QVBoxLayout] ''[doc.qt.nokia.com]''). Как было сказано выше, виджеты могут содержать другие виджеты. Можно явно указать границы (расположение и размер) дочерних виджетов, но удобнее использовать компоновщик (''layout''). Компоновщик управляет границами дочерних виджетов. [http://doc.qt.nokia.com/4.7/qvboxlayout.html QVBoxLayout] ''[doc.qt.nokia.com]'', например, размещает дочерние виджеты вертикально.
На строке 12 создаётся вертикальный компоновщик ([http://doc.qt.nokia.com/4.7/qvboxlayout.html QVBoxLayout]). Как было сказано выше, виджеты могут содержать другие виджеты. Можно явно указать границы (расположение и размер) дочерних виджетов, но удобнее использовать компоновщик (''layout''). Компоновщик управляет границами дочерних виджетов. [http://doc.qt.nokia.com/4.7/qvboxlayout.html QVBoxLayout], например, размещает дочерние виджеты вертикально.


На строках 13 и 14 текстовый редактор и кнопка добавляются в компоновщик. На строке 17 компоновщик устанавливается на виджет.
На строках 13 и 14 текстовый редактор и кнопка добавляются в компоновщик. На строке 17 компоновщик устанавливается на виджет.


===Дополнительная информация===
=== Дополнительная информация ===
|Тема|Статья|
|Сигналы и слоты|[http://doc.qt.nokia.com/4.7/signalsandslots.html| Signals & Slots]
|Компоновки|[http://doc.qt.nokia.com/4.7/layout.html Layout Management], [http://doc.qt.nokia.com/4.7/widgets-and-layouts.html Widgets and Layouts], [http://doc.qt.nokia.com/4.7/examples-layouts.html| Layout Examples]
|Виджеты Qt|[http://doc.qt.nokia.com/4.7/gallery.html Qt Widget Gallery], [http://doc.qt.nokia.com/4.7/examples-widgets.html| Widget Examples]


{| class="infotable line"
== Наследование QWidget ==
| Тема
Представим, что при выходе пользователя из приложения нам надо показать диалог для подтверждения выхода. В этом примере мы наследуем [http://doc.qt.nokia.com/4.7/qwidget.html QWidget] и добавим слот, который соединим с кнопкой выхода '''Quit'''.
| Статья
 
|-
p=. [[Image:http://doc.qt.nokia.com/4.7/images/gs3.png|Наследуемся от QWidget]]
| Сигналы и слоты
|
[http://doc.qt.nokia.com/4.7/signalsandslots.html Signals &amp; Slots] ''[doc.qt.nokia.com]''
|-
| Компоновки
|
[http://doc.qt.nokia.com/4.7/layout.html Layout Management] ''[doc.qt.nokia.com]'', [http://doc.qt.nokia.com/4.7/widgets-and-layouts.html Widgets and Layouts] ''[doc.qt.nokia.com]'', [http://doc.qt.nokia.com/4.7/examples-layouts.html Layout Examples] ''[doc.qt.nokia.com]''
|-
| Виджеты Qt
|
[http://doc.qt.nokia.com/4.7/gallery.html Qt Widget Gallery] ''[doc.qt.nokia.com]'', [http://doc.qt.nokia.com/4.7/examples-widgets.html Widget Examples] ''[doc.qt.nokia.com]''
|}


==Наследование QWidget==
Давайте взглянем на код:
<code>
class Notepad : public QWidget
{
Q_OBJECT


Представим, что при выходе пользователя из приложения нам надо показать диалог для подтверждения выхода. В этом примере мы наследуем [http://doc.qt.nokia.com/4.7/qwidget.html QWidget] ''[doc.qt.nokia.com]'' и добавим слот, который соединим с кнопкой выхода '''Quit'''.
public:
Notepad();


[[Image:gs3.png|Наследуемся от QWidget]]
private slots:
void quit();


Давайте взглянем на код:<br />
private:
QTextEdit *textEdit;
QPushButton *quitButton;
};
</code>


Макрос ''Q_OBJECT'' должен быть первой инструкцией в объявлении класса. Этот макрос объявляет наш класс как [http://doc.qt.nokia.com/4.7/qobject.html QObject] ''[doc.qt.nokia.com]'' (естественно, класс должен быть унаследован от [http://doc.qt.nokia.com/4.7/qobject.html QObject] ''[doc.qt.nokia.com]''). [http://doc.qt.nokia.com/4.7/qobject.html QObject] ''[doc.qt.nokia.com]'' добавляет несколько возможностей обычным классам C++. Например, имя класса и имена его слотов могут быть запрошены во время выполнения программы. Также можно вызывать слоты и узнавать типы их параметров.
Макрос ''Q_OBJECT'' должен быть первой инструкцией в объявлении класса. Этот макрос объявляет наш класс как [http://doc.qt.nokia.com/4.7/qobject.html QObject] (естественно, класс должен быть унаследован от [http://doc.qt.nokia.com/4.7/qobject.html QObject]). [http://doc.qt.nokia.com/4.7/qobject.html QObject] добавляет несколько возможностей обычным классам C++. Например, имя класса и имена его слотов могут быть запрошены во время выполнения программы. Также можно вызывать слоты и узнавать типы их параметров.


Строка 13 объявляет слот ''quit()''. Для объявления слотов используется макрос ''slots''. Теперь этот слот может быть подключен к сигналам с подходящей сигнатурой (то есть к сигналам без параметров).
Строка 13 объявляет слот ''quit()''. Для объявления слотов используется макрос ''slots''. Теперь этот слот может быть подключен к сигналам с подходящей сигнатурой (то есть к сигналам без параметров).


Вместо настройки графического интерфейса пользователя и соединения слота в функции ''main()'' мы используем конструктор класса Notepad.<br />
Вместо настройки графического интерфейса пользователя и соединения слота в функции ''main()'' мы используем конструктор класса Notepad.
<code>
Notepad::Notepad()
{
textEdit = new QTextEdit;
quitButton = new QPushButton(tr("Quit"));


Как видно из определения класса, используются указатели на экземпляры [http://doc.qt.nokia.com/4.7/qobject.html QObject] ''[doc.qt.nokia.com]'' (''textEdit'' и ''quitButton''). Как правило, вы всегда должны создавать наследников [http://doc.qt.nokia.com/4.7/qobject.html QObject] ''[doc.qt.nokia.com]'' в динамической памяти (''heap'') и никогда не копировать их.
connect(quitButton, SIGNAL (clicked()), this, SLOT (quit()));


Также мы используем функцию [http://doc.qt.nokia.com/4.7/qobject.html#tr tr()] ''[doc.qt.nokia.com]'' для видимых пользователю строк. Эта функция нужна когда приложение должно быть более чем на одном языке (например, на китайском и английском). Мы не будем углубляться в детали, но все подробности можно посмотреть по ссылке о Qt Linguist в дополнительной информации.
QVBoxLayout '''layout = new QVBoxLayout;
layout->addWidget(textEdit);
layout->addWidget(quitButton);


===Дополнительная информация===
setLayout(layout);


{| class="infotable line"
setWindowTitle(tr("Notepad"));
| Тема
}
| Статья
</code>
|-
 
| tr() и интернационализация
Как видно из определения класса, используются указатели на экземпляры [http://doc.qt.nokia.com/4.7/qobject.html QObject] (''textEdit'' и ''quitButton''). Как правило, вы всегда должны создавать наследников [http://doc.qt.nokia.com/4.7/qobject.html QObject] в динамической памяти (''heap'') и никогда не копировать их.
|
 
[http://doc.qt.nokia.com/4.7/linguist-manual.html Qt Linguist Manual] ''[doc.qt.nokia.com]'', [http://doc.qt.nokia.com/4.7/i18n-source-translation.html Writing Source Code for Translation] ''[doc.qt.nokia.com]'', [http://doc.qt.nokia.com/4.7/linguist-hellotr.html Hello tr() Example] ''[doc.qt.nokia.com]'', [http://doc.qt.nokia.com/4.7/internationalization.html Internationalization with Qt] ''[doc.qt.nokia.com]''
Также мы используем функцию [http://doc.qt.nokia.com/4.7/qobject.html#tr tr()] для видимых пользователю строк. Эта функция нужна когда приложение должно быть более чем на одном языке (например, на китайском и английском). Мы не будем углубляться в детали, но все подробности можно посмотреть по ссылке о Qt Linguist в дополнительной информации.
|-
 
|
=== Дополнительная информация ===
[http://doc.qt.nokia.com/4.7/qtwebkit-bridge.html#qobjects QObject] ''[doc.qt.nokia.com]'' и объектная модель Qt (необходимо для понимания Qt)
|Тема|Статья|
|
|tr() и интернационализация|[http://doc.qt.nokia.com/4.7/linguist-manual.html Qt Linguist Manual], [http://doc.qt.nokia.com/4.7/i18n-source-translation.html Writing Source Code for Translation], [http://doc.qt.nokia.com/4.7/linguist-hellotr.html Hello tr() Example], [http://doc.qt.nokia.com/4.7/internationalization.html| Internationalization with Qt]
[http://doc.qt.nokia.com/4.7/object.html Object Model] ''[doc.qt.nokia.com]''
|[http://doc.qt.nokia.com/4.7/qtwebkit-bridge.html#qobjects QObject] и объектная модель Qt (необходимо для понимания Qt)|[http://doc.qt.nokia.com/4.7/object.html| Object Model]
|-
|qmake и система сборки Qt|[http://doc.qt.nokia.com/4.7/qmake-manual.html| qmake Manual]
| qmake и система сборки Qt
 
|
=== Создание .pro файла ===
[http://doc.qt.nokia.com/4.7/qmake-manual.html qmake Manual] ''[doc.qt.nokia.com]''
Для этого примера мы напишем собственный .pro файл вместо использования опции _qmake -project_.
|}
<code>
HEADERS = notepad.h
SOURCES = notepad.cpp  main.cpp
</code>
 
Соберем приложение:
<code>
qmake
make
</code>
 
== Использование QMainWindow ==
Многие приложения могут выиграть от использования [http://doc.qt.nokia.com/4.7/qmainwindow.html QMainWindow], у которого есть собственный компоновщик куда вы можете добавить меню, прикрепляемые виджеты (''dock widgets''), панель инструментов (''tool bars'') и строку состояния (''status bar''). У [http://doc.qt.nokia.com/4.7/qmainwindow.html QMainWindow] есть центральная область где можно разместить любой виджет. В нашем случае мы разместим там наш текстовый редактор.
 
p=. [[Image:http://doc.qt.nokia.com/4.7/images/gs4.png|Используем QMainWindow]]


===Создание .pro файла===
Давайте взглянем на новое определение класса Notepad.
<code>
#include <QtGui>


Для этого примера мы напишем собственный .pro файл вместо использования опции ''qmake -project''.<br />
class Notepad : public QMainWindow
{
Q_OBJECT


Соберем приложение:<br />
public:
Notepad();


==Использование QMainWindow==
private slots:
void open();
void save();
void quit();


Многие приложения могут выиграть от использования [http://doc.qt.nokia.com/4.7/qmainwindow.html QMainWindow] ''[doc.qt.nokia.com]'', у которого есть собственный компоновщик куда вы можете добавить меню, прикрепляемые виджеты (''dock widgets''), панель инструментов (''tool bars'') и строку состояния (''status bar''). У [http://doc.qt.nokia.com/4.7/qmainwindow.html QMainWindow] ''[doc.qt.nokia.com]'' есть центральная область где можно разместить любой виджет. В нашем случае мы разместим там наш текстовый редактор.
private:
QTextEdit *textEdit;


[[Image:gs4.png|Используем QMainWindow]]
QAction *openAction;
QAction *saveAction;
QAction *exitAction;


Давайте взглянем на новое определение класса Notepad.<br />
QMenu '''fileMenu;
};
</code>


Здесь появились еще два слота для сохранения и загрузки файла. Они будут реализованы в следующем разделе.
Здесь появились еще два слота для сохранения и загрузки файла. Они будут реализованы в следующем разделе.


Часто в главном окне один и тот же слот должен быть вызван сразу несколькими виджетами. Например, элементами меню и кнопками на панели инструментов. Для упрощения подобных вещей в Qt есть [http://doc.qt.nokia.com/4.7/qaction.html QAction] ''[doc.qt.nokia.com]'', который может быть использован несколькими виджетами и который может быть соединён со слотом. Например, и [http://doc.qt.nokia.com/4.7/qmenu.html QMenu] ''[doc.qt.nokia.com]'', и [http://doc.qt.nokia.com/4.7/qtoolbar.html QToolBar] ''[doc.qt.nokia.com]'' могут создавать элементы меню и кнопки инструментов из одного [http://doc.qt.nokia.com/4.7/qaction.html QAction] ''[doc.qt.nokia.com]''. Мы скоро увидим как это работает.<br /> Как и ранее, для настройки графического интерфейса пользователя мы используем конструктор Notepad.<br />
Часто в главном окне один и тот же слот должен быть вызван сразу несколькими виджетами. Например, элементами меню и кнопками на панели инструментов. Для упрощения подобных вещей в Qt есть [http://doc.qt.nokia.com/4.7/qaction.html QAction], который может быть использован несколькими виджетами и который может быть соединён со слотом. Например, и [http://doc.qt.nokia.com/4.7/qmenu.html QMenu], и [http://doc.qt.nokia.com/4.7/qtoolbar.html QToolBar] могут создавать элементы меню и кнопки инструментов из одного [http://doc.qt.nokia.com/4.7/qaction.html QAction]. Мы скоро увидим как это работает.
Как и ранее, для настройки графического интерфейса пользователя мы используем конструктор Notepad.
<code>
Notepad::Notepad()
{
saveAction = new QAction(tr("&Open"), this);
saveAction = new QAction(tr("&Save"), this);
exitAction = new QAction(tr("E&xit"), this);


Экземпляры [http://doc.qt.nokia.com/4.7/qaction.html QAction] ''[doc.qt.nokia.com]'' создаются с указанием текста, который будет отображен на виджетах (в нашем случае, на элементах меню). Если мы хотим добавить их на панель инструментов, то нам может потребоваться задать ещё и [http://doc.qt.nokia.com/4.7/qicon.html иконки] ''[doc.qt.nokia.com]''.
connect(openAction, SIGNAL (triggered()), this, SLOT (open()));
connect(saveAction, SIGNAL (triggered()), this, SLOT (save()));
connect(exitAction, SIGNAL (triggered()), qApp, SLOT (quit()));
 
fileMenu = menuBar()->addMenu(tr("&File"));
fileMenu->addAction(openAction);
fileMenu->addAction(saveAction);
fileMenu->addSeparator();
fileMenu->addAction(exitAction);
 
textEdit = new QTextEdit;
setCentralWidget(textEdit);
 
setWindowTitle(tr("Notepad"));
}
</code>
 
Экземпляры [http://doc.qt.nokia.com/4.7/qaction.html QAction] создаются с указанием текста, который будет отображен на виджетах (в нашем случае, на элементах меню). Если мы хотим добавить их на панель инструментов, то нам может потребоваться задать ещё и [http://doc.qt.nokia.com/4.7/qicon.html иконки].


Теперь, когда будет выбран пункт меню, он активирует действие и вызовется соответствующий слот.
Теперь, когда будет выбран пункт меню, он активирует действие и вызовется соответствующий слот.


===Дополнительная информация===
=== Дополнительная информация ===
|Тема|Статья|
|Главные окна и классы главного окна|[http://doc.qt.nokia.com/4.7/mainwindow.html Application Main Window], [http://doc.qt.nokia.com/4.7/examples-mainwindow.html| Main Window Examples]
|Приложения с многодокументным интерфейсом (MDI)|[http://doc.qt.nokia.com/4.7/qmdiarea.html QMdiArea], [http://doc.qt.nokia.com/4.7/mainwindows-mdi.html| MDI Example]


{| class="infotable line"
== Сохранение и загрузка ==
| Тема
В этом примере мы реализуем слоты ''open()'' и ''save()'', которые были добавлены в предыдущем примере.
| Статья
|-
| Главные окна и классы главного окна
|
[http://doc.qt.nokia.com/4.7/mainwindow.html Application Main Window] ''[doc.qt.nokia.com]'', [http://doc.qt.nokia.com/4.7/examples-mainwindow.html Main Window Examples] ''[doc.qt.nokia.com]''
|-
| Приложения с многодокументным интерфейсом (<span class="caps">MDI</span>)
|
[http://doc.qt.nokia.com/4.7/qmdiarea.html QMdiArea] ''[doc.qt.nokia.com]'', [http://doc.qt.nokia.com/4.7/mainwindows-mdi.html <span class="caps">MDI</span> Example] ''[doc.qt.nokia.com]''
|}


==Сохранение и загрузка==
p=. [[Image:http://doc.qt.nokia.com/4.7/images/gs5.png|Открытие файла в Kubuntu]]


В этом примере мы реализуем слоты ''open()'' и ''save()'', которые были добавлены в предыдущем примере.
Начнем со слота ''open()'':
<code>
QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "",
tr("Text Files ('''.txt);;C++ Files ('''.cpp'''.h)"));


[[Image:gs5.png|Открытие файла в Kubuntu]]
if (fileName != "") {
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
QMessageBox::critical(this, tr("Error"),
tr("Could not open file"));
return;
}
QString contents = file.readAll().constData();
textEdit->setPlainText(contents);
file.close();
}
</code>


Начнем со слота ''open()'':<br />
Сначала у пользователя запрашивается имя открываемого файла. В Qt есть класс [http://doc.qt.nokia.com/4.7/qfiledialog.html QFileDialog], который является диалогом выбора файла. Выше показан такой диалог в Kubuntu. Статический метод [http://doc.qt.nokia.com/4.7/qfiledialog.html#getOpenFileName getOpenFileName()] отображает модальный диалог выбора файла и не завершается, пока пользователь не выберет файл. Он возвращает путь к выбранному файлу или пустую строку, если пользователь отменил диалог.


Сначала у пользователя запрашивается имя открываемого файла. В Qt есть класс [http://doc.qt.nokia.com/4.7/qfiledialog.html QFileDialog] ''[doc.qt.nokia.com]'', который является диалогом выбора файла. Выше показан такой диалог в Kubuntu. Статический метод [http://doc.qt.nokia.com/4.7/qfiledialog.html#getOpenFileName getOpenFileName()] ''[doc.qt.nokia.com]'' отображает модальный диалог выбора файла и не завершается, пока пользователь не выберет файл. Он возвращает путь к выбранному файлу или пустую строку, если пользователь отменил диалог.
Если пользователь выбрал файл, то попробуем его открыть с помощью метода [http://doc.qt.nokia.com/4.7/qiodevice.html#open open()], который возвращает истину в случае успеха. Мы не будем углубляться в обработку ошибок (подробнее про них можно почитать в дополнительной информации). Если не удалось открыть файл, то отображается диалог [http://doc.qt.nokia.com/4.7/qmessagebox.html QMessageBox] с сообщением об ошибке.


Если пользователь выбрал файл, то попробуем его открыть с помощью метода [http://doc.qt.nokia.com/4.7/qiodevice.html#open open()] ''[doc.qt.nokia.com]'', который возвращает истину в случае успеха. Мы не будем углубляться в обработку ошибок (подробнее про них можно почитать в дополнительной информации). Если не удалось открыть файл, то отображается диалог [http://doc.qt.nokia.com/4.7/qmessagebox.html QMessageBox] ''[doc.qt.nokia.com]'' с сообщением об ошибке.
Фактически, чтение данных выполняется с помощью одного метода [http://doc.qt.nokia.com/4.7/qiodevice.html#readAll readAll()], который возвращает все содержимое файла в [http://doc.qt.nokia.com/4.7/qbytearray.html QByteArray]. Метод [http://doc.qt.nokia.com/4.7/qbytearray.html#constData constData()] возвращает содержимое [http://doc.qt.nokia.com/4.7/qbytearray.html QByteArray] в виде const char''', для которого у [http://doc.qt.nokia.com/4.7/qstring.html QString] есть конструктор. Затем содержимое файла отображается в текстовом редакторе. В конце работы вызывается метод [http://doc.qt.nokia.com/4.7/qiodevice.html#close close()] который закроет файл и вернет файловый дескриптор операционной системе.


Фактически, чтение данных выполняется с помощью одного метода [http://doc.qt.nokia.com/4.7/qiodevice.html#readAll readAll()] ''[doc.qt.nokia.com]'', который возвращает все содержимое файла в [http://doc.qt.nokia.com/4.7/qbytearray.html QByteArray] ''[doc.qt.nokia.com]''. Метод [http://doc.qt.nokia.com/4.7/qbytearray.html#constData constData()] ''[doc.qt.nokia.com]'' возвращает содержимое [http://doc.qt.nokia.com/4.7/qbytearray.html QByteArray] ''[doc.qt.nokia.com]'' в виде const char *, для которого у [http://doc.qt.nokia.com/4.7/qstring.html QString] ''[doc.qt.nokia.com]'' есть конструктор. Затем содержимое файла отображается в текстовом редакторе. В конце работы вызывается метод [http://doc.qt.nokia.com/4.7/qiodevice.html#close close()] ''[doc.qt.nokia.com]'' который закроет файл и вернет файловый дескриптор операционной системе.
Рассмотрим слот ''save()'':
<code>
QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "",
tr("Text Files ('''.txt);;C++ Files ('''.cpp *.h)"));


Рассмотрим слот ''save()'':<br />
if (fileName != "") {
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly)) {
// error message
} else {
QTextStream stream(&file);
stream << textEdit->toPlainText();
stream.flush();
file.close();
}
}
</code>


Для записи данных в файл воспользуемся классом [http://doc.qt.nokia.com/4.7/qtextstream.html QTextStream] ''[doc.qt.nokia.com]'' (текстовый поток), который в нашем случае будет оберткой над экземпляром [http://doc.qt.nokia.com/4.7/qfile.html QFile] ''[doc.qt.nokia.com]''. Текстовый поток может записывать [http://doc.qt.nokia.com/4.7/qstring.html QString] ''[doc.qt.nokia.com]'' непосредственно в файл; [http://doc.qt.nokia.com/4.7/qfile.html QFile] ''[doc.qt.nokia.com]'' же принимает лишь сырые данные (''char*'') или [http://doc.qt.nokia.com/4.7/qbytearray.html QByteArray] ''[doc.qt.nokia.com]'' с помощью методов [http://doc.qt.nokia.com/4.7/qiodevice.html#write write()] ''[doc.qt.nokia.com]'' класса-предка [http://doc.qt.nokia.com/4.7/qiodevice.html <span class="caps">QIOD</span>evice] ''[doc.qt.nokia.com]''.
Для записи данных в файл воспользуемся классом [http://doc.qt.nokia.com/4.7/qtextstream.html QTextStream] (текстовый поток), который в нашем случае будет оберткой над экземпляром [http://doc.qt.nokia.com/4.7/qfile.html QFile]. Текстовый поток может записывать [http://doc.qt.nokia.com/4.7/qstring.html QString] непосредственно в файл; [http://doc.qt.nokia.com/4.7/qfile.html QFile] же принимает лишь сырые данные (''char*'') или [http://doc.qt.nokia.com/4.7/qbytearray.html QByteArray] с помощью методов [http://doc.qt.nokia.com/4.7/qiodevice.html#write write()] класса-предка [http://doc.qt.nokia.com/4.7/qiodevice.html QIODevice].


===Дополнительная информация===
=== Дополнительная информация ===


{| class="infotable line"
{|
| Тема
|Тема
| Статья
|Статья
|-
|-
| Файлы и устройства ввода-вывода
|Файлы и устройства ввода-вывода
|
|[http://doc.qt.nokia.com/4.7/qfile.html QFile], [http://doc.qt.nokia.com/4.7/qiodevice.html QIODevice]
[http://doc.qt.nokia.com/4.7/qfile.html QFile] ''[doc.qt.nokia.com]'', [http://doc.qt.nokia.com/4.7/qiodevice.html <span class="caps">QIOD</span>evice] ''[doc.qt.nokia.com]''
|}
|}

Latest revision as of 12:21, 17 April 2015

This article may require cleanup to meet the Qt Wiki's quality standards. Reason: Auto-imported from ExpressionEngine.
Please improve this article if you can. Remove the {{cleanup}} tag and add this page to Updated pages list after it's clean.


Начало работы с Qt

Добро пожаловать в мир Qt — кроссплатформенного набора инструментов (toolkit) для разработки графического интерфейса пользователя (GUI). В данном руководстве мы изучим основы Qt, написав простое приложение "Блокнот". После прочтения этого руководства вы сможете лучше ориентироваться в документации и найти там всю необходимую информацию для разработки своих приложений.

Привет, Блокнот!

В качестве первого примера создадим и отобразим текстовый редактор (QTextEdit). Это, пожалуй, самая простая программа на Qt с графическим интерфейсом пользователя, которая только может существовать.

p=. Самое простое приложение на Qt

Исходный код:

#include <QApplication>
#include <QTextEdit>

int main(int argv, char **args)
{
 QApplication app(argv, args);

QTextEdit textEdit;
 textEdit.show();

return app.exec();;
}

Давайте рассмотрим каждую строку кода. На первых двух строках мы подключаем заголовочные файлы для 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

Так как утилита qmake может работать в двух режимах- для создания Makefile или для создания .pro файла, мы должны импользовать ее два раза.

После этого в каталоге появится исполняемый файл (обратите внимание, что в Windows вместо make необходимо выполнить nmake и исполняемый файл будет в подкаталоге debug или release). qmake – это инструмент Qt для сборки приложения, использующий конфигурационный файл, который создается при запуске qmake с ключом -project. Используя заданный конфигурационный файл (файл с расширением .pro), qmake создаёт файл для утилиты make, которая будет собирать ваше приложение. Мы рассмотрим написание собственных .pro файлов позже.

Дополнительная информация

|Тема|Статья| |Виджеты и геометрия окна|Window and Dialog Widgets |События и их обработка|The Event System


Добавление кнопки выхода

В настоящем приложении обычно требуется более одного виджета. Добавим кнопку (QPushButton) под текстовым редактором. Кнопка будет закрывать Блокнот при нажатии на неё.

p=. Кнопка выход

Давайте взглянем на код.

#include <QtGui>

int main(int argv, char **args)
{
 QApplication app(argv, args);

 QTextEdit textEdit;
 QPushButton quitButton("Quit");

 QObject::connect(&quitButton, SIGNAL (clicked()), qApp, SLOT (quit()));

 QVBoxLayout layout;
 layout.addWidget(&textEdit);
 layout.addWidget(&quitButton);

 QWidget window;
 window.setLayout(&layout);

 window.show();

 return app.exec();
}

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

На строке 10 используется механизм сигналов и слотов Qt для выхода из приложения при нажатии кнопки Quit. Слот это функция, которая может быть вызвана во время выполнения программы (runtime) с помощью её имени (в виде строки). Сигнал это функция, которая вызывает связанные с ней слоты; мы называем это подключением слота к сигналу (connect) и отправкой сигнала (emit).

quit() — это слот QApplication, который закрывает приложение. clicked() – это сигнал, посылаемый кнопкой (QPushButton) при нажатии. Статическая функция QObject::connect() соединяет сигнал со слотом. SIGNAL и SLOT это два макроса, которые принимают сигнатуры соединяемых функций сигнала и слота. Также необходимо передать указатели на соединяемые объекты.

На строке 12 создаётся вертикальный компоновщик (QVBoxLayout). Как было сказано выше, виджеты могут содержать другие виджеты. Можно явно указать границы (расположение и размер) дочерних виджетов, но удобнее использовать компоновщик (layout). Компоновщик управляет границами дочерних виджетов. QVBoxLayout, например, размещает дочерние виджеты вертикально.

На строках 13 и 14 текстовый редактор и кнопка добавляются в компоновщик. На строке 17 компоновщик устанавливается на виджет.

Дополнительная информация

|Тема|Статья| |Сигналы и слоты|Signals & Slots |Компоновки|Layout Management, Widgets and Layouts, Layout Examples |Виджеты Qt|Qt Widget Gallery, Widget Examples

Наследование QWidget

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

p=. Наследуемся от QWidget

Давайте взглянем на код:

class Notepad : public QWidget
{
 Q_OBJECT

public:
 Notepad();

private slots:
 void quit();

private:
 QTextEdit *textEdit;
 QPushButton *quitButton;
};

Макрос Q_OBJECT должен быть первой инструкцией в объявлении класса. Этот макрос объявляет наш класс как QObject (естественно, класс должен быть унаследован от QObject). QObject добавляет несколько возможностей обычным классам C++. Например, имя класса и имена его слотов могут быть запрошены во время выполнения программы. Также можно вызывать слоты и узнавать типы их параметров.

Строка 13 объявляет слот quit(). Для объявления слотов используется макрос slots. Теперь этот слот может быть подключен к сигналам с подходящей сигнатурой (то есть к сигналам без параметров).

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

Notepad::Notepad()
{
 textEdit = new QTextEdit;
 quitButton = new QPushButton(tr("Quit"));

 connect(quitButton, SIGNAL (clicked()), this, SLOT (quit()));

 QVBoxLayout '''layout = new QVBoxLayout;
 layout->addWidget(textEdit);
 layout->addWidget(quitButton);

 setLayout(layout);

 setWindowTitle(tr("Notepad"));
}

Как видно из определения класса, используются указатели на экземпляры QObject (textEdit и quitButton). Как правило, вы всегда должны создавать наследников QObject в динамической памяти (heap) и никогда не копировать их.

Также мы используем функцию tr() для видимых пользователю строк. Эта функция нужна когда приложение должно быть более чем на одном языке (например, на китайском и английском). Мы не будем углубляться в детали, но все подробности можно посмотреть по ссылке о Qt Linguist в дополнительной информации.

Дополнительная информация

|Тема|Статья| |tr() и интернационализация|Qt Linguist Manual, Writing Source Code for Translation, Hello tr() Example, Internationalization with Qt |QObject и объектная модель Qt (необходимо для понимания Qt)|Object Model |qmake и система сборки Qt|qmake Manual

Создание .pro файла

Для этого примера мы напишем собственный .pro файл вместо использования опции _qmake -project_.

HEADERS = notepad.h
SOURCES = notepad.cpp  main.cpp

Соберем приложение:

qmake
make

Использование QMainWindow

Многие приложения могут выиграть от использования QMainWindow, у которого есть собственный компоновщик куда вы можете добавить меню, прикрепляемые виджеты (dock widgets), панель инструментов (tool bars) и строку состояния (status bar). У QMainWindow есть центральная область где можно разместить любой виджет. В нашем случае мы разместим там наш текстовый редактор.

p=. Используем QMainWindow

Давайте взглянем на новое определение класса Notepad.

#include <QtGui>

class Notepad : public QMainWindow
{
 Q_OBJECT

public:
 Notepad();

private slots:
 void open();
 void save();
 void quit();

private:
 QTextEdit *textEdit;

 QAction *openAction;
 QAction *saveAction;
 QAction *exitAction;

 QMenu '''fileMenu;
};

Здесь появились еще два слота для сохранения и загрузки файла. Они будут реализованы в следующем разделе.

Часто в главном окне один и тот же слот должен быть вызван сразу несколькими виджетами. Например, элементами меню и кнопками на панели инструментов. Для упрощения подобных вещей в Qt есть QAction, который может быть использован несколькими виджетами и который может быть соединён со слотом. Например, и QMenu, и QToolBar могут создавать элементы меню и кнопки инструментов из одного QAction. Мы скоро увидим как это работает. Как и ранее, для настройки графического интерфейса пользователя мы используем конструктор Notepad.

Notepad::Notepad()
{
 saveAction = new QAction(tr("&Open"), this);
 saveAction = new QAction(tr("&Save"), this);
 exitAction = new QAction(tr("E&xit"), this);

 connect(openAction, SIGNAL (triggered()), this, SLOT (open()));
 connect(saveAction, SIGNAL (triggered()), this, SLOT (save()));
 connect(exitAction, SIGNAL (triggered()), qApp, SLOT (quit()));

 fileMenu = menuBar()->addMenu(tr("&File"));
 fileMenu->addAction(openAction);
 fileMenu->addAction(saveAction);
 fileMenu->addSeparator();
 fileMenu->addAction(exitAction);

 textEdit = new QTextEdit;
 setCentralWidget(textEdit);

 setWindowTitle(tr("Notepad"));
}

Экземпляры QAction создаются с указанием текста, который будет отображен на виджетах (в нашем случае, на элементах меню). Если мы хотим добавить их на панель инструментов, то нам может потребоваться задать ещё и иконки.

Теперь, когда будет выбран пункт меню, он активирует действие и вызовется соответствующий слот.

Дополнительная информация

|Тема|Статья| |Главные окна и классы главного окна|Application Main Window, Main Window Examples |Приложения с многодокументным интерфейсом (MDI)|QMdiArea, MDI Example

Сохранение и загрузка

В этом примере мы реализуем слоты open() и save(), которые были добавлены в предыдущем примере.

p=. Открытие файла в Kubuntu

Начнем со слота open():

QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), "",
 tr("Text Files ('''.txt);;C++ Files ('''.cpp'''.h)"));

if (fileName != "") {
 QFile file(fileName);
 if (!file.open(QIODevice::ReadOnly)) {
 QMessageBox::critical(this, tr("Error"),
 tr("Could not open file"));
 return;
 }
 QString contents = file.readAll().constData();
 textEdit->setPlainText(contents);
 file.close();
}

Сначала у пользователя запрашивается имя открываемого файла. В Qt есть класс QFileDialog, который является диалогом выбора файла. Выше показан такой диалог в Kubuntu. Статический метод getOpenFileName() отображает модальный диалог выбора файла и не завершается, пока пользователь не выберет файл. Он возвращает путь к выбранному файлу или пустую строку, если пользователь отменил диалог.

Если пользователь выбрал файл, то попробуем его открыть с помощью метода open(), который возвращает истину в случае успеха. Мы не будем углубляться в обработку ошибок (подробнее про них можно почитать в дополнительной информации). Если не удалось открыть файл, то отображается диалог QMessageBox с сообщением об ошибке.

Фактически, чтение данных выполняется с помощью одного метода readAll(), который возвращает все содержимое файла в QByteArray. Метод constData() возвращает содержимое QByteArray в виде const char, для которого у QString есть конструктор. Затем содержимое файла отображается в текстовом редакторе. В конце работы вызывается метод close() который закроет файл и вернет файловый дескриптор операционной системе.

Рассмотрим слот save():

QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"), "",
 tr("Text Files ('''.txt);;C++ Files ('''.cpp *.h)"));

if (fileName != "") {
 QFile file(fileName);
 if (!file.open(QIODevice::WriteOnly)) {
 // error message
 } else {
 QTextStream stream(&file);
 stream << textEdit->toPlainText();
 stream.flush();
 file.close();
 }
}

Для записи данных в файл воспользуемся классом QTextStream (текстовый поток), который в нашем случае будет оберткой над экземпляром QFile. Текстовый поток может записывать QString непосредственно в файл; QFile же принимает лишь сырые данные (char*) или QByteArray с помощью методов write() класса-предка QIODevice.

Дополнительная информация

Тема Статья
Файлы и устройства ввода-вывода QFile, QIODevice