|
|
| (не показано 16 промежуточных версий 2 участников) |
| Строка 1: |
Строка 1: |
| − | | + | #REDIRECT [[FAQ:WinAPI_VCPP]] |
| − | | + | |
| − | === Как сделать обработчик сообщения для нескольких контролов (элементов управления) сразу? ===
| + | |
| − | | + | |
| − | Без помощи визарда (Wizard) это можно сделать переопределением виртуальной функции OnCommand() :
| + | |
| − | <syntaxhighlight>
| + | |
| − | 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);
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | === Когда я запускаю программу, все надписи на русском языке теряются - показываются вопросики. Что делать? ===
| + | |
| − | | + | |
| − | Лечится проблема так: непосредственно после создания проекта открываем дерево ресурсов и в свойствах каждого элемента дерева ставим язык Russian. Если этого не сделать сразу, то все русские буквы при компиляции ресурсов потеряются.
| + | |
| − | | + | |
| − | === Как в проекте VC6 MFC программно получить путь, откуда был запущен экзешник (исполняемый модуль) самой программы? ===
| + | |
| − | | + | |
| − | Нужно использовать функцию GetModuleFileName():
| + | |
| − | <syntaxhighlight>
| + | |
| − | 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 - содержит путь
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | === Как получить доступ к элементам управления панели CReBar, принадлежащей классу MainFrame? ===
| + | |
| − | | + | |
| − | <syntaxhighlight>
| + | |
| − | #include "MainFrm.h" | + | |
| − | | + | |
| − | //CMyApp - класс вашего приложения. theApp - глобальная переменная,
| + | |
| − | //поэтому для доступа к ней используем extern
| + | |
| − | extern CMyApp theApp;
| + | |
| − | | + | |
| − | void CMyView::F()
| + | |
| − | {
| + | |
| − | //Получаем главное окно приложения в любом месте программы
| + | |
| − | CMainFrame* pMainFrame=(CMainFrame*)(theApp.m_pMainWnd);
| + | |
| − | | + | |
| − | pMainFrame->m_wndDlgBar ....//Делаем что хотим
| + | |
| − | ...
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | === Как загрузить и показать один из стандартных курсоров? ===
| + | |
| − | | + | |
| − | <syntaxhighlight>
| + | |
| − | 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>
| + | |
| − | void CMainFrame::OnClose()
| + | |
| − | {
| + | |
| − | if(......)
| + | |
| − | {
| + | |
| − | //не разрешаем закрыть
| + | |
| − | return;
| + | |
| − | }
| + | |
| − |
| + | |
| − | CFrameWnd::OnClose();
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | === Как создать на диалоге группу элементов "RadioButton" и как задать порядок их обхода клавишей Tab? ===
| + | |
| − | | + | |
| − | Последовательность действий следующая:
| + | |
| − | | + | |
| − | 1) кладём на форму нужное количество элементов RadioButton.
| + | |
| − | | + | |
| − | 2) у первого элемента из группы ставим свойство Group, у остальных в группе - убираем это свойство.
| + | |
| − | | + | |
| − | 3) порядок обхода (Tab Order) задаётся так: нажимаем Ctrl+D (загораются номера таб-порядка). Затем щёлкаем элементы в группе в таком порядке, который требуется.
| + | |
| − | | + | |
| − | === Где лучше устанавливать начальные значения элемента CComboBox? ===
| + | |
| − | | + | |
| − | Это можно сделать парой способов:
| + | |
| − | | + | |
| − | 1) В редакторе форм - открыть свойства элемента CComboBox , "данные" (для ввода очередной строки данныхых нажать Ctrl+Enter)
| + | |
| − | | + | |
| − | 2) В функции OnInitDialog (в случае диалога) или в функции OnInitialUpdate (для CView)
| + | |
| − | | + | |
| − | === Как перевести RichEdit в режим замены символов? ===
| + | |
| − | | + | |
| − | Имеется несколько способов.
| + | |
| − | | + | |
| − | 1) Программно, если известен хендл элемента (hWnd), это делается так:
| + | |
| − | <syntaxhighlight>
| + | |
| − | //помещаем в конец очереди сообющений контрола сообщение WM_KEYDOWN
| + | |
| − | //с нужными параметрами
| + | |
| − | ::PostMessage(hWnd,WM_KEYDOWN,VK_INSERT,1);
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | 2) Пользователь во время работы может нажать клавишу Insert.
| + | |
| − | | + | |
| − | === Как вызвать метод главного окна (если используется класс CMainFrame) из любого места программы? ===
| + | |
| − | | + | |
| − | Это можно сделать так:
| + | |
| − | | + | |
| − | <syntaxhighlight>
| + | |
| − | AfxGetApp()->m_pMainWnd-> ...;
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | или так
| + | |
| − | <syntaxhighlight>
| + | |
| − | extern CMyAppXXX theApp;//здесь CMyAppXXX - название класса вашего приложения
| + | |
| − | theApp.m_pMainWnd-> ...;
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | === Как запретить появление полос прокруток на форме класса CFormView, когда пользователь делает размер главного окна меньше размера формы ? ===
| + | |
| − | | + | |
| − | Это можно сделать методом SetScaleToFitSize():
| + | |
| − | <syntaxhighlight>
| + | |
| − | void CMyView::OnInitialUpdate()
| + | |
| − | {
| + | |
| − | CFormView::OnInitialUpdate();
| + | |
| − | | + | |
| − | //скрываем полосы прокрутки
| + | |
| − | GetParentFrame()->RecalcLayout();
| + | |
| − | ResizeParentToFit();//это уберёт полосы прокрутки со вьюхи
| + | |
| − | SIZE s={0,0};
| + | |
| − | SetScaleToFitSize(s);
| + | |
| − | //далее вызовется обработчик OnPaint(), о котором ниже
| + | |
| − | /////////
| + | |
| − | ...
| + | |
| − | ...
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | Также обратите внимание на одну особенность: в дебаг-версии программы вызов OnPaint после выполнения SetScaleToFitSize() с параметром s={0,0} происходит с ошибкой (программа при этом завершается).
| + | |
| − | Обходится это так:
| + | |
| − | <syntaxhighlight>
| + | |
| − | void CMyView::OnPaint()
| + | |
| − | {
| + | |
| − | #ifdef _DEBUG
| + | |
| − | CPaintDC dc(this);
| + | |
| − | #else
| + | |
| − | CFormView::OnPaint();
| + | |
| − | #endif
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | или даже вообще так:
| + | |
| − | <syntaxhighlight>
| + | |
| − | void CMyView::OnPaint()
| + | |
| − | {
| + | |
| − | CPaintDC dc(this);
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | === Как нарисовать прямоугольник с вертикальным цветовым градиентом? ===
| + | |
| − | | + | |
| − | Нужно задасться граничными значениями цветов, затем равномерно нарисовать несколько прямоугольников постепенно меняющегося цвета. Количество прямоугольников (а, значит, плавность гралдиента) задаётся точностью.
| + | |
| − | Пример:
| + | |
| − | <syntaxhighlight>
| + | |
| − | //вертикальный градиент
| + | |
| − | //pdc - указатель на контекст устройства
| + | |
| − | //pSize - указатель на структуру
| + | |
| − | //SIZE с размером прямоугольника
| + | |
| − | // dwdColor1, dwdColor2 - начальный и конечный цвет
| + | |
| − | //bySteps - количество шагов градиента (1...255)
| + | |
| − | void sFillVertGradientRect(CDC* pdc,SIZE *pSize, COLORREF dwdColor1, COLORREF dwdColor2,BYTE bySteps)
| + | |
| − | {
| + | |
| − | if(!bySteps)bySteps=1;
| + | |
| − | WORD i;
| + | |
| − |
| + | |
| − | long W,H,x1,x2;
| + | |
| − | BYTE R1,G1,B1,R2,G2,B2;
| + | |
| − | float dh,dR,dG,dB,y1,y2,Rc,Gc,Bc;
| + | |
| − |
| + | |
| − | //ширина и высота
| + | |
| − | 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;
| + | |
| − | }
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | пример вызова:
| + | |
| − | <syntaxhighlight>
| + | |
| − | SIZE Size={100,100};
| + | |
| − | sFillGradientRect(&dc,&Size, RGB(200,0,0), RGB(0,200,0),10);
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | === Как под Windows отслеживать изменение файла? ===
| + | |
| − | | + | |
| − | Нужно использовать функции:
| + | |
| − | | + | |
| − | FindFirstChangeNotification
| + | |
| − | | + | |
| − | FindNextChangeNotification
| + | |
| − | | + | |
| − | FindCloseChangeNotification
| + | |
| − | | + | |
| − | (подробности - в MSDN)
| + | |
| − | | + | |
| − | === Как конвертировать массив char[] в CString? ===
| + | |
| − | Это можно сделать методами самого класса CString:
| + | |
| − | <syntaxhighlight>
| + | |
| − | char buf[]="text";
| + | |
| − | | + | |
| − | //строка должна обязательно заканчиваться нулём!!!
| + | |
| − | | + | |
| − | //конвертируем так
| + | |
| − | CString txt(buf);
| + | |
| − | | + | |
| − | //или так
| + | |
| − | CString txt;
| + | |
| − | txt=buf;
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | === Как зарезервировать в CString буфер нужной длины? ===
| + | |
| − | | + | |
| − | Это можно сделать при помощи методов класса:
| + | |
| − | | + | |
| − | <syntaxhighlight>
| + | |
| − | CString::GetBuffer(...)
| + | |
| − | </syntaxhighlight>
| + | |
| − | и
| + | |
| − | <syntaxhighlight>
| + | |
| − | CString::GetBufferSetLength(...)
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | Разница между GetBuffer(nLen) и GetBufferSetLength(nLen) в том, что первый возвращает строку НЕ МЕНЬШЕ заданной длины, а второй возвращает строку точно равную заданной длине. Обе могут перераспределять память если надо. В обычных случаях лучше использовать GetBuffer.
| + | |
| − | | + | |
| − | Если содержимое буфера менялось, то после этого нужно вызвать CString::ReleaseBuffer с указанием новой длины. Значение -1 в вызове CString::ReleaseBuffer означает, что длина строки будет вычислена автоматом (функцией strlen) в методе."-1" удобно использовать, если известно, что строка заканчивается нулем.
| + | |
| − | | + | |
| − | === Как передать больше одного параметр в процедуру потока? ===
| + | |
| − | | + | |
| − | Для этого нужно определить структуру со всеми параметрами (или указателями на них), которые нужно передать. А в процедуру потока передать лишь указатель на заполненную структуру.
| + | |
| − | Пример:
| + | |
| − | <syntaxhighlight>
| + | |
| − | struct mystr
| + | |
| − | {
| + | |
| − | CEdit* pEd;
| + | |
| − | CDialog* pDlg;
| + | |
| − | DWORD* pdwd;
| + | |
| − | int *pn;
| + | |
| − | };
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | запуск потока:
| + | |
| − | | + | |
| − | <syntaxhighlight>
| + | |
| − | mystr *pparam=new mystr;//экземпляр не должен быть временным!!!
| + | |
| − | | + | |
| − | memset(pparam,0,sizeof(*pparam));
| + | |
| − | pparam->pEd=...;
| + | |
| − | pparam->pdwd=...;
| + | |
| − | | + | |
| − | ::AfxBeginThread(thread,pparam);
| + | |
| − | //тут экземпляр *(pparam) уже нельзя использовать в нашем примере, так как
| + | |
| − | //он у нас удалиля в процедуре потока
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | процедура потока:
| + | |
| − | <syntaxhighlight>
| + | |
| − | //поток:
| + | |
| − | UINT threadLoader(LPVOID pParam)
| + | |
| − | {
| + | |
| − | //копируем данные из структуры в локальную структуру
| + | |
| − | mystr data=*((mystr*)pParam);
| + | |
| − | //освобождаем память временной структуры
| + | |
| − | delete ((mystr*)pParam);
| + | |
| − | pParam=0;
| + | |
| − |
| + | |
| − | | + | |
| − | ...
| + | |
| − | data.pDlg->...;
| + | |
| − | (*data.pdwd)=...;
| + | |
| − | ...
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | === Как убрать главное меню из окна CMainFrame? ===
| + | |
| − | Это можно сделать в виртуальной функции PreCreateWindow:
| + | |
| − | <syntaxhighlight>
| + | |
| − | BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
| + | |
| − | {
| + | |
| − | //обнуляем хендл меню до вызова CFrameWnd::PreCreateWindow
| + | |
| − | cs.hMenu = 0;
| + | |
| − |
| + | |
| − | if(!CFrameWnd::PreCreateWindow(cs))
| + | |
| − | return FALSE;
| + | |
| − | ...
| + | |
| − | ...
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | === Как работающая программа может определить, что пользователь завершает работу Windows? ===
| + | |
| − | | + | |
| − | Когда пользователь завершает работу Windows, всем процессам посылается сообщение WM_QUERYENDSESSION. Его нужно отловить в обработчике OnQueryEndSession(). Если вернуть из обработчика значение 0, то Windows продолжит работу.
| + | |
| − | | + | |
| − | === Как сделать всплывающую подсказку для класса CWnd и классов, от него производных? ===
| + | |
| − | | + | |
| − | Допустим, имеется диалог класса CMyDlg. Делаем подсказки для элементов управления (для CStatic контролов не забудьте поставить свойство Notify) :
| + | |
| − | <syntaxhighlight>
| + | |
| − | 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);
| + | |
| − | }
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | === Как в отладчике Visual С++ просмотреть содержимое std::vector<string> ?===
| + | |
| − | | + | |
| − | Это можно сделать так. К примеру, имеется
| + | |
| − | <syntaxhighlight>
| + | |
| − | std::vector<string> V;
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | режиме отладки открываем окно "Watch" (ALT+3) и вставляем выражения:
| + | |
| − | | + | |
| − | V._Myfirst (- будет показан первый элемент V)
| + | |
| − | V._Myfirst+1 (- второй элемент V,)
| + | |
| − | | + | |
| − | и т.д.
| + | |
| − | | + | |
| − | === Как при выводе текста на контекст устройства определить ширину и высоту выведенных символов текста в пикселах? ===
| + | |
| − | | + | |
| − | Для этого нужно использовать процедуру API:
| + | |
| − | <syntaxhighlight>
| + | |
| − | BOOL GetTextExtentPoint32(
| + | |
| − | HDC hdc,// хендл контекста
| + | |
| − | LPCTSTR lpString,// выводимая строка
| + | |
| − | int cbString,// длина строки в символах
| + | |
| − | LPSIZE lpSize// указатель на структуру SIZE, куда
| + | |
| − | //будут помещены размеры
| + | |
| − | );
| + | |
| − | </syntaxhighlight>
| + | |
| − | | + | |
| − | Функция вычисляет длину лишь одной символов, оканчивающейся нулём. Поэтому, чтобы вычислить "размер" многострочнокго текста, текст вначале необходимо разбить на строки, разделённые символами '\r' и '\n', и определить ширину и высоту каждой отдельно взятой строки.
| + | |
| − | | + | |
| − | [[Category:FAQ]]
| + | |