Litvek: лучшие книги недели
Топ книга - Империи Средневековья. От Каролингов до Чингизидов [Мари-Селин Исайя] - читаем полностью в LitvekТоп книга - Без подводных камней [Мария Воронова] - читаем полностью в LitvekТоп книга - Уравнение Бога. В поисках теории всего [Мичио Каку] - читаем полностью в LitvekТоп книга - Сестра луны [Люсинда Райли] - читаем полностью в LitvekТоп книга - Клуб убийств по четвергам [Ричард Томас Осман] - читаем полностью в LitvekТоп книга - Черные кувшинки [Мишель Бюсси] - читаем полностью в LitvekТоп книга - Легкий способ бросить курить [Аллен Карр] - читаем полностью в LitvekТоп книга - Остров тринадцати приговоренных [Юлия Ефимова] - читаем полностью в Litvek
Litvek - онлайн библиотека >> Алекс Jenter >> C, C++, C# и др. >> Программирование на Visual C++. Архив рассылки >> страница 3
варианта я буду делать лично, никакой автоматической генерации. Enjoy.

ОБРАТНАЯ СВЯЗЬ
Мне пришло интересное письмо на тему предыдущего выпуска. Хочу предложить его вашему вниманию:

Приветствую!

Я только что обнаружил эту рассылку, подписался и 2 первых выпуска прочитал в архиве. Очень надеюсь, что смогу оказать посильную помощь автору и читателям рассылки, так как около 30 лет занимаюсь программированием и последние 3-4 года – Visual C++. На работе сейчас я программирую именно на этом [языке – AJ], Visual Studio 6.0

В отношении вопроса Броника. Конечно, система сериализации для ActiveX имеется. Для этого рекомендуется использовать класс COLEControl (порожденный из CWnd –>CCMDTarget->CObject).

Вот пример из MSDN (у меня есть этот хелп и на работе и дома)

void CMyCtrl::Serialize(CArchive& ar) {

 DWORD dwVersion = SerializeVersion(ar, MAKELONG(_wVerMinor, _wVerMajor));

 SerializeExtent(ar);

 SerializeStockProps(ar);

 if (ar.IsLoading()) {

  // загрузить свойства

 } else {

  // сохранить свойства

 }

}

Пару замечаний относительно сериализации. Вот пример, как можно поддерживать версию при сериализации. Это важная вещь, поскольку в классы регулярно заносятся новые данные, и чтение-сериализация должны поддерживать старые версии распространенных среди пользователей Вашей программы файлов.

IMPLEMENT_SERIAL(CMyClass, CObject, VERSIONABLE_SCHEMA | 2)

// 2- Номер текущей (новой) версии. 1 - номер старой версии


void CMyClass::Serialize(CArchive& ar) {

 if (ar.IsLoading()) {

  UINT Version;

  ar.ReadClass(RUNTIME_CLASS(CMyClass), &Version);

  switch(Version) {

  case 2:

   // чтение по-новому

   break;

  case 1:

   // чтение по-старому

   break;

  }

 }

 if (ar.IsStoring()) {

  ar.WriteClass( RUNTIME_CLASS(CMyClass));

  // запись по-новому

 }

}

Понятное дело, при продвижении версии номер в IMPLEMENT_SERIAL возрастает, и добавляется новый случай case только при чтении соответствующих версий.

Еще одно важное замечание. При использовании механизма сериализации мы платим некоторую цену: не допускается никаких абстрактных классов – забудьте, что это существует!

Boris Berdichevski
Что ж, огромное спасибо Борису за комментарии и дополнения. Я надеюсь, он и в будущем будет нам посильно помогать. Что касается вопроса Броника – думаю, он все-таки спрашивал не о том, как сделать сериализацию для ActiveX(хотя это тоже очень интересный момент), а как организовать структурированное хранение данных в файле , наподобие того, что присутствует в ActiveX. Ответа на этот вопрос, за исключением предложенного мной в предыдущем выпуске, пока нет.

Просьба: когда пишете мне, пожалуйста оговаривайте ваше отношение к публикации вашего e-mail адреса. Я оставляю за собой право решать, какие из ваших писем появятся в рассылке. По умолчанию адрес публиковаться не будет.   Если вы хотите связаться с человеком, письмо которого  вы прочитали в рассылке, но чей адрес не был указан, пишите мне с пометкой в subject'e для кого это письмо.

