Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Поcобие_БЕЛОВ_Графический_интерфейс_API

.pdf
Скачиваний:
141
Добавлен:
18.03.2016
Размер:
2.75 Mб
Скачать

121

SetBkColor(hdc, RGB(255-i*15,255-i*20,255-i*25));

Этим завершают процедуру установки атрибутов контекста отображения. Теперь можно вывести текст:

TextOut( hdc, 0, cyClient-30, szFont, strlen(szFont));

Шрифт hNFont больше не требуется. Поэтому в контекст выбираем предыдущий шрифт и удаляем шрифт hNFont:

SelectObject(hdc.hOFont); DeteteObject(hNFont);

Освобождают контекст отображения:

EndPaint(hwnd,&ps);

3.4.5. Определение метрик шрифта

Метрику шрифта, выбранного в контекст отображения hdc, определяют с помощью функции GetTextMetrics:

BOOL GetTextMetrics( HDC hdc, LPTEXTMETRIC lptm);

Параметр lptm указывает на структуру типа TEXTMETRIC, в которую необходимо записать метрики шрифта. Все размеры записываются в логических единицах контекста отображения hdc. При успешном выполнении функция возвращает ненулевое значение.Структура TEXTMETRIC предназначена для описания базовой информации о метриках шрифта и описана следующим образом:

typedef struct { LONG tmHeight; LONG tmAscent;

LONG tmDescent;

LONG tmInternalLeading; LONG tmExternalLeading; LONG tmAveCharWidth; LONG tmMaxCharWidth; LONG tmWeight;

LONG tmOverhang;

LONG tmDigitizedAspectX; LONG tmDigitizedAspectY; BCHAR tmFirstChar; BCHAR tmLastChar; BCHAR tmDefaultChar; BCHAR tmBreakChar; BYTE tmItalic;

BYTE tmUnderlined;

122

BYTE tmStruckOut; BYTE tmPitchAndFamily; BYTE tmCharSet;

}TEXTMETRIC;

Рассмотрим назначение полей этой структуры:

1)tmHeight – общая высота букв, равна tmAscent+tmDescent;

2)tmAscent – часть высоты букв от базовой линии с учетом таких элементов, как тильда в букве «И»;

3)tmDescent – часть высоты букв ниже базовой линии;

4)tmInternalLeading – высота таких выступающих элементов, как тильда в букве «Й», и может быть равна нулю;

5)tmExternalLeading – высота межстрочного интервала, рекомендуемая разработчиком шрифта, может быть приравнена нулю.

6)tmAveCharWidth – средняя ширина строчных букв, равна ширине латинской буквы «х»;

7)tmMaxCharWidth – ширина самой широкой буквы;

8)tmWeight – жирность шрифта, может находиться в пределах от 0 до 1000, как и для логического шрифта;

9)tmOverhang – величина изменения ширины символов при построении наклонного или полужирного шрифта из нормального шрифта;

10)tmDigitizedAspectX – разрешение устройства отображения по горизонтали;

11)tmDigitizedAspectY – разрешение устройства отображения по вертикали;

12)tmFirstChar – код первого символа в шрифте.

13)tmLastChar – код последнего символа в шрифте;

14)tmDefaultChar – код символа, заменяющего любой отсутствующий в шрифте символ;

15)tmBreakChar – код символа переноса слов с одной строки на другую при выравнивании текста;

16)tmItalic – означает наклонный шрифт;

17)tmUnderlined – означает подчеркнутый шрифт;

18)tmStruckOute – означает перечеркнутый шрифт;

19)tmPitchAndFamily – код семейства шрифта. Четыре младших бита этого кода комбинацией следующих констант определяют информацию о шаге и типе шрифта:

 

123

 

 

Константа

Пояснение

TMPF_FIXED_PITCH

Если этот бит установлен, то шрифт с переменным

 

шагом, иначе – с постоянным

TMPF_VECTOR

Если этот бит установлен, то шрифт векторного

 

типа

 

 

TMPF_TRUETYPE

Если этот бит установлен, то шрифт типа TrueType

