Большой архив статей, книг, документации по программированию, вебдизайну, компьютерной графике, сетям, операционным системам и многому другому
 
<Добавить в Избранное>    <Сделать стартовой>    <Реклама на сайте>    <Контакты>
  Главная Документация Программы Обои   Экспорт RSS E-Books
 
 

   Программирование -> C/C++ -> Уроки программирования на C/C++ под Windows 95


Вывод текста (продолжение)

На предыдущем уроке мы говорили о функции GetTextMetrics, с помощью которой можно узнать параметры текущего шрифта. Мы не будем говорить о структуре TEXTMETRIC подробно, Вам вполне достаточно будет следующего рисунка, который поясняет некоторые поля этой структуры.

 

     


Невозможно узнать точную ширину одного символа (если шрифт непропорциональный), поэтому можно говорить лишь об усредненной ширине символа - tmAveCharWidth. Есть еще такой параметр, как ширина самого широкого символа - tmMaxCharWidth. Ширину прописных букв можно рассчитать как 150% от tmAveCharWidth.
Следует обратить внимание, что размеры символов зависят от разрешающей способности дисплея, поэтому не пишите программы, опирающиеся на какие-либо фиксированные значения размеров символов, пользуйтесь функцией GetTextMetrics.
Чтобы продемонстрировать использование функций TextOut и GetTextMetrics, приведем пример программы:


//файл sm.h

#define N_LINES sizeof(sm) / sizeof(sm[0])



struct {

  int i;

  CHAR *szLabel;

  CHAR *szDesc;

} sm[] = {



SM_CMOUSEBUTTONS,  "SM_CMOUSEBUTTONS",

 "Number of buttons on mouse.",

SM_CXBORDER,       "SM_CXBORDER",

 "The width, in pixels, of a window border.",

SM_CYBORDER,       "SM_CYBORDER",

 "The height, in pixels, of a window border.",

SM_CXCURSOR,       "SM_CXCURSOR",

 "Width, in pixels, of a cursor.",

SM_CYCURSOR,       "SM_CYCURSOR",

 "Height, in pixels, of a cursor.",

SM_CXHSCROLL,      "SM_CXHSCROLL",

 "Width, in pixels, of a horizontal scroll bar",

SM_CYHSCROLL,      "SM_CYHSCROLL",

 "Height, in pixels, of a horizontal scroll bar",

SM_CXHTHUMB,       "SM_CXHTHUMB",

 "Width, in pixels, of the thumb box

 in a horizontal scroll bar.",

SM_CXICON,         "SM_CXICON",

 "The default width, in pixels, of an icon.",

SM_CYICON,	       "SM_CYICON",

 "The default height, in pixels, of an icon.",

SM_CXMAXIMIZED,    "SM_CXMAXIMIZED",

 "The default width, in pixels, of a

 maximized top-level window.",

SM_CYMAXIMIZED,	   "SM_CYMAXIMIZED",

 "The default height, in pixels, of a

 maximized top-level window.",

SM_CXMAXTRACK,     "SM_CXMAXTRACK",

 "The default maximum width, in pixels, of a

 window that has a caption and sizing borders.",

SM_CYMAXTRACK,     "SM_CYMAXTRACK",

 "The default maximum height, in pixels, of a

 window that has a caption and sizing borders.",

SM_CXMENUCHECK,    "SM_CXMENUCHECK",

 "The width, in pixels, of the default

 menu check-mark bitmap.",

SM_CYMENUCHECK,    "SM_CYMENUCHECK",

 "The height, in pixels, of the default

 menu check-mark bitmap.",

SM_CXMENUSIZE,     "SM_CXMENUSIZE",

 "The width, in pixels, of menu bar buttons,

 such as multiple document (MIDI) child close.",

SM_CYMENUSIZE,     "SM_CYMENUSIZE",

 "The height, in pixels, of menu bar buttons,

 such as multiple document (MIDI) child close.",

SM_CXMIN,          "SM_CXMIN",

 "Minimum width, in pixels, of a window.",

SM_CYMIN,          "SM_CYMIN",

 "Minimum height, in pixels, of a window.",

SM_CXMINIMIZED,    "SM_CXMINIMIZED",

 "The width, in pixels, of a normal

 minimized window.",

SM_CYMINIMIZED,    "SM_CYMINIMIZED",

 "The height, in pixels, of a normal

 minimized window.",

SM_CXMINSPACING,   "SM_CXMINSPACING",

 "The width, in pixels, of a grid cell

 for minimized windows.",

SM_CYMINSPACING,   "SM_CYMINSPACING",

 "The height, in pixels, of a grid cell

 for minimized windows.",

SM_CXMINTRACK,     "SM_CXMINTRACK",

 "Minimum tracking width, in pixels, of a window.",

SM_CYMINTRACK,     "SM_CYMINTRACK",

 "Minimum tracking height, in pixels, of a window.",

SM_CXSCREEN,       "SM_CXSCREEN",

 "Width, in pixels, of the screen.",

SM_CYSCREEN,       "SM_CYSCREEN",

 "Height, in pixels, of the screen.",

SM_CXSIZE,         "SM_CXSIZE",

 "Width, in pixels, of a button in a window's

 caption or title bar.",

SM_CYSIZE,         "SM_CYSIZE",

 "Height, in pixels, of a button in a window's

 caption or title bar.",

SM_CXSIZEFRAME,    "SM_CXSIZEFRAME",

 "Thickness, in pixels, of the sizing border around

 the perimeter of a window that can be resized.",

SM_CYSIZEFRAME,	   "SM_CYSIZEFRAME",

 "Thickness, in pixels, of the sizing border around

 the perimeter of a window that can be resized.",

SM_CXSMICON,       "SM_CXSMICON",

 "Recommended width, in pixels, of a small icon.",

SM_CYSMICON,       "SM_CYSMICON",

 "Recommended height, in pixels, of a small icon.",

SM_CXSMSIZE,       "SM_CXSMSIZE",

 "Width, in pixels, of small caption buttons.",

SM_CYSMSIZE,       "SM_CYSMSIZE",

 "Height, in pixels, of small caption buttons.",

SM_CYMENU,         "SM_CYMENU",

 "Height, in pixels, of single-line menu bar."

};



