Аннотация:
Как известно, окна в Windows квадратные. И в принципе этого достаточно для большинства приложений. Если это, например, файл-менеджер, то очень даже неплохо, что он квадратный. Однако иногда хочется, чтобы программа выглядела не как все. Классическим примером могут служить WinAmp или Window Media Player, а также многие autoran'ы для CD дисков. Отличительной особенностью этих программ является то, что все они обладают окнами произвольной формы, с опять же произвольным фоновым изображением, а плэйеры к тому же могут менять свой внешний вид.
У разработчика подобного окна выбор средств не богатый: это функция SetWindowRgn() — устанавливающая регион, занимаемый окном и обработчик события WM_ERASEBKGND, в котором следует поместить код, выводящий фоновую картинку в окно. И если окно не меняет свой размер, этого достаточно, иначе придется потрудиться, чтобы корректно отображать фон и пересчитывать регион окна. Если вам это занятие не по душе, то предлагаю воспользоваться моим новым MFC-классом диалога CSkinBaseDialog, который возьмет всю эту работу на себя.
Обнаружен баг в функции
POSITION CSkinBaseDialog::FindMoveInfo(int nIDEvent)
Выражается он в том что если запускаешь движение части диалога, то все запущенные таймеры диалога затыкаются. Предлагаю другой вариант тела функции:
POSITION CSkinBaseDialog::FindMoveInfo(int nIDEvent)
{
POSITION result=NULL, pos=m_lstActiveMoves.GetHeadPosition();
CMoveInfo* pMI;
while(pos != NULL)
{
result=pos;
pMI=m_lstActiveMoves.GetNext(pos);
if(pMI->m_nIDEvent==nIDEvent) return result;
}
return NULL;
}
Для того чтобы контролы правильно отрисовывались на бакграунде диалога, необходимо при инициализации сначала делать все вызовы AddSkinDIB, а уже потом вызавать AddOwnerDrawControl для каждого контрола. Если же вызвать AddOwnerDrawControl ДО AddSkinDIB может произойти ситуация при которой уже отрисованый контрол перекроется изображением фона.
P.S. Целый день мучался, пока понял в чем дело :(
В статье сказано, что для синхронной отрисовки контролов нужно использовать функцию AddOwnerDrawControl. Так же в классе контрола должна быть реализована функция SkinDraw.
Я сделал свой цветной CStatic, но почему-то при отрисовке диалога текст в статике сначала удаляется. Не пойму в чем дело? Вроде и функция SkinDraw вызывается вовремя, но после OnEraseBkgnd для диалога изображения контрола на бакграунде нет. Оно появляется уже после OnPaint'а для контрола. Может кто подскажет почему так происходит?
Господа, если у кого есть какие-нибудь скины в таком формате и вам не жалко ими поделиться ( для некоммерческого, разумеется, использования), не могли бы ими, собственно, поделиться? Из меня художник, как выяснилось, никакой, и дцатая подряд попытка изобразить что-нибудь пристойное не увенчалась успехом. Заранее спасибо!!
-------------------------------------------------------------------
Вызывает презедент к себе коров и говорит:
— Ну, что будем сдавать, молоко или мясо?
(с) Г. Явлинский TV6 — Герой дня (18.04.2002)
Почему, когда делаешь toggle-button, ее положение фиксируется при нажатии на кнопку мыши, а вот метод, связанный с этой кнопкой выполняется только при отпускании. Поэтому, если нажать на такую кнопку и не отпуская кнопки мыши вынести курсор за ее пределы, и только там отпустить, то получим нажатую кнопу, а вот метод, с ней связанный не выполнится.
А вообще, огромное спасибо за этот класс. Очень помог!
Ideya prosto zamechatel'naya. Pravda pervaya zhe popytka zapustit' demostracionnoe prilozhenie v Win95 zakonchilos' neudachej :(( Est' li u kogo idei na etu temu???
P.S. Izveni za latinskij shrift, no ya ne doma a na rabote vybora netu:(
Что убирается контекстное меню и иконка в Taskbare. Из-за этого окно
начинает вести себя, если говорить чесно ненормально.
Хотя прекрасно понимаю все проблемы, с которыми придется столкнуться
в противном случае.
Все дело в том, что контролы не добавляются на выдвигающуюся часть. Они добавляются в диалог, как и другие контролы, а потом просто выдвигаются вместе с выдвигающейся (небольшая тавтология) частью.
В демо-проекте, выдвижение инициируется нажатием кнопки, обработчик которой выглядит
следующим образом.
ARR_BK_PARTS ar; //массив
ar.Add(GetAt(10)); //выдвигающая часть диалога
ar.Add(GetAt(11)); //кнопка
//Выдвигаем все, что есть в массиве ar. В том числе кнопки и картинки.
StartMoveBkParts(ar, CSize(0, s_bMoveOut ? 90 : -90), 5, 101);
}
Но это был простой пример, когда выдвигающаяся кнопка всегда видна на экране. Допустим необходимо, чтобы контрол первоначально был скрыт и потом плавно "выезжал". Сделать это будет посложней и в текущей версии CSkinBaseDialog очень заморочено, но тем не менее возможны два варианта:
Вариант 1. Контрол не поддерживает функцию SkinDraw (см. статью выше). Тогда о плавном выдвижении можно забыть. В этом случае, контрол сначала скрыт, а после того, как выдвигающаяся часть "вылезет" наружу, его нужно вручную показать вызовом ShowWindow(SW_SHOW) в переопределенной функции OnEndMoveBkParts. В обратном случае, когда выдвигающаяся часть начинает "заползать" обратно, этот контрол нужно скрыть вызовом ShowWindow(SW_HIDE) в переопределенной функции OnBeginMoveBkParts.
Вариант 2. Контрол поддерживает функцию SkinDraw. В этом случае можно организовать его плавное выдвижение. Для этого нужно при добавлении контрола указать перекрывающие его картинки.
//задаем картинки, которые перекрывают контрол
GetAt(11)->m_aOverBkParts.Add(GetAt(4));
GetAt(11)->m_aOverBkParts.Add(GetAt(7));
Во-вторых, Контрол должен отрисовываться только в функции SkinDraw и никак иначе (OnPaint, OnEraseBkgnd). В-третьих, в текущей версии есть баг, поэтому чтобы контрол действительно перекрывался, нужно исправить функцию CSkinOwnerDrawControl::Draw
В win95 это работать не будет, точнее работать будет только диалог CSkinBaseDialog, а расположенные на нем кнопки CSkinBaseButton — нет (из-за функции TrackMouseEvent), так что нужно сменить кнопку, либо винды. Если решишь сменить винды, то вот версии в которых я проверял демо приложение: XP/98/ME, теоретически должно работать и в NT4.0/2000
Здравствуйте, 2Los, Вы писали:
L>Ну на самом деле иконка в Taskbare никуда не пропала, тока меню.
Нашёлся способ добавить меню в Taskbar'е для таких SkinBase диалогов.
Когда кликаешь правой кнопкой мыши на кнопке диалога в таскбаре, то окну приходит сообщение за номером 0x0313. Тока обработчик этой мессаги должен сразу вернуть результат(т.е. нельзя вызывать TrackPopupMenu в этом обработчике), а то винда использует её в своих системных целях, для определения "зависнутости" окна.
Но возникла проблема:
В диалоге создаю child-окно. Это окно наследую от CSkinBaseDialog.
Если не использовать функцию AddSkinDIB, то все работает нормально (отображаются контроллы и фон по умолчанию)
Когда же использую эту функцию для создания фона, то ничего не отображается
Child-окно самостоятельно не перерисовывается (или я не прав?)
Но посылая сообщение от ParentWindow на перерисовку (оно доходит), окно все равно не перерисовывается
С popup-окном все работает нормально.
Подскажите, как выйти из сложившейся ситуации?
Здравствуйте, 2Los, Вы писали:
L>У разработчика подобного окна выбор средств не богатый: это функция SetWindowRgn() — устанавливающая регион, занимаемый окном и обработчик события WM_ERASEBKGND, в котором следует поместить код, выводящий фоновую картинку в окно. И если окно не меняет свой размер, этого достаточно, иначе придется потрудиться, чтобы корректно отображать фон и пересчитывать регион окна. Если вам это занятие не по душе, то предлагаю воспользоваться моим новым MFC-классом диалога CSkinBaseDialog, который возьмет всю эту работу на себя.
Такое предложение.
Следующим шагом должно быть добавление сглаживания (anti-alias) по границам окна. Насколько я представляю, начиная с Win2K это возможно — то есть, там, где есть функция WinAPI AlphaBlend (находится в msimg32.lib). Идея в том, чтобы подготовить 32-битовый битмап с альфа-каналом формата BGRA и в обработчике WM_ERASEBKGND использовать AlphaBlend() вместо чего-либо другого. Рисовать в битмап с альфа-каналом можно, например с помошью той же GDI+. Или, например, AGG. Работа с регионами при этом остается в силе, но регион должен быть чуть шире визуальных границ и охватывать область, где значения alpha > 0.
Хотя я не уверен на 100%, что все будет работать как надо. Возможно, при перемещении окна и перерисовках, в полупрозрачных пикселах будут появляться дефекты.
И вообще — можно ли каким-либо способом (начиная с Win2K) сделать полупрозрачное окно произвольной формы? При этом, надо уметь задавать значения Alpha не для всего окна глобально, а для каждого отдельного пиксела этого окна. То есть, то, что называется Alpha-Mask.
McSeem
Я жертва цепи несчастных случайностей. Как и все мы.
L>Авторы: L> 2Los
L>Аннотация: L>Как известно, окна в Windows квадратные. И в принципе этого достаточно для большинства приложений. Если это, например, файл-менеджер, то очень даже неплохо, что он квадратный. Однако иногда хочется, чтобы программа выглядела не как все. Классическим примером могут служить WinAmp или Window Media Player, а также многие autoran'ы для CD дисков. Отличительной особенностью этих программ является то, что все они обладают окнами произвольной формы, с опять же произвольным фоновым изображением, а плэйеры к тому же могут менять свой внешний вид.
L>У разработчика подобного окна выбор средств не богатый: это функция SetWindowRgn() — устанавливающая регион, занимаемый окном и обработчик события WM_ERASEBKGND, в котором следует поместить код, выводящий фоновую картинку в окно. И если окно не меняет свой размер, этого достаточно, иначе придется потрудиться, чтобы корректно отображать фон и пересчитывать регион окна. Если вам это занятие не по душе, то предлагаю воспользоваться моим новым MFC-классом диалога CSkinBaseDialog, который возьмет всю эту работу на себя.
Помогите, плиз.
Решил я зяюзать этот клас, но вот несколько ошибок появилось при написании проги.
Пишу на Визуал Студио 2005.
Короче добавил я класы SkinBaseDialog.h и CDIB.H себе в проэкт.
Все зделал по инструкции как в статье.
Пришлось только в AfxMessageBox везде макросы _T() поставить.
потом выскочила ошибка при компиляции что нет такого класса
#include "stdafx.h"
//#include "SkinDialog.h" ------вот это я закоментил. Или тут мне надо включить свой клас приложения?
#include "SkinBaseDialog.h"