The OpenNET Project / Index page

[ новости /+++ | форум | wiki | теги | ]

Каталог документации / Раздел "Программирование, языки" / Оглавление документа

18.3. Управление сеансами.

В момент завершения сеанса X11, некоторые оконные менеджеры выдают запрос на подтверждение завершения сеанса. Если мы подтверждаем завершение сессии, то приложения, которые работали в этот момент, будут автоматически запущены в начале следующего сеанса, с теми же экранными координатами и, в идеале, в том же самом состоянии.

Компонент X11, который управляет сохранением и восстановлением сеанса называется менеджер сеанса (или, если хотите, менеджер сессии). Чтобы добавить в Qt-приложение возможность сохранения своего состояния, в момент завершения сессии, необходимо перекрыть метод QApplication::saveState(), в котором выполнять сохранение всех необходимых параметров.

Рисунок 18.6. Окно запроса подтверждения завершения сеанса в KDE.


Операционные системы Windows 2000/XP (и некоторые Unix-системы) предлагают иной механизм сохранения сеансов, который носит название гибернация (hibernation). Когда пользователь переводит систему в режим гибернации, то она просто скидывает дамп памяти на диск и на следующем запуске загружает его. В этом случае приложениям ничего не надо делать, им даже нет необходимости что либо "знать" о гибернации.

Момент завершения работы может быть перехвачен приложением, для этого надо перекрыть метод 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. Внешний вид приложения "Крестики-нолики".


Ниже приводится определение класса Application:
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. Запрос на подтверждение завершения работы программы.


Теперь перейдем к рассмотрению класса TicTacToe:
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.




Спонсоры:
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2021 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру