|
Символы кириллицы выводит некорректно. Как сделать чтобы выводился читабельный текст на русском языке? Тип приложения - не Qt, Qt Creator 4.5.0 основан на Qt 5.10.0. Win7.
|
Лекция 15: Разработка приложений с графическим интерфейсом
15.4 Стандартные диалоги
Диалог выбора файла для открытия и сохранения, диалог выбора шрифта, окна сообщений об ошибках являются примерами диалоговых окон, с которыми часто приходится сталкиваться при работе с программами. Такие диалоги обычно имеют стандартные для всех программ в системе вид и функциональность. Qt позволяет воспользоваться готовыми диалогами для этих целей, которые легко вызвать в программе. Классы для работы с диалогами, которые часто используют в программе, приведены в табл. 15.1.
| Класс | Описание особенностей |
|---|---|
| QInputDialog | Используют для удобства в случае когда необходимо ввести числовое значение или строку текста. Имеет несколько сигналов, которые сигнализируют об изменении значения в поле ввода. Класс имеет статические методы для вызова диалога ввода числа (getDouble(), getInt()), ввода (getText()) выбора элемента из списка (getItem()). |
| QColorDialog | Стандартный диалог выбoра цвета. Класс имеет статический метод getColor() для удобного вызова диалога. |
| QFontDialog | Стандартный диалог выбoра шрифта. Класс имеет статический метод getFont() для удобного вызова диалога. |
| QFileDialog | Стандартный диалог выбора файла. Имеет большое количество настроек, возможность фильтрации файлов по расширению. Класс имеет статические методы (getExistingDirectory(), getOpenFileName(), getOpenFileNames(), getSaveFileName()) для вызова диалога |
| QMessageBox | Диалог сообщение. Используют для вывода информации, сообщений об ошибках и вопросов. Класс имеет статические методы для удобного вызова в программе информационных окон (about(), aboutQt()), сообщений об ошибках (critical(), warning()), вопросов (question()) и сообщений (information()). |
В нашем примере мы будем использовать класс QFileDialog для выбора файла при открытии и сохранении, а также класс QMessageBox. Добавим описание слотов для открытия и сохранения файла:
private slots : void slotOpen ( ); void slotSave ( );
Подключим необходимые заголовочные файлы в mainwindow.cpp:
#include <QFileDialog> #include <QMessageBox> #include <QDir>
Добавим реализацию для слотов slotOpen() и slotSave():
//Слот для открытия файла в редакторе
void MainWindow::slotOpen ( )
{
//Вызвать системный диалог открытия файла в домашней папке пользователя
QString lFileName=QFileDialog::getOpenFileName ( this, " open file...", QDir : :
homePath ( ), " Text files ( * .txt );; All files ( *.* ) " );
//указываем фильтры для просмотра файлов
if ( lFileName.isEmpty ( ) ) //Если пользователь не выбрал ни одного файла
{
return; //выйти из метода
}
//Спросить пользователя о сохранении документа
if ( ! askForFileSaveAndclose ( ) )
{
//Если пользователь нажал "Отмена" игнорировать вызов — продолжать работу
return;
}
QFile lFile ( lFileName ); //Устанавливаем имя открытого файла
//Если текстовый файл открыт только для чтения...
if ( lFile.open ( QIODevice::ReadOnly | QIODevice::Text ) )
{
mFileName = lFileName; //задать имя файла
//читаем все содержимое и устанавливаем текст для редактора
ui->plainTextEdit ->setPlainText( lFile.readAll ( ) );
lFile.close ( ); //закрываем открытый файл
//устанавливаем состояние окна — содержимое не модифицировано
setWindowModified ( false );
//и обновляем заголовок окна для демонстрации названия текущего открытого файла
updateTitle ( );
}
else
{
//Если при открытии файла возникла ошибка выводим диалоговое окно с сообщением,
//содержащим имя файла, одну кнопку "Ок" и заголовок "Error"
QMessageBox::warning ( this, " Error ", QString ( " Could not open File %1 for
reading " ).arg ( lFile.FileName ( ) ), QMessageBox::Ok);
}
}
//Слот для сохранения изменений в текущем файле
void MainWindow::slotsave ( )
{
//Если содержимое не модифицировано...
if ( ! isWindowModified ( ) ) //Если содержимое не модифицировано
{
return; //Выйти из метода — продолжить работу
}
//Вызвать системный диалог сохранения файла в домашней папке пользователя
QString lFileName=QFileDialog::getSaveFileName ( this, t r ( " Save File..." ),
QDir::homePath ( ), tr ( " Text files ( *.txt );; All files ( *.* ) " ) );
//Если пользователь не выбрал имя файла для сохранения...
if ( lFileName.isEmpty ( ) )
{
return; // ... выйти из метода
}
QFile lFile ( lFileName ); //Устанавливаем имя открытого файла
//Если текстовый файл открыт для записи
if ( lFile.open ( QIODevice::WriteOnly | QIODevice::Text ) )
{
mFileName = lFileName; //Задать имя файла
//Создаем временный QByteArray для записи данных
QByteArray lData;
//Читаем текст из редактора и добавляем QByteArray, записываем в файл
//и закрываем файл после записи
lData.append ( ui->plainTextEdit ->toPlainText( ) );
lFile.write ( lData );
lFile.close ( );
//Устанавливаем состояние окна — содержимое не модифицировано
setWindowModified ( false );
}
else
{
//Если при открытии файла возникла ошибка выводим диалоговое окно с сообщением,
//содержащим имя файла, одну кнопку "Ок" и заголовок "Error"
QMessageBox::warning ( this, " Error ", QString ( " Could not open File %1 for
writing " ).arg ( lFile.FileName ( ) ), QMessageBox::Ok);
}
}Здесь в начале каждого из слотов мы вызываем диалог для выбора файла с помощью статических методов класса QFileDialog. Диалог для открытия файла мы вызываем с помощью метода QFileDialog::getOpenFileName(), а для сохранения — с помощью QFileDialog ::getSaveFileName(). Для каждого из случаев диалог будет иметь соответствующий вид. Для того, чтобы добавить фильтр для текстовых файлов мы передаем строку с описанием фильтра — "Text files (*.txt );;AllFiles (*.*)". В описании — названия для фильтров и шаблоны для фильтрации (в скобках). Можно задавать несколько шаблонов через пробел при необходимости. Фильтры в списке разделяем с помощью двойной точки с запятой.
После выбора пользователем файла, статический метод вернет полный путь к нему. В случае, когда пользователь закрыл диалог или нажал "Отмена", метод вернет пустую строку. Для выбранного файла мы выполняем чтение содержимого и сохранения. Если при открытии возникла ошибка, мы выводим ее с помощью статического метода QMessageBox::warning().
При открытии файла мы использовали собственный метод askForFileSaveAndClose (), который должен проверить текущий открытый файл на изменения и предложить пользователю сохранить их перед открытием другого файла. Добавим описание этого метода к описанию класса MainWindow:
private : bool askForFileSaveAndclose ( );
и его реализацию в файл mainwindow.cpp:
//Метод для проверки текущего файла на изменения и вывода диалога для пользователя,
//с предложением сохранить изменения. Метод возвращает логическое значение,
//содержащее false в случае, когда пользователь нажал в диалоге кнопку "Cancel"
bool MainWindow::askForFileSaveAndclose ( )
{
if ( isWindowMod ified ( ) ) //Если содержимое окна модифицировано
{
//вызываем диалог с вопросом, нужно ли сохранять изменения: подставляем в текст диалога
//название текущего открытого файла, задаем кнопки: "Да", "Нет" и "Отмена".
//Результат работы диалога (нажатой кнопки) записываем в переменную
int lResult = QMessageBox::question ( this, t r ( " Save changes " ),
QString ( tr ( " File %1 is modified.Do you want to save your changes ? " ) ).arg
( mFile.FileName ( ) ), QMessageBox::Yes, QMessageBox::No, QMessageBox : :
Cancel );
if ( QMessageBox::Yes == lResult ) //Если нажали кнопку "Да"
{
slotSave ( ); //сохранить изменения
}
else
{
if ( QMessageBox::Cancel == lResult ) //Если нажали кнопку "Отменить"
{
return false;
}
}
}
return true;
}В этом фрагменте программы мы использовали статический метод QMessageBox :: question, и задали заголовок, текст и кнопки на диалоге с помощью специальных констант (QMessageBox::Yes, QMessageBox::No, QMessageBox::Cancel). Он, как и почти все статические методы QMessageBox, возвращает значение нажатой кнопки. Это значение мы сравниваем со значениями констант для кнопок, чтобы определить, какие дальнейшие действия выбрал пользователь. Используем метод askForFileSaveAndClose() также и в слоте для нового текстового файла:
//Спросить пользователя о сохранении документа
if ( ! askForFileSaveAndclose ( ) )
{
//Если пользоватеель нажал "Отменить" игнорировать вызов — продолжать работу
return;
}Осталось реализовать вывод информации о программе. Для этого сначала добавим к .pro-файлу информацию о версии. Например, добавим переменные с большим и меньшим номерами версии, а потом передадим их в переменную DEFINES таким образом, чтобы они были объявлены в программе. Это может быть удобно для дальнейшего изменения версии при разработке программы:
MAJOR_VERSION = 1 MINOR_VERSION = 0 DEFINES += \ MAJOR_VERSION=$$MAJOR_VERSION \ MINOR_VERSION=$$MINOR_VERSION
После изменений в файле проекта не забудьте вызвать qmake еще раз, чтобы программа обработала все изменения в файле проекта (выберите в главном меню Build->Run qmake) Теперь в файле main.cpp зададим версию, а также название для QApplication:
int main ( int arg c, char * argv [ ] )
{
QApplication a ( arg c, argv );
a.setApplicationName ( " TextEditor " );
a.setApplicationVersion ( QString ( " % 1.% 2 " )
. arg (MAJOR_VERSION)
. arg (MINOR_VERSION) );
MainWindow w;
w.show ( );
return a.exec ( );
}Теперь используем объект QApplication для получения версии и названия программы в слоте отображения информации. Добавим объявления слота, а также следующую его реализацию:
//Слот для отображения информации о программе
void MainWindow::slotAboutProgram ( )
{
//Выводим диалоговое информационное окно с сообщением, куда подставляем версию и название
//программы возвращаемых QApplication. Указываем — окно содержит заголовок "About".
QMessageBox::about ( this, t r ( " About " ),
QString ( " %1 v.%2 " ).arg ( qApp->
ApplicationName ( ) ).arg ( qApp->Application Version ( ) ) );
}В конце подсоединяем сигналы от пунктов главного меню к созданным слотам:
//Присоединяем действия к созданным слотам connect ( ui->action_New, SIGNAL( triggered ( ) ), this, SLOT( slotNew ( ) ), Qt : : UniqueConnection ); connect ( ui->action_Open, SIGNAL( triggered ( ) ), this, SLOT( slotOpen ( ) ), Qt : : UniqueConnection ); connect ( ui->act ion_Save, SIGNAL( triggered ( ) ), this, SLOT( slotsave ( ) ), Qt : : UniqueConnection ); connect ( ui->actionAbout_Qt, SIGNAL( triggered ( ) ), qApp, SLOT( aboutQt ( ) ), Qt : : UniqueConnection ); connect ( ui->actionAbout_program, SIGNAL( triggered ( ) ), this, SLOT( slotAboutProgram ( ) ), Qt::UniqueConnection );