Символы кириллицы выводит некорректно. Как сделать чтобы выводился читабельный текст на русском языке? Тип приложения - не 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 );