Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > custom button


Автор: GP1000 10.4.2009, 18:49
Подскажите пожалуйста как сделать кнопку на основе иконки .
Эта кнопка должна быть прозрачной по отношению к фону на котором она лежит .То есть в нормальном положении это должна быть одна иконка в нажатом положении другая . 
Я пробовал делать так :
Код

BOOL DrawFreeStyleBtn(LPDRAWITEMSTRUCT pis)
{
    POINT pos;
    HICON hIcon = LoadIcon(g_hInstance,MAKEINTRESOURCE(IDI_ICON1));
        
    switch(pis->itemAction)
        {
        case ODA_SELECT:
            if( pis->itemState & ODS_SELECTED){
               hIcon = LoadIcon(g_hInstance,MAKEINTRESOURCE(IDI_ICON2));
            }
            break;
        default:
            break;
        }
        DrawIconEx(pis->hDC,0,0,hIcon,WIDTH,HEIGHT,0,0,DI_NORMAL);
     return TRUE;
    return FALSE;
}
//...где то внутри процедуры окна 
case WM_DRAWITEM:
return DrawFreeStyleBtn( (LPDRAWITEMSTRUCT) lParam );

Иконка отрисовывается ,но кнопочный фон серый все равно остается .
Где и что я не правильно сделал?

Что бы решить эту проблему я пошел другим путем - создавая свои дочерние окна  и отрисовывавая в  них иконки  и самостоятельно отрабатывать их логику . Можно ли все это проще , через обычные кнопки ?? 

Автор: GremlinProg 15.4.2009, 17:38
можно попробовать поиграться со стилем WS_EX_TRANSPARENT
но похоже, все равно придется перехватывать некоторый функционал кнопки, чтобы встроенная процедура окна ее не заливала
тут возможны 2 случая:

1. если фон закрашивается на WM_ERASEBKGND, то достаточно переопределить класс кнопки с нулевой кистьюWNDCLASS::hbrBackground (но я, честно говоря, не припомню, чтобы встроенные классы явно пользовались этим параметром)

2. если фон кнопки закрашивается еще и при рисовании, на WM_PAINT, (а скорее всего так и есть), то можно переопределить класс окна кнопки с заглушками на сообщения WM_ERASEBKGNDWM_PAINT и WM_PRINT, но это, по сути - создание нового класса окна

Автор: Andrey44 16.4.2009, 07:07
По моему это только писать самому свой класс для кнопки, по крайней мере я так и делал.
Но можно еще в WM_DRAWITEM рисовать кнопки, но это скажем не очень-то удобно, если кнопок много.

Автор: GremlinProg 16.4.2009, 10:26
GP1000, через WM_DRAWITEM и рисует

Автор: Andrey44 16.4.2009, 11:20
GremlinProg, Я вижу что он рисует и как рисует.
А не выходит у него потому-что рисует в том HDC который приходит в LPDRAWITEMSTRUCT.
А нужно создавать в памяти рисовать в нем а потом выдавать на отрисовку. Я так и делал. 
Но очень неудобно когда много кнопок и много картинок.

Автор: GremlinProg 16.4.2009, 13:00
Цитата(Andrey44 @  16.4.2009,  13:20 Найти цитируемый пост)
А нужно создавать в памяти рисовать в нем а потом выдавать на отрисовку.

 smile двойная буферизация тут совсем ни при чем, и ошибки тут нет


GP1000, пробовал с WS_EX_TRANSPARENT?

Автор: Andrey44 16.4.2009, 14:18
Цитата(GremlinProg @  16.4.2009,  13:00 Найти цитируемый пост)
двойная буферизация тут совсем ни при чем, и ошибки тут нет

А кто говорил об ошибке?
Цитата(GP1000 @  10.4.2009,  18:49 Найти цитируемый пост)
Иконка отрисовывается ,но кнопочный фон серый все равно остается .
Где и что я не правильно сделал?

А надо рисовать то что находится под кнопкой. Правильно?

Автор: GremlinProg 16.4.2009, 14:35
Цитата(Andrey44 @  16.4.2009,  16:18 Найти цитируемый пост)
А кто говорил об ошибке?

Цитата(Andrey44 @  16.4.2009,  13:20 Найти цитируемый пост)
А не выходит у него потому-что рисует в том HDC который приходит в LPDRAWITEMSTRUCT.


