Форум программистов, компьютерный форум, киберфорум
Visual Basic
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 Аватар для BasicMan
19318 / 2625 / 84
Регистрация: 17.02.2009
Сообщений: 30,364

Техника программирования сложных окон в VB

22.05.2009, 20:32. Показов 9032. Ответов 0
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Введение

Mногие из Вас наверняка видели в Windows программах окна нестандартной формы (круглые, треугольные и т.д.) и задавали себе вопрос: как мне сделать такое окно? Если прочитать документацию по Visual Basic, то можно сделать вывод, что стандартные средства языка не предоставляют такой возможности. А что же делать, если очень хочется? Тогда следует вспомнить, что в распоряжении программиста на VB есть еще и Windows API, который должен нам в этом помочь.

Теоретические основы

Для начала давайте разберемся, как это можно сделать теоретически. Из документации Windows видно, что каждое окно в системе описывается множеством параметров, из которых нас с Вами интересует <видимая область окна>. Видимая область окна в системе, создаваемое Visual Basic <по умолчанию> имеет вид прямоугольника, но, в принципе, ничто не мешает изменить форму этой области. Данная область окна описывается с помощью специального объекта, который называется Region. Регион можно представить в виде поверхности, ограниченной координатами, описываемыми угловые точки этой области. Проще говоря, можно описать область любой формы, затем создать из неё, с помощью специальных функций, регион и <прикрепить> его к нужому нам окну.

Существует несколько функций Windows API для создания регионов, основными из которых являются следующие:

* CombineRgn - Комбинирует два региона между собой
* CreateEllipticRgn - Создает регион в виде эллипса или окружности
* CreatePolygonRgn - Создает регион в виде многоугольника
* CreateRectRgn - Создает прямоугольный регион
* CreateRoundRectRgn - Создает регион со скругленными краями из прямоугольной области
* SetWindowRgn - Прикрепляет регион к указанному окну

Я не буду приводить подробное описание этих функций, так как его можно найти в описании Win32 API. Кроме этих функций существуют ещё несколько функций для работы с регионами, но нам они не потребуются.

Создание простых нестандартных окон

Теперь, когда нам известны основные функции, для создания регионов, мы можем применить полученные знания на практике. Загрузите проект pTestRgn и внимательно изучите его код. В этом проете, для изменения формы окна на овальную, используется всего три строки кода и три функции Win32 API. Вначале с помощью CreateEllipticRgn создается регион, затем он прикрепляется к окну и, наконец, завершающая фаза удаление, ставшего ненужным, созданного нами региона. Если же Вы не удалите ненужный Вам больше объект, то Windows, создав регион для Вас будет хранить его в своих <недрах> и ждать дальнейших указаний по его использованию. В общем, нехорошо <захламлять> выделенную память, и настигнет Вас кара небесная, и затянется небо тучами синими, и будет страшный суд над всеми неверующими: Короче код выглядит так:

Visual Basic
1
2
3
4
5
6
7
Private Sub cmbCreateOval_Click()
   Dim lRgn As Long
   lRgn = CreateEllipticRgn(0, 0, Me.ScaleWidth / Screen.TwipsPerPixelX, _
   Me.ScaleHeight / Screen.TwipsPerPixelY)
   SetWindowRgn Me.hwnd, lRgn, True
   DeleteObject lRgn
End Sub
Так же всё просто, скажете Вы? Да, на первый взгляд всё очень просто, но это только кажется. Тот пример, который Вы только что видели, почти не имеет практического применения в настоящих приложениях Windows. Кому же нужно просто овальное окно, которое к тому же жестко задается на этапе программирования? А вот окно, которое свободно могло бы менять свою форму вполне может потребоваться. Примеры? Пожалуйста, WinAmp, Помощник в Microsoft Office и другие программы. Как же там всё это реализовано? Давайте разберемся с таким применением регионов.

Создание сложных нестандартных окон

