Класс CSkinBaseDialog
От: 2Los  
Дата: 28.02.02 22:25
Оценка: 160 (7)
Статья:
Класс CSkinBaseDialog
Автор(ы): 2Los
Дата: 01.03.2002


Авторы:
2Los

Аннотация:
Как известно, окна в Windows квадратные. И в принципе этого достаточно для большинства приложений. Если это, например, файл-менеджер, то очень даже неплохо, что он квадратный. Однако иногда хочется, чтобы программа выглядела не как все. Классическим примером могут служить WinAmp или Window Media Player, а также многие autoran'ы для CD дисков. Отличительной особенностью этих программ является то, что все они обладают окнами произвольной формы, с опять же произвольным фоновым изображением, а плэйеры к тому же могут менять свой внешний вид.

У разработчика подобного окна выбор средств не богатый: это функция SetWindowRgn() — устанавливающая регион, занимаемый окном и обработчик события WM_ERASEBKGND, в котором следует поместить код, выводящий фоновую картинку в окно. И если окно не меняет свой размер, этого достаточно, иначе придется потрудиться, чтобы корректно отображать фон и пересчитывать регион окна. Если вам это занятие не по душе, то предлагаю воспользоваться моим новым MFC-классом диалога CSkinBaseDialog, который возьмет всю эту работу на себя.
Прикольно :) , но Обидно
От: OlegO Россия http://www.mediachase.ru
Дата: 01.03.02 22:25
Оценка:
Что убирается контекстное меню и иконка в Taskbare. Из-за этого окно
начинает вести себя, если говорить чесно ненормально.
Хотя прекрасно понимаю все проблемы, с которыми придется столкнуться
в противном случае.
С уважением, OlegO.
Вопрос по теме!
От: RadSal  
Дата: 06.03.02 19:22
Оценка:
Где конкретно можно найти остальные элементы управления, которые хорошо бы смотрелись с этими окнами?
Eto zdorovo! Tolko v kakih Windah eto zarabotaet?
От: Michel http://www.tatianafineart.com
Дата: 14.03.02 05:49
Оценка:
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
От: 2Los  
Дата: 23.03.02 15:11
Оценка:
В win95 это работать не будет, точнее работать будет только диалог CSkinBaseDialog, а расположенные на нем кнопки CSkinBaseButton — нет (из-за функции TrackMouseEvent), так что нужно сменить кнопку, либо винды. Если решишь сменить винды, то вот версии в которых я проверял демо приложение: XP/98/ME, теоретически должно работать и в NT4.0/2000
Re: Прикольно :) , но Обидно
От: 2Los  
Дата: 23.03.02 15:12
Оценка:
Ну на самом деле иконка в Taskbare никуда не пропала, тока меню.
Re: Вопрос по теме!
От: 2Los  
Дата: 23.03.02 15:12
Оценка:
Загляни на www.codeguru.com или www.codeproject.com, там много всяких контролов.
Возможная проблема!
От: RadSal  
Дата: 24.03.02 19:21
Оценка:
Почему, когда делаешь toggle-button, ее положение фиксируется при нажатии на кнопку мыши, а вот метод, связанный с этой кнопкой выполняется только при отпускании. Поэтому, если нажать на такую кнопку и не отпуская кнопки мыши вынести курсор за ее пределы, и только там отпустить, то получим нажатую кнопу, а вот метод, с ней связанный не выполнится.
А вообще, огромное спасибо за этот класс. Очень помог!
Re: Возможная проблема!
От: 2Los  
Дата: 30.03.02 16:50
Оценка:
А можешь пример кода с кнопкой привести, а то у меня вроде все нормально?
Небольшой - не баг, а просто недочёт!
От: Gambler  
Дата: 06.04.02 02:08
Оценка:
Что бы кнопки произвольной формы рисовались правильно добавте в
CSkinBaseButton.h

в метод void DrawButton(CDC* pDC, CRect rc, int iButton)

в самом конце вот такой код.

Удачи всем.


//.......................................
HRGN hrgn = CreateRectRgn(0,0,0,0);
GetWindowRgn(hrgn);
CRgn *pRgn = CRgn::FromHandle(hrgn);
pDC->SelectClipRgn(pRgn);
//.......................................