Цитата(Andrey44 @  16.4.2009,  16:18 Найти цитируемый пост)
А надо рисовать то что находится под кнопкой. Правильно?

правильно, но двойной буфер без WS_EX_TRANSPARENT прозрачности не принесет ни коим образом

Автор: Andrey44 16.4.2009, 14:42
Цитата(GremlinProg @  16.4.2009,  14:35 Найти цитируемый пост)
без WS_EX_TRANSPARENT прозрачности не принесет ни коим образом 

А причем тут WS_EX_TRANSPARENT? Он по-моему вообще не работает. Хотя не стану утверждать.
А делал я так. Брал HDC родительского окна брал из его битмапа область над которой находится кнопка и рисовал ее на саму кнопку, по-моему все понятно , а вы стали ко мне придираться.

Автор: GremlinProg 16.4.2009, 14:58
Цитата(Andrey44 @  16.4.2009,  16:42 Найти цитируемый пост)
Брал HDC родительского окна брал из его битмапа область над которой находится кнопка и рисовал ее на саму кнопку, по-моему все понятно , а вы стали ко мне придираться.

я не придираюсь, такой метод будет работать только если родительское окно не отсекает дочерние и это не самый хороший вариант, поскольку накладывает ограничения на родительское окно, а WS_EX_TRANSPARENT заставляет это родительское окно рисовать себя прежде, чем дочернее будет отрисовано, тогда можно гарантировать, что задний фон дочернего уже будет содержать часть родителя, без дополнительных операций

Автор: Andrey44 16.4.2009, 15:09
GremlinProg, вы хотите сказать если я кнопке поставлю стиль WS_EX_TRANSPARENT, то она будет прозрачная?

Автор: GremlinProg 16.4.2009, 15:18
Цитата(Andrey44 @  16.4.2009,  17:09 Найти цитируемый пост)
вы хотите сказать если я кнопке поставлю стиль WS_EX_TRANSPARENT, то она будет прозрачная?

нет, я уже писал что для этого требуется: http://forum.vingrad.ru/index.php?showtopic=255037&view=findpost&p=1843435

Автор: Andrey44 16.4.2009, 15:21
Хорошо, не будем спорить.
Но я написал то что делал, и все работает.

Автор: Emura 21.4.2009, 15:14
Задам здесь вопрос.

Andrey44
Цитата

А делал я так. Брал HDC родительского окна брал из его битмапа область над которой находится кнопка и рисовал ее на саму кнопку, по-моему все понятно


GremlinProg
Цитата

такой метод будет работать только если родительское окно не отсекает дочерние


Именно WS_CLIPCHILDREN и не дает нормально реализовать прозрачность, подскажите как побороть..



Автор: GremlinProg 21.4.2009, 17:05
ладно, уговорили,
привожу пример использования WS_EX_TRANSPARENT:
Код

// transparency.cpp : Defines the entry point for the application.
//
#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers
#include <windows.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <string>

LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK    TransparencyControl(HWND, UINT, WPARAM, LPARAM);