TMPF_DEVICE

Если этот бит установлен, шрифт определен

 

устройством

 

 

Четыре старших бита кода tmPitchAndFamily описывают семейство шрифта, так же как и для логического шрифта.

20) tmCharSet – код используемого набора символов, такой же, как и для логического шрифта.

Задача. В рабочей области окна вывести таблицу. В заголовке перечислить названия функций, а в строках таблицы отобразить значения этих функций. Причем вывод таблицы ограничить числом столбцов и строк, которые полностью помещаются в рабочей области.

Следующее приложение решает эту задачу. Листинг 3.7. Вывод таблицы в окно.

#include <windows.h> #include <math.h>

BOOL RegClass(WNDPROC, LPCTSTR, UINT); LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); HINSTANCE hInstance;

char szClass[ ] = "TableClass";

//Структура столбца данных typedef struct

{

char

str[15]; //Поле имени столбца

 

double

val[50}; //Массив данных столбца

}

COLUMN; //Имя типа

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow)

{MSG msg; HWND hwnd;

::hInstance=hInstance;

if (!RegClass(WndProc, szClass, COLOR_WINDOW)) return FALSE;

124

hwnd = CreateWindow(szClass, "ТАБЛИЦА", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0,0, hInstance, NULL);

if (!hwnd) return FALSE; while(GetMessage(&msg, 0,0,0)) DispatchMessage(&msg);

return msg.wParam;

}

BOOL RegClass(WNDPROC Proc, LPCTSTR szName, UINT brBackground)

{WNDCLASS wc;

wc.style = CS_HREDRAW | CS_VREDRAW; wc.cbClsExtra=wc.cbWndExtra=0; wc.lpfnWndProc = Proc;

wc.hInstance = hInstance; wc.lpszClassName = szName;

wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(brBackground+1); wc.lpszMenuName = NULL;

return (RegisterClass(wc) != 0);

BOOL DrawLine( HDC hdc, int x0, int y0, int x, int y) { MoveToEx(hdc,x0,y0, NULL);

return LineTo(hdc, x, у);

}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam,

LPARAM lParam)

