API и FreeBasic. (дочерние окна-static)

Основные и главные особенности дочерних окон:

  • имеют окно - владельца, которое может изменяться
  • могут и чаще всего имеют идентификатор (ID)
  • некоторые события от дочерних окон проходят через процедуру окна владельца
  • автоматически уничтожаются после уничтожения окна владельца

Все что видит пользователь в основном окне: кнопки, надписи, ползунки, скролы и пр., чаще всего это дочерние окна. Почему пишу чаще всего? В реале все что мы видим на экране - это всего лишь результат рисования. Именно поэтому не сложно сэмулировать кнопку, нарисовав ее в нужном месте , но она может не являться дочерним окном.
В системе Windows разработчики сделали встроенные классы окон. Из-за чего процесс разработки программ резко упростился. Хотя бы из-за этой особенности, большинство программистов выбирает Windows. Встроенные классы имеют свою процедуру событий, и нам не надо заботиться о перерисовке в этом окне. За нас это делает система. Для нас приготовлены удобные и проверенные временем методы для реализации нужных задач(получить событие от нажатия кнопки, сдвигать ползунок по требованию и др.).
В этой статье я хочу коснуться класса Static. Данный класс позволяет создать окно, в котором можно выводить текст или картинку. Создаются дочерние окна, в том числе и Static все той же функцией CreateWindowEx (или CreateWindow) . Однако вы наверное поняли , что  регистрировать класс уже не нужно. Достаточно только при создании окна указать правильно имя класса, в стилях окна прописать стиль WS_CHILD и в один из параметров функции CreateWindowEx записать хендл окна владельца. Так же по желанию или точнее в зависимости от поставленной задачи можно указать идентификатор этого дочернего окна (далее буду писать КОНТРОЛА). В примере ниже реализованы два контрола с классом Static. Один будет отображать надпись, а другой рисунок (в папке с исходным текстом программы должен быть рисунок с именем 1.bmp):

#INCLUDE "windows.bi"
Dim msg As MSG 'структурированная переменная MSG
Dim As WNDCLASSEX wc 'структурированная переменная WNDCLASSEX
Dim As String NameClass="MyClass" ' переменная имени класса
Dim As HINSTANCE Hinst=GetModuleHandle(0) ' хендл модуля
' функция класса
Function wndproc(hwnd As HWND, msg As Uinteger,_
    wparam As WPARAM, lparam As LPARAM) As Integer
    Dim As HBITMAP bmp
    Dim image As HWND
    Select Case msg
        Case WM_CREATE
            CreateWindowEx(0,"Static","Надпись",WS_VISIBLE Or WS_CHILD,10,10,100,20,hwnd,Cast(HMENU,1),0,0)
            image=CreateWindowEx(0,"Static","",WS_VISIBLE Or SS_BITMAP Or WS_CHILD,10,50,100,100,hwnd,Cast(HMENU,2),0,0)
            bmp=LoadImage(0,"1.bmp",IMAGE_BITMAP,0,0,LR_LOADFROMFILE)
            SendMessage(image,STM_SETIMAGE,IMAGE_BITMAP,Cast(LPARAM,bmp))
        Case WM_DESTROY
            DeleteObject(bmp)
            PostQuitMessage(0)
    End Select
    Return DefWindowProc(hwnd,msg,wparam,lparam)
End Function
' Заполнение структуры WNDCLASSEX
With wc
    .cbSize=SizeOf(WNDCLASSEX)
    .style=CS_HREDRAW Or CS_VREDRAW
    .lpfnWndProc=@wndproc
    .hInstance=Hinst
    .hIcon=LoadIcon(0,IDI_QUESTION)
    .hCursor=LoadCursor(0,IDC_ARROW)
    .hbrBackground=Cast(HBRUSH,COLOR_WINDOW)
    .lpszClassName=StrPtr(NameClass)
    .hIconSm=.hIcon