int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow){
    MSG msg;
    WNDCLASSEX wcex;
    HWND hWnd,hWndChild;
    //
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);
    //
    wcex.cbSize            = sizeof(WNDCLASSEX);
    wcex.style            = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra        = 0;
    wcex.cbWndExtra        = 0;
    wcex.hInstance        = hInstance;
    wcex.hIcon            = ::LoadIcon(NULL,IDI_APPLICATION);
    wcex.hCursor        = ::LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground    = ::GetSysColorBrush(COLOR_BTNFACE);
    wcex.lpszMenuName    = NULL;
    wcex.lpszClassName    = _T("TransparencyControlApplication");
    wcex.hIconSm        = ::LoadIcon(NULL,IDI_APPLICATION);
    if( ::RegisterClassEx(&wcex) ){
        hWnd = ::CreateWindowEx(
            0,
            wcex.lpszClassName,
            _T("пример для флага WS_EX_TRANSPARENT"),
            WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
            CW_USEDEFAULT,0,
            300,300,NULL,NULL,
            hInstance,NULL
        );
        if(!hWnd){
            return FALSE;
        }
        wcex.style            = 0;
        wcex.lpfnWndProc    = TransparencyControl;
        wcex.cbClsExtra        = 0;
        wcex.cbWndExtra        = 0;
        wcex.hInstance        = hInstance;
        wcex.hIcon            = NULL;
        wcex.hCursor        = ::LoadCursor(NULL,IDC_ARROW);
        wcex.hbrBackground    = NULL;
        wcex.lpszMenuName    = NULL;
        wcex.lpszClassName    = _T("TransparencyControl");
        wcex.hIconSm        = NULL;
        if( ::RegisterClassEx(&wcex) ){
            hWndChild    = ::CreateWindowEx(
                WS_EX_TRANSPARENT,
                wcex.lpszClassName,
                _T("Иконка IDI_EXCLAMATION на фоне текста с прозрачным фоном\r\nразноцветные прямоугольники рисуются на родителе"),
                WS_CHILD,0,0,150,150,
                hWnd,NULL,
                hInstance,NULL
                );
            if( hWndChild ){
                ::ShowWindow(hWndChild, nCmdShow);
            }
        }
        ::ShowWindow(hWnd, nCmdShow);
        ::UpdateWindow(hWnd);
    }
    while(::GetMessage(&msg, NULL, 0, 0)){
        ::TranslateMessage(&msg);
        ::DispatchMessage(&msg);
    }
    return(int)msg.wParam;
}
LRESULT CALLBACK TransparencyControl(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
    switch( message ){
        case WM_PAINT:{
            PAINTSTRUCT ps;
            RECT rc;
            std::wstring text;
            HGDIOBJ hBrush,hPen;
            HICON hIcon;
            //
            ::GetClientRect(hWnd,&rc);
            ::BeginPaint(hWnd,&ps);
            text.resize( ::GetWindowTextLength(hWnd) );
            hBrush    = ::SelectObject(ps.hdc,::GetStockObject(NULL_BRUSH));
            hPen    = ::SelectObject(ps.hdc,::GetStockObject(DC_PEN));
            ::SetDCPenColor(ps.hdc,RGB(0,255,0));
            ::Rectangle(ps.hdc,rc.left,rc.top,rc.right,rc.bottom);
            if( !text.empty() ){
                ::InflateRect(&rc,-1,-1);
                ::GetWindowTextW(hWnd,&*text.begin(),text.size() + 1);
                ::SetBkMode(ps.hdc,TRANSPARENT);
                ::DrawTextW(ps.hdc,text.c_str(),text.size(),&rc, DT_VCENTER | DT_CENTER | DT_WORDBREAK);
            }
            hIcon    = ::LoadIcon(NULL,IDI_EXCLAMATION);
            ::DrawIconEx(ps.hdc,0,0,hIcon,0,0,0,NULL,DI_NORMAL);
            ::DestroyIcon(hIcon);
            ::SelectObject(ps.hdc,hPen);
            ::SelectObject(ps.hdc,hBrush);
            ::EndPaint(hWnd,&ps);
            break;
        }
    }
    return::DefWindowProc(hWnd,message,wParam,lParam);
}
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam){
    switch( message ){
        case WM_PAINT:{
            PAINTSTRUCT ps;
            RECT rc;
            HGDIOBJ hPen;
            //
            ::BeginPaint(hWnd, &ps);
            ::SetRect(&rc,10,10,160,160);
            hPen    = ::SelectObject(ps.hdc,::GetStockObject(DC_PEN));
            for(int i = 10;i--;){
                if(i & 1){
                    ::SetDCPenColor(ps.hdc,RGB(255,0,0));
                }else{
                    ::SetDCPenColor(ps.hdc,RGB(0,0,255));
                }
                ::Rectangle(ps.hdc,rc.left,rc.top,rc.right,rc.bottom);
                ::InflateRect(&rc,-3,-3);
            }
            ::SelectObject(ps.hdc,hPen);
            ::EndPaint(hWnd,&ps);
            break;
        }
        case WM_DESTROY:{
            ::PostQuitMessage(0);
            break;
        }
    }
    return::DefWindowProc(hWnd, message, wParam, lParam);
}

в приложении - скомпилированный exe'шник
как видно, все прозрачно без лишних заморочек

Добавлено через 3 минуты и 3 секунды
Цитата(Emura @  21.4.2009,  17:14 Найти цитируемый пост)
Именно WS_CLIPCHILDREN и не дает нормально реализовать прозрачность, подскажите как побороть..

в пример этот флаг тоже включен

Автор: Emura 21.4.2009, 18:57
Спасибо! smile
Буду разбираться. Отпишусь о результате.

Посмотрел  smile работает!
 
теперь вопрос smile Это дело буферизиривать реально? Чтобы при ресайзе не подмигивало.




