FAQ:WinAPI, VCPP Part 2 — различия между версиями
(→Как в отладчике Visual С++ просмотреть содержимое std::vector ?) |
RXL (обсуждение | вклад) м (Форматирование.) |
||
Строка 1: | Строка 1: | ||
+ | ===Как сделать обработчик сообщения для нескольких контролов (элементов управления) сразу?=== | ||
+ | Без помощи визарда (Wizard) это можно сделать переопределением виртуальной функции OnCommand(): | ||
− | + | <syntaxhighlight lang="cpp"> | |
− | + | BOOL CMyDialog::OnCommand(WPARAM wParam, LPARAM lParam) | |
− | + | ||
− | <syntaxhighlight> | + | |
− | BOOL CMyDialog::OnCommand(WPARAM wParam, LPARAM lParam) | + | |
{ | { | ||
− | WORD wMess=(wParam>>16);//командное сообщение | + | WORD wMess = (wParam >> 16); //командное сообщение |
− | int nID=(int)(wParam &0x0000ffff));//ID контрола | + | int nID = (int)(wParam &0x0000ffff)); //ID контрола |
− | HWND hW=(HWND)lParam;//хендл контрола | + | HWND hW = (HWND)lParam; //хендл контрола |
− | //смотрим, какой контрол | + | // смотрим, какой контрол |
− | switch(nID) | + | switch (nID) |
{ | { | ||
//кнопки | //кнопки | ||
Строка 20: | Строка 19: | ||
{ | { | ||
//смотрим, какое сообщение | //смотрим, какое сообщение | ||
− | switch(wMess) | + | switch (wMess) |
{ | { | ||
− | case BN_CLICKED:{ ... }break; | + | case BN_CLICKED: { ... } break; |
} | } | ||
} | } | ||
break; | break; | ||
− | //едиты | + | // едиты |
case ID_ED1: | case ID_ED1: | ||
case ID_ED2: | case ID_ED2: | ||
Строка 33: | Строка 32: | ||
case ID_ED4: | case ID_ED4: | ||
{ | { | ||
− | //смотрим, какое сообщение | + | // смотрим, какое сообщение |
− | switch(wMess) | + | switch (wMess) |
{ | { | ||
− | case EN_CHANGE:{ ... }break; | + | case EN_CHANGE: { ... } break; |
− | case EN_KILLFOCUS:{ ... }break; | + | case EN_KILLFOCUS: { ... } break; |
} | } | ||
} | } | ||
Строка 47: | Строка 46: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | === Когда я запускаю программу, все надписи на русском языке теряются - показываются вопросики. Что делать? | + | ===Когда я запускаю программу, все надписи на русском языке теряются - показываются вопросики. Что делать?=== |
+ | |||
+ | Лечится проблема так: непосредственно после создания проекта открываем дерево ресурсов и в свойствах каждого элемента дерева ставим язык Russian. Если этого не сделать сразу, то все русские буквы при компиляции ресурсов потеряются. | ||
− | + | ===Как в проекте VC6 MFC программно получить путь, откуда был запущен экзешник (исполняемый модуль) самой программы?=== | |
− | + | Нужно использовать функцию GetModuleFileName(): | |
− | |||
<syntaxhighlight> | <syntaxhighlight> | ||
TCHAR pszFileName[MAX_PATH]; | TCHAR pszFileName[MAX_PATH]; | ||
− | pszFileName[0]=0; | + | pszFileName[0] = 0; |
+ | |||
GetModuleFileName(NULL, pszFileName, MAX_PATH); | GetModuleFileName(NULL, pszFileName, MAX_PATH); | ||
− | CString stModulePath = | + | CString stModulePath = pszFileName; |
− | //ищем первый слеш с конца и удаляем | + | |
− | //его вместе с именем файла EXE | + | // ищем первый слеш с конца и удаляем |
+ | // его вместе с именем файла EXE | ||
int nEnd = stModulePath.ReverseFind('\\'); | int nEnd = stModulePath.ReverseFind('\\'); | ||
− | stModulePath.Delete(nEnd, stModulePath.GetLength()-nEnd); | + | stModulePath.Delete(nEnd, stModulePath.GetLength() - nEnd); |
− | //stModulePath - содержит путь | + | // stModulePath - содержит путь |
</syntaxhighlight> | </syntaxhighlight> | ||
− | === Как получить доступ к элементам управления панели CReBar, принадлежащей классу MainFrame? | + | ===Как получить доступ к элементам управления панели CReBar, принадлежащей классу MainFrame?=== |
− | <syntaxhighlight> | + | <syntaxhighlight lang="cpp"> |
#include "MainFrm.h" | #include "MainFrm.h" | ||
− | //CMyApp - класс вашего приложения. theApp - глобальная переменная, | + | // CMyApp - класс вашего приложения. theApp - глобальная переменная, |
− | //поэтому для доступа к ней используем extern | + | // поэтому для доступа к ней используем extern |
+ | |||
extern CMyApp theApp; | extern CMyApp theApp; | ||
void CMyView::F() | void CMyView::F() | ||
{ | { | ||
− | //Получаем главное окно приложения в любом месте программы | + | // Получаем главное окно приложения в любом месте программы |
− | CMainFrame* pMainFrame=(CMainFrame*)(theApp.m_pMainWnd); | + | CMainFrame* pMainFrame = (CMainFrame*)(theApp.m_pMainWnd); |
− | pMainFrame->m_wndDlgBar ....//Делаем что хотим | + | pMainFrame->m_wndDlgBar ....; // Делаем что хотим |
... | ... | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | === Как загрузить и показать один из стандартных курсоров? | + | ===Как загрузить и показать один из стандартных курсоров?=== |
− | <syntaxhighlight> | + | <syntaxhighlight lang="cpp"> |
HCURSOR hCursor; | HCURSOR hCursor; | ||
− | |||
− | |||
− | |||
− | |||
− | + | hCursor = AfxGetApp()->LoadStandardCursor(IDC_UPARROW); | |
− | + | if (hCursor) | |
+ | SetCursor(hCursor); | ||
+ | </syntaxhighlight> | ||
− | + | Идентификаторы стандартных курсоров: | |
+ | * IDC_ARROW | ||
+ | * IDC_IBEAM | ||
+ | * IDC_WAIT | ||
+ | * IDC_CROSS | ||
+ | * IDC_UPARROW | ||
+ | * IDC_SIZENWSE | ||
+ | * IDC_SIZENESW | ||
+ | * IDC_SIZEWE | ||
+ | * IDC_SIZENS | ||
+ | * IDC_SIZEALL | ||
− | + | ===Как запретить пользователю закрыть программу нажатием на кнопку с крестиком?=== | |
− | + | Для этого нужно добавить обработчик сообщения WM_CLOSE (функция OnClose() в MFC) в главное окно программы. Для диалоговых приложений такое окно - это главный диалог, для одно- и много-документных приложений - это CMainFrame. | |
− | + | <syntaxhighlight lang="cpp"> | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | <syntaxhighlight> | + | |
void CMainFrame::OnClose() | void CMainFrame::OnClose() | ||
{ | { | ||
− | if( | + | if (....) |
{ | { | ||
− | //не разрешаем закрыть | + | // не разрешаем закрыть |
return; | return; | ||
} | } | ||
Строка 131: | Строка 129: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | === Как создать на диалоге группу элементов "RadioButton" и как задать порядок их обхода клавишей Tab? | + | ===Как создать на диалоге группу элементов "RadioButton" и как задать порядок их обхода клавишей Tab?=== |
Последовательность действий следующая: | Последовательность действий следующая: | ||
+ | # Помещаем на форму нужное количество элементов RadioButton; | ||
+ | # У первого элемента из группы ставим свойство Group, у остальных в группе - убираем это свойство; | ||
+ | # Порядок обхода (Tab Order) задаётся так: нажимаем Ctrl+D (загораются номера таб-порядка). Затем щёлкаем элементы в группе в таком порядке, который требуется. | ||
− | + | ===Где лучше устанавливать начальные значения элемента CComboBox?=== | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | === Где лучше устанавливать начальные значения элемента CComboBox? | + | |
Это можно сделать парой способов: | Это можно сделать парой способов: | ||
+ | # В редакторе форм - открыть свойства элемента CComboBox, "данные" (для ввода очередной строки данныхых нажать Ctrl+Enter); | ||
+ | # В функции OnInitDialog (в случае диалога) или в функции OnInitialUpdate (для CView). | ||
− | + | ===Как перевести RichEdit в режим замены символов?=== | |
− | + | Имеется несколько способов. | |
− | + | 1. Программно, если известен хендл элемента (hWnd), это делается так: | |
− | + | <syntaxhighlight lang="cpp"> | |
− | + | // помещаем в конец очереди сообющений контрола сообщение WM_KEYDOWN | |
− | + | // с нужными параметрами | |
− | <syntaxhighlight> | + | ::PostMessage(hWnd, WM_KEYDOWN, VK_INSERT, 1); |
− | + | ||
− | + | ||
− | + | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | 2 | + | 2. Пользователь во время работы может нажать клавишу Insert. |
− | === Как вызвать метод главного окна (если используется класс CMainFrame) из любого места программы? | + | ===Как вызвать метод главного окна (если используется класс CMainFrame) из любого места программы?=== |
Это можно сделать так: | Это можно сделать так: | ||
− | <syntaxhighlight> | + | <syntaxhighlight lang="cpp"> |
− | + | AfxGetApp()->m_pMainWnd-> ...; | |
</syntaxhighlight> | </syntaxhighlight> | ||
или так | или так | ||
− | <syntaxhighlight> | + | <syntaxhighlight lang="cpp"> |
− | + | extern CMyAppXXX theApp; // здесь CMyAppXXX - название класса вашего приложения | |
− | + | theApp.m_pMainWnd-> ...; | |
</syntaxhighlight> | </syntaxhighlight> | ||
− | === Как запретить появление полос прокруток на форме класса CFormView, когда пользователь делает размер главного окна меньше размера формы ? | + | ===Как запретить появление полос прокруток на форме класса CFormView, когда пользователь делает размер главного окна меньше размера формы ?=== |
Это можно сделать методом SetScaleToFitSize(): | Это можно сделать методом SetScaleToFitSize(): | ||
− | <syntaxhighlight> | + | |
+ | <syntaxhighlight lang="cpp"> | ||
void CMyView::OnInitialUpdate() | void CMyView::OnInitialUpdate() | ||
{ | { | ||
CFormView::OnInitialUpdate(); | CFormView::OnInitialUpdate(); | ||
− | //скрываем полосы прокрутки | + | // скрываем полосы прокрутки |
GetParentFrame()->RecalcLayout(); | GetParentFrame()->RecalcLayout(); | ||
− | ResizeParentToFit();//это уберёт полосы прокрутки со вьюхи | + | ResizeParentToFit(); // это уберёт полосы прокрутки со вьюхи |
− | SIZE s={0,0}; | + | SIZE s = {0, 0}; |
SetScaleToFitSize(s); | SetScaleToFitSize(s); | ||
//далее вызовется обработчик OnPaint(), о котором ниже | //далее вызовется обработчик OnPaint(), о котором ниже | ||
− | // | + | |
− | + | // ... | |
− | + | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | Также обратите внимание на одну особенность: в | + | Также обратите внимание на одну особенность: в отладочной версии программы вызов OnPaint после выполнения SetScaleToFitSize() с параметром s = {0, 0} происходит с ошибкой (программа при этом завершается). |
Обходится это так: | Обходится это так: | ||
− | <syntaxhighlight> | + | |
− | void CMyView::OnPaint() | + | <syntaxhighlight lang="cpp"> |
+ | void CMyView::OnPaint() | ||
{ | { | ||
#ifdef _DEBUG | #ifdef _DEBUG | ||
Строка 209: | Строка 204: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | + | Или так: | |
− | <syntaxhighlight> | + | |
− | void CMyView::OnPaint() | + | <syntaxhighlight lang="cpp"> |
+ | void CMyView::OnPaint() | ||
{ | { | ||
CPaintDC dc(this); | CPaintDC dc(this); | ||
Строка 217: | Строка 213: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | === Как нарисовать прямоугольник с вертикальным цветовым градиентом? | + | ===Как нарисовать прямоугольник с вертикальным цветовым градиентом?=== |
+ | |||
+ | Нужно задасть граничные значения цветов, затем равномерно нарисовать несколько прямоугольников постепенно меняющегося цвета. Количество прямоугольников, а, значит - плавность градиента, задаётся точностью. | ||
− | |||
Пример: | Пример: | ||
− | <syntaxhighlight> | + | |
− | //вертикальный градиент | + | <syntaxhighlight lang="cpp"> |
− | //pdc - указатель на контекст устройства | + | // вертикальный градиент |
− | //pSize - указатель на структуру | + | // pdc - указатель на контекст устройства |
− | //SIZE с размером прямоугольника | + | // pSize - указатель на структуру |
+ | // SIZE с размером прямоугольника | ||
// dwdColor1, dwdColor2 - начальный и конечный цвет | // dwdColor1, dwdColor2 - начальный и конечный цвет | ||
− | //bySteps - количество шагов градиента (1...255) | + | // bySteps - количество шагов градиента (1...255) |
− | void sFillVertGradientRect(CDC* pdc,SIZE *pSize, COLORREF dwdColor1, COLORREF dwdColor2,BYTE bySteps) | + | void sFillVertGradientRect(CDC* pdc, SIZE *pSize, COLORREF dwdColor1, |
+ | COLORREF dwdColor2, BYTE bySteps) | ||
{ | { | ||
− | |||
WORD i; | WORD i; | ||
+ | long W, H, x1, x2; | ||
+ | BYTE R1, G1, B1, R2, G2, B2; | ||
+ | float dh, dR, dG, dB, y1, y2, Rc, Gc, Bc; | ||
− | + | if (!bySteps) | |
− | + | bySteps = 1; | |
− | + | ||
− | + | ||
//ширина и высота | //ширина и высота | ||
− | W=pSize->cx; | + | W = pSize->cx; |
− | H=pSize->cy; | + | H = pSize->cy; |
− | //раскладываем цвета на их составляющие | + | // раскладываем цвета на их составляющие |
− | //для удобства дальнейших вычислений | + | // для удобства дальнейших вычислений |
− | R1=(BYTE)((dwdColor1&0x000000ff)); | + | R1 = (BYTE)((dwdColor1 & 0x000000ff)); |
− | G1=(BYTE)((dwdColor1&0x0000ff00)>>8); | + | G1 = (BYTE)((dwdColor1 & 0x0000ff00) >> 8); |
− | B1=(BYTE)((dwdColor1&0x00ff0000)>>16); | + | B1 = (BYTE)((dwdColor1 & 0x00ff0000) >> 16); |
− | R2=(BYTE)((dwdColor2&0x000000ff)); | + | R2 = (BYTE)((dwdColor2 & 0x000000ff)); |
− | G2=(BYTE)((dwdColor2&0x0000ff00)>>8); | + | G2 = (BYTE)((dwdColor2 & 0x0000ff00) >> 8); |
− | B2=(BYTE)((dwdColor2&0x00ff0000)>>16); | + | B2 = (BYTE)((dwdColor2 & 0x00ff0000) >> 16); |
− | //высота разноцветных прямоугольников | + | // высота разноцветных прямоугольников |
− | dh=((float)H)/((float)bySteps); | + | dh = ((float)H) / ((float)bySteps); |
− | //величина шагов составляющих цветов | + | |
− | dR=(((float)R2)-((float)R1))/((float)bySteps); | + | // величина шагов составляющих цветов |
− | dG=(((float)G2)-((float)G1))/((float)bySteps); | + | dR = (((float)R2) - ((float)R1)) / ((float)bySteps); |
− | dB=(((float)B2)-((float)B1))/((float)bySteps); | + | dG = (((float)G2) - ((float)G1)) / ((float)bySteps); |
− | //выводим прямоугольники | + | dB = (((float)B2) - ((float)B1)) / ((float)bySteps); |
− | x1=0;x2=W;y1=0;y2=dh; | + | |
− | Rc=R1;Gc=G1;Bc=B1; | + | // выводим прямоугольники |
− | for(i=0;i<bySteps;i++) | + | x1 = 0; |
+ | x2 = W; | ||
+ | y1 = 0; | ||
+ | y2 = dh; | ||
+ | Rc = R1; | ||
+ | Gc = G1; | ||
+ | Bc = B1; | ||
+ | |||
+ | for (i = 0; i < bySteps; i++) | ||
{ | { | ||
− | //текущий цвет | + | // текущий цвет |
− | pdc->FillSolidRect(x1,(int)y1,x2-x1,(int)(y2-y1),RGB((BYTE)Rc,(BYTE)Gc,(BYTE)Bc)); | + | pdc->FillSolidRect( |
− | //следующий цвет и координаты | + | x1, |
− | y1+=dh;y2+=dh; | + | (int)y1, x2 - x1, |
− | Rc+=dR;Gc+=dG;Bc+=dB; | + | (int)(y2 - y1), |
+ | RGB((BYTE)Rc, | ||
+ | (BYTE)Gc, | ||
+ | (BYTE)Bc) | ||
+ | ); | ||
+ | |||
+ | // следующий цвет и координаты | ||
+ | y1 += dh; | ||
+ | y2 += dh; | ||
+ | Rc += dR; | ||
+ | Gc += dG; | ||
+ | Bc += dB; | ||
} | } | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | + | Пример вызова: | |
− | <syntaxhighlight> | + | |
− | SIZE Size={100,100}; | + | <syntaxhighlight lang="cpp"> |
− | sFillGradientRect(&dc,&Size, RGB(200,0,0), RGB(0,200,0),10); | + | SIZE Size = {100, 100}; |
+ | sFillGradientRect(&dc, &Size, RGB(200, 0, 0), RGB(0, 200, 0), 10); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | === Как под Windows отслеживать изменение файла? | + | ===Как под Windows отслеживать изменение файла?=== |
− | Нужно использовать функции: | + | Нужно использовать функции: |
− | + | * FindFirstChangeNotification | |
− | FindFirstChangeNotification | + | * FindNextChangeNotification |
− | + | * FindCloseChangeNotification | |
− | FindNextChangeNotification | + | |
− | + | ||
− | FindCloseChangeNotification | + | |
(подробности - в MSDN) | (подробности - в MSDN) | ||
− | === Как конвертировать массив char[] в CString? | + | ===Как конвертировать массив char[] в CString?=== |
+ | |||
Это можно сделать методами самого класса CString: | Это можно сделать методами самого класса CString: | ||
− | |||
− | |||
− | //строка должна обязательно заканчиваться нулём!!! | + | <syntaxhighlight lang="cpp"> |
+ | char buf[] = "text"; | ||
+ | // строка должна обязательно заканчиваться нулём!!! | ||
− | //конвертируем так | + | // конвертируем так |
CString txt(buf); | CString txt(buf); | ||
− | //или так | + | // или так |
CString txt; | CString txt; | ||
− | txt=buf; | + | txt = buf; |
</syntaxhighlight> | </syntaxhighlight> | ||
− | === Как зарезервировать в CString буфер нужной длины? | + | ===Как зарезервировать в CString буфер нужной длины?=== |
− | Это можно сделать при помощи методов класса: | + | Это можно сделать при помощи методов класса: |
− | <syntaxhighlight> | + | <syntaxhighlight lang="cpp"> |
− | CString::GetBuffer(...) | + | CString::GetBuffer(...); |
</syntaxhighlight> | </syntaxhighlight> | ||
+ | |||
и | и | ||
− | <syntaxhighlight> | + | |
− | CString::GetBufferSetLength(...) | + | <syntaxhighlight lang="cpp"> |
+ | CString::GetBufferSetLength(...); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | Разница между GetBuffer(nLen) и GetBufferSetLength(nLen) в том, что первый возвращает строку | + | Разница между GetBuffer(nLen) и GetBufferSetLength(nLen) в том, что первый возвращает строку ''не меньше'' заданной длины, а второй возвращает строку, точно равную заданной длине. Обе могут перераспределять память, если необходимо. В обычных случаях лучше использовать GetBuffer. |
− | Если содержимое буфера менялось, то после этого нужно вызвать CString::ReleaseBuffer с указанием новой длины. Значение -1 в вызове CString::ReleaseBuffer означает, что длина строки будет вычислена автоматом (функцией strlen) в методе."-1" удобно использовать, если известно, что строка заканчивается нулем. | + | Если содержимое буфера менялось, то после этого нужно вызвать CString::ReleaseBuffer с указанием новой длины. Значение -1 в вызове CString::ReleaseBuffer означает, что длина строки будет вычислена автоматом (функцией strlen) в методе. "-1" удобно использовать, если известно, что строка заканчивается нулем. |
− | === Как передать больше одного параметр в процедуру потока? | + | ===Как передать больше одного параметр в процедуру потока?=== |
Для этого нужно определить структуру со всеми параметрами (или указателями на них), которые нужно передать. А в процедуру потока передать лишь указатель на заполненную структуру. | Для этого нужно определить структуру со всеми параметрами (или указателями на них), которые нужно передать. А в процедуру потока передать лишь указатель на заполненную структуру. | ||
+ | |||
Пример: | Пример: | ||
− | <syntaxhighlight> | + | |
+ | <syntaxhighlight lang="cpp"> | ||
struct mystr | struct mystr | ||
{ | { | ||
Строка 333: | Строка 355: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | запуск потока: | + | запуск потока: |
− | <syntaxhighlight> | + | <syntaxhighlight lang="cpp"> |
− | mystr *pparam=new mystr;//экземпляр не должен быть временным!!! | + | mystr *pparam = new mystr; // экземпляр не должен быть временным!!! |
− | memset(pparam,0,sizeof(*pparam)); | + | memset(pparam, 0, sizeof(*pparam)); |
− | pparam->pEd=...; | + | pparam->pEd = ...; |
− | pparam->pdwd=...; | + | pparam->pdwd = ...; |
− | ::AfxBeginThread(thread,pparam); | + | ::AfxBeginThread(thread, pparam); |
− | //тут экземпляр *(pparam) уже нельзя использовать в нашем примере, так как | + | // тут экземпляр *(pparam) уже нельзя использовать в нашем примере, так как |
− | //он у нас удалиля в процедуре потока | + | // он у нас удалиля в процедуре потока |
</syntaxhighlight> | </syntaxhighlight> | ||
− | + | Процедура потока: | |
− | <syntaxhighlight> | + | |
− | //поток: | + | <syntaxhighlight lang="cpp"> |
− | UINT threadLoader(LPVOID pParam) | + | // поток: |
− | { | + | UINT threadLoader(LPVOID pParam) |
− | //копируем данные из структуры в локальную структуру | + | { |
− | mystr data=*((mystr*)pParam); | + | // копируем данные из структуры в локальную структуру |
− | //освобождаем память временной структуры | + | mystr data = *((mystr*)pParam); |
+ | // освобождаем память временной структуры | ||
delete ((mystr*)pParam); | delete ((mystr*)pParam); | ||
− | pParam=0; | + | pParam = 0; |
− | + | ||
... | ... | ||
data.pDlg->...; | data.pDlg->...; | ||
− | (*data.pdwd)=...; | + | (*data.pdwd) = ...; |
... | ... | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | === Как убрать главное меню из окна CMainFrame? | + | ===Как убрать главное меню из окна CMainFrame?=== |
+ | |||
Это можно сделать в виртуальной функции PreCreateWindow: | Это можно сделать в виртуальной функции PreCreateWindow: | ||
− | <syntaxhighlight> | + | |
+ | <syntaxhighlight lang="cpp"> | ||
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) | BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) | ||
{ | { | ||
− | //обнуляем хендл меню до вызова CFrameWnd::PreCreateWindow | + | // обнуляем хендл меню до вызова CFrameWnd::PreCreateWindow |
cs.hMenu = 0; | cs.hMenu = 0; | ||
− | if(!CFrameWnd::PreCreateWindow(cs)) | + | if (!CFrameWnd::PreCreateWindow(cs)) |
return FALSE; | return FALSE; | ||
− | + | ||
... | ... | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | === Как работающая программа может определить, что пользователь завершает работу Windows? | + | ===Как работающая программа может определить, что пользователь завершает работу Windows?=== |
Когда пользователь завершает работу Windows, всем процессам посылается сообщение WM_QUERYENDSESSION. Его нужно отловить в обработчике OnQueryEndSession(). Если вернуть из обработчика значение 0, то Windows продолжит работу. | Когда пользователь завершает работу Windows, всем процессам посылается сообщение WM_QUERYENDSESSION. Его нужно отловить в обработчике OnQueryEndSession(). Если вернуть из обработчика значение 0, то Windows продолжит работу. | ||
− | === Как сделать всплывающую подсказку для класса CWnd и классов, от него производных? | + | ===Как сделать всплывающую подсказку для класса CWnd и классов, от него производных?=== |
− | Допустим, имеется диалог класса CMyDlg. Делаем подсказки для элементов управления (для CStatic контролов не забудьте поставить свойство Notify) : | + | Допустим, имеется диалог класса CMyDlg. Делаем подсказки для элементов управления (для CStatic контролов не забудьте поставить свойство Notify): |
− | <syntaxhighlight> | + | |
+ | <syntaxhighlight lang="cpp"> | ||
class CMyDlg:puplic CDialog | class CMyDlg:puplic CDialog | ||
{ | { | ||
− | CToolTipCtrl m_ToolTip;//мембер класса CMyDlg | + | CToolTipCtrl m_ToolTip; // мембер класса CMyDlg |
}; | }; | ||
− | + | ||
− | //массив, в котором перечислены идентификаторы | + | // массив, в котором перечислены идентификаторы |
− | //контролов и тексты подсказок к ним | + | // контролов и тексты подсказок к ним |
− | struct{int ID;const char* pch;} m_a_Tips[]= | + | struct |
+ | { | ||
+ | int ID; | ||
+ | const char* pch; | ||
+ | } | ||
+ | m_a_Tips[] = | ||
{ | { | ||
− | {IDC_BUTTON1,"Кнопка"}, | + | {IDC_BUTTON1, "Кнопка"}, |
− | {IDC_STATIC1,"Текст"}, | + | {IDC_STATIC1, "Текст"}, |
− | + | {0, 0} // признак конца массива | |
− | {0,0} | + | |
}; | }; | ||
− | + | ||
− | //в инициализации диалога (хотя, в принципе, | + | // в инициализации диалога (хотя, в принципе, |
− | //можно и не тут) создаём и привязываем подсказки | + | // можно и не тут) создаём и привязываем подсказки |
− | BOOL CMyDlg::OnInitDialog() | + | BOOL CMyDlg::OnInitDialog() |
{ | { | ||
CDialog::OnInitDialog(); | CDialog::OnInitDialog(); | ||
− | //создаём элемент TOOLTIP | + | // создаём элемент TOOLTIP |
m_ToolTip.Create(this); | m_ToolTip.Create(this); | ||
− | //Привязка подсказок | + | // Привязка подсказок |
− | for(int i=0; m_a_Tips[i].ID; i++) | + | for (int i = 0; m_a_Tips[i].ID; i++) |
{ | { | ||
m_ToolTip.AddTool( | m_ToolTip.AddTool( | ||
GetDlgItem(m_a_Tips[i].ID), | GetDlgItem(m_a_Tips[i].ID), | ||
m_a_Tips[i].pch | m_a_Tips[i].pch | ||
− | + | ); | |
} | } | ||
− | //включаем показ подсказок | + | // включаем показ подсказок |
m_ToolTip.Activate(1); | m_ToolTip.Activate(1); | ||
− | + | ||
... | ... | ||
} | } | ||
− | + | ||
− | //для того, чтобы подсказки отображались как реакция на движение | + | // для того, чтобы подсказки отображались как реакция на движение |
− | //курсора мыши, транслируем получаемые окнами сообщения в | + | // курсора мыши, транслируем получаемые окнами сообщения в |
− | //виртуальной PreTranslateMessage() | + | // виртуальной PreTranslateMessage() |
− | BOOL CMyDlg::PreTranslateMessage(MSG* pMsg) | + | BOOL CMyDlg::PreTranslateMessage(MSG* pMsg) |
{ | { | ||
− | //транслируем | + | // транслируем |
− | if(m_ToolTip.m_hWnd)m_ToolTip.RelayEvent(pMsg); | + | if (m_ToolTip.m_hWnd) |
− | + | m_ToolTip.RelayEvent(pMsg); | |
+ | |||
return CDialog::PreTranslateMessage(pMsg); | return CDialog::PreTranslateMessage(pMsg); | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | === Как в отладчике Visual С++ просмотреть содержимое std::vector<string> ?=== | + | ===Как в отладчике Visual С++ просмотреть содержимое std::vector<string>?=== |
− | Это можно сделать так | + | Это можно сделать так: к примеру, имеется: |
− | <syntaxhighlight> | + | |
+ | <syntaxhighlight lang="cpp"> | ||
std::vector<string> V; | std::vector<string> V; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | режиме отладки открываем окно "Watch" (ALT+3) и вставляем выражения: | + | В режиме отладки открываем окно "Watch" (ALT+3) и вставляем выражения: |
+ | * "V._Myfirst" - будет показан первый элемент V | ||
+ | * "V._Myfirst+1" - второй элемент V | ||
+ | и т.д. | ||
− | + | ===Как при выводе текста на контекст устройства определить ширину и высоту выведенных символов текста в пикселах?=== | |
− | + | Для этого нужно использовать процедуру API: | |
− | + | <syntaxhighlight lang="cpp"> | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | <syntaxhighlight> | + | |
BOOL GetTextExtentPoint32( | BOOL GetTextExtentPoint32( | ||
− | + | HDC hdc, // хендл контекста | |
− | + | LPCTSTR lpString, // выводимая строка | |
− | + | int cbString, // длина строки в символах | |
− | + | LPSIZE lpSize // указатель на структуру SIZE, куда будут помещены размеры | |
− | + | ||
); | ); | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | Функция вычисляет | + | Функция вычисляет ширину строки символов, оканчивающейся нулём. Поэтому, чтобы вычислить габариты многострочного текста, текст, в начале, необходимо разбить на строки, разделённые символами '\r' и '\n', и определить ширину и высоту каждой отдельно взятой строки. |
[[Category:FAQ]] | [[Category:FAQ]] |
Версия 11:05, 18 октября 2008
Содержание
- 1 Как сделать обработчик сообщения для нескольких контролов (элементов управления) сразу?
- 2 Когда я запускаю программу, все надписи на русском языке теряются - показываются вопросики. Что делать?
- 3 Как в проекте VC6 MFC программно получить путь, откуда был запущен экзешник (исполняемый модуль) самой программы?
- 4 Как получить доступ к элементам управления панели CReBar, принадлежащей классу MainFrame?
- 5 Как загрузить и показать один из стандартных курсоров?
- 6 Как запретить пользователю закрыть программу нажатием на кнопку с крестиком?
- 7 Как создать на диалоге группу элементов "RadioButton" и как задать порядок их обхода клавишей Tab?
- 8 Где лучше устанавливать начальные значения элемента CComboBox?
- 9 Как перевести RichEdit в режим замены символов?
- 10 Как вызвать метод главного окна (если используется класс CMainFrame) из любого места программы?
- 11 Как запретить появление полос прокруток на форме класса CFormView, когда пользователь делает размер главного окна меньше размера формы ?
- 12 Как нарисовать прямоугольник с вертикальным цветовым градиентом?
- 13 Как под Windows отслеживать изменение файла?
- 14 Как конвертировать массив char[] в CString?
- 15 Как зарезервировать в CString буфер нужной длины?
- 16 Как передать больше одного параметр в процедуру потока?
- 17 Как убрать главное меню из окна CMainFrame?
- 18 Как работающая программа может определить, что пользователь завершает работу Windows?
- 19 Как сделать всплывающую подсказку для класса CWnd и классов, от него производных?
- 20 Как в отладчике Visual С++ просмотреть содержимое std::vector<string>?
- 21 Как при выводе текста на контекст устройства определить ширину и высоту выведенных символов текста в пикселах?
Как сделать обработчик сообщения для нескольких контролов (элементов управления) сразу?
Без помощи визарда (Wizard) это можно сделать переопределением виртуальной функции OnCommand():
BOOL CMyDialog::OnCommand(WPARAM wParam, LPARAM lParam) { WORD wMess = (wParam >> 16); //командное сообщение int nID = (int)(wParam &0x0000ffff)); //ID контрола HWND hW = (HWND)lParam; //хендл контрола // смотрим, какой контрол switch (nID) { //кнопки case ID_BN1: case ID_BN2: case ID_BN3: { //смотрим, какое сообщение switch (wMess) { case BN_CLICKED: { ... } break; } } break; // едиты case ID_ED1: case ID_ED2: case ID_ED3: case ID_ED4: { // смотрим, какое сообщение switch (wMess) { case EN_CHANGE: { ... } break; case EN_KILLFOCUS: { ... } break; } } break; } return CDialog::OnCommand(wParam, lParam); }
Когда я запускаю программу, все надписи на русском языке теряются - показываются вопросики. Что делать?
Лечится проблема так: непосредственно после создания проекта открываем дерево ресурсов и в свойствах каждого элемента дерева ставим язык Russian. Если этого не сделать сразу, то все русские буквы при компиляции ресурсов потеряются.
Как в проекте VC6 MFC программно получить путь, откуда был запущен экзешник (исполняемый модуль) самой программы?
Нужно использовать функцию GetModuleFileName():
Указан неподдерживаемый язык.
Вы должны указать язык следующим образом: <source lang="html4strict">...</source>
Поддерживаемые языки:
4cs, 6502acme, 6502kickass, 6502tasm, 68000devpac, abap, actionscript, actionscript3, ada, aimms, algol68, apache, applescript, arm, asm, asp, asymptote, autoconf, autohotkey, autoit, avisynth, awk, bascomavr, bash, basic4gl, bf, bibtex, blitzbasic, bnf, boo, c, caddcl, cadlisp, cfdg, cfm, chaiscript, chapel, cil, clojure, cmake, cobol, coffeescript, cpp, csharp, css, cuesheet, d, dart, dcl, dcpu16, dcs, delphi, diff, div, dos, dot, e, ecmascript, eiffel, email, epc, erlang, euphoria, ezt, f1, falcon, fo, fortran, freebasic, freeswitch, fsharp, gambas, gdb, genero, genie, gettext, glsl, gml, gnuplot, go, groovy, gwbasic, haskell, haxe, hicest, hq9plus, html4strict, html5, icon, idl, ini, inno, intercal, io, ispfpanel, j, java, java5, javascript, jcl, jquery, kixtart, klonec, klonecpp, latex, lb, ldif, lisp, llvm, locobasic, logtalk, lolcode, lotusformulas, lotusscript, lscript, lsl2, lua, m68k, magiksf, make, mapbasic, matlab, mirc, mmix, modula2, modula3, mpasm, mxml, mysql, nagios, netrexx, newlisp, nginx, nimrod, nsis, oberon2, objc, objeck, ocaml, octave, oobas, oorexx, oracle11, oracle8, oxygene, oz, parasail, parigp, pascal, pcre, per, perl, perl6, pf, php, pic16, pike, pixelbender, pli, plsql, postgresql, postscript, povray, powerbuilder, powershell, proftpd, progress, prolog, properties, providex, purebasic, pycon, pys60, python, q, qbasic, qml, racket, rails, rbs, rebol, reg, rexx, robots, rpmspec, rsplus, ruby, rust, sas, scala, scheme, scilab, scl, sdlbasic, smalltalk, smarty, spark, sparql, sql, standardml, stonescript, systemverilog, tcl, teraterm, text, thinbasic, tsql, typoscript, unicon, upc, urbi, uscript, vala, vb, vbnet, vbscript, vedit, verilog, vhdl, vim, visualfoxpro, visualprolog, whitespace, whois, winbatch, xbasic, xml, xpp, yaml, z80, zxbasic
TCHAR pszFileName[MAX_PATH]; pszFileName[0] = 0; GetModuleFileName(NULL, pszFileName, MAX_PATH); CString stModulePath = pszFileName; // ищем первый слеш с конца и удаляем // его вместе с именем файла EXE int nEnd = stModulePath.ReverseFind('\\'); stModulePath.Delete(nEnd, stModulePath.GetLength() - nEnd); // stModulePath - содержит путь
Как получить доступ к элементам управления панели CReBar, принадлежащей классу MainFrame?
#include "MainFrm.h" // CMyApp - класс вашего приложения. theApp - глобальная переменная, // поэтому для доступа к ней используем extern extern CMyApp theApp; void CMyView::F() { // Получаем главное окно приложения в любом месте программы CMainFrame* pMainFrame = (CMainFrame*)(theApp.m_pMainWnd); pMainFrame->m_wndDlgBar ....; // Делаем что хотим ... }
Как загрузить и показать один из стандартных курсоров?
HCURSOR hCursor; hCursor = AfxGetApp()->LoadStandardCursor(IDC_UPARROW); if (hCursor) SetCursor(hCursor);
Идентификаторы стандартных курсоров:
- IDC_ARROW
- IDC_IBEAM
- IDC_WAIT
- IDC_CROSS
- IDC_UPARROW
- IDC_SIZENWSE
- IDC_SIZENESW
- IDC_SIZEWE
- IDC_SIZENS
- IDC_SIZEALL
Как запретить пользователю закрыть программу нажатием на кнопку с крестиком?
Для этого нужно добавить обработчик сообщения WM_CLOSE (функция OnClose() в MFC) в главное окно программы. Для диалоговых приложений такое окно - это главный диалог, для одно- и много-документных приложений - это CMainFrame.
void CMainFrame::OnClose() { if (....) { // не разрешаем закрыть return; } CFrameWnd::OnClose(); }
Как создать на диалоге группу элементов "RadioButton" и как задать порядок их обхода клавишей Tab?
Последовательность действий следующая:
- Помещаем на форму нужное количество элементов RadioButton;
- У первого элемента из группы ставим свойство Group, у остальных в группе - убираем это свойство;
- Порядок обхода (Tab Order) задаётся так: нажимаем Ctrl+D (загораются номера таб-порядка). Затем щёлкаем элементы в группе в таком порядке, который требуется.
Где лучше устанавливать начальные значения элемента CComboBox?
Это можно сделать парой способов:
- В редакторе форм - открыть свойства элемента CComboBox, "данные" (для ввода очередной строки данныхых нажать Ctrl+Enter);
- В функции OnInitDialog (в случае диалога) или в функции OnInitialUpdate (для CView).
Как перевести RichEdit в режим замены символов?
Имеется несколько способов.
1. Программно, если известен хендл элемента (hWnd), это делается так:
// помещаем в конец очереди сообющений контрола сообщение WM_KEYDOWN // с нужными параметрами ::PostMessage(hWnd, WM_KEYDOWN, VK_INSERT, 1);
2. Пользователь во время работы может нажать клавишу Insert.
Как вызвать метод главного окна (если используется класс CMainFrame) из любого места программы?
Это можно сделать так:
AfxGetApp()->m_pMainWnd-> ...;
или так
extern CMyAppXXX theApp; // здесь CMyAppXXX - название класса вашего приложения theApp.m_pMainWnd-> ...;
Как запретить появление полос прокруток на форме класса CFormView, когда пользователь делает размер главного окна меньше размера формы ?
Это можно сделать методом SetScaleToFitSize():
void CMyView::OnInitialUpdate() { CFormView::OnInitialUpdate(); // скрываем полосы прокрутки GetParentFrame()->RecalcLayout(); ResizeParentToFit(); // это уберёт полосы прокрутки со вьюхи SIZE s = {0, 0}; SetScaleToFitSize(s); //далее вызовется обработчик OnPaint(), о котором ниже // ... }
Также обратите внимание на одну особенность: в отладочной версии программы вызов OnPaint после выполнения SetScaleToFitSize() с параметром s = {0, 0} происходит с ошибкой (программа при этом завершается). Обходится это так:
void CMyView::OnPaint() { #ifdef _DEBUG CPaintDC dc(this); #else CFormView::OnPaint(); #endif }
Или так:
void CMyView::OnPaint() { CPaintDC dc(this); }
Как нарисовать прямоугольник с вертикальным цветовым градиентом?
Нужно задасть граничные значения цветов, затем равномерно нарисовать несколько прямоугольников постепенно меняющегося цвета. Количество прямоугольников, а, значит - плавность градиента, задаётся точностью.
Пример:
// вертикальный градиент // pdc - указатель на контекст устройства // pSize - указатель на структуру // SIZE с размером прямоугольника // dwdColor1, dwdColor2 - начальный и конечный цвет // bySteps - количество шагов градиента (1...255) void sFillVertGradientRect(CDC* pdc, SIZE *pSize, COLORREF dwdColor1, COLORREF dwdColor2, BYTE bySteps) { WORD i; long W, H, x1, x2; BYTE R1, G1, B1, R2, G2, B2; float dh, dR, dG, dB, y1, y2, Rc, Gc, Bc; if (!bySteps) bySteps = 1; //ширина и высота W = pSize->cx; H = pSize->cy; // раскладываем цвета на их составляющие // для удобства дальнейших вычислений R1 = (BYTE)((dwdColor1 & 0x000000ff)); G1 = (BYTE)((dwdColor1 & 0x0000ff00) >> 8); B1 = (BYTE)((dwdColor1 & 0x00ff0000) >> 16); R2 = (BYTE)((dwdColor2 & 0x000000ff)); G2 = (BYTE)((dwdColor2 & 0x0000ff00) >> 8); B2 = (BYTE)((dwdColor2 & 0x00ff0000) >> 16); // высота разноцветных прямоугольников dh = ((float)H) / ((float)bySteps); // величина шагов составляющих цветов dR = (((float)R2) - ((float)R1)) / ((float)bySteps); dG = (((float)G2) - ((float)G1)) / ((float)bySteps); dB = (((float)B2) - ((float)B1)) / ((float)bySteps); // выводим прямоугольники x1 = 0; x2 = W; y1 = 0; y2 = dh; Rc = R1; Gc = G1; Bc = B1; for (i = 0; i < bySteps; i++) { // текущий цвет pdc->FillSolidRect( x1, (int)y1, x2 - x1, (int)(y2 - y1), RGB((BYTE)Rc, (BYTE)Gc, (BYTE)Bc) ); // следующий цвет и координаты y1 += dh; y2 += dh; Rc += dR; Gc += dG; Bc += dB; } }
Пример вызова:
SIZE Size = {100, 100}; sFillGradientRect(&dc, &Size, RGB(200, 0, 0), RGB(0, 200, 0), 10);
Как под Windows отслеживать изменение файла?
Нужно использовать функции:
- FindFirstChangeNotification
- FindNextChangeNotification
- FindCloseChangeNotification
(подробности - в MSDN)
Как конвертировать массив char[] в CString?
Это можно сделать методами самого класса CString:
char buf[] = "text"; // строка должна обязательно заканчиваться нулём!!! // конвертируем так CString txt(buf); // или так CString txt; txt = buf;
Как зарезервировать в CString буфер нужной длины?
Это можно сделать при помощи методов класса:
CString::GetBuffer(...);
и
CString::GetBufferSetLength(...);
Разница между GetBuffer(nLen) и GetBufferSetLength(nLen) в том, что первый возвращает строку не меньше заданной длины, а второй возвращает строку, точно равную заданной длине. Обе могут перераспределять память, если необходимо. В обычных случаях лучше использовать GetBuffer.
Если содержимое буфера менялось, то после этого нужно вызвать CString::ReleaseBuffer с указанием новой длины. Значение -1 в вызове CString::ReleaseBuffer означает, что длина строки будет вычислена автоматом (функцией strlen) в методе. "-1" удобно использовать, если известно, что строка заканчивается нулем.
Как передать больше одного параметр в процедуру потока?
Для этого нужно определить структуру со всеми параметрами (или указателями на них), которые нужно передать. А в процедуру потока передать лишь указатель на заполненную структуру.
Пример:
struct mystr { CEdit* pEd; CDialog* pDlg; DWORD* pdwd; int *pn; };
запуск потока:
mystr *pparam = new mystr; // экземпляр не должен быть временным!!! memset(pparam, 0, sizeof(*pparam)); pparam->pEd = ...; pparam->pdwd = ...; ::AfxBeginThread(thread, pparam); // тут экземпляр *(pparam) уже нельзя использовать в нашем примере, так как // он у нас удалиля в процедуре потока
Процедура потока:
// поток: UINT threadLoader(LPVOID pParam) { // копируем данные из структуры в локальную структуру mystr data = *((mystr*)pParam); // освобождаем память временной структуры delete ((mystr*)pParam); pParam = 0; ... data.pDlg->...; (*data.pdwd) = ...; ... }
Как убрать главное меню из окна CMainFrame?
Это можно сделать в виртуальной функции PreCreateWindow:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { // обнуляем хендл меню до вызова CFrameWnd::PreCreateWindow cs.hMenu = 0; if (!CFrameWnd::PreCreateWindow(cs)) return FALSE; ... }
Как работающая программа может определить, что пользователь завершает работу Windows?
Когда пользователь завершает работу Windows, всем процессам посылается сообщение WM_QUERYENDSESSION. Его нужно отловить в обработчике OnQueryEndSession(). Если вернуть из обработчика значение 0, то Windows продолжит работу.
Как сделать всплывающую подсказку для класса CWnd и классов, от него производных?
Допустим, имеется диалог класса CMyDlg. Делаем подсказки для элементов управления (для CStatic контролов не забудьте поставить свойство Notify):
class CMyDlg:puplic CDialog { CToolTipCtrl m_ToolTip; // мембер класса CMyDlg }; // массив, в котором перечислены идентификаторы // контролов и тексты подсказок к ним struct { int ID; const char* pch; } m_a_Tips[] = { {IDC_BUTTON1, "Кнопка"}, {IDC_STATIC1, "Текст"}, {0, 0} // признак конца массива }; // в инициализации диалога (хотя, в принципе, // можно и не тут) создаём и привязываем подсказки BOOL CMyDlg::OnInitDialog() { CDialog::OnInitDialog(); // создаём элемент TOOLTIP m_ToolTip.Create(this); // Привязка подсказок for (int i = 0; m_a_Tips[i].ID; i++) { m_ToolTip.AddTool( GetDlgItem(m_a_Tips[i].ID), m_a_Tips[i].pch ); } // включаем показ подсказок m_ToolTip.Activate(1); ... } // для того, чтобы подсказки отображались как реакция на движение // курсора мыши, транслируем получаемые окнами сообщения в // виртуальной PreTranslateMessage() BOOL CMyDlg::PreTranslateMessage(MSG* pMsg) { // транслируем if (m_ToolTip.m_hWnd) m_ToolTip.RelayEvent(pMsg); return CDialog::PreTranslateMessage(pMsg); }
Как в отладчике Visual С++ просмотреть содержимое std::vector<string>?
Это можно сделать так: к примеру, имеется:
std::vector<string> V;
В режиме отладки открываем окно "Watch" (ALT+3) и вставляем выражения:
- "V._Myfirst" - будет показан первый элемент V
- "V._Myfirst+1" - второй элемент V
и т.д.
Как при выводе текста на контекст устройства определить ширину и высоту выведенных символов текста в пикселах?
Для этого нужно использовать процедуру API:
BOOL GetTextExtentPoint32( HDC hdc, // хендл контекста LPCTSTR lpString, // выводимая строка int cbString, // длина строки в символах LPSIZE lpSize // указатель на структуру SIZE, куда будут помещены размеры );
Функция вычисляет ширину строки символов, оканчивающейся нулём. Поэтому, чтобы вычислить габариты многострочного текста, текст, в начале, необходимо разбить на строки, разделённые символами '\r' и '\n', и определить ширину и высоту каждой отдельно взятой строки.