Вы здесь

Visual Styles: CA-Visual Objects, bBrowser и все-все-все…

 

Стиль

 
 
В своё время я написал большую и красивую программу на языке CA-Visual Objects 2.5. Время шло, мода на интерфейс менялась… Встал вопрос о новшествах. Увы, люди «любят» глазами, оценивая «крутизну» программ по внешнему виду. И только мы – по «красоте» кода. Но, так как не пользователи существуют для нас, а мы для них – всегда идём навстречу.
 
 
Здесь основных решений – два:
  • Использовать «шкурки» (skins). Красиво, но есть свои тонкости. Будет, у кого интерес – могу рассказать.
  • Или – темы Windows. Ничего страшного и минимум проблем. Всё отлично работает, начиная с WinXP. На этом я и остановился.
 
Опять же, годных способов включения поддержки тем Windows – тоже всего два: или создать файл манифеста и таскать его за собой (с исполняемым файлом приложения), или непосредственно прописать его в коде (в ресурсы приложения). Подробно об этом можно прочесть, например, здесь:
 
Самое главное – не забыть включить службу «Темы» («Themes»)! Что, где и как – писать не буду – интернет под рукой. (Если, конечно, чьи-то «шаловливые ручки» что-то не открутили).
 
 
Продолжим. После CA-Vo 2.5 я перешёл на 2.6, а там и на 2.7. CA-Visual Objects 2.7 уже умел работать с темами Windows. Это решалось просто: при создании нового приложения, в разделе «Option» ставим «галочку» на «Windows XP Themes support» и у нас автоматически генерируется модуль «Manifest». Если этого модуля по какой-то причине нет (например, в КаВо 2.5) – его можно создать вручную и поместить туда код:
 
RESOURCE CREATEPROCESS_MANIFEST_RESOURCE_ID RC_RT_MANIFEST %appwizdir%\cctl6.man
 
Т.к. моя программа была написана ещё в CA-Visual Objects 2.5, этот модуль я, конечно, сделал сам. Получилось. И с этого момента, программа стала слушаться Windows.J
 
Может так случиться, что требуемого файла («cctl6.man») у Вас нет, или Вам захочется «помучаться» - этот файл можно создать «руками», просто записав в него текст:
 
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
    version="1.0.0.0"
    processorArchitecture="X86"
    name=" The Pencil.Test"
    type="win32"
/>
<description>The program "Test".</description>
<dependency>
    <dependentAssembly>
        <assemblyIdentity
            type="win32"
            name="Microsoft.Windows.Common-Controls"
            version="6.0.0.0"
            processorArchitecture="X86"
            publicKeyToken="6595b64144ccf1df"
            language="*"
        />
    </dependentAssembly>
</dependency>
</assembly>
 
Где в теге «description» можно написать что-то своё.
Примечание: но писать на русском – не надо, это приведёт к ошибке.
 
 
Вот так. Программа обновилась и стала «современной». Только тут сразу же, появились ворчливые пользователи... Почему-то большинство из них захотело вернуться к старому классическому интерфейсу.
 
В CA-Visual Objects 2.7.40 я обнаружил полезную функцию EnableAppVisualTheme().
Написав EnableAppVisualTheme( FALSE ), мы можем отключить поддержку тем Windows, а «TRUE» – включить. То, что надо! А главное, нужную настройку можно вынести, например, в .ini-файл, читая её при старте:
 
IF IsThemeEnabled() .AND. oIniFile:GetString( "Start", "Themes", "" ) = "1"
      EnableAppVisualTheme( TRUE )
ELSE
      EnableAppVisualTheme( FALSE )
ENDIF                              // «Да это просто праздник какой-то!» J
 