PS: была бы возможность поставил плюс! 
имхо, ограничение в 100 сообщений - совсем лишее.

Автор: GremlinProg 21.4.2009, 20:11
Цитата(Emura @  21.4.2009,  20:57 Найти цитируемый пост)
Это дело буферизиривать реально?

ну, это немного другой вопрос
буферизировать, конечно, реально
но эффект от этого будет не полный, поскольку на WS_EX_TRANSPARENT об этой буферизации ни чего не знает

хотя в XP этот недочет можно устранить:
поставь родительскому окну стиль WS_EX_COMPOSITED, при создании (это встроенная буферизация)
после этого, дополнительно, ни чего буферизировать не потребуется

Автор: Emura 21.4.2009, 20:18
Ага, заработало. GremlinProg, Спасибо! 

А какой негатив от WS_EX_COMPOSITED может проявится? На Висту эта опция распространяется?

Автор: GremlinProg 21.4.2009, 20:35
негатива 2 штуки:
1. не видно некоторых операций с мышью, при которых какие-нибудь кнопки меняют состояние
2. подержка этого флага только в XP (и более ни где)

по сути, WS_EX_TRANSPARENT с ним и должен использоваться, но раз в последующих версиях WS_EX_COMPOSITED удален, а WS_EX_TRANSPARENT остался, то можно предположить, что эту проблему:
Цитата(GremlinProg @  21.4.2009,  22:11 Найти цитируемый пост)
но эффект от этого будет не полный, поскольку на WS_EX_TRANSPARENT об этой буферизации ни чего не знает

там решили, т.е. в последующих ручная двойная буферизация  будет работать полноценно

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

Автор: GremlinProg 21.4.2009, 20:56
похоже, есть еще один негатив, с AlphaBlend:
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=100477

Автор: Emura 21.4.2009, 21:10
Да уж.. не обнадеживает. Чтож так все антипрозрачно с этой прозрачностью.

Кстати а можно на лету вкл\ выкл WS_CLIPCHILDREN ?
Если можно, то к примеру 
1. при показе родителя WS_CLIPCHILDREN выкл, 
2. копируем фон родителя 
3. вкл WS_CLIPCHILDREN
4. используем скопируемый фон для отрисовки потомков как душе угодно

или это бред?


Автор: GremlinProg 21.4.2009, 21:18
если нужна двойная буферизация, то делай как советовал Andrey44
возможно даже не придется отключать WS_CLIPCHILDREN (если копировать фон не с родителя, а с самого себя)

Добавлено через 4 минуты и 39 секунд
хотя сечас вот, засомневался

если WS_CLIPCHILDREN не убирать, то все равно придется фон родителя воспроизводить на прозрачном окне по-новой
(хотя это и не проблема, если фон известен, например: статическая картинка)

Добавлено через 10 минут и 43 секунды
Цитата(Emura @  21.4.2009,  23:10 Найти цитируемый пост)

1. при показе родителя WS_CLIPCHILDREN выкл,
2. копируем фон родителя
3. вкл WS_CLIPCHILDREN
4. используем скопируемый фон для отрисовки потомков как душе угодно

а, без разницы, сам подумай,
если использовать экран в качестве буфера заднего фона, то он в любом случае ОБНОВИТСЯ ДВАЖДЫ:
1. прорисуется родитель
2. прорисуется дочерний, затирая родителя

даже если это обновление будет не частым, моргание будет видно

Автор: Emura 21.4.2009, 21:29
GremlinProg 
Да,я тоже сомневаюсь. 

Andrey44:
Цитата

А делал я так. Брал HDC родительского окна брал из его битмапа область над которой находится кнопка и рисовал ее на саму кнопку


Взять область при WS_CLIPCHILDREN не получится. Она то как раз и вырезана, там нет фона из-за WS_CLIPCHILDREN.
А использовал он WS_CLIPCHILDREN или нет я так и не понял, скорее всего нет, если у него получилось то, что он описал.

Цитата

хотя это и не проблема, если фон известен, например: статическая картинка

возможно, а если она стретчится. в зависимости о размера окна это не вариант.. 
проблем нет если родитель одноцветен.

аа понял, впринципе да, согласен на счет картинки. точно! А вот если градиент программно рисуем? то тут нифига.

Автор: GremlinProg 21.4.2009, 21:37
Цитата(Emura @  21.4.2009,  23:29 Найти цитируемый пост)
возможно, а если она стретчится. в зависимости о размера окна это не вариант..