ВОПРОС – ОТВЕТ
Q. Идея рассылки и её тематика очень понравились, даже добавлять или изменять ничего не хочется, как по заказу. И даже уже вопрос созрел. При первом знакомстве с MFC помню была одна проблема. Никак не получалось сменить пиктограмку курсора во время выполнения программы. Т.е. последовательность стандартных действий LoadCursor и SetCursor не срабатывала, хотя при создании окна этих действий хватало. В связи с этим вопрос: Какие ещё действия надо выполнить для смены пиктограмки курсора во время работы приложения. Сейчас, к сожалению, интересы лежат не в области C++ и MFC. Поэтому на разрешение вопроса своими силами просто нет времени.

softmax
A. Спасибо за добрые слова о рассылке. По вопросу – проблема здесь в том, что система автоматически при каждом движении мыши восстанавливает тот курсор, который был указан при регистрации класса окна. Вообще я знаю три способа изменить курсор в MFC-приложении, причем два из них имеют некоторые ограничения: один используется, в самом деле, при создании окна, а второй работает только с одним курсором – стандартными песочными часами. Думаю, что стоит описать все три способа, для того, чтобы вы могли выбрать наиболее для вас подходящий. Итак:

Способ №1 (универсальный). Нужно перекрыть функцию OnSetCursor() класса CWnd, родителя вашего окна (вида). В ней необходимо сообщение обработать самому, устанавливая нужный курсор. Для тех, кто не знает, сообщение WM_SETCURSOR посылается окну тогда, когда курсор мыши двигается внутри окна, причем  мышь приложением  не захвачена (с помощью функции SetCapture()). Вот пример из MSDN:

BOOL CMyView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) {

 if (m_ChangeCursor) {

  // устанавливаем стандартный курсор вида "I"

  ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_IBEAM));

  return TRUE;

 }

 return CView::OnSetCursor(pWnd, nHitTest, message);

}

Конечно, можно установить и ваш собственный курсор, только вместо LoadStandardCursor() нужно будет воспользоваться LoadCursor() или LoadOEMCursor(). С помощью параметра nHitTest можно определить область, в которой сейчас находится курсор. Вообще, этот способ лучше применять только тогда, когда вам в самом деле нужно динамически менять один курсор на другой (причем отличный от песочных часов), потому этот способ самый нерациональный (прикиньте-ка. сколько раз будет выполняться этот обработчик). Лучше все нужные курсоры загрузить заранее, а из функции– обработчика Load..Cursor() не вызывать. Хотя, в принципе, я для примера сделал такой обработчик – никакой разницы в скорости не заметил…но это уже зависит от конкретного компьютера, наверное. И потом, наверное не стали бы в MSDN это советовать, если бы не знали, что делали ;) 

Ну а тем, кому лишь надо видом курсора  показать пользователю, что компьютер сейчас занят какой-то операцией, идеально подходит

Способ №2 (песочные часы). Этот способ самый простой. Вызывайте функцию BeginWaitCursor() перед началом операции и EndWaitCursor() после ее завершения. Единственный нюанс здесь в том, что если эти два вызова должны находиться в разных функциях-обработчиках, то вам все же придется перекрыть OnSetCursor(), причем это выглядит примерно так:

BOOL CMyView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) {

 if (m_ChangeCursor) {

  RestoreWaitCursor(); // восстанавливаем курсор-пес.часы

  return TRUE;

 }

 return CView::OnSetCursor(pWnd, nHitTest, message);

}

В этом случае перед вызовом BeginWaitCursor()  m_ChangeCursor нужно приравнять к TRUE, а после EndWaitCursor() – к FALSE.

Способ №3 (класс окна). Этот метод применяется, когда вам для какого-то окна нужно установить конкретный курсор, причем желательно на все время существования окна. Перекрываете PreCreateWindow() и регистрируете свой класс окна, изменяя поле lpszClass параметра cs типа CREATESTRUCT:

BOOL CMyView::PreCreateWindow(CREATESTRUCT& cs) {

 cs.lpszClass = AfxRegisterWndClass(

  CS_DBLCLKS |