Каждый получил, что хотел. «Кричали женщины: Ура! И в воздух чепчики бросали»
 
 
Но, однажды что-то сломалось L. Снова пошли жалобы от тех, кто использовал старый классический интерфейс. Сначала при запуске программы у них всё было правильно, но по ходу работы (после открытия-закрытия окон) темы таинственным образом  включались. «Барабашка». Что же делать? Времени на эксперименты у меня не было, а реагировать надо срочно.
 
Помыкавшись, я применил «древний» вариант с использованием файла манифеста (он продолжал работать!), а строку с указанием ресурса – закомментировал. Есть файл – темы работают, нет – нет и поддержки. Ужасные рассказы о том, что после удаления файла-манифеста, программа «глючит» - неправда. Программа одинаково хорошо работает как с файлом, так и без него.
 
Да, чуть не забыл: файл манифеста должен именоваться, как и программа. Например, если исполняемый модуль программы «Test.exe», то файл манифеста должен называться «Test.exe.manifest».
 
 
Конечно, использование дополнительного файла – это извращение, временный «костыль». Поэтому, улучив минуту, я занялся поисками кардинального решения.
 
«Убив» время на изучение SDK CA-Vo, я решил пойти методом «исключений». Что сразу дало результат: проблема локализировалась, расставив всё по местам. Стало ясно, как день, «корень зла» – в библиотеке bBrowser3! «Глюк» работает, как часы: если в приложении предварительно отключить поддержку тем Windows, а потом открыть окно с контролом этой библиотеки – темы «волшебным» образом сами собой включаются.
 
Это становилось интересным J. Я углубился в SDK немецкой мысли… Хороший добротный модуль «bVisualStyles (Tools)». Уважаю германцев за их тщательность, подготовленность и скрупулёзность. Действительно, в модулях bBrowser можно увидеть много чего интересного, например, ряд полезных недокументированных функций, аналоги которых появились только в CA-Visual Objects 2.8.
 
Мы отвлеклись, а нам нужен источник ошибки. Напоминаю, проблему приносят контролы. Значит, открываю модуль «bBrowser (Control)» и концентрирую свой взгляд на метод bBrowser:Init(). Так и есть, в самом конце читается маленький кусочек кода с анализом состояния тем:
 
// Support für Visual Styles initialisieren
IF bvsIsVisualStylesInit()
      SELF:lThemeSupported := TRUE
      SELF:lThemeEnabled := TRUE
      SELF:iThemeParts := ;
                 _OR(BVSTP_TITLE, BVSTP_CAPTION, BVSTP_FOOTER, BVSTP_SELECTOR, ;
                       BVSTP_GRID, BVSTP_DATA, BVSTP_INFO)
 
      IF bvsVerifyVisualStylesState()
            SELF:InitVisualStyles()
      ENDIF
ENDIF
 
Ясно что, если функция bvsIsVisualStylesInit() ответит «да», поддержка стилей включится.
 
FUNCTION bvsIsVisualStylesInit() AS LOGIC PASCAL
//
=====================================================
// Beschreibung: Prüfen, ob die Visual Styles initialisiert sind.
//
// Historie:      27.05.2005 JB    Funktion implementiert.
//          26.08.2009 JB    Auswertung der umbenannten globalen Variable __biVSInit
//                                 (vorher __blVSInit) implementiert.
//
=====================================================
      RETURN (__biVSInit >= BVSIS_INITIALIZED)
 
Что сказать? Немцы проделали большую работу и даже ушли вперёд, но почему-то забыли о совместимости своего детища (допускаю, что в более новой версии CA-Visual Objects этого нет, но не проверял). Будем искать выход!
 
Долго искать не пришлось. Для согласования действий bBrowser с основной библиотекой «GUI Classes» очень даже подходит функция IsThemeEnabled(). Для быстроты, я применил грубую замену. В рабочей библиотеке «bBrowser Classes» я закомментировал (отключил) родную функцию bvsIsVisualStylesInit(), а вместо неё – написал свой код:
 