End With
' Регистрация класса окна
If RegisterClassEx(@wc)=0 Then
    Print "Register error, press any key"
    Sleep
    End
Endif
'Создание окна
CreateWindowEx(0,NameClass,"Главное окно",_
WS_VISIBLE Or WS_OVERLAPPEDWINDOW,100,100,170,220,0,0,Hinst,0)
' Цикл сообщений
While GetMessage(@msg,0,0,0)
    TranslateMessage(@msg)
    DispatchMessage(@msg)
Wend


При отлове сообщения WM_CREATE , мы создали 2 контрола с помощью функции CreateWindowEx. Обоим в 9 параметре функции присвоили хендл нашего главного окна. А в 10 параметре для каждого указали свой идентификатор. Хотя по сути именно для этой программы, можно было вместо идентификаторов указать ноль. Если присмотритесь, то поймете , что существенная разница в создании указывается при установке стиля окна. Так во втором контроле мы указали стиль SS_BITMAP , он даст понять системе, что мы будем в контроле размещать рисунок(битмап).
В данном параметре любого дочернего окна предусмотрены дополнительные стили к имеющимся стилям при создании обычного окна. Они обычно начинаются с абревиатуры контрола и знака нижнего подчеркивания. Так например:

SS_BITMAP , можно расшифровать: Static Style Bitmap
ES_CENTER ,можно расшифровать: Editor Style Center
BS_RIGHT ,можно расшифровать: Button Style Right

Даже из расшифрованного часто удается понять что делает данный стиль. Но конечно правильно всегда иметь справочник по функциям API , при том лучше оригинальный английский вариант.
Давайте рассмотрим какие стили можно использовать с Static контролом:

  • SS_BITMAP - Определяет, что в статическом элементе управления должен отобразиться точечный рисунок. Текст кода ошибки - имя точечного рисунка (не имя файла) определенного в другом месте файла ресурса. Стиль игнорирует параметры nWidth и nHeight; элемент управления автоматически устанавливает собственные размеры, чтобы поместить точечный рисунок.
  • SS_BLACKFRAME - Определяет окно с рамкой, использующей тот же самый цвет, как и у рамки основного окна. Этот цвет черный по умолчанию в системе цветов Windows.
  • SS_BLACKRECT - Определяет прямоугольник, заполненный текущим цветом рамки окна. По умолчанию этот цвет черный в системе цветов Windows.
  • SS_CENTER - Определяет простой прямоугольник и выравнивает по центру текст кода ошибки в прямоугольнике. Текст форматируется перед отображением его на экране. Слова, которые выходят за пределы конца строки автоматически переносятся в начало следующей центрированной строки.
  • SS_CENTERIMAGE - Определяет, что средняя точка статического элемента управления со стилем SS_BITMAP или SS_ICON должна остаться фиксированной, когда элемент управления изменяется. Четыре стороны корректируются так, чтобы поместить новый точечный рисунок или пиктограмму. Если статический элемент управления имеет стиль SS_BITMAP, а точечный рисунок меньше чем рабочая область элемента управления, рабочая область заполняется цветом пикселя левого верхнего угла точечного рисунка. Если статический элемент управления имеет стиль SS_ICON, пиктограмма появляется, но не окрашивает рабочую область.
  • SS_GRAYFRAME - Определяет поле окна с рамкой, выведенной тем же самым цветом, что и экранный фон (рабочий стол). По умолчанию в системе цветов Windows этот цвет серый.
  • SS_GRAYRECT - Определяет прямоугольник, заполненный текущим экранным цветом фона. По умолчанию в системе цветов Windows этот цвет серый.
  • SS_ICON - Определяет пиктограмму, отображаемую в диалоговом окне. Данный текст - имя пиктограммы (не имя файла) определенный в другом месте файла ресурса. Стиль игнорирует параметры nWidth и nHeight; пиктограмма автоматически устанавливает свою величину.
  • SS_LEFT - Определяет простой прямоугольник и выравнивание по левому краю текста, помещенного в прямоугольнике. Текст форматируется перед его отображением. Слова, которые выходят за пределы конца строки автоматически переносятся в начало следующей выровненной по левой границе строки.
  • SS_LEFTNOWORDWRAP - Определяет простой прямоугольник и выравнивание по левому краю текста, помещенного в прямоугольнике. Планшеты расширяются, но слова не переносятся. Текст, который выходит за пределы конца строки, отсекается.
  • SS_METAPICT - Определяет, что изображение метафайла должно отобразиться в статическом элементе управления. Данный текст - имя изображения метафайла (не имя файла) определенный в другом месте в файле ресурса. Статический элемент управления метафайла имеет фиксированный размер; изображение метафайла масштабируется, чтобы приспособить рабочую область статического элемента управления.
  • SS_NOPREFIX - Предотвращает интерпретацию любого символа амперсанта (&) в тексте элемента управления как символа префикса акселератора. Они отображаются с удаленным амперсантом и следующим за ним подчеркнутым символом в строке. Этот стиль статического элемента управления может быть включен с любым из определенных статических элементов управления. Прикладная программа может объединять SS_NOPREFIX с другими стилями, используя поразрядный оператор OR = ИЛИ (|). Это может быть полезно, когда имена файлов или другие строки, которые могут содержать амперсант (&) должны отображаться в статическом элементе управления диалогового окна.
  • SS_NOTIFY - Посылает родительскому окну уведомительные сообщения STN_CLICKED и STN_DBLCLK, когда пользователь щелкает или дважды щелкает мышью по элементу управления.
  • SS_RIGHT - Определяет простой прямоугольник и выравнивает по правому краю текста помещенный в прямоугольнике. Текст форматируется перед его отображением на экране. Слова, которые выходят за пределы конца строки автоматически переносятся в начало следующей выровненной по правой границе строки.
  • SS_RIGHTIMAGE - Определяет, что угол правой нижней части статического элемента управления со стилем SS_BITMAP или SS_ICON должен остаться фиксированным, когда элемент управления изменяется. Только верхняя и левая стороны корректируются, чтобы поместить новый точечный рисунок или пиктограмму.
  • SS_SIMPLE - Определяет простой прямоугольник и отображает одиночную строку выровненного по левой границе текста в прямоугольнике. Текстовая строка не может быть, сокращена или изменена в любом случае. Родительское окно панели управления или диалоговое окно не должны обрабатывать сообщение WM_CTLCOLORSTATIC.
  • SS_WHITEFRAME - Определяет поле окна с рамкой, выведенной тем же самым цветом как фон окна. По умолчанию, в системе цветов Windows - этот цвет белый.
  • SS_WHITERECT - Определяет прямоугольник, заполненный текущим цветом фона окна. По умолчанию, в системе цветов Windows - этот цвет белый.

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

Давайте вернемся к коду. Что касается текстового контрола, то тут должно быть все ясно. Тот текст который мы хотим видеть в контроле, нужно указать в 3 параметре функции CreateWindowEx. Что касается изображений, то тут следует понять, что перед тем как разместить изображение в контроле, нужно загрузить его в память компьютера. При удачной загрузке, система возвратит его хендл. В данном случае мы используем функцию LoadImage. Она способна загружать форматы bmp,ico,cur. После того, как удачно получен хендл изображения, мы привязываем этот хендл к нашему контролу с помощью функции SendMessage, отправляя сообщение STM_SETIMAGE .

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

Подробнее о функции SendMessage:

Одна из самых часто используемых функций API.  Способна отправлять заданное сообщение окну или окнам. Функция вызывает оконную процедуру для заданного окна и не возвращает значение до тех пор, пока оконная процедура не обработает сообщение. В нашем случае мы отправили сообщение окну нашего контрола, зная его хендл и передавая этот хендл в первом параметре. Во втором параметре мы указали константу STM_SETIMAGE. Именно это событие должно обработаться системой в оконной процедуре контрола Static. В третьем параметре так же указана константа IMAGE_BITMAP , указывающая, что передается хендл битмапа, который в свою очередь так же передается в 4 параметре функции. Общий синтаксис SendMessage:

  • hWnd - Дескриптор окна, оконная процедура которого примет сообщение. Если этот параметр - HWND_BROADCAST, сообщение отправляется всем окнам верхнего уровня в системе, включая заблокированные или невидимые, не имеющие владельца, перекрывающие и выскакивающие окна; но сообщение не отправляется дочерним окнам.
  • Msg - Определяет сообщение, которое будет отправлено.
  • wParam - Определяет дополнительную конкретизирующую сообщение информацию.
  • lParam - Определяет дополнительную конкретизирующую сообщение информацию.

Подробнее о функции LoadImage:

Это очень удобная функция, если вам нужно загрузить рисунок формата bmp. Она способна загружать рисунок не только напрямую из файла, но и из ресурсов.Сейчас я не хочу касаться работы с  ресурсами(это отдельная большая тема). В первом параметре функции мы передаем ноль, поскольку НЕ будем использовать стандартные изображения, а так же изображения из ресурсов. Во втором параметре передаем путь к нашему рисунку. В третьем указываем тип загружаемого изображения. В 4 и 5 параметрах передаем нули, поскольку нам нужны реальные размеры рисунка. И в 6 параметре передаем флаг LR_LOADFROMFILE, сигнализирующий системе, что загрузка будет из файла.  Синтаксис функции:

  • hinst - Дескриптор экземпляра модуля, который содержит загружаемое изображение. Чтобы загрузить  OEM изображение, установите этот параметр в нуль.
  • lpszName - Устанавливает загружаемое изображение. Если параметр  hinst - не ПУСТО (NULL), а параметр  fuLoad не включает LR_LOADFROMFILE, параметр  lpszName устанавливает ресурс изображения в модуле  hinst. Если ресурс изображения загружается по имени,  параметр  lpszName - указатель на символьную строку с нулем в конце, которая содержит имя ресурса изображения. Если ресурс изображения загружается по порядковому номеру, используя макрос MAKEINTRESOURCE, то порядковый номер изображения преобразуется в форму, которая может быть передана в функцию LoadImage. Если параметр  hinst - ПУСТО (NULL), а параметр  fuLoad не включает значение LR_LOADFROMFILE,  lpszName устанавливает загружаемое OEM изображение. Идентификаторы  OEM изображения определены в  Winuser.bi и имеют нижеследующие префиксы:
    • OBM_   OEM точечные рисунки
    • OIC_     OEM значки
    • OCR_    OEM курсоры
    Чтобы передать эти константы в функцию LoadImage, используйте макрос MAKEINTRESOURCE. Например, чтобы загрузить курсор OCR_NORMAL, передайте  MAKEINTRESOURCE  (OCR_NORMAL) как параметр  lpszName и ПУСТО (NULL) как параметр hinst.Если параметр  fuLoad включает значение LR_LOADFROMFILE,  lpszName - имя файла, который содержит изображение.
  • uType - Устанавливает тип загружаемого изображения. Этим параметром может быть одно из ниже перечисленных значений:
    • IMAGE_BITMAP  Загружает точечный рисунок
    • IMAGE_CURSOR  Загружает курсор
    • IMAGE_ICON
  • cxDesired - Устанавливает ширину значка или курсора, в пикселях. Если этот параметр равняется нулю, а параметр  fuLoad - LR_DEFAULTSIZE, функция, чтобы установить ширину, использует системное значение размера  SM_CXICON или SM_CXCURSOR. Если этот параметр равняется нулю и  LR_DEFAULTSIZE не используется, функция использует фактическую ширину ресурса.
  • cyDesired - Устанавливает высоту значка или курсора, в пикселях. Если этот параметр равняется нулю, а параметр  fuLoad - LR_DEFAULTSIZE, функция, чтобы установить высоту, использует системное значение размера  SM_CYICON или SM_CYCURSOR. Если этот параметр равняется нулю и  LR_DEFAULTSIZE не используется, функция использует фактическую высоту ресурса.
  • fuLoad - Этот параметр может состоять из одного или нескольких нижеследующих значений:
    • LR_DEFAULTCOLOR  Задаваемый по умолчанию флажок; он ничего не делает. Все, что это означает - это "не  LR_MONOCHROME".
    • LR_CREATEDIBSECTION  Когда параметр  uType устанавливает IMAGE_BITMAP, то заставляет функцию возвращать точечный рисунок  DIB секции, а не совместимый точечный рисунок. Этот флажок полезен чтобы загрузить точечный рисунок без отображения его в цвете  устройства вывода на экран.
    • LR_DEFAULTSIZE  Использует ширину или высоту, определенную системными значениями размеров для курсоров или значков, если параметры  cxDesired или  cyDesired устанавливаются в нуль. Если этот флажок не определен, а  cxDesired и  cyDesired установлены в нуль, функция использует фактический размер ресурса. Если ресурс содержит несколько изображений, функция использует размер первого изображения.
    • LR_LOADFROMFILE  Загружает изображение из файла, указанного параметром lpszName. Если этот флажок не определен,  lpszName - имя ресурса.
    • LR_LOADMAP3DCOLORS  Ищет таблицу цветов изображения и заменяет нижеследующие оттенки серого  соответствующим трехмерным цветом:
      • Темно-серый, RGB (128,128,128)                     COLOR_3DSHADOW
      • Серый,RGB(192,192,192)                                  COLOR_3DFACE
      • Светло-серый RGB(223,223,223)                     COLOR_3DLIGHT
      Не используйте этот параметр, если Вы загружаете точечный рисунок с глубиной цвета больше чем 8 bpp (битов на пиксель).
    • LR_LOADTRANSPARENT  Извлекает код цвета первого пикселя в изображении и заменяет соответствующую запись в таблице цветов с заданным по умолчанию цветом окна (COLOR_WINDOW). Все пиксели в изображении, которые используют эту запись, становятся заданным по умолчанию цветом окна. Это значение применяется только к изображениям, которые имеют соответствующие таблицы цветов. Не используйте этот параметр, если Вы загружаете точечный рисунок с глубиной цвета больше чем 8 bpp (битов на пиксель).
      Если параметр  fuLoad включает в себя значения и LR_LOADTRANSPARENT, и LR_LOADMAP3DCOLORS, то LR_LOADTRANSPARENT имеет приоритет. Однако, запись таблицы цветов заменяется на COLOR_3DFACE, а не COLOR_WINDOW.
    • LR_MONOCHROME  Загружает изображение в черно-белом цвете.
    • LR_SHARED  Совместно использует дескриптор изображения, если изображение загружено несколько раз. Если  LR_SHARED не установлен, второй вызов функции  LoadImage для одного и того же ресурса загрузит изображение снова и возвратит другой дескриптор. Когда Вы используете этот флажок, система уничтожает ресурс, когда он больше не нужен.
      Не используйте  LR_SHARED для изображений, которые имеют нестандартные размеры, которые могут измениться после загрузки, или которые загружаются из файла. При загрузке системного значка или курсора, Вы должны использовать флажок LR_SHARED, или функция будет не в состоянии загрузить ресурс. Windows 95/98/Me: функция находит первое изображение с затребованным именем ресурса в кэше, независимо от затребованного размера.
    • LR_VGACOLOR  Используются истинные  VGA цвета.

