FAQ:WinAPI, VCPP Part 2 — различия между версиями

Материал из Весельчак У
Перейти к: навигация, поиск
(Выделение 5 статей в отдельные страницы.)
(Удалены 5 статей: разделение.)
Строка 1: Строка 1:
===Как нарисовать прямоугольник с вертикальным цветовым градиентом?===
 
 
Нужно задать граничные значения цветов, затем равномерно нарисовать несколько прямоугольников постепенно меняющегося цвета. Количество прямоугольников, а, значит - плавность градиента, задаётся точностью.
 
 
Пример:
 
 
<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?===
 
===Как убрать главное меню из окна CMainFrame?===
  

Версия 20:28, 2 ноября 2008

Как убрать главное меню из окна 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', и определить ширину и высоту каждой отдельно взятой строки.