m_dibButtonStates.Draw(pDC, rc.TopLeft(), rc.Size(), CPoint(m_szButton.cx*iButton, 0), CSize(m_szButton.cx, m_szButton.cy));
-------------------------------------------------------------------

Вызывает презедент к себе коров и говорит:
— Ну, что будем сдавать, молоко или мясо?
(с) Г. Явлинский TV6 — Герой дня (18.04.2002)
Skins
От: Hobos  
Дата: 08.10.02 07:58
Оценка:
Господа, если у кого есть какие-нибудь скины в таком формате и вам не жалко ими поделиться ( для некоммерческого, разумеется, использования), не могли бы ими, собственно, поделиться? Из меня художник, как выяснилось, никакой, и дцатая подряд попытка изобразить что-нибудь пристойное не увенчалась успехом. Заранее спасибо!!
OwnerDraw Controls
От: Saruman Россия none
Дата: 19.03.03 09:02
Оценка:
В статье сказано, что для синхронной отрисовки контролов нужно использовать функцию AddOwnerDrawControl. Так же в классе контрола должна быть реализована функция SkinDraw.
Я сделал свой цветной CStatic, но почему-то при отрисовке диалога текст в статике сначала удаляется. Не пойму в чем дело? Вроде и функция SkinDraw вызывается вовремя, но после OnEraseBkgnd для диалога изображения контрола на бакграунде нет. Оно появляется уже после OnPaint'а для контрола. Может кто подскажет почему так происходит?
Типа того что как бы...
Re: OwnerDraw Controls
От: 2Los  
Дата: 19.03.03 22:08
Оценка:
Проверь, не забыл ли ты в функции SkinDraw преобразовать
координаты перед отрисовкой, примерно так:

CRect client;
GetWindowRect(client);
GetParent()->ScreenToClient(client);

//client — клиентский прямоугольник, в котором и следует рисовать
Важное дополнение!
От: Saruman Россия none
Дата: 20.03.03 11:38
Оценка:
Для того чтобы контролы правильно отрисовывались на бакграунде диалога, необходимо при инициализации сначала делать все вызовы AddSkinDIB, а уже потом вызавать AddOwnerDrawControl для каждого контрола. Если же вызвать AddOwnerDrawControl ДО AddSkinDIB может произойти ситуация при которой уже отрисованый контрол перекроется изображением фона.
P.S. Целый день мучался, пока понял в чем дело :(
Типа того что как бы...
Контролы на движушихся частях диалога
От: Saruman Россия none
Дата: 25.03.03 04:23
Оценка:
2Los, а не могли бы вы описать каким образом добавлять контролы на выдвигающуюся часть диалога? Что-то я совсем сообразить не могу как это сделать.
Типа того что как бы...
Баг обнаружен.
От: Saruman Россия none
Дата: 25.03.03 12:12
Оценка:
Обнаружен баг в функции
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;
}
Типа того что как бы...
Re: Контролы на движушихся частях диалога
От: 2Los  
Дата: 25.03.03 22:42
Оценка:
Все дело в том, что контролы не добавляются на выдвигающуюся часть. Они добавляются в диалог, как и другие контролы, а потом просто выдвигаются вместе с выдвигающейся (небольшая тавтология) частью.

В демо-проекте, выдвижение инициируется нажатием кнопки, обработчик которой выглядит
следующим образом.