FUNCTION bvsIsVisualStylesInit( ) AS LOGIC PASCAL
            RETURN ( IsThemeEnabled() .AND. ms_bvsIsVisualStylesInit() )
 
_DLL FUNCTION ms_bvsIsVisualStylesInit( ) AS LOGIC PASCAL:bBrw30.bvsIsVisualStylesInit
//_DLL FUNCTION bvsIsVisualStylesInit() AS LOGIC PASCAL:bBrw30.bvsIsVisualStylesInit
            //
 
Запускаю программу… А «глюк»-то на месте!.. Я сделал всё правильно, этого не может быть! Не может быть вообще!
 
 
И когда у меня «опустились руки», вдруг появилась Муза:
– Мне кажется, что это трюк: рабочая библиотека «bBrowser Classes» отличается от варианта в SDK.
– И как же нам проверить?
– Да, очень просто. Закомментировать строку bBrowser:Init(), скопировав туда исходный текст из SDK.
 
Музы – она капризная. С ней не спорят. Быстро делаю, как сказано, собираю программу, запускаю – voilà. Всё работает замечательно! Убираю файл манифеста, включаю назад использование его через ресурсы… Всё работает, как надо!
 
 
Но, Муза просила «вкусненького»! Я решил усовершенствовать использование тем Windows. Как могли бы заметить сведущие программисты, темы можно настраивать по-разному. Есть разные трюки и ходы, известные «глюки» и обходы. Потратив некоторое время в и-нете, я нашёл ряд информативных статей:
 
Вы уже догадались, куда я клоню: при включении тем, практически всегда задаётся стандартный набор _OR( STAP_ALLOW_NONCLIENT, STAP_ALLOW_CONTROLS, STAP_ALLOW_WEBCONTENT ). А, вот, при выключении – бывает по-разному… В частности, заглянув в SDK можно увидеть, что у CA-Visual Objects и bBrowser свои подходы.
 
Кстати, информацию о «флагах» можно почерпнуть здесь:
 
Так как я люблю сам всем управлять, сделал следующее: в основной библиотеке CA-Visual Objects 2.7.40 «GUI Classes» я поменял модуль «XP Theme Support» на аналогичный, но из SDK CA-Visual Objects 2.8. И написал дополнительную функцию ms_EnableAppVisualTheme():
 
FUNCTION ms_EnableAppVisualTheme( lEnable := TRUE AS LOGIC,;
                         liThemeFlags := -1 AS LONG ) AS LOGIC PASCAL
      //
      LOCAL dwStyle AS DWORD
 
      EnableAppVisualTheme( lEnable )
      IF liThemeFlags >= 0
            dwStyle := DWORD( _CAST, liThemeFlags )
            SetThemeAppProperties( dwStyle )
      ENDIF
      RETURN ( VerifyThemeState() )
 
Таким образом, задав например: ms_EnableAppVisualTheme( FALSE, STAP_ALLOW_CONTROLS ), я получу только частичное отключение (кнопки и другие элементы окон будут показываться в «теме»). А кому это не интересно, может пользоваться по-старинке: ms_EnableAppVisualTheme( FALSE ). И тоже будет хорошо. В итоге, я полностью управляю процессом включения-выключения.
 
Что ещё? Есть такой маленький «глючёк» в элементе SingleLineEdit, когда через него вводится пароль в режиме скрытия (вместо вводимых символов должны рисоваться звёздочки). Если темы отключить, то в этом элементе будут по-прежнему рисоваться чёрточки и чёрные точки, как будто стиль остался прежним.
 
Как исправить? И-нет спешит на помощь:
 
Здесь я выбрал самый простой вариант:
SendMessage( SELF:oDCslePassword:Handle(), EM_SETPASSWORDCHAR, Asc( "*" ), 0L )
 
 
Вечерело… Время закончить эксперименты и вернуть рабочие библиотеки «bBrowser Classes» и «GUI Classes» в исходное состояние. Давайте подведём черту: CA-Vo и bBrowser работают с темами Windows независимо друг от друга, формируя при этом свои собственные переменные. А значит, чтобы их «подружить» - надо сделать «кентавра», который учтёт пожелания сторон. За основу я взял EnableAppVisualTheme() и сделал усовершенствованный вариант:
 
