Красивый градиентный ProgressBar на Ассемблере
Элемент ProgressBar, он же индикатор прогресса, используется в тех случаях, когда нужно показать пользователю степень завершения какого-либо действия. Есть стандартный элемент msctls_progress32, но он практически не поддается настройке в плане дизайна. Например, его нельзя сделать градиентным, чтобы заливка плавно перетекала от зеленого, через желтый и до красного. Но можно нарисовать красивую полосу ProgressBar самостоятельно. Идею я позаимствовал у kero, знаю, что он сюда иногда заглядывает и надеюсь, что он будет не против. Оригинал написан на MASM, я доработал его и портировал на FASM.Принцип создания градиентного ProgressBar
Принцип создания градиентного прогрессбара заключается в том, что на элемент STATIC на всю его площадь накладывается готовое изображение. Затем создается дополнительное непрозрачное окно, являющееся дочерним к STATIC и расположенное поверх него. Регулируя размер и положение этого дочернего окна, открывается та или иная площадь изображения, пропорционально нужному проценту заполнения. Это чем-то напоминает создание рейтингов на CSS. Еще одна хитрость заключается в том, что изображение прогрессбара загружается из ресурсов функцией LoadImage, которая позволяет сразу указывать нужные размеры. Если исходное изображение меньше, то оно автоматически растягивается. Таким образом, для создания цветного прогрессбара достаточно однопиксельного изображения, а из крохотного bitmap'а шириной всего в три пиксела получается красивый градиентный прогрессбар любого размера.
Для того, чтобы в своем приложении было удобно работать с такими самодельными элементами интерфейса, я оформил все в виде отдельной процедуры. Никаких дополнительных переменных объявлять не надо, все что нужно, хранится в пользовательских данных самого STATIC. Ну и картинки в ресурсах, конечно.
Code (Assembler) : Убрать нумерацию
- ;----------------------------------------------------------------------
- ; Процедура отрисовки градиентного ProgressBar
- ;----------------------------------------------------------------------
- ; Автор: ManHunter / PCL (http://www.manhunter.ru)
- ; на основе кода kero (http://www.geocities.ws/xmemor)
- ;----------------------------------------------------------------------
- ; Параметры:
- ; hWnd - хэндл STATIC, на котором будет отрисован ProgressBar
- ; dProc - процент заполнения (0..100)
- ;----------------------------------------------------------------------
- proc ProgressBar hWnd:DWORD, dProc:DWORD
- locals
- wXY RECT
- width dd ?
- height dd ?
- endl
- ; Индексы изображений в ресурсах
- INDEX_HORIZONTAL_BITMAP = 1
- INDEX_VERTICAL_BITMAP = 2
- pusha
- ; Получить размеры STATIC для отрисовки ProgressBar
- lea ebx,[wXY]
- invoke GetClientRect,[hWnd],ebx
- mov eax,[ebx+RECT.right]
- sub eax,[ebx+RECT.left]
- mov [width],eax
- mov eax,[ebx+RECT.bottom]
- sub eax,[ebx+RECT.top]
- mov [height],eax
- ; Слайдер уже есть?
- invoke GetWindowLong,[hWnd],GWL_USERDATA
- or eax,eax
- jnz .set_slider
- ; Загрузить изображение и растянуть его до нужных размеров
- invoke ShowWindow,[hWnd],SW_HIDE
- invoke GetModuleHandle,0
- ; Выбрать тип изображения для загрузки
- mov ebx,[width]
- cmp ebx,[height]
- jb .load_vertical_image
- .load_horizontal_image:
- invoke LoadImage,eax,INDEX_HORIZONTAL_BITMAP,\
- IMAGE_BITMAP,[width],[height],LR_DEFAULTCOLOR
- jmp @f
- .load_vertical_image:
- invoke LoadImage,eax,INDEX_VERTICAL_BITMAP,IMAGE_BITMAP,\
- [width],[height],LR_DEFAULTCOLOR
- @@:
- ; Установить изображение на STATIC
- invoke SendMessage,[hWnd],STM_SETIMAGE,IMAGE_BITMAP,eax
- ; Создать дочернее окно слайдера
- invoke GetModuleHandle,0
- invoke CreateWindowEx,0,.class,0,WS_CHILD+WS_VISIBLE,\
- 0,0,[width],[height],[hWnd],0,eax,0
- .set_slider:
- ; Хэндл слайдера
- mov ebx,eax
- ; Сохранить или обновить хэнд слайдера
- invoke SetWindowLong,[hWnd],GWL_USERDATA,eax
- ; Вычислить размер слайдера
- mov eax,[width]
- cmp eax,[height]
- jb .set_vertical_slider
- .set_horizontal_slider:
- mov eax,[dProc]
- cmp eax,100
- jbe @f
- mov eax,100
- @@:
- xor edx,edx
- mov ecx,[width]
- imul ecx
- mov ecx,100
- div ecx
- ; Передвинуть слайдер на прогресс-баре
- invoke MoveWindow,ebx,eax,0,[width],[height],TRUE
- jmp .show_slider
- .set_vertical_slider:
- mov eax,[dProc]
- cmp eax,100
- jbe @f
- mov eax,100
- @@:
- xor edx,edx
- mov ecx,[height]
- imul ecx
- mov ecx,100
- div ecx
- ; Передвинуть слайдер на прогресс-баре
- mov ecx,[height]
- sub ecx,eax
- invoke MoveWindow,ebx,0,0,[width],ecx,TRUE
- .show_slider:
- invoke ShowWindow,[hWnd],SW_SHOW
- popa
- ret
- .class db 'STATIC',0
- endp
Code (Assembler) : Убрать нумерацию
- section '.rsrc' resource data readable
- resource bitmaps,\
- INDEX_HORIZONTAL_BITMAP,LANG_NEUTRAL,progress1,\
- INDEX_VERTICAL_BITMAP,LANG_NEUTRAL,progress2
- bitmap progress1,'progress_h.bmp'
- bitmap progress2,'progress_v.bmp'
Code (Assembler) : Убрать нумерацию
- ; Получить хэндл STATIC
- invoke GetDlgItem,[hwnddlg],ID_PROGRESSBAR
- ; Установить прогрессбар на позицию percent
- stdcall ProgressBar,eax,[percent]
Code (Assembler) : Убрать нумерацию
- ;----------------------------------------------------------------------
- ; Процедура отрисовки горизонтального градиентного ProgressBar
- ;----------------------------------------------------------------------
- ; Автор: ManHunter / PCL (http://www.manhunter.ru)
- ; на основе кода kero (http://www.geocities.ws/xmemor)
- ;----------------------------------------------------------------------
- ; Параметры:
- ; hWnd - хэндл STATIC, на котором будет отрисован ProgressBar
- ; dProc - процент заполнения (0..100)
- ;----------------------------------------------------------------------
- proc ProgressBar hWnd:DWORD, dProc:DWORD
- locals
- wXY RECT
- width dd ?
- height dd ?
- endl
- ; Индекс изображения в ресурсах
- INDEX_HORIZONTAL_BITMAP = 1
- pusha
- ; Получить размеры STATIC для отрисовки ProgressBar
- lea ebx,[wXY]
- invoke GetClientRect,[hWnd],ebx
- mov eax,[ebx+RECT.right]
- sub eax,[ebx+RECT.left]
- mov [width],eax
- mov eax,[ebx+RECT.bottom]
- sub eax,[ebx+RECT.top]
- mov [height],eax
- ; Слайдер уже есть?
- invoke GetWindowLong,[hWnd],GWL_USERDATA
- or eax,eax
- jnz .set_slider
- ; Загрузить изображение и растянуть его до нужных размеров
- invoke ShowWindow,[hWnd],SW_HIDE
- invoke GetModuleHandle,0
- invoke LoadImage,eax,INDEX_HORIZONTAL_BITMAP,\
- IMAGE_BITMAP,[width],[height],LR_DEFAULTCOLOR
- ; Установить изображение на STATIC
- invoke SendMessage,[hWnd],STM_SETIMAGE,IMAGE_BITMAP,eax
- ; Создать дочернее окно слайдера
- invoke GetModuleHandle,0
- invoke CreateWindowEx,0,.class,0,WS_CHILD+WS_VISIBLE,\
- 0,0,[width],[height],[hWnd],0,eax,0
- .set_slider:
- ; Хэндл слайдера
- mov ebx,eax
- ; Сохранить или обновить хэнд слайдера
- invoke SetWindowLong,[hWnd],GWL_USERDATA,eax
- ; Вычислить размер слайдера
- mov eax,[dProc]
- cmp eax,100
- jbe @f
- mov eax,100
- @@:
- xor edx,edx
- mov ecx,[width]
- imul ecx
- mov ecx,100
- div ecx
- ; Передвинуть слайдер на прогресс-баре
- invoke MoveWindow,ebx,eax,0,[width],[height],TRUE
- invoke ShowWindow,[hWnd],SW_SHOW
- popa
- ret
- .class db 'STATIC',0
- endp
Просмотров: 3047 | Комментариев: 5
Внимание! Статья опубликована больше года назад, информация могла устареть!
Комментарии
Отзывы посетителей сайта о статье
ManHunter
(25.07.2016 в 17:54):
А это уже как-нибудь сам.
Жека
(25.07.2016 в 17:48):
стоп, стоп, стоп.
А серую полоску Child?
А серую полоску Child?
ManHunter
(25.07.2016 в 14:21):
Нигде, это фотошопная картинка для демонстрации принципа формирования прогрессбара. Но такой градиент без проблем растягивается из трехпиксельного битмапа, только цвета надо подобрать.
Добавил в архив персональный прогрессбар.
Добавил в архив персональный прогрессбар.
Жека
(25.07.2016 в 13:59):
а где пример со скрина? Тот прогрессбар ещё интереснее
prostovova
(24.07.2016 в 15:21):
Красиво.
Есть еще (GRush Controls) homm86.narod.ru, посмотреть бы пример на FASM.
Есть еще (GRush Controls) homm86.narod.ru, посмотреть бы пример на FASM.
Добавить комментарий
Заполните форму для добавления комментария