{//Описываем массив из 10 столбцов static COLUMN cols[10];

static int ex, cy, cxChar, cyChar; switch (msg)

{case WM_SIZE;

{cx=LOWORD(lParam);

cy=HIWORD(lParam); return 0;

125

}

case WM_CREATE:

{//Заполняем заголовки столбцов strcpy(cols[0].str,T); strcpy(cols[1].str,"10*sin(i/10.)"); strcpy(cols[2].str,"20*sin(i/20.)"); strcpy(cols[3].str,"30*sin(i/30.)"); strcpy(cols[4].str,"40*sin(i/40.)"); strcpy(cols[5].str,"50*sin(i/50.)"); strcpy(cols[6].str,"60*sin(i/60.)"); strcpy(cols[7].str,"70*sin(i/70.)"); strcpy(cols[8].str,"80*sin(i/80.)"); strcpy(cols[9].str/90*sin(i/90.)");

//Заполняем массивы данных столбцов for (int i=0; i<50; i++)

{//В первом столбце будут номера строк cols[0].val[i]=i;

//В остальных столбцах будут данные for(intj=1;j<10;j++)

cols[j].val[i]=10*sin(i/10./j);

}

//Определяем средние высоту и ширину символов

{TEXTMETRIC tm;

HDC hdc=GetDC(hwnd); //Определяем метрики текста

GetTextMetrics(hdc, &tm); ReleaseDC(hwnd.hdc);

//Число пикселей в высоте символа

cyChar = tm.tmHeight + tm.tmExtemaiLeading

//Число пикселей в средней ширине cxChar=tm.tmAveCharWidth+1;

}

return 0;

}

caseWM_PAINT:

{PAINTSTRUCT ps;

HDC hdc=BeginPaint(hwnd,&ps); char str[20];

126 //Установим начальные параметры для вывода

int left=cxChar,

//Левый край

top=cyChar/2

//Верх

dx=cxChar,

//Пробел по оси X

dy=cyChar/4,

//Пробел по оси Y

hy=cyChar+dy+dy,

//Высота для строки

right=cx-cxChar,

//Правый край

bottom=cy-cyChar, //Низ

int bounds[10], //Массив ширин столбцов i=0,j=0; //Заполняем массив ширинами столбцов while (j<10)

{//Для j-ro столбца выбираем ширину bounds[j]=strlen(cols[j].str);

for (i=0; i<50; i++) { _gcvt( cols[j].val[i], 7, str ); int ss=strlen(str); if (bounds[j]<ss) bounds[j]=ss;

}

if (bounds[j]<=3) bounds[j]=4; if (bounds[j]>10) bounds[j]-=2; bounds[j] = cxChar*(bounds[j]);

}

//Определяем максимальное число столбцов, //которое помещается на ширине рабочей области int dd=left, maxcol=0;

while (maxcol<10)

{if (dd+bounds[maxcol]>right) break;

dd += bounds[maxcol]; maxcol++;

}

//right теперь указывает на правый край таблицы rignt=dd;

//Подгоняем ширину окна к числу столбцов

{RECT re; GetWindowRect(hwnd, &rc);

MoveWindow(hwnd, rc.left, rc.top,

//Изменяем только ширину окна

re. rig ht-rc. Ieft-(cx-right)+dx, rc.bottom-rc.top, TRUE);

}

127

//////НАЧАЛО ВЫВОДА ТАБЛИЦЫ//////

//Устанавливаем режим выравнивания

SetTextAlign(hdc, TA_RIGHT);

//////Начало вывода шапки таблицы//////

int y=top; //Текущая координата по оси Y //Горизонтальная линия на всю ширину

DrawLine(hdc,left,y,right,y);

//Заголовки столбцов

int x=left; //Текущая координата по оси X //Вертикальная линия слева от столбца

DrawLine(hdc, x, у, х, y+hy); for (j=0;j<maxcol; j++)

{//Устанавливаем х на правой границе столбца x+=boundsO];

TextOut(hdc,x-dx,y+dy, cols[j].str,strlen(cols[j].str));

//Вертикальная линия справа от столбца

DrawLine(hdc,x,y,x,y+hy);

}

//Горизонтальная линия на всю ширину y+=hy; DrawLine(hdc, left,y,right,y);

//////Конец вывода шапки таблицы//////

//////Начало вывода данных таблицы//////

1=0;//Счетчик номера строки данных while (i<50 && y<bottom)

{//Вертикальная линия слева от столбца x=left;

DrawLine(hdc,x,y,x,y+hy);

for (j=0;j<maxcol; j++) { x+=boundsO]; //Преобразуем целое число в строку if(j==0) itoa((int)cols[0].va1[i], str, 10);

//Преобразуем вещественное число в строку else _gcvt( cols[j].val[i], 7, str); TextOut(hdc,x-dx,y+dy,str,strlen(str)); //Вертикальная линия справа от столбца

DrawLine(hdc,x,y,x,y+hy);

}

//Горизонтальная линия на всю ширину y+=hy; DrawLine(hdc,left,y,right,y);

i++;

128

}

//////Конец вывода данных таблицы//////

EndPaint(hwnd,&ps); return 0;

}

case WM_DESTROY: { PostQuitMessage(0); return 0; }

}

return

DefWindowProc(hwnd, msg, wParam, lParam);

}

Рассмотрим основные шаги решения данной задачи.

 

А. Сначала создают в памяти таблицу.

1.

Описывают тип структуры столбца данных:

typedef struct

 

{

char str[15];

//Поле имени столбца

 

double val[50];

//Массив данных столбца

}

COLUMN;

//Имя типа

2.Описывают массив cols из 10 столбцов этого типа: static COLUMN cols[10];

3.Заполняют этот массив некоторыми значениями. Сначала заполняются заголовки столбцов:

strcpy(cols[0].str,"i");

strcpy(cols[1].str,"10*sin(i/10.)");