FUNCTION ms_EnableAppVisualTheme( lEnable := TRUE AS LOGIC,;
                              liThemeFlags := -1 AS LONG ) AS LOGIC PASCAL
      //
      LOCAL dwStyle AS DWORD
 
// Сначалаотрабатываемчерез bBrowser
      bvsEnableVisualStyles( lEnable )
 
// Ужененадо, т.к. сделалиэточерез bvsEnableVisualStyles
//    EnableAppVisualTheme( lEnable )
 
// Принудительно делаем как в КаВо, т.к. у bBrowser-а оно по-другому.
      IF liThemeFlags >= 0
            dwStyle := DWORD( _CAST, liThemeFlags )
      ELSE
            IF lEnable
                  dwStyle := _OR(STAP_ALLOW_NONCLIENT, STAP_ALLOW_CONTROLS, STAP_ALLOW_WEBCONTENT)
            ELSE
                  dwStyle := STAP_ALLOW_NONCLIENT
            ENDIF
      ENDIF
 
      SetThemeAppProperties( dwStyle )
 
//    RETURN ( VerifyThemeState() )      // ДляКаВо 28
      RETURN ( IsThemeEnabled() ) // Для КаВо 27
 
Теперь, если вместо стандартной функции EnableAppVisualTheme() использовать ms_ EnableAppVisualTheme() – «семейная жизнь» bBrowser и CA-Vo наладится.
– А вот это – совсем другое дело, - сказал Карандаш. Довольный проделанной работой, он надел наушники и включил Sander Van Doorn «Love Is Darkness (Interlude)».
 
09.11.2011 г.    Карандаш.
 
 
P.S.: В статье используются данные из SDK bBrowser v. 3.0.8.94 (что было актуально на момент написания). А в настоящее время (с 07.06.2012) - уже актуальна версия 3.0.10.111, поэтому приведённый код из SDK отличается. Но... Суть проблемы и её решение - остались прежними! Так что, моё решение - правильное и работоспособное. Пользуйтесь на здоровье!
 

Комментарии

Действительно интересный материальчик. А Вы серьезно писать не подумывали? Думаю, у Вас бы получилось. По крайней мере, можно было бы очень посещаемый блог получить. Сейчас в интернете с уникальными интересными текстами проблема.

   К сожалению, времени не сильно хватает... Сейчас переделываю модуль управления заказами. Хочу на днях закончить :))
   Если успею - выложу статейку по штрих-кодам. А то народ уже спрашивал-интересовался.
 
   Так что - ждите :))
 
Карандаш.

Ваши записи произвели на меня огромное впечатление, заставили думать по-другому. Продолжайте свои творческие поиски, а я буду следовать за Вами!

         Здесь не форум и не чат. Данное сообщение оставляю только для примера "как не надо писать". Меня больше интересуют комментарии, критика и предложения.
 
Спасибо за понимание.

Hi! I know this is kind of off topic but I was wondering which blog platform are you using for this website? I'm getting tired of Wordpress because I've had problems with hackers and I'm looking at options for another platform. I would be awesome if you could point me in the direction of a good platform.

This site is made on Drupal. Don't look for absolute protection – it isn't present and won't be. The spam was, is and will be. By the way, the best example – your comment in which I deleted advertizing links.

Bообще я с Baми полноcтью coгласeн. 3дeсь eсть нaд чем подумaть и погoворить. В oбщем-то мнe пoнpавилось,буду зaходить сюдa eще,мoжeт,что-тo новенькое увижу у вaс.

Спасибо, мне понравилось.

Theme by Danetsoft and Danang Probo Sayekti inspired by Maksimer