я конкретно в таком случае использовал IPicture::Render, т.е. именно воспроизвожу статический рисунок (с растяжкой)
прекрасно работало, попробуй

Добавлено через 2 минуты и 28 секунд
родитель же известен, следовательно его координаты - тоже
можно спокойно идентифицировать свой участок фона, даже с учетом масштабирования

Добавлено через 7 минут
Цитата(Emura @  21.4.2009,  23:29 Найти цитируемый пост)
Взять область при WS_CLIPCHILDREN не получится. Точнее получится, но будет она прозрачна

да, похоже, область будет прозрачна вплоть до первого пра-родителя, с включенным WS_CLIPCHILDREN, а при отсутствии таковых - будет светиться десктоп и все, что на нем в данный момент

Автор: GremlinProg 21.4.2009, 21:55
вообще, я уже писал про WM_PRINT и WM_PRINTCLIENT - очень удобно, и воспроизводить по- сути - ни чего не нужно, и поддержка этих сообщений уже встроена на уровне системных компонент (EDIT, COMBO, TOOLBAR, и т.п.)

рисование второго буфера тогда сводится к посылке самому себе WM_PRINT/CLIENT,
то же самое касается и родителя (WS_CLIPCHILDREN используется только в BeginPaint, так что буфера в памяти это не каснется)
чтобы получить часть родителя, достаточно создать девайс в памяти и послать его с WM_PRINT/CLIENT, а дальше - действительно - делай шо хошь

Автор: Emura 22.4.2009, 03:09
на счет WM_PRINT и WM_PRINTCLIENT 
попробовал стащить битмап с родителя, что-то не вышло (если имелось ввиду это) . Видимо от того что я отрисовываю в WM_PAINT или фиг знает.. С помощью WM_PRINT можно получить hdc окна без вырезок под контролы-потомки? 
GremlinProg, разъясни пожалуйста.


ps. 
по сути если использовать картинку для фона то тогда практически в любых ситуациях можно сотворить прозрачность. но хочется без лишних ресурсов обойтись.


у кого виста под рукой протестите пожалуйста: 
http://forum.vingrad.ru/index.php?showtopic=255037&view=findpost&p=1848827



Автор: Andrey44 22.4.2009, 07:43
Цитата(Emura @  21.4.2009,  21:29 Найти цитируемый пост)
А использовал он WS_CLIPCHILDREN или нет я так и не понял, скорее всего нет, если у него получилось то, что он описал.


WS_CLIPCHILDREN я не использовал, и WS_EX_TRANSPARENT тоже.

Автор: GremlinProg 22.4.2009, 11:57
с WM_PRINT'ом и с двойным буфером, это будет выглядеть так:
Код

// transparency.cpp : Defines the entry point for the application.
//
#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers
#include <windows.h>
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <string>

LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK    TransparencyControl(HWND, UINT, WPARAM, LPARAM);