strcpy(cols[9].str,”90*sin(i/90.)");

Затем заполняют массивы данных столбцов: for (int i=0; i<50; i++)

{ cols[0].val[i]=i; for(intj=1;j<10;j++)colsy].val[i]=10*sin(i/10./j);

}

При этом в первый столбец записывают номера строк, а в другие столбцы записывают значения функций.

Б. Определяют геометрические параметры вывода таблицы в рабочую область.

1. Определяют среднюю высоту и ширину символов установленного шрифта:

TEXTMETRIC tm; HDC hdc=GetDC(hwnd);

129 //Определяем метрики текста

GetTextMetrics(hdc, &tm); ReleaseDC(hwnd,hdc);

//Число пикселей в высоте символа

cyChar = tm.tmHeight + tm.tmExternalLeading; //Число пикселей в средней ширине cxChaFtm.tmAveCharWidth+1;

Метрики шрифта определяют на этапе создания окна, так как используют шрифт по умолчанию. Иначе метрики необходимо определять после выбора шрифта в контекст отображения.

2.Устанавливают границы вывода таблицы. Здесь left указьшает налевую, top – на верхнюю, right – на правую, bottom – на нижнююграницу таблицы в рабочей области. Параметр dx равен величине пробела по оси X, a dy – по оси Y, hy задает высоту строки таблицы.Также описывают переменные bounds[10], i и j.

3.Массив bounds заполняют значениями ширины столбцов:

while (j<10)

{bounds[j]=strlen(cols[j].str); for (i=0; i<50; i++)

{_gcvt( cols[j].val[i], 7, str); int ss=strlen(str);

if (bounds[j]<ss) bounds[j]=ss;

}

if (bounds[j]<=3) bounds[j]=4; if (bounds[j]>10) bounds[j]-=2; bounds[j] = cxChar*(bounds[j]); j++

}

Для j-го столбца вычисляют число символов заголовка: bounds[j]=strlen(cols[j].str);

Далее определяют максимально необходимое число символов для вывода в этот столбец:

_gcvt( cols[j].val[i], 7, str);

int ss=strlen(str); if (bounds[j]<ss) bounds[j]=ss;

После определения необходимого числа символов вносят незначительные коррекции. Так, в столбце выделяют место для вывода не менее четырех символов:

130 if (bounds[j]<=3) bounds[j]=4;

При большом (более 10) числе символов уменьшают число выделяемых позиций:

if(bounds[0]>10) bounds[j]-=2;

Вычисляют ширину столбца в пикселях: bounds[j] = cxChar*bounds[j];

4. Определяют максимальное число maxcol столбцов, которое помещается в установленных границах:

int dd=left, maxcol=0; while (maxcol<10)

{ if (dd+bounds[maxcol]>right) break; dd += bounds[maxcol]; maxcol++;

}

5.Значение right переносят на правую границу столбца maxcol: right=dd;

6.Уменьшают ширину окна так, чтобы она была достаточна для вывода только maxcol столбцов:

RECT re; GetWindowRect(hwnd, &rc); MoveWindow(hwnd, rc.left, rc.top, rc.right-rc.left-(cx-right)+dx, rc.bottom-rc.top, TRUE);

В. Выводят таблицу.

1.Устанавливают режим выравнивания по правой границе:

SetTextAlign(hdc, TA_RIGHT);

Обратите внимание на то, что в этом режиме горизонтальная координата вывода текста указывает на точку, где завершается вывод правого конца выводимой строки.

2.Рисуют заголовки столбцов таблицы.

В первую очередь рисуют горизонтальную линию на всю ширину таблицы (от левой границы – left до правой границы – right):

DrawLine(hdc,left,y,right,y);

Для рисования заголовков столбцов вспомогательную координату по оси X устанавливают на левой границе (x=left). После этого рисуют вертикальную линию на левой границе таблицы высотой hy:

DrawLine(hdc, x, у, х, y+hy);

Вывод заголовка j-ro столбца содержит следующие шаги: 1) устанавливают х на правой границе столбца: x+=bounds[j];