Аннотация:
Как известно, окна в Windows квадратные. И в принципе этого достаточно для большинства приложений. Если это, например, файл-менеджер, то очень даже неплохо, что он квадратный. Однако иногда хочется, чтобы программа выглядела не как все. Классическим примером могут служить WinAmp или Window Media Player, а также многие autoran'ы для CD дисков. Отличительной особенностью этих программ является то, что все они обладают окнами произвольной формы, с опять же произвольным фоновым изображением, а плэйеры к тому же могут менять свой внешний вид.
У разработчика подобного окна выбор средств не богатый: это функция SetWindowRgn() — устанавливающая регион, занимаемый окном и обработчик события WM_ERASEBKGND, в котором следует поместить код, выводящий фоновую картинку в окно. И если окно не меняет свой размер, этого достаточно, иначе придется потрудиться, чтобы корректно отображать фон и пересчитывать регион окна. Если вам это занятие не по душе, то предлагаю воспользоваться моим новым MFC-классом диалога CSkinBaseDialog, который возьмет всю эту работу на себя.
Что убирается контекстное меню и иконка в Taskbare. Из-за этого окно
начинает вести себя, если говорить чесно ненормально.
Хотя прекрасно понимаю все проблемы, с которыми придется столкнуться
в противном случае.
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:(
Re: Eto zdorovo! Tolko v kakih Windah eto zarabota
В win95 это работать не будет, точнее работать будет только диалог CSkinBaseDialog, а расположенные на нем кнопки CSkinBaseButton — нет (из-за функции TrackMouseEvent), так что нужно сменить кнопку, либо винды. Если решишь сменить винды, то вот версии в которых я проверял демо приложение: XP/98/ME, теоретически должно работать и в NT4.0/2000
Почему, когда делаешь toggle-button, ее положение фиксируется при нажатии на кнопку мыши, а вот метод, связанный с этой кнопкой выполняется только при отпускании. Поэтому, если нажать на такую кнопку и не отпуская кнопки мыши вынести курсор за ее пределы, и только там отпустить, то получим нажатую кнопу, а вот метод, с ней связанный не выполнится.
А вообще, огромное спасибо за этот класс. Очень помог!
-------------------------------------------------------------------
Вызывает презедент к себе коров и говорит:
— Ну, что будем сдавать, молоко или мясо?
(с) Г. Явлинский TV6 — Герой дня (18.04.2002)
Господа, если у кого есть какие-нибудь скины в таком формате и вам не жалко ими поделиться ( для некоммерческого, разумеется, использования), не могли бы ими, собственно, поделиться? Из меня художник, как выяснилось, никакой, и дцатая подряд попытка изобразить что-нибудь пристойное не увенчалась успехом. Заранее спасибо!!
В статье сказано, что для синхронной отрисовки контролов нужно использовать функцию AddOwnerDrawControl. Так же в классе контрола должна быть реализована функция SkinDraw.
Я сделал свой цветной CStatic, но почему-то при отрисовке диалога текст в статике сначала удаляется. Не пойму в чем дело? Вроде и функция SkinDraw вызывается вовремя, но после OnEraseBkgnd для диалога изображения контрола на бакграунде нет. Оно появляется уже после OnPaint'а для контрола. Может кто подскажет почему так происходит?
Для того чтобы контролы правильно отрисовывались на бакграунде диалога, необходимо при инициализации сначала делать все вызовы AddSkinDIB, а уже потом вызавать AddOwnerDrawControl для каждого контрола. Если же вызвать AddOwnerDrawControl ДО AddSkinDIB может произойти ситуация при которой уже отрисованый контрол перекроется изображением фона.
P.S. Целый день мучался, пока понял в чем дело :(
Обнаружен баг в функции
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;
}
Все дело в том, что контролы не добавляются на выдвигающуюся часть. Они добавляются в диалог, как и другие контролы, а потом просто выдвигаются вместе с выдвигающейся (небольшая тавтология) частью.
В демо-проекте, выдвижение инициируется нажатием кнопки, обработчик которой выглядит
следующим образом.
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
Здравствуйте, 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"