Допустим, что у нас есть рисунок в BMP формате, из которого нужно сделать форму, а белый цвет (например) на нём означает <пустоту>. Как же сделать форму? Очень просто, нужно взять все <не белые> пиксели на рисунке, создать из их координат регион и прикрепить его к нужному нам окну. Анализировать пиксели можно GetPixel, эта функция по координатам возвращает его цвет. Давайте теперь напишем такой алгоритм для анализа BMP матрицы. Я думаю, что такой алгоритм Вам известен, и мы не будем его подробно разбирать, отмечу только, что анализ производится построчно и Pixel-и добавляются в регион не по одному, а группами построчно. Такой подход сильно экономит ресурсы процессора, выигрыш в производительности достигает 100%.

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Public Function lGetRegion(pic As PictureBox, lBackColor As Long) As Long
   Dim lRgn As Long
   Dim lSkinRgn As Long
   Dim lStart As Long
   Dim lX As Long
   Dim lY As Long
   Dim lHeight As Long
   Dim lWidth As Long
 
   'создаем пустой регион, с которого начнем работу
   lSkinRgn = CreateRectRgn(0, 0, 0, 0)
   With pic
      'подсчитаем размеры рисунка в Pixel
      lHeight = .Height / Screen.TwipsPerPixelY
      lWidth = .Width / Screen.TwipsPerPixelX
      For lX = 0 To lHeight - 1
         lY = 0
         Do While lY < lWidth
            'ищем нужный Pixel
            Do While lY < lWidth And GetPixel(.hDC, lY, lX) = lBackColor
               lY = lY + 1
            Loop
            If lY < lWidth Then
               lStart = lY
            Do While lY < lWidth And GetPixel(.hDC, lY, lX) <> lBackColor
               lY = lY + 1
            Loop
            If lY > lWidth Then lY = lWidth
               'нужный Pixel найден, добавим его в регион
               lRgn = CreateRectRgn(lStart, lX, lY, lX + 1)
               CombineRgn lSkinRgn, lSkinRgn, lRgn, RGN_OR
               DeleteObject lRgn
            End If
         Loop
      Next
   End With
   lGetRegion = lSkinRgn
End Function
Итак, для проверки на практике этого алгоритма загрузите пример pTestRgnSkin и внимательно изучите его код. В этом проекте нужный нам рисунок, для удобства, <зашит> в файле ресурсов, кроме того проект запускается процедурой Main, в которой и происходят все преобразования. Вначале загружается форма, затем в PictureBox из ресурсов загружается нужный нам рисунок, далее вызывается функция, которая создает регион и, наконец, завершающий этап - прикрепление региона к нужному нам окну. Для удобства здесь же вызывается функция, помещающая окно <поверх всех>, чтобы оно <не потерялось> у Вас на рабочем столе Windows. Кроме того, для нормальной работы программы необходимо, чтобы для PictureBox свойство AutoRedraw было установленно в True, иначе ничего не получится.

Visual Basic
1
2
3
4
5
6
7
8
9
10
Sub Main()
   Dim lRgn As Long
   Load frmTestRgnSkin
   frmTestRgnSkin.pic.Picture = LoadResPicture(101, vbResBitmap)
   lRgn = lGetRegion(frmTestRgnSkin.pic, vbWhite)
   SetWindowRgn frmTestRgnSkin.hWnd, lRgn, True
   DeleteObject lRgn
   frmTestRgnSkin.Show
   SetFormPosition frmTestRgnSkin.hWnd, True
End Sub
Теперь можно запускать проект... О, знакомое лицо, скажите Вы, это же <Скрепыш> из Microsoft Office. Да, похож, но не совсем, <Скрепыш> двигается, а этот нет. Что же нужно сделать, чтобы это окно динамически изменяло свою форму по рисунку, отображаемому в данный момент времени в PictureBox?

Динамическое изменение формы окна