Для того, чтобы сменить текст у первого контрола , можно так же воспользоваться функцией SendMessage , отправляя сообщение WM_SETTEXT. При этом в третьем параметре передается 0, а в четвертом указатель на строковую переменную. Если нужно получить текст из контрола, то есть похожее сообщение WM_GETTEXT. В этом случае в четвертом параметре указатель на принимающий буфер, а в третьем параметре передается кол-во принимаемых символов. Кроме функции SendMessage, можно использовать специально-предназначенные для этих целей функции: SetWindowText и GetWindowText. У этих функций вычеркнуты лишние параметры, которые приходится прописывать у универсальной функции SendMessage. Синтаксис этих функций:

SetWindowText

  • hWnd,                   хендл окна
  • lpString                 указатель на строку

GetWindowText

  • hWnd                   хендл окна
  • lpString                указатель на буфер
  • maxCount            максимальное кол-во символов для помещения в буфер

Пример:

#INCLUDE "windows.bi"
Dim msg As MSG 'структурированная переменная MSG
Dim As WNDCLASSEX wc 'структурированная переменная WNDCLASSEX
Dim As String NameClass="MyClass" ' переменная имени класса
Dim As HINSTANCE Hinst=GetModuleHandle(0) ' хендл модуля
Dim Shared As HWND Mhwnd,STText
' функция класса
Function wndproc(hwnd As HWND, msg As Uinteger,_
    wparam As WPARAM, lparam As LPARAM) As Integer
    Dim As String*32 text,textM
    Select Case msg
        Case WM_CREATE
            STText=CreateWindowEx(0,"Static","Надпись",WS_VISIBLE Or WS_CHILD,10,10,100,20,hwnd,Cast(HMENU,1),0,0)
        Case WM_LBUTTONDOWN
            SendMessage(STText,WM_GETTEXT,32,Cast(lparam,@text))
            GetWindowText(Mhwnd,Cast(LPSTR,@textM),32)
            SendMessage(STText,WM_SETTEXT,0,Cast(lparam,@textM))
            SetWindowText(Mhwnd,Cast(LPSTR,@text))
        Case WM_DESTROY
            PostQuitMessage(0)
    End Select
    Return DefWindowProc(hwnd,msg,wparam,lparam)
