Модераторы: feodorv, GremlinProg, xvr, Fixin
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Нестандартное окно, прозрачность и последствия, Проблемы создания нестандартных окон 
:(
    Опции темы
evkwarrior
Дата 14.5.2009, 08:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 22
Регистрация: 15.3.2007

Репутация: 1
Всего: 1



Всем доброго времени суток.
Тема, которую я затронул, давно изъезжена вдоль и поперёк, я нашёл в поиске более десятка тем со схожей тематикой, но нигде не было полного ответа на все вопросы. Я не буду лаконичен и постараюсь последовательно (по мере создания и совершенствования проекта) изложить основные проблемы, с которыми я столкнулся.

1) исходные данные:
- чистый WinAPI
- несколько готовых модулей на WinAPI, инкапсулирующих рутину, в т.ч. класс CLASS_GUIAPP, поведение методов которого будет ясно из контекста


2) предварительная задача:
создать полупрозрачное окно нестандартной формы (желательно с дырками внутри)
- окно должно быть изменяемым по размеру
- желательно наличие рамки окна
- должны быть видны изменения содержимого под окном при их изменении
- должен быть предусмотрен механизм минимизации/максимизации окна.

Иными словами, функциональность такого окна не должна ухудшаться в ущерб сложности реализации.

3) выбор метода решения проблемы.
Прочитав не одну статью, я извлёк для себя две основных методики создания окон нестандартной формы с эффектами прозрачности:
- создание обычного окна, SetWindowRgn и игра с регионами
- создание окна со стилем WS_EX_LAYERED, создание картинки с предопределённым цветом в качестве прозрачного, загрузка картинки, работа с SetLayeredWindowAttributes или UpdateLayeredWindow.

Решение 1 показалось мне более сложным из-за необходимости работы с регионами и выполнением с ними линейных преобразований (масштабирование, пересечение, исключение регионов т.д.)
Поэтому я выбрал 2 метод.

4) Основной алгоритм:
Код


DWORD   UserMainProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

////////////////////////////////////////////////////////////////////////////////////////////////////
extern CLASS_GUIAPP        *App = 0;
HBITMAP                     h_wnd_bmp;

////////////////////////////////////////////////////////////////////////////////////////////////////

WINAPI WinMain(HINSTANCE hinst, HINSTANCE hprevinst, LPSTR, int)
{
    try
    {
        App = new CLASS_GUIAPP ();
        App->bUseExceptions = true;
        App->lpfUserProc = UserMainProc;

        App->GetWndCrParams();
        App->sWndCrParPub.dwExStyle = WS_EX_LAYERED;
        App->sWndCrParPub.style = WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
        App->SetWndCrParams();

        h_wnd_bmp = LoadBitmap (App->GetHINST(), L"window_03");
        if (! h_wnd_bmp) throw Errors (FROM_SYSTEM);

        App->Register ();
        App->CreateMainWindow ();
        SetLayeredWindowAttributes (App->GetHWND(), TR_COLOR, 0x80, LWA_COLORKEY | LWA_ALPHA);

        App->SetWndSize (400, 300);
        ShowWindow (App->GetHWND(), SW_SHOW);

        App->MessageLoop ();
    }

    catch (Errors &obj)
    {
        obj.Message (App->GetHWND());    
    }

    delete App;
    return 0;
}



Программу прикрепляю в приложении. В итоге получается 50% прозрачное окно нестандартной формы с дырками (выполнено основное требование)

В оконной процедуре впринципе ничего не надо обрабатывать, кроме прорисовки окна. Так как окно голое, я делаю эту обработку в WM_ERASEBKND:

Код

        case WM_ERASEBKGND:
        {
            HDC         h_comp_dc;

            hdc = (HDC) wParam;
            h_comp_dc = CreateCompatibleDC (hdc);

            SelectObject (h_comp_dc, h_wnd_bmp);

            //copy bits to device
            BitBlt (hdc, 0, 0, 400, 300, h_comp_dc, 0, 0, SRCCOPY);


            DeleteDC (h_comp_dc);
            ReleaseDC (App->GetHWND (), hdc);
        }
        return PROCESSED_MSG;



5) продожение.
- Как сделать рамку?
Я нашёл такое решение: сделать уже готовое изображение с рамкой, и дальше при изменении размеров вызывать StretchBlt. Но тогда ширина рамки будет меняться, что плохо. Другого решения я не нашёл..
Может, у кого-то есть идеи?