void CSkinDialogDlg::OnButton()
{
BOOL s_bMoveOut=m_button.GetCheck();

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. В этом случае можно организовать его плавное выдвижение. Для этого нужно при добавлении контрола указать перекрывающие его картинки.

//добавляем кнопку
AddOwnerDrawControl(&m_button, sbdLeft, sbdBottom);

//задаем картинки, которые перекрывают контрол
GetAt(11)->m_aOverBkParts.Add(GetAt(4));
GetAt(11)->m_aOverBkParts.Add(GetAt(7));

Во-вторых, Контрол должен отрисовываться только в функции SkinDraw и никак иначе (OnPaint, OnEraseBkgnd). В-третьих, в текущей версии есть баг, поэтому чтобы контрол действительно перекрывался, нужно исправить функцию CSkinOwnerDrawControl::Draw

virtual void Draw(CDC *pDC=NULL)
{
if(m_nType!=sbdOwnerDrawControl || pDC==NULL)
{
CRgn rgn;
GetDestRgn(&rgn, TRUE);
pDC->SelectClipRgn(&rgn);
rgn.DeleteObject();
CSkinBkPart::Draw(pDC);
}
else if(IsVisible())
m_pOwnerDrawControl->SkinDraw(pDC);
}

И последнее, вариант номер два я не проверял, поэтому если он заработает, то я сильно удивлюсь:)
Re: Баг обнаружен.
От: 2Los  
Дата: 25.03.03 22:44
Оценка:
Теперь твоя очередь объяснять, в чем тут дело. А то я никак не могу уловить разницу с текущим вариантом тела функции FindMoveInfo :)
Re: Баг обнаружен.
От: Saruman Россия none
Дата: 26.03.03 08:08
Оценка:
Я тебе письмо с объяснением отправил.
Типа того что как бы...
Re: Баг обнаружен.
От: 2Los  
Дата: 26.03.03 20:38
Оценка:
Да, ты прав, в функции FindMoveInfo действительно баг.
Re[2]: Прикольно :) , но Обидно
От: Saruman Россия none
Дата: 12.09.03 10:20
Оценка:
Здравствуйте, 2Los, Вы писали:

L>Ну на самом деле иконка в Taskbare никуда не пропала, тока меню.


Нашёлся способ добавить меню в Taskbar'е для таких SkinBase диалогов.

Когда кликаешь правой кнопкой мыши на кнопке диалога в таскбаре, то окну приходит сообщение за номером 0x0313. Тока обработчик этой мессаги должен сразу вернуть результат(т.е. нельзя вызывать TrackPopupMenu в этом обработчике), а то винда использует её в своих системных целях, для определения "зависнутости" окна.
Типа того что как бы...
Re: проблема с Child-окнами
От: BaToH Беларусь  
Дата: 19.08.05 10:30
Оценка:
Здраствуйте!

Класс очень хороший, спасибо =)

Но возникла проблема:
В диалоге создаю child-окно. Это окно наследую от CSkinBaseDialog.
Если не использовать функцию AddSkinDIB, то все работает нормально (отображаются контроллы и фон по умолчанию)

Когда же использую эту функцию для создания фона, то ничего не отображается

Child-окно самостоятельно не перерисовывается (или я не прав?)
Но посылая сообщение от ParentWindow на перерисовку (оно доходит), окно все равно не перерисовывается

С popup-окном все работает нормально.
Подскажите, как выйти из сложившейся ситуации?
Всё возможно.
Re: Класс CSkinBaseDialog
От: McSeem2 США http://www.antigrain.com
Дата: 20.08.05 15:08
Оценка:
Здравствуйте, 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
Я жертва цепи несчастных случайностей. Как и все мы.
Re: Класс CSkinBaseDialog
От: Аноним  
Дата: 21.05.07 12:16
Оценка:
Здравствуйте, 2Los, Вы писали:

L>Статья:

L>Класс CSkinBaseDialog
Автор(ы): 2Los
Дата: 01.03.2002


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"

короче ошибка вот такая

d:\projects\tets\tets\skinbasedialog.cpp(524) : error C2065: 'i' : undeclared identifier

вот этом куске кода

int CSkinBaseDialog::HitTestBkPart(CPoint point)
{
for(int i=0; i<GetCount(); i++)
if(GetAt(i)->HitTest(point))
break;
return i<GetCount() ? i : -1;<<<<<<<<<<<<<<<<<<<<<<<<<<<<!!!!!!!!!!!!!!!!!!!!!!!!!>>>>>>>>>>>>>>>>>>>

}

В чем ошибка?
Re[2]: Класс CSkinBaseDialog
От: BaToH Беларусь  
Дата: 21.05.07 12:46
Оценка:
SKIP

А>вот этом куске кода


А>int CSkinBaseDialog::HitTestBkPart(CPoint point)

А>{
А> for(int i=0; i<GetCount(); i++)
А> if(GetAt(i)->HitTest(point))
А> break;
А> return i<GetCount() ? i : -1;<<<<<<<<<<<<<<<<<<<<<<<<<<<<!!!!!!!!!!!!!!!!!!!!!!!!!>>>>>>>>>>>>>>>>>>>

А>}


А>В чем ошибка?


А ошибка у тебя в том, что i определён внутри массива и соответственно в операторе return его не видно.

Объяви i как внутреннюю переменную перед циклом for
Всё возможно.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.