//файл main.cpp

#include <windows.h>

#include "sm.h"



//описание оконной процедуры

LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);



//Это главная функция программы.

int WINAPI WinMain(HINSTANCE hInst,

                   HINSTANCE hPrevInst,

                   PSTR szCmdLine,

                   int iCmdShow)

{

  HWND hwnd;

  MSG  msg;

  WNDCLASSEX w;

  static CHAR *szAppName={"TextOutExample"};

  w.cbSize=sizeof(w);

  w.style=CS_HREDRAW|CS_VREDRAW;

  w.lpfnWndProc=WndProc;

  w.cbClsExtra=0;

  w.cbWndExtra=0;

  w.hInstance=hInst;

  w.hIcon=LoadIcon(NULL,IDI_APPLICATION);

  w.hCursor=LoadCursor(NULL,IDC_ARROW);

  w.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);

  w.lpszMenuName=NULL;

  w.lpszClassName=szAppName;

  w.hIconSm=w.hIcon;

  RegisterClassEx(&w);



  hwnd=CreateWindow(

       szAppName,

       "System metrics",

       WS_OVERLAPPEDWINDOW|WS_VSCROLL,

       CW_USEDEFAULT, CW_USEDEFAULT,

       CW_USEDEFAULT, CW_USEDEFAULT,

       NULL,

       NULL,

       hInst,

       NULL);

  ShowWindow(hwnd,iCmdShow);

  UpdateWindow(hwnd);



  while(GetMessage(&msg,NULL,0,0))

  {

    TranslateMessage(&msg);

    DispatchMessage(&msg);

  }

  return msg.wParam;

}



//Оконная процедура

LRESULT CALLBACK WndProc(HWND hwnd, UINT imsg,

                         WPARAM wParam, LPARAM lParam)

{

  PAINTSTRUCT ps;

  HDC         hdc;

  TEXTMETRIC  tm;

  static int  cxChar,cyChar,iVscrollPos=0,i,y,cyClient;

  CHAR        szBuffer[10];



  switch(imsg)

  {

    case WM_CREATE:

         hdc=GetDC(hwnd);

         GetTextMetrics(hdc,&tm);

         cxChar=tm.tmAveCharWidth;

         cyChar=tm.tmHeight+tm.tmExternalLeading;

         ReleaseDC(hwnd,hdc);

         SetScrollRange(hwnd,SB_VERT,0,N_LINES,FALSE);

         SetScrollPos(hwnd,SB_VERT,iVscrollPos,TRUE);

         return 0;



    case WM_SIZE:

         cyClient=HIWORD(lParam);

         return 0;



    case WM_PAINT:

         hdc=BeginPaint(hwnd, &ps);

         for(i=0; i<N_LINES; i++)

         {

           y=cyChar*(1-iVscrollPos+i);

           TextOut(hdc,cxChar,y,sm[i].szLabel,

                   lstrlen(sm[i].szLabel));

           wsprintf(szBuffer,"%5d",

                    GetSystemMetrics(sm[i].i));

           TextOut(hdc,cxChar+22*cxChar,y,szBuffer,

                   lstrlen(szBuffer));

           TextOut(hdc,cxChar+24*cxChar+8*cxChar,y,

                   sm[i].szDesc,lstrlen(sm[i].szDesc));

         }

         EndPaint(hwnd, &ps);

         return 0;



    case WM_VSCROLL:

         switch(LOWORD(wParam))

         {

           case SB_LINEUP:

                iVscrollPos--;

                break;

           case SB_LINEDOWN:

                iVscrollPos++;

                break;

           case SB_PAGEUP:

                iVscrollPos-=cyClient/cyChar;

                break;

           case SB_PAGEDOWN:

                iVscrollPos+=cyClient/cyChar;

                break;

           case SB_THUMBPOSITION:

                iVscrollPos=HIWORD(wParam);

                break;

         }



         iVscrollPos=max(0,min(iVscrollPos,N_LINES));

         if(iVscrollPos!=GetScrollPos(hwnd,SB_VERT))

         {

           SetScrollPos(hwnd,SB_VERT,iVscrollPos,TRUE);

           InvalidateRect(hwnd,NULL,TRUE);

         }

         return 0;



    case WM_DESTROY:

         PostQuitMessage(0);

         return 0;

  }



  return DefWindowProc(hwnd,imsg,wParam,lParam);

}