- окно получается голым и надо продумать механизм его перемещения по столу и минимизации/максимизации
Изменение позиции я реализовал с помощью перетаскивания окна в любом месте (этот код давно всем известен)
А вот с эмуляцией системного меню я впал в ступор....
Была идея создать отдельно кнопки, но меня она не вдохновила...
В одной SDK статье я когда-то мельком читал, что системное меню можно создать, как дочернее окно, зная его имя в системе, но заново найти статью мне не удалось...
Ещё одна идея - это кнопка приложения на таскбаре. Если у программы есть системное меню, то щелкнув по кнопке в таскбаре правой кнопкой мыши можно вызвать контекстное меню, в котором есть системные команды.. Но у меня нет системного меню, и щелчки по таскбар кнопке вообще никак не воспринимаются системой

6) В общем в итоге я заступорился на сл вопросах:
- как быть при изменении размера окна?
- подспутный вопрос: придётся ли при приближении курсора к внешней границе региона окна самому реализовывать смену курсора на значок "двойная стрелка" и если придётся, то как лучше это сделать?
- если реализовывать системные команды с помощью динамического создания системного меню в любом месте окна, то как это сделать?
- если реализовывать системные команды с помощью обработки щелчков по кнопке приложения в таскбаре, то как отловить эти команды и что это за команды?

Очень буду признателен за полноценные ответы.

Присоединённый файл ( Кол-во скачиваний: 16 )
Присоединённый файл  LayerWnd.zip 91,56 Kb
PM MAIL   Вверх
jonie
Дата 14.5.2009, 09:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 5613
Регистрация: 21.8.2005
Где: Владимир

Репутация: 7
Всего: 118



Цитата

- как быть при изменении размера окна?

рисоваться!

Цитата

- подспутный вопрос: придётся ли при приближении курсора к внешней границе региона окна самому реализовывать смену курсора на значок "двойная стрелка" и если придётся, то как лучше это сделать?
да, придется. Мышиные сообщения нужно мониторить и сверять координаты мыши (приходят с сообщением в lparam или wparam) с областью sizeGrip-а (ну, или как у тебя с областью конца окна). Можно сверять цвет под координатой. Но тогда этот цвет нигде более использовать нельзя (зато не надо считать "край-некрай").



Цитата

- если реализовывать системные команды с помощью динамического создания системного меню в любом месте окна, то как это сделать?
http://www.codeguru.com/csharp/csharp/cs_misc/userinterface/article.php/c9327  вот пример (не смотрите что c#, все функции winAPIшные дергаются)
Цитата

- если реализовывать системные команды с помощью обработки щелчков по кнопке приложения в таскбаре, то как отловить эти команды и что это за команды?

используйте утилиту spy++ из поставки VS или скачайте тут: http://www.windows-spy.com/download/  и смотрите какие сообщения приходят окну. На них и реагируйте )


--------------------
Что-то не поняли? -> Напейтесь до зеленых человечков... эта сверхцивилизация Вам поможет...
PM MAIL Jabber   Вверх
mekhanikus
Дата 14.5.2009, 10:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Вольноопределяющийся
*


Профиль
Группа: Участник
Сообщений: 186
Регистрация: 16.6.2008
Где: Спасск-Дальний

Репутация: 1
Всего: 1



Цитата(evkwarrior @ 14.5.2009,  08:48)

- подспутный вопрос: придётся ли при приближении курсора к внешней границе региона окна самому реализовывать смену курсора на значок "двойная стрелка" и если придётся, то как лучше это сделать?

В этом тебе поможет сама винда.
Лови WM_NCHITTEST и возвращай соответсвующие значения.
Винда сделает с курсором все, что нужно.
Цитата(evkwarrior @ 14.5.2009,  08:48)

- если реализовывать системные команды с помощью динамического создания системного меню в любом месте окна, то как это сделать?

Если создать окно со стилем WS_SYSMENU, то отлавливая WM_NCRBUTTONDOWN в можно вызвать системное меню:
Код

case WM_NCRBUTTONDOWN:
            HMENU menu = GetSystemMenu(hWnd,FALSE);
            POINTS pt = MAKEPOINTS(lParam);
            TrackPopupMenu(menu,TPM_LEFTALIGN|TPM_LEFTBUTTON,
                           pt.x,pt.y,0,hWnd,NULL);
            break;


Это сообщение отредактировал(а) mekhanikus - 14.5.2009, 11:11
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.2726 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.