int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow){
    MSG msg;
    WNDCLASSEX wcex;
    HWND hWnd,hWndChild;
    //
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);
    //
    wcex.cbSize            = sizeof(WNDCLASSEX);
    wcex.style            = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra        = 0;
    wcex.cbWndExtra        = 0;
    wcex.hInstance        = hInstance;
    wcex.hIcon            = ::LoadIcon(NULL,IDI_APPLICATION);
    wcex.hCursor        = ::LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground    = ::GetSysColorBrush(COLOR_BTNFACE);
    wcex.lpszMenuName    = NULL;
    wcex.lpszClassName    = _T("TransparencyControlApplication");
    wcex.hIconSm        = ::LoadIcon(NULL,IDI_APPLICATION);
    if( ::RegisterClassEx(&wcex) ){
        hWnd = ::CreateWindowEx(
            0,
            wcex.lpszClassName,
            _T("пример для флага WS_EX_TRANSPARENT"),
            WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
            CW_USEDEFAULT,0,
            350,350,NULL,NULL,
            hInstance,NULL
        );
        if(!hWnd){
            return FALSE;
        }
        wcex.style            = CS_PARENTDC;
        wcex.lpfnWndProc    = TransparencyControl;
        wcex.cbClsExtra        = 0;
        wcex.cbWndExtra        = 0;
        wcex.hInstance        = hInstance;
        wcex.hIcon            = NULL;
        wcex.hCursor        = ::LoadCursor(NULL,IDC_ARROW);
        wcex.hbrBackground    = NULL;
        wcex.lpszMenuName    = NULL;
        wcex.lpszClassName    = _T("TransparencyControl");
        wcex.hIconSm        = NULL;
        if( ::RegisterClassEx(&wcex) ){
            hWndChild    = ::CreateWindowEx(
                0,
                wcex.lpszClassName,
                _T("Иконка IDI_EXCLAMATION на фоне текста с прозрачным фоном\r\nразноцветные прямоугольники рисуются на родителе"),
                WS_CHILD,50,50,150,150,
                hWnd,NULL,
                hInstance,NULL
                );
            if( hWndChild ){
                ::ShowWindow(hWndChild, nCmdShow);
            }
        }
        ::ShowWindow(hWnd, nCmdShow);
        ::UpdateWindow(hWnd);
    }
    while(::GetMessage(&msg, NULL, 0, 0)){
        ::TranslateMessage(&msg);
        ::DispatchMessage(&msg);
    }
    return(int)msg.wParam;
}
LRESULT CALLBACK TransparencyControl(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){
    switch( message ){
        case WM_PRINTCLIENT:{
            RECT rc;
            POINT pt,org;
            std::wstring text;
            HDC hdc;
            HGDIOBJ hBrush,hPen;
            HICON hIcon;
            //
            hdc    = (HDC)wParam;
            ::GetClientRect(hWnd,&rc);
            //    рисуем прозрачный фон
            org    = (POINT&)rc;
            ::MapWindowPoints(hWnd,::GetAncestor(hWnd,GA_PARENT),&org,1);
            ::GetWindowOrgEx(hdc,&pt);
            ::SetWindowOrgEx(hdc,pt.x + org.x,pt.y + org.y,NULL);
            ::SendMessage(::GetAncestor(hWnd,GA_PARENT),WM_ERASEBKGND,(WPARAM)hdc,0);
            ::SendMessage(::GetAncestor(hWnd,GA_PARENT),WM_PRINTCLIENT,(WPARAM)hdc,PRF_CLIENT);
            ::SetWindowOrgEx(hdc,pt.x,pt.y,NULL);
            //    рисуем свое содержимое
            text.resize( ::GetWindowTextLength(hWnd) );
            hBrush    = ::SelectObject(hdc,::GetStockObject(NULL_BRUSH));
            hPen    = ::SelectObject(hdc,::GetStockObject(DC_PEN));
            ::SetDCPenColor(hdc,RGB(0,255,0));
            ::Rectangle(hdc,rc.left,rc.top,rc.right,rc.bottom);
            if( !text.empty() ){
                ::InflateRect(&rc,-1,-1);
                ::GetWindowTextW(hWnd,&*text.begin(),text.size() + 1);
                ::SetBkMode(hdc,TRANSPARENT);
                ::DrawTextW(hdc,text.c_str(),text.size(),&rc, DT_VCENTER | DT_CENTER | DT_WORDBREAK);
            }
            hIcon    = ::LoadIcon(NULL,IDI_EXCLAMATION);
            ::DrawIconEx(hdc,0,0,hIcon,0,0,0,NULL,DI_NORMAL);
            ::DestroyIcon(hIcon);
            ::SelectObject(hdc,hPen);
            ::SelectObject(hdc,hBrush);
            break;
        }
        case WM_PAINT:{
            PAINTSTRUCT ps;
            HDC hdc;
            HGDIOBJ hBitmap;
            int x,y,cx,cy;
            //
            ::BeginPaint(hWnd,&ps);
            x        = ps.rcPaint.left;
            y        = ps.rcPaint.top;
            cx        = ps.rcPaint.right - ps.rcPaint.left;
            cy        = ps.rcPaint.bottom - ps.rcPaint.top;
            hdc        = ::CreateCompatibleDC(ps.hdc);
            hBitmap    = ::CreateCompatibleBitmap(ps.hdc,cx,cy);
            hBitmap    = ::SelectObject(hdc,hBitmap);
            ::SetWindowOrgEx(hdc,x,y,NULL);
            //
            ::SendMessage(hWnd,WM_PRINTCLIENT,(WPARAM)hdc,PRF_CLIENT);
            ::BitBlt(ps.hdc,x,y,cx,cy,hdc,x,y,SRCCOPY);
            //
            hBitmap    = ::SelectObject(hdc,hBitmap);
            ::DeleteObject(hBitmap);
            ::DeleteDC(hdc);
            ::EndPaint(hWnd,&ps);
            break;
        }
    }
    return::DefWindowProc(hWnd,message,wParam,lParam);
}
LRESULT CALLBACK WndProc(HWND hWnd,UINT message,WPARAM wParam,LPARAM lParam){
    switch( message ){
        case WM_PRINTCLIENT:{
            RECT rc;
            HGDIOBJ hPen;
            HDC hdc;
            //
            hdc    = (HDC)wParam;
            ::SetRect(&rc,10,10,160,160);
            hPen    = ::SelectObject(hdc,::GetStockObject(DC_PEN));
            for(int i = 10;i--;){
                if(i & 1){
                    ::SetDCPenColor(hdc,RGB(255,0,0));
                }else{
                    ::SetDCPenColor(hdc,RGB(0,0,255));
                }
                ::Rectangle(hdc,rc.left,rc.top,rc.right,rc.bottom);
                ::InflateRect(&rc,-3,-3);
            }
            ::SelectObject(hdc,hPen);
            break;
        }
        case WM_ERASEBKGND:{
            if( ::WindowFromDC((HDC)wParam) == hWnd ){
                return TRUE;
            }
            break;
        }
        case WM_PAINT:{
            PAINTSTRUCT ps;
            HDC hdc;
            HGDIOBJ hBitmap;
            int x,y,cx,cy;
            //
            ::BeginPaint(hWnd,&ps);
            x        = ps.rcPaint.left;
            y        = ps.rcPaint.top;
            cx        = ps.rcPaint.right - ps.rcPaint.left;
            cy        = ps.rcPaint.bottom - ps.rcPaint.top;
            hdc        = ::CreateCompatibleDC(ps.hdc);
            hBitmap    = ::CreateCompatibleBitmap(ps.hdc,cx,cy);
            hBitmap    = ::SelectObject(hdc,hBitmap);
            ::SetWindowOrgEx(hdc,x,y,NULL);
            //
            ::SendMessage(hWnd,WM_ERASEBKGND,(WPARAM)hdc,0);
            ::SendMessage(hWnd,WM_PRINTCLIENT,(WPARAM)hdc,PRF_CLIENT);
            ::BitBlt(ps.hdc,x,y,cx,cy,hdc,x,y,SRCCOPY);
            //
            hBitmap    = ::SelectObject(hdc,hBitmap);
            ::DeleteObject(hBitmap);
            ::DeleteDC(hdc);
            ::EndPaint(hWnd,&ps);
            break;
        }
        case WM_DESTROY:{
            ::PostQuitMessage(0);
            break;
        }
    }
    return::DefWindowProc(hWnd, message, wParam, lParam);
}


