Разработка графического интерфейса с помощью библиотеки Qt3 | ||
---|---|---|
Пред. | Глава 18. Платформо-зависимые особенности. | След. |
В момент завершения сеанса X11, некоторые оконные менеджеры выдают запрос на подтверждение завершения сеанса. Если мы подтверждаем завершение сессии, то приложения, которые работали в этот момент, будут автоматически запущены в начале следующего сеанса, с теми же экранными координатами и, в идеале, в том же самом состоянии.
Компонент X11, который управляет сохранением и восстановлением сеанса называется менеджер сеанса (или, если хотите, менеджер сессии). Чтобы добавить в Qt-приложение возможность сохранения своего состояния, в момент завершения сессии, необходимо перекрыть метод QApplication::saveState(), в котором выполнять сохранение всех необходимых параметров.
Рисунок 18.6. Окно запроса подтверждения завершения сеанса в KDE.
Момент завершения работы может быть перехвачен приложением, для этого надо перекрыть метод QApplication::commitData(). Это позволит сохранить любые несохраненные данные и запросить что либо у пользователя, если в этом возникнет необходимость. Это поведение реализуется одинаково на обеих платформах: X11 и Windows.
Мы исследуем поведение приложения, которое может взаимодействовать с менеджером сеанса, на примере программы "Крестики-нолики". Сначала рассмотрим функцию main():
int main(int argc, char *argv[])
{
Application app(argc, argv);
TicTacToe tic(0, "tic");
app.setTicTacToe(&tic);
tic.show();
return app.exec();
}
Здесь создается экземпляр класса Application, производный от класса QApplication. Этот класс перекрывает методы предка --
commitData() и saveState().Затем создается виджет TicTacToe и выводится на экран. Виджету TicTacToe было присаоено имя "tic". Если вы хотите обеспечить взаимодействие программы с менеджером сеанса, то всем виджетам верхнего уровня должны быть присвоены уникальные имена.
Рисунок 18.7. Внешний вид приложения "Крестики-нолики".
class Application : public QApplication
{
Q_OBJECT
public:
Application(int &argc, char *argv[]);
void setTicTacToe(TicTacToe *tic);
void commitData(QSessionManager &sessionManager);
void saveState(QSessionManager &sessionManager);
private:
TicTacToe *ticTacToe;
};
Класс Application хранит указатель на
виджет TicTacToe в приватной переменной.
void Application::saveState(QSessionManager &sessionManager)
{
QString fileName = ticTacToe->saveState();
QStringList discardCommand;
discardCommand << "rm" << fileName;
sessionManager.setDiscardCommand(discardCommand);
}
На платформе X11, менеджер сеансов вызывает функцию
saveState(), для сохранения состояния
приложения. Она доступна и на других платформах, но никогда не
вызывается. Аргумент типа QSessionManager позволяет взаимодействовать с
менеджером сеансов.Функция начинается с сохранения состояния виджета TicTacToe в файл. Затем менеджеру сеанса передается команда удаления. Команда удаления -- это команда, которая будет использована менеджером сеанса для удаления любой информации, имеющей отношение к текущему состоянию приложения. В данном случае команда выглядит как:
rm file
где file -- это имя файла, в котором
сохраняется информация о текущем состоянии, а rm -- это стандартная команда Unix, выполняющая удаление
файлов.Менеджеру сеанса может быть передана команда восстановления, которая будет выполнена менеджером для перезапуска приложения. По-умолчанию, Qt устанавливает команду восстановления:
appname -session id_key
где appname берется из argv[0], id -- идентификатор
сессии, поставляемый самим менеджером. Менеджер сеансов гарантирует
уникальность идентификатора для каждого экземпляра приложения. И
наконец key -- дополнительная информация,
содержащая время сохранения состояния приложения. По различным
причинам, функция saveState() может
вызываться несколько раз, на протяжении одной сессии, таким образом
пара id и key
гарантируют уникальность каждого из сохраненных состояний.Из-за ограничений, существующих в менеджерах сеансов, путь к исполняемому файлу приложения должен быть прописан в переменной PATH. В данном конкретном случае, если вы пожелаете испытать приложение "Крестики-нолики", вы должны переписать исполняемый файл программы в каталог, скажем, /usr/bin, и запустить ее командой tictactoe.
Для простых приложений, таких как "Крестики-нолики", состояние может быть сохранено в виде аргумента командной строки, которая перезапускает приложение в начале следующей сессии, например:
tictactoe -state OX-XO-X-O
В этом случае отпадает необходимость сохранения информации в
отдельный файл и установки команды удаления файла.
void Application::commitData(QSessionManager &sessionManager)
{
if (ticTacToe->gameInProgress()
&& sessionManager.allowsInteraction()) {
int ret = QMessageBox::warning(ticTacToe, tr("Tic-Tac-Toe"),
tr("The game hasn t finished.\n"
"Do you really want to quit?"),
QMessageBox::Yes | QMessageBox::Default,
QMessageBox::No | QMessageBox::Escape);
if (ret == QMessageBox::Yes)
sessionManager.release();
else
sessionManager.cancel();
}
}
Функция commitData() вызывается в
момент завершения сеанса. Здесь выводится запрос на подтверждение
завершения приложения, чтобы предотвратить потерю данных. По-умолчанию
она закрывает все виджеты верхнего уровня, точно так же, как и в случае
завершения приложения нажатием на кнопку "X", в заголовке
окна. В Главе 3 мы уже демонстрировали, как
перекрыть метод closeEvent() и вывести
запрос на подтверждение.В данном примере, мы перекрыли метод commitData() и выводим запрос на подтверждение из него, если менеджер сеанса позволяет это сделать. Когда пользователь щелкает по кнопке Yes, то вызывается функция release(), которая сообщает менеджеру сеанса о том, что он может продолжить процедуру завершения сессии. В противном случае процедура завершения сеанса будет остановлена, вызовом метода cancel().
Рисунок 18.8. Запрос на подтверждение завершения работы программы.
class TicTacToe : public QWidget
{
Q_OBJECT
public:
TicTacToe(QWidget *parent = 0, const char *name = 0);
QSize sizeHint() const;
bool gameInProgress() const;
QString saveState() const;
protected:
void paintEvent(QPaintEvent *event);
void mousePressEvent(QMouseEvent *event);
private:
enum { Empty = '-', Cross = 'X', Nought = 'O' };
void clearBoard();
void restoreState();
QString sessionFileName() const;
QRect cellRect(int row, int col) const;
int cellWidth() const { return width() / 3; }
int cellHeight() const { return height() / 3; }
char board[3][3];
int turnNumber;
};
Класс TicTacToe порожден от
QWidget и перекрывает методы предка:
sizeHint(), paintEvent() и mousePressEvent(). Он так же реализует новые
методы: gameInProgress() и saveState(), которые используются классом
Application.
TicTacToe::TicTacToe(QWidget *parent, const char *name)
: QWidget(parent, name)
{
setCaption(tr("Tic-Tac-Toe"));
clearBoard();
if (qApp->isSessionRestored())
restoreState();
}
В конструкторе производится очистка игрового поля и, если
приложение вызвано с ключом -session, то вызывается приватная функция
restoreState().
void TicTacToe::clearBoard()
{
for (int row = 0; row < 3; ++row) {
for (int col = 0; col < 3; ++col) {
board[row][col] = Empty;
}
}
turnNumber = 0;
}
Функция clearBoard() выполняет
очистку ячеек игрового поля и записывает значение 0 в переменную
turnNumber (номер хода).
QString TicTacToe::saveState() const
{
QFile file(sessionFileName());
if (file.open(IO_WriteOnly)) {
QTextStream out(&file);
for (int row = 0; row < 3; ++row) {
for (int col = 0; col < 3; ++col) {
out << board[row][col];
}
}
}
return file.name();
}
В функции saveState() производится
сохранение состояния игрового поля в файл. Формат файла очень прост --
на место крестика записывается символ 'X', на место нолика --
'O' и на место пустой ячейки -- '-'.
QString TicTacToe::sessionFileName() const
{
return QDir::homeDirPath() + "/.tictactoe_"
+ qApp->sessionId() + "_" + qApp->sessionKey();
}
Функция sessionFileName() возвращает
имя файла, которое соответствует текущему идентификатору и ключу
сеанса. Эта функция вызывается как из saveState(), так и из restoreState().
void TicTacToe::restoreState()
{
QFile file(sessionFileName());
if (file.open(IO_ReadOnly)) {
QTextStream in(&file);
for (int row = 0; row < 3; ++row) {
for (int col = 0; col < 3; ++col) {
in >> board[row][col];
if (board[row][col] != Empty)
++turnNumber;
}
}
}
repaint();
}
Функция restoreState() загружвет
файл, в котором было сохранено предыдущее состояние приложения и
заполняет игровое поле. Номер хода рассчитывается как сумма крестиков и
ноликов на игровом поле.Функция restoreState() вызывается в конструкторе класса TicTacToe, если QApplication::isSessionRestored() возвращает true. В этом случае, функции sessionId() и sessionKey() возвращают те же значения, с которыми было сохранено предыдущее состояние приложения. Отсюда и sessionFileName() вернет имя файла, соответствующее этой сессии.
Отладка взаимодействия с менеджером сеанса может оказаться занятием нудным и трудоемким, поскольку придется неоднократно перезапускать сессию. К счастью, в состав X11 входит утилита xsm. На запуске, эта утилита откроет окно менеджера сеанса и терминал. Приложения, запускаемые из терминала, будут использовать xsm, в качестве менеджера сеанса. После этого мы можем завершать и перезапускать сессии и следить за поведением отлаживаемого приложения. Дополнительные сведения по этой теме вы найдете по адресу: http://doc.trolltech.com/3.2/session.html.
Пред. | В начало | След. |
ActiveX. | На уровень выше | Об авторах. |