Эта программа выводит не просто текст, а достаточно полезную системную информацию, (такую, как размеры экрана, число кнопок мыши и т.д.) которую можно получить с помощью вызова функции GetSystemMetrics. Функция GetSystemMetrics имеет всего один параметр, определяющий то, какую информацию Вы хотите получить. Например, если в качестве параметра этой функции Вы зададите SM_CXSCREEN, то возвращаемое значение будет определять ширину экрана в пикселах.
В нашей программе функция GetSystemMetrics вызывается в цикле при обработке сообщения WM_PAINT каждый раз с новым параметром. В файле sm.h определяется структура sm, в которой описаны различные параметры вызова функции GetSystemMetrics (поле sm.i) и комментарии (sm.szLabel - название параметра, sm.szDesc - краткое описание параметра). Вы можете посмотреть Help по функции GetSystemMetrics и добавить в файл sm.h другие параметры вызова GetSystemMetrics.
Оконная процедура WndProc обрабатывает несколько сообщений (WM_CREATE, WM_SIZE, WM_PAINT, WM_VSCROLL, WM_DESTROY). Большинство из них Вы уже знаете.
Рассмотрим подробнее обработку каждого сообщения.

WM_CREATE

При обработке этого сообщения оконная процедура получает контекст устройства (вызовом GetDC) и затем узнает размеры символов текущего шрифта (с помощью вызова GetTextMetrics). Высота символа сохраняется в переменной cyChar, а усредненная ширина - в cxChar.
Для установки диапазона вертикальной прокрутки вызывается функция SetScrollRange. Она устанавливает диапазон прокрутки от 0 до N_LINES (т.к. структура sm содержит N_LINES элементов). Текщая позиция бегунка вертикальной прокрутки устанавливается в 0 вызовом функции SetScrollPos (параметр функции - переменная iVscrollPos вначале равна нулю).

WM_SIZE

Это сообщение поступает тогда, когда размер окна изменяется. В данной программе при обработке этого сообщения просто запоминается высота рабочей области (в переменной cyClient).

WM_PAINT

Здесь выполняется вся основная работа программы - получение (GetSystemMetrics) и вывод (TextOut) информации.
Как обычно, вначале получаем описатель контекста устройства (BeginPaint). Затем в цикле вычисляем координату Y очередной строки (с учетом положения ползунка вертикальной прокрутки - iVscrollPos), выводим поля структуры sm и результаты вызова функции GetSystemMetrics.
Если Вы заметили, в программе появилась еще одна функция - wsprintf. Она работает аналогично стандартной sprintf (т.е осуществляет форматированный вывод в строку) за исключением того, что в ней нельзя использовать числа с плавающей точкой. (Для тех, кто не знаком даже с sprintf рекомендуется прочитать Help по этим двум функциям). Преимущество в использовании wsprintf вместо sprintf в том, что первая не увеличивает размер выполняемого модуля Вашей программы, т.к. находится в одной из библиотек (DLL) Windows.

WM_VSCROLL

Прежде, чем говорить о сообщении WM_VSCROLL, отметим, что в программе используются макросы LOWORD и HIWORD. Как Вам уже должно быть известно, параметры оконной процедуры wParam и lParam - 32-разрядные целые числа. Очень часто для передачи информации достаточно только 16-ти разрядов, (напр. координаты чего-либо не могут быть слишком большими, чтобы для этого требовались 32-х разрядные числа). В таких случаях в одном параметре (напр. wParam) передается сразу два числа - одно в старшем слове, другое - в младшем. Если Вы используете вызов:

var=LOWORD(wParam);