Добавлено через 12 минут и 39 секунд
WS_EX_TRANSPARENT этот пример конечно не касается, он здесь не используется, просто забыл заголовки поправить, но, тем не менее, этот пример переносим на любую ось, а эффект такой же, как и с WS_EX_TRANSPARENT | WS_EX_COMPOSITED (если, конечно неклиентскую область рисовать так же, через буфер)

т.е., все негативы снимаются, кроме главного, сопутствующего вообще двойным буферам: при большом количестве таких дочерних компонент, будет заметно общее притормаживание вывода графики (хотя это вопрос оптимизации GUI, т.е. грамотного планирования интерфейса: не должно у пользователя перед глазами маячить сотни кнопок на одной форме, для него это комфорту не прибавит)

Автор: Emura 22.4.2009, 14:45
Andrey44
Цитата

WS_CLIPCHILDREN я не использовал, и WS_EX_TRANSPARENT тоже.

Спасибо за уточнения!  smile Интересно и мельтешня контролов устраивала?? smile 


GremlinProg
Сейчас посмотрим.

Автор: Emura 22.4.2009, 15:50
Такс, посмотрел код. GremlinProg, очередной респект. 

вопрос:

Как я понял отрисовывается так:

а). родитель отрисовывается, путем отсылки самому себе  WM_PRINTCLIENT. Вся отрисовка находится в WM_PRINTCLIENT. а в WM_PAINT только двойная буферизация и вывод.

б). контрол отрисовывается таким же способом, но перед отрисовкой в WM_PRINTCLIENT отсылаем еще и родителю сообщение WM_PRINTCLIENT, который отрисовывает сам себя и возвращает нам hdc. который мы используем, чтобы сделать контрол "прозрачным".