End Function
' Заполнение структуры WNDCLASSEX
With wc
    .cbSize=SizeOf(WNDCLASSEX)
    .style=CS_HREDRAW Or CS_VREDRAW
    .lpfnWndProc=@wndproc
    .hInstance=Hinst
    .hIcon=LoadIcon(0,IDI_QUESTION)
    .hCursor=LoadCursor(0,IDC_ARROW)
    .hbrBackground=Cast(HBRUSH,COLOR_WINDOW)
    .lpszClassName=StrPtr(NameClass)
    .hIconSm=.hIcon
End With
' Регистрация класса окна
If RegisterClassEx(@wc)=0 Then
    Print "Register error, press any key"
    Sleep
    End
Endif
'Создание окна
Mhwnd=CreateWindowEx(0,NameClass,"Главное окно",_
WS_VISIBLE Or WS_OVERLAPPEDWINDOW,100,100,250,100,0,0,Hinst,0)
' Цикл сообщений
While GetMessage(@msg,0,0,0)
    TranslateMessage(@msg)
    DispatchMessage(@msg)
Wend

В примере при нажатии на левую кнопку мыши по клиентской области окна, происходит обмен надписями у заголовка окна и контрола Static. Здесь я использовал оба вышеописанных способа получения и установки текста при помощи SendMessage и функций SetWindowText , GetWindowText. Хотя если честно, всегда для получения и установки текста, пользуюсь функциями SetWindowText и GetWindowText. В обработке сообщения WM_LBUTTONDOWN первые две строчки получают текстовые значения в буфер, следующие две отправляют новые значения окнам.

Беря данные примеры как основу, вы можете эксперементировать с разными стилями контрола Static. Не забывайте что у функции CreateWindowEx есть первый параметр дополнительных стилей, который тоже кое-что визуально меняет у контрола Static...

Изменять размеры контрола можно точно так же как и с обычным окном с помощью MoveWindow. Если пропустили , читаем в этой статье Что касается изменения цвета текста или шрифта, то для этого возможно будет отдельная статья. На этом все, всего доброго!

содержание | назад | вперед