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