Так ли я понял?  smile


Кстати, можно ведь попробовать обойтись и без WM_PRINTCLIENT. Создаем например: 
1. метод который рисует контрол, например DrawBuffer(), возвращающий тотже hdc или bitmap, даже параметры для метода замутить, чтото вроде (_возвращаем всю область || _возвращаем нужный квадрат) 
2. метод который выводит, например Draw().
Код

Draw(
DrawBuffer();
)

3. и при отрисовки потомка обращаемся к методу родителя DrawBuffer(), и получаем то что хотели
Код

Draw(
DrawBuffer(parent->DrawBuffer(нужный_квадрат));
)
 
Правильно мыслю? Поправьте если что не так. 
Естесственно это относится в большей степени к самописным контролам.

Цитата

 т.е., все негативы снимаются, кроме главного, сопутствующего вообще двойным буферам: при большом количестве таких дочерних компонент, будет заметно общее притормаживание вывода графики (хотя это вопрос оптимизации GUI, т.е. грамотного планирования интерфейса: не должно у пользователя перед глазами маячить сотни кнопок на одной форме, для него это комфорту не прибавит)

Согласен, само собой.

ps наконец-то проблема вроде решается причем без негативных моментов и сложного то ничего нет, всё просто до безобразия  smile 

Автор: GremlinProg 22.4.2009, 16:27
Цитата(Emura @  22.4.2009,  17:50 Найти цитируемый пост)
б). контрол отрисовывается таким же способом, но перед отрисовкой в WM_PRINTCLIENT отсылаем еще и родителю сообщение WM_PRINTCLIENT, который отрисовывает сам себя и возвращает нам hdc. который мы используем, чтобы сделать контрол "прозрачным".

в том-то и дело, что родителю, ровным счетом, все равно на чем рисовать, он не возвращает девайс, а использует тот, что ему передается в параметре WPARAM

тут есть еще 2 возможных варианта рисования фона:
1. рисовать фон родителя прямо в WM_PAINT, перед посылкой WM_PRINTCLIENT
2. рисовать фон родителя как он сейчас и рисуется, в WM_PRINTCLIENT

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

т.о., по возможности, следует использовать второй вариант

Цитата(Emura @  22.4.2009,  17:50 Найти цитируемый пост)
Кстати, можно ведь попробовать обойтись и без WM_PRINTCLIENT. Создаем например...

ну конечно, если у тебя прозрачное окно четко привязано к родителю
Цитата(Emura @  22.4.2009,  17:50 Найти цитируемый пост)
Естесственно это относится в большей степени к самописным контролам.

именно так

WM_PRINT - универсальный вариант, если на него опираться во всех контролах проекта, то можно спокойно решать сложные полиморфные граф. задачи, разделяя функционал по классам и наследуя один от другого (именно для этого и производится полноценная посылка сообщений "самому-себе", т.е. не завершаем класс, а позволяем его продолжить, перекрыть)

Автор: Emura 22.4.2009, 16:35
Цитата

он не возвращает девайс, а использует тот, что ему передается в параметре WPARAM

именно, опечатался.

Цитата

ну конечно, если у тебя прозрачное окно четко привязано к родителю

да, пока именно так.
остоется эксперементировать с полученной информацией и выбирать подходящий вариант.

GremlinProg, огромное спасибо за участие в дискуссии и за помощь в разрешении проблемы!  smile 

Автор: Andrey44 23.4.2009, 07:18
Цитата(Emura @  22.4.2009,  14:45 Найти цитируемый пост)
Спасибо за уточнения!  smile Интересно и мельтешня контролов устраивала?? smile 

А какая мельтешня что-то я не понял?Никаких морганий и чего-то подобного нет.
Вот попробую собрать маленький пример завтра, тогда и покажу.

Автор: Emura 25.5.2009, 21:40
эх, практически любимая тема smile 

с прозрачностью контролов и способами ее реализации разобрались. GremlinProg, Andrey44 спасибо за помощь, это тема еще многим ищущим будет полезна!

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

если делать регионом то как возможно реализовать ресайз?


подкиньте пожалуйста мыслей для решения задачи.


Автор: GremlinProg 25.5.2009, 22:50
в этой теме и так решается уже более одного вопроса
если так дальше ее нагружать, она будет нечитабельной
создай новую тему

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)