то переменной var присваивается значение младшего слова параметра wParam. Аналогично, при использовании HIWORD можно выделить старшее слово.
Если окно имеет недостаточную высоту для того, чтобы в нем поместилась вся информация и при регистрации класса окна использовался стиль WS_VSCROLL, то автоматически появляется вертикальная полоса прокрутки. Но из-за того, что полоса прокрутки появилась, работать она автоматически не станет. Ведь операционной системе неизвестно, что именно следует делать, если пользователь будет выполнять скроллинг. Об этом должна позаботиться сама программа.
В нашей программе анализируется несколько действий:

  • Пользователь нажал на кнопку прокрутки на одну строку вверх -
    LOWORD(wParam)=SB_LINEUP
  • Пользователь нажал на кнопку прокрутки на одну строку вниз -
    LOWORD(wParam)=SB_LINEDOWN
  • Пользователь прокручивает страницу назад, наступая мышкой на полосу прокрутки выше ползунка -
    LOWORD(wParam)=SB_PAGEUP
  • Пользователь прокручивает страницу вперед, наступая мышкой на полосу прокрутки ниже ползунка -
    LOWORD(wParam)=SB_PAGEDOWN
  • Производится установка ползунка в определенное положение -
    LOWORD(wParam)=SB_THUMBPISITION

При выполнении первых четырех действий ничего необычного не делается - просто вычисляется новое положение ползунка (напр. для SB_PAGEUP: от текущего значения iVscrollPos отнимается значение, равное числу строк, помещающихся на странице - cyClient / cyChar). Затем, если текущее значение переменной iVscrollPos не равно прочитанному (с помощью GetScrollPos) положению ползунка, значит ползунок нужно установить в новое положение (это делается с помощью SetScrollPos).
Если младшее слово параметра wParam равно SB_THUMBPISITION, то старшее слово wParam определяет текущее положение полосы прокрутки. Оно присваивается переменной iVscrollPos, и дальше все происходит, как описано выше.
После того, как положение ползунка полосы прокрутки изменилось, вызывается функция InvalidateRect, которая делает недействительной всю рабочую область окна. Как только рабочая область окна станет недействительной, Windows пошлет окну сообщение WM_PAINT. Таким образом, после каждого действия пользователя с полосой прокрутки, содержимое окна полностью обновляется.
О функции InvalidateRect стоит поговорить подробнее. У нее 3 параметра:

  • HWND hwnd - дескриптор окна, рабочую область которого нужно сделать недействительной;
  • RECT *lpRect - структура типа RECT с координатами области, которую нужно сделать недействительной. Если этот параметр равен NULL, становится недействительной вся рабочая область окна;
  • BOOL bErase - флаг, показывающий, что нужно делать с фоном рабочей области. Если bErase равно TRUE, перед перерисовкой рабочей области она будет закрашена кистью, которая задавалась при регистрации класса окна. Если этот параметр равен FALSE, фон обновляться не будет.

Сообщение SB_THUMBPISITION посылается только тогда, когда пользователь отпускает левую кнопку мыши после того, как он изменил положение ползунка прокрутки. Вы это легко заметите, когда запустите программу. Окно не будет прокручиваться до тех пор, пока Вы не оставите ползунок в покое.
Если Вам хочется, чтобы прокрутка выполнялась немедленно при любом движении ползунка, вместе с SB_THUMBPISITION обрабатывайте и сообщение SB_THUMBTRACK:

       ...

     case SB_THUMBPOSITION:

     case SB_THUMBTRACK:

          iVscrollPos=HIWORD(wParam);

          break;

       ...

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

 

[   ОГЛАВЛЕНИЕ   ]


 

 
Интересное в сети
 
10 новых программ
CodeLobster PHP Edition 3.7.2
WinToFlash 0.7.0008
Free Video to Flash Converter 4.7.24
Total Commander v7.55
aTunes 2.0.1
Process Explorer v12.04
Backup42 v3.0
Predator 2.0.1
FastStone Image Viewer 4.1
Process Lasso 3.70.4
FastStone Image Viewer 4.0
Xion Audio Player 1.0.125
Notepad GNU v.2.2.8.7.7
K-Lite Codec Pack 5.3.0 Full


Наши сервисы
Рассылка новостей. Подпишитесь на рассылку сейчас и вы всегда будете в курсе последних событий в мире информационных технологий.
Новостные информеры. Поставьте наши информеры к себе и у вас на сайте появится дополнительный постоянно обновляемый раздел.
Добавление статей. Если вы являетесь автором статьи или обзора на тему ИТ присылайте материал нам, мы с удовольствием опубликуем его у себя на сайте.
Реклама на сайте. Размещая рекламу у нас, вы получите новых посетителей, которые могут стать вашими клиентами.
 
Это интересно
 

Copyright © CompDoc.Ru
При цитировании и перепечатке ссылка на www.compdoc.ru обязательна. Карта сайта.