Шрифт:
Интервал:
Закладка:
Спасибо Андрею и Алексу за это дополнение, теперь мы с вами знаем четыре способа изменить курсор;). Должен признаться, в предыдущем выпуске я допустил оплошность , ляпнув что первый параметр у AfxRegisterWndClass() можно заменить на cs.style, причем, как назло, понял свою ошибку как раз в тот момент, когда отправлял рассылку "в эфир". Мне не преминули на эту ошибку указать, и я очень рад этому. Пожалуйста, будьте бдительны!!! Я тоже человек! Подробности читайте ниже…
Спасибо Вам за создание действительно нужной рассылки. [Мерси за комплимент ;) – AJ]
Я не так давно начал использовать MFC, и информация, ответы на вопросы мне очень пригодятся. Интересно, что уже в первом прочитанном мной выпуске обсуждался вопрос о курсоре, решение которого я буквально только что искал сам. Поэтому я решил написать этот отзыв в виде нескольких замечаний. На всякий случай оговорю, что все ниже написанное не более чем мое humble opinion :-))
1) Мне не кажется, что описанный Вами универсальный способ изменения курсора нерационален. Не этот обработчик, так CWnd::OnSetCursor() все равно вызывается при каждом движении мыши. Поэтому разнице в скорости практически неоткуда взяться. Хотя, LoadCursor() действительно лучше вызвать один раз (когда этот курсор впервые устанавливается), сохранить дескриптор нового курсора, который и передавать системной функции SetCursor() в обработчике. Мне кажется, это будет по сути то же самое, что делается при обработке события WM_SETCURSOR по умолчанию.
2) О "песочных часах". Если операция, на время которой высвечиваются часики, относительно невелика по времени, и при ее выполнении приложение может не реагировать на другие события, проще всего выделить блок обработки и определить в этом блоке локальный объект CWaitCursor. Все необходимые операции по установке и удалению курсора будут сделаны конструктором и деструктором этого объекта. Именно так, например, в MFC реализованы часики при открытии и сохранении документа. Если же во время операции система реагирует на другие события, то удобнее применять Begin/Restore/EndWaitCursor() [Итак, способов уже пять! – AJ]
3) Вы показываете пример с переопределением precreatewindow(), в котором регистрируется новый класс окна, и в конце пишете: "В качестве первого параметра для AfxRegisterWndClass() можно указать "cs.style", чтобы установить стиль окна по умолчанию." По-моему, это некорректно. Ведь cs.style есть комбинация стилей для окна , а не для класса окна , что требуется при регистрации класса. [Виновен, Ваша честь! – AJ] Мне пришлось столкнуться с этой проблемой, когда я хотел для своего класса CMyView добавить стиль CS_OWNDC, не меняя ничего больше. Дело в том, что при самом первом вызове CMyView::PreCreateWindow() класс окна просмотра еще не существует, так как он регистрируется в CView::PreCreateWindow(). Поэтому пришлось вызывать родительскую функцию дважды. Вот мое решение, которое, быть может, будет кому-то полезно:
//h-файл
class CMyView :public CView {
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
static LPCTSTR lpszViewClassName;
}
//cpp-файл
LPCTSTR CMyView::lpszViewClassName = NULL;
BOOL CMyView::PreCreateWindow(CREATESTRUCT& cs) {
if (lpszViewClassName == NULL) {
CView::PreCreateWindow(cs);
WNDCLASS wc;
//пытаемся получить информацию о классе
//если не удается, выходим с ошибкой
if (!::GetClassInfo(AfxGetInstanceHandle(), cs.lpszClass, &wc)) return FALSE;
// теперь изменяем в wc все, что нужно
// например, стиль класса
wc.style |= CS_OWNDC;
// регистрируем класс
lpszViewClassName = AfxRegisterWndClass(wc.style, wc.hCursor, wc.hbrBackground, wc.hIcon);
}
// изменяем класс окна на созданный нами:
cs.lpszClass = lpszViewClassName;
return CView::PreCreateWindow(cs);
}
[Я немножко подправил код и добавил комментарии. Надеюсь, автор на меня не обидится – AJ]
Есть у меня и вопросы, ответы на которые, возможно, будут интересны не только мне.
Q1) В приложении есть операция, которая требует, скажем, больше пяти минут времени, причем по некоторым причинам дальнейшее выполнение не может быть продолжено до завершения этой операции. Хотелось бы, чтобы при этом окно приложения нормально обновлялось, могло быть свернуто-развернуто и т.п. Я нашел некоторое решение, но оно требует создания второго цикла обработки сообщений и потому мне не очень нравится, хотелось бы сделать более естественно.
Q2) Можно ли переопределенный обработчик событий сделать подставляемым (inline)?
Куканов Алексей ([email protected])Очень хорошее, обстоятельное письмо. Хотя оно и содержит вопросы, я все же решил поместить его в "обратную связь", т.к. по большей части относится к теме, ну а разбивать письмо на две части – это было бы варварство. Если кто-нибудь знает ответы на заданные вопросы – очень прошу поделиться ! Вопросы действительно интересные.
Если у вас есть еще какие-либо комментарии на тему смены курсора мыши, пишите лучше сейчас. После следующего выпуска тема будет считаться закрытой.
ВОПРОС – ОТВЕТВопросы прислал IvanPouzyrevsky. И хотя у некоторых из вас они могут вызвать улыбку, я решил опубликовать их в рассылке вместо личного ответа, т.к. все-таки довольно большое число начинающих программистов на VC далеко не сразу понимает, как работать с диалогами в концепции MFC.
Q. Создаю кнопку About. В MFC Class Wizard создаю функцию: IDS_ABOUT->BN_CLICKED. А какой код на открытие окна About?
A. Чтобы вызвать модальный (т.е. не разрешающий переключаться куда-то еще в приложении, пока пользователь не закрыл его) диалог, следует воспользоваться ф-цией DoModal():
CAboutDlg aboutDlg;
aboutDlg.DoModal();
AppWizard генерирует такой код сам на команду ID_APP_ABOUT. Так что проще всего, если вы при создании приложения попросили AppWizard создать окно About, назначить Вашей кнопке идентификатор ID_APP_ABOUT. Тогда больше ничего делать не надо.
А вообще, таким образом можно вызвать не только диалоговое окно About, но и любое другое. Кому не совсем ясно, как обеспечить обмен данными с диалогом, присылайте заявки . В случае наличия интереса это станет одной из следующих тем выпуска.
Господа опытные программисты, прошу не тратить силы на ворчание – я не могу угодить всем! Для вас тоже будет кое-что интересное.
Q. У меня в программе при написании слова выполняется функция. Например:
if (UpperValue==CALCULATOR) {
system("calc.exe");
m_TestEdit="";
UpdateData(FALSE);
}
Но тут вопрос: как пользователю без изменения кода добавлять в базу данных слова?
Например диал. окно
Слово=
Файл Запуска=
И как указывать путь к файлу, а то при system("d:unrealtournamentsystemunrealtournament.exe") пишет, что файл не найден?
A. Попробуйте сделать два массива (или списка) CString – один для слов, другой для файлов. Добавляйте в массивы данные по мере ввода их пользователем. При запуске вызывайте нужный файл. Это можно более эффективно сделать с использованием ассоциативного списка (СMap), но сейчас, пожалуй, лучше не забивайте этим голову.
В C++ в строках символ "" воспринимается как управляющий, чтобы представлять такие вещи, как "n" – Enter, "b"– звонок, " " – "косой ноль" и др. В частности, управляющая последовательность "\" сама представляет символ "", поэтому в строке его надо удвоить, а т.к. используются длинные имена, то лучше еще заключить строку в дополнительные кавычки с помощью управляющей посл-ти " (хотя у меня работало и без них):
system(""D:\UnrealTournament\System\unrealtournament.exe"");
Да, надо сказать, уважаемый Ivan, что мне дико нравится файл, который Вы запускаете ;)
В ПОИСКАХ ИСТИНЫНу вот, как я и обещал – новая рубрика. Ваши вопросы, на которые я надеюсь от вас же получить ответы. Ну, поехали:
Q. При вылизывании проекта под MS Visual C++ 5.0 была произведена замена операции заполнения служебных переменных данными из файла на диске на операцию заполнения из строковых ресурсов проекта (файл .rc). Используется ф-ция LoadString() MFC класса CString с использованием в качестве аргумента ф-ции числового идентификатора ресурса (передается не IDS_XXXX, а его числовое значение). Файл "resource.h" в необходимые файлы включен. Под VC++ 6.0 – картина аналогичная :(. Компиляция проекта при этом происходит без ошибок и предупреждений. При выполнении проекта в Debug-версии на этапе выполнения указанной выше ф-ции возникает "Debug Assertion Failed" в файле afxwin1.inl на строке 22. Этот блок из себя представляет следующее:
_AFX_WININLINE HINSTANCE AFXAPI AfxGetResourceHandle() {
ASSERT(afxCurrentResourceHandle != NULL); //строка 22
return afxCurrentResourceHandle;
}
При нажатии на клавишу "Пропустить" программа идет дальше и вываливается на следующей операции загрузки строки с теми же симптомами и так до тех пор, пока не будут загружены все строки. После этого выполнение программы продолжается в нормальном режиме и все остальное работает как надо (строки все-таки загружаются!). В Release-версии программа пролетает это место без спотыканий.
- Программирование - Ирина Козлова - Программирование
- Программирование — вторая грамотность - Андрей Ершов - Программирование
- 97 этюдов для архитекторов программных систем - Нил Форд - Программирование
- Платформа J2Me - Автор неизвестен - Программирование