API и FreeBasic. (дочерние окна-гиперссылки)

Microsoft создавала свои контролы исходя из первоначальной задачи: сделать их простыми. И можно сказать им это удалось, но все же есть вещи в которых они не преуспели. Одна из них это контрол SysLink. Для того чтобы использовать этот контрол, нужно обязательное включение стиля XP (нужен файл manifest.xml в ресурсах программы) . Зависимость одного от другого не есть хорошо, поскольку включение стиля не даст использовать ручные установки цвета для некоторых других контролов( напр. Tooltip). Даже если вас устроит включение манифеста, все равно убогий вид контрола у которого при наведении не меняется ни вид курсора ни цвет ссылки, вряд ли порадует. Именно поэтому разработчики прибегнули к простому, но эффективному способу: изготовить контрол самим вручную. Главное что потребуется, это контрол Static. Я не буду останавливаться на вопросе , касающегося изменения цвета, поскольку для цвета и шрифтов решил написать отдельные статьи. Но остальное в примере постараюсь объяснить. И так пример:

#INCLUDE "windows.bi"
#INCLUDE Once "win/shellapi.bi"
Dim msg As MSG 'структурированная переменная MSG
Dim As WNDCLASSEX wc 'структурированная переменная WNDCLASSEX
Dim As String NameClass="MyClass" ' переменная имени класса
Dim As HINSTANCE Hinst=GetModuleHandle(0) ' хендл модуля
Function IsMouseOver(Byval wnd As HWND) As Integer Export
    Dim As RECT re
    Dim As Point pt
    GetWindowRect(wnd,@re)
    GetCursorPos(@pt)
    If pt.x<re.left   Then Return 0
    If pt.x>re.right  Then Return 0
    If pt.y<re.top    Then Return 0
    If pt.y>re.bottom Then Return 0
    Return 1
End Function
' функция класса
Function wndproc(hwnd As HWND, msg As Uinteger,_
    wparam As WPARAM, lparam As LPARAM) As Integer
    Static As Integer a,col=&hff
    Static Hyper As HWND
    Static hBrush As HBRUSH=1
    Select Case msg
        Case WM_MOUSEMOVE
            If IsMouseOver(Hyper)  Then
                SetCursor(LoadCursor(0,IDC_HAND))
                If a=0 Then
                    col=&hff0000
                    InvalidateRect(Hyper,0,1)
                    a=1
                Endif
            Else
                If a=1 Then
                    col=&h0000ff
                    InvalidateRect(Hyper,0,1)
                    a= 0
                Endif
            Endif
        Case WM_CTLCOLORSTATIC
            DeleteObject(hBrush)
            hBrush= CreateSolidBrush(&hffffff)
            SetBkColor(Cast(HDC,wparam),&hffffff)
            SetTextColor(Cast(HDC,wParam),col)
            Return Cast(Long,hBrush)
        Case WM_DESTROY
            PostQuitMessage(0)
        Case WM_CREATE
            Hyper=CreateWindowEx(0, "Static", "Перейти на сайт",_
            WS_VISIBLE Or WS_CHILD,30,20,120,20, hwnd, Cast(HMENU,1), 0, 0)
        Case WM_LBUTTONDOWN
            If IsMouseOver(Hyper) Then
                ShellExecute(0,@"Open" , @"http://users.freebasic-portal.de/freebasicru/","","" ,1 )
                col=&hff
                InvalidateRect(Hyper,0,1)
            Endif
    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_WINLOGO)
    .hCursor=LoadCursor(0,IDC_ARROW)
    .hbrBackground=Cast(HBRUSH,COLOR_WINDOWFRAME)
    .lpszClassName=StrPtr(NameClass)
    .hIconSm=.hIcon
End With
' Регистрация класса окна
If RegisterClassEx(@wc)=0 Then
    Print "Register error, press any key"
    Sleep
    End
Endif
'Создание окна
CreateWindowEx(0,NameClass,"HyperLink",_
WS_VISIBLE Or WS_OVERLAPPEDWINDOW,100,100,200,100,0,0,Hinst,0)
' Цикл сообщений
While GetMessage(@msg,0,0,0)
    TranslateMessage(@msg)
    DispatchMessage(@msg)
Wend


Вот что примерно должно получится:

hyper.png

  • В сообщении WM_CREATE создаем обычный контрол Static.
  • В сообщении WM_MOUSEMOVE отлавливаются перемещения мыши.Для того, чтобы определить находится или нет мышь над контролом Static, создана специальная функция IsMouseOver, которая вернет единичку при положительном результате. В этой процедуре уже знакомые нам по прошлым статьям две структуры RECT и POINT, а так же функция GetWindowRect , определяющая координаты окна. Незнакомая до сих пор функция GetCursorPos, имеющая в своем параметре адрес на структуру POINT, как наверно ясно из названия, определяет позицию курсора и сохраняет результат в структуре POINT. Далее идет банальное сравнение соответствия результатов координат. После определения соответствия координат, в одном из случаев загружаем курсор изображения руки с помощью LoadCursor и устанавливаем его с помощью SetCursor. Описание этих функций:
    • LoadCursor(
          HINSTANCE hInstance, // Дескриптор экземпляра модуля
          LPCTSTR lpCursorName // Указатель на строку с ресурсом или предопределенный системой курсор
      );
    • SetCursor(
          HCURSOR hCursor // загруженный курсор с помощью LoadCursor
      );
    Поскольку изменение курсора требует постоянного "подогрева", изменять его на нормальный программно не нужно. Система сама за нас это сделает, когда курсор будет не над контролом. Так же в зависимости от расположения курсора, мы изменяем переменную col , в которой указывается шестнадцатеричное значение цвета. Ну и конечно перерисовываем окно контрола функцией InvalidateRect. Для того, чтобы избежать мерцания , при движении по контролу, я ввел флаг А , который не даст лишней перерисовки окна контрола.
  • Сообщение WM_CTLCOLORSTATIC отвечает за цвет контрола Static. И как я и говорил, рассматривать его сейчас не будем
  • В сообщении WM_LBUTTONDOWN (нажатие на левую кнопку мыши) так же определяется расположение при нажатии с помощью IsMouseOver и с помощью ShellExecute запускаем страницу интернета. Функция ShellExecute очень мощная и многофункциональная, способная запускать любые файлы с указанием параметров командной строки и директории по умолчанию. Вот ее описание:
    • ShellExecute(
       HWND hwnd,             // указатель  на  окно  (откуда вызвано)
       LPCTSTR lpOperation,   // Указатель но определенные операции для выполнения
       LPCTSTR lpFile,        // Указатель на имя фала или папки
       LPCTSTR lpParameters,  // Параметры выполнения операции
       LPCTSTR lpDirectory,   // Указатель на каталог по умолчанию
       INT nShowCmd           // Тип окна для вывода. 
      );
      Описание ее констант и декларация находятся в файле shellapi.bi . Именно поэтому в начале файла мы включили его. Более подробно о ней можете почитать в справочнике WINAPI
    И последний штрих: после клика по ссылке изменяем содержимое переменной col и перерисовываем контрол.

Вот собственно и все, удачи!

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