Аннотация:
Как известно, окна в 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'а для контрола. Может кто подскажет почему так происходит?
Господа, если у кого есть какие-нибудь скины в таком формате и вам не жалко ими поделиться ( для некоммерческого, разумеется, использования), не могли бы ими, собственно, поделиться? Из меня художник, как выяснилось, никакой, и дцатая подряд попытка изобразить что-нибудь пристойное не увенчалась успехом. Заранее спасибо!!
Почему, когда делаешь 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