Существуют программы в которых необходимо динамически во время работы изменять форму окна (например анимированный персонаж из Microsoft Office). Все это не очень сложно реализовать, нужно в событие PictureBox.Change добавить следующий код:

Visual Basic
1
2
3
4
lRgn = lGetRegion(frmTestRgnSkin.pic, vbWhite)
SetWindowRgn frmTestRgnSkin.hWnd, lRgn, True
DeleteObject lRgn
SetFormPosition frmTestRgnSkin.hWnd, True
В принципе всё готово, осталось только добавить код для изменения картинки на форме, и <Скрепыш> оживёт. В нашем примере изменять рисунок будем в Timer циклически, т.е. анимация будет непрерывна, так проще. Итак, добавим на форму Timer и поместим <в него> небольшой код, отвечающий за изменения рисунка в PictureBox. Рисунков в файле ресурсов десять штук, поэтому I должно изменяться от 101 до 110. Код изменения выглядит так:

Visual Basic
1
2
3
4
5
Static i As Long
If i < 101 Then i = 101
If i > 110 Then i = 101
frmAnimateForm.pic.Picture = LoadResPicture(i, vbResBitmap)
i = i + 1
Готово, можно запускать проект, и если Вы счастливый обладатель Pentium III или Athlon, то Вам улыбнется удача, так как <Скрепыш> будет двигаться. Но если Ваш процессор Pentium II и ниже, то компьютер не сможет выполнять необходимые расчеты за нужное нам время, так как для плавной анимации необходимо (для нашего случая) показывать порядка 15 кадров в секунду, а точнее каждые 80 милисекунд по кадру и ещё оставлять время для других задач компьютера. Как мы видим наши алгоритмы явно не тянут для таких задач и предназначены для <работ> не требующих таких быстрых изменений формы окна, так как, например на Celeron 333 один кадр формируется около 100 милисекунд. Что же делать?

Оптимизация алгоритма для быстрой анимации

Анализ работы алгоритма показывает, что наибольшие затраты времени приходятся на функцию GetPixel. Это происходит потому, что анализ картинки идет непосредственно на экране. Единственный путь увеличения быстродействия алгоритма, это перенос анализа в память компьютера и использование при этом Win 32 API. Такие алгоритмы существуют, но это тема отдельного разговора, скажу только, что для оптимизации работы алгоритм пишется отдельно для каждой глубины цвета и при применении такой схемы быстродействие увеличивается почти в четыре раза и позволяет делать практически любую анимацию.
8
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
22.05.2009, 20:32
Ответы с готовыми решениями:

Техника программирования: выражения.
Здравствуйте! Сдал тест на 2, прошу подсказать ход решения. В ответе написал 0,false,true,1,-1,empty,00:30:00 У меня есть подозрение,...

Работа с окнами (расположение окон каскадом,расположение окон вертикально,расположение окон)
не работает private void расположениеОконКаскадомToolStripMenuItem_Click(object sender, EventArgs e) private void...

ПХП и техника
Слушайте,я в пхп никогда не работал, но тут на меня взвалили труд.. Дело такое: есть контроллер который работает с мультимедиа...

0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
22.05.2009, 20:32
Помогаю со студенческими работами здесь

техника чтения
Ученики начальной школы сдают технику чтения. Нормы следующие: в 1 клас-се ребёнок должен читать не менее 20 слов в минуту; во втором...

Микропроцессорная техника
Может не туда, но всё же.

Микропроцессорная техника
Помогите пожалуйста . Если не туда кинул то перекиньте куда нужно З,Ы. Заранее Благодарю

Техника Refurbished
Сейчас довольно часто можно встретить технику с пометкой &quot;Refurbished&quot;. Есть у кого опыт? _NAWCTMW5J0

техника под градусом
Видел по ящику выпуск &quot;авиаторов&quot;, где один сюжет начался со взлёта ИЛ-76 градусов за 80 к горизонту, то есть даже не как истребитель, а...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
1
Закрытая тема Создать тему
Новые блоги и статьи
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru