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


Автор: PirateTigo 20.9.2009, 14:20
Я уверен в том, что у меня классическая проблема и разобраться с ней не составит труда опытным программистам WinAPI.

В общем так:

В программе создано несколько диалоговых окон в числе которых существует три немодальных. Программа работает с графическим объектом, который в процессе работы программы видоизменяется. Для поддержки двойной буферизации создан пользовательский обработчик перерисовки клиентской области приложения, который вызывается по сообщению USER_WM, вот его объявление:
Код

enum UserMsg {USER_WM = WM_USER + 1};


в обработчике сообщения WM_PAINT находится следующий код:
Код

case WM_PAINT:        
        DefWindowProc (hWnd, message, wParam, lParam);
        SendMessage (hWnd, USER_WM, 0, 0);
        break;


в обработчике сообщения USER_WM используется совместимый с контекстом окна hdc контекст memdc. Все действия по обработке изображения выполняются в контексте memdc, а затем содержимое контекста копируется в контекст окна hdc с помощью этой функции:
Код

BitBlt (hdc, 0, 0, rect.right, rect.bottom, memdc, 0, 0, SRCCOPY);


В обработчике сообщения WM_CREATE создается немодальное диалоговое окно, использующееся для отображения некоторых параметров графического объекта:
Код

hActVert = CreateDialog (hInst, MAKEINTRESOURCE (IDD_ACTVERT), hWnd, ActVert);


Здесь hActVert  - дескриптор немодального диалогового окна, ActVert - Процедура обработки сообщений для этого окна,
IDD_ACTVERT - шаблон этого окна, hInst - дескриптор экземпляра основного окна приложения.

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

Заранее благодарен.

Автор: GremlinProg 20.9.2009, 14:43
а зачем пересылать из WM_PAINT к USER_WM, когда все можно рисовать прямо в WM_PAINT
Цитата(PirateTigo @  20.9.2009,  16:20 Найти цитируемый пост)
Какой код и куда мне нужно поместить, чтобы мое немодальное диалоговое окно не затиралось, а вполне себе успешно отображалось в клиентской области окна приложения в процессе работы программы?

не совсем понятно, что значит "затиралось", 
тут могут быть разные ситуации:
- рисование немодального диалога (который затирается) не производится на WM_PAINT (при этом затирается не весь диалог, а только пользовательское содержимое)
- процедура окна немодального диалога блокируется каким-либо образом
- производится какое-либо долгосрочное вычисление, мещающее основной работе окна (в диспетчере задач при этом показана 100% загрузка CPU)

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

Автор: PirateTigo 20.9.2009, 15:07
На счет WM_PAINT согласен - не подумал.

Код достаточно объемный, поэтому весь его я привести не могу, так как размер сообщения ограничен, попробую отписаться вырезками из диалоговой процедуры основного окна..

Код

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    static HDC hdc, memdc;
    static HRGN hRgn;
    RECT rect;
    static int X, Y, R;
    static VertName Active;    
    static VertName Iterator;
    static VertName IterAct;
    static float h = 0.;
    static bool bTracking = false;
    static HBITMAP hBmp;
    static HBRUSH hBrush;
    static int count = 0;
    static SimpleGraph<VertexData *, EdgeData>::iterator GIT;
//===================================================================================
    switch (message)
    {
    case WM_CREATE:
        hinst_msimg32 = LoadLibrary(TEXT("msimg32.dll"));        
        if (hinst_msimg32)
        {
            GFill = (bool (WINAPI *)(HDC, TRIVERTEX*, 
                unsigned long, void*, unsigned long, unsigned long))
            GetProcAddress(hinst_msimg32, "GradientFill");
        }    

        LPPNTS = (VertexData **)malloc (sizeof (VertexData *)*100000);
        for (int i=0; i<100000; i++)
            LPPNTS[i] = PNTS+i;

        graphData.V = "10";
        graphData.Directed = false;
        graphData.TP = IDC_L;

        GetClientRect(hWnd, &rect);
        X = (rect.left + rect.right) / 2;
        Y = (rect.bottom + rect.top) / 2;
        R = min (Y/2, X/2);    
        
        hBrush = CreateSolidBrush (RGB (255,255,255));
        hdc = GetDC (hWnd);        
        SetClassLong (hWnd, GCL_HBRBACKGROUND, (LONG)hBrush);
        memdc = CreateCompatibleDC (hdc);
        hBmp = CreateCompatibleBitmap (memdc, rect.right, rect.bottom);        
        SelectObject (memdc, hBmp);
        SetGraphicsMode (memdc, GM_ADVANCED);    
        hRgn = CreateRectRgnIndirect (&rect);
        hActVert = CreateDialog (hInst, MAKEINTRESOURCE (IDD_ACTVERT), hWnd, ActVert);
        hRgn = AdjDlgPlace (hRgn, hActVert);        
        break;



Код

    case WM_SIZE:        
        GetClientRect(hWnd, &rect);                
        X = (rect.left + rect.right) / 2;
        Y = (rect.bottom + rect.top) / 2;
        R = min (Y/2, X/2);
        if (G != NULL) {
            int i=0, j;
            for (multimap<string, int>::iterator iter = NAMES.begin();
                i<G->V(); iter++, i++) {
                    double alpha = i*h*Pi/180.;
                    VertName temp (&((*iter).second),sizeof (int));
                    (**(G->Vertex (temp)->GetData())).SetXY ((int)(X + sin (alpha)*R),(int)(Y - R*cos (alpha)));
                }            
            i=0;
            for (multimap<string, int>::iterator iter1 = NAMES.begin();
                i<G->V(); iter1++, i++) {
                    j=i+1;
                for (multimap<string, int>::iterator iter2 = iter1;
                    j<G->V(); j++) {
                        iter2++;
                        VertName SrcName (&((*iter1).second), sizeof (int));
                        VertName DstName (&((*iter2).second), sizeof (int));
                        Edge<VertName, EdgeData> *temp1 = new Edge<VertName, EdgeData>(
                            SrcName, DstName, NULL, NULL);
                        Edge<VertName, EdgeData> *temp2 = new Edge<VertName, EdgeData>(
                            DstName, SrcName, NULL, NULL);
                        EdgeData *temp1s=NULL, *temp2s=NULL;
                        if ((temp1s=G->Edge (temp1))!=NULL) {
                            temp1s->SetXYSrc (
                                (*(G->Vertex (SrcName)->GetData ()))->x,
                                (*(G->Vertex (SrcName)->GetData ()))->y
                                );
                            temp1s->SetXYDst (
                                (*(G->Vertex (DstName)->GetData ()))->x,
                                (*(G->Vertex (DstName)->GetData ()))->y
                                );
                            delete temp1;
                        }
                        if ((temp2s=G->Edge (temp2))!=NULL) {
                            temp2s->SetXYSrc (
                                (*(G->Vertex (DstName)->GetData ()))->x,
                                (*(G->Vertex (DstName)->GetData ()))->y
                                );
                            temp2s->SetXYDst (
                                (*(G->Vertex (SrcName)->GetData ()))->x,
                                (*(G->Vertex (SrcName)->GetData ()))->y
                                );
                            delete temp2;
                        }                                            
                }    
            }
        }                    
        hBmp = CreateCompatibleBitmap (hdc, rect.right, rect.bottom);
        DeleteObject (SelectObject (memdc, hBmp));
        BitBlt (memdc, 0, 0, rect.right, rect.bottom, hdc, 0, 0, SRCCOPY);        
        break;
//=================================================================================
    case WM_PAINT:        
        DefWindowProc (hWnd, message, wParam, lParam);
        SendMessage (hWnd, USER_WM, 0, 0);
        break;

    case USER_WM:
        {    
            GetClientRect (hWnd, &rect);        
            if (!count) {
                BitBlt (memdc, 0, 0, rect.right, rect.bottom, hdc, 0, 0, SRCCOPY);
                count++;
            }            
            FillRect (memdc, &rect, hBrush);
                
            if (G != NULL) {            
                int i=0, j;
                for (multimap<string, int>::iterator iter = NAMES.begin();
                    i<G->V(); iter++, i++) {
                        int temp = (*iter).second;
                        VertName Name (&temp, sizeof (int));
                        (*(G->Vertex (Name)->GetData ()))->Draw (memdc);
                }

                i=0;
                for (multimap<string, int>::iterator iter1 = NAMES.begin();
                    i<G->V(); iter1++, i++) {
                        j=i+1;
                    for (multimap<string, int>::iterator iter2 = iter1;
                        j<G->V(); j++) {
                            iter2++;
                            VertName SrcName (&((*iter1).second), sizeof (int));
                            VertName DstName (&((*iter2).second), sizeof (int));
                            Edge<VertName, EdgeData> *temp1 = new Edge<VertName, EdgeData>(
                                SrcName, DstName, NULL, NULL);
                            Edge<VertName, EdgeData> *temp2 = new Edge<VertName, EdgeData>(
                                DstName, SrcName, NULL, NULL);
                            EdgeData *temp1s=NULL, *temp2s=NULL;
                            if ((temp1s=G->Edge (temp1))!=NULL | 
                                (temp2s=G->Edge (temp2))!=NULL) {                                    
                                    if (temp1s!=NULL) temp1s->Draw (memdc);
                                    else temp2s->Draw (memdc);
                                    if (temp1s!=NULL) temp1s->DrawDir (memdc);
                                    if (temp2s!=NULL) temp2s->DrawDir (memdc);
                            }    
                            delete temp1, temp2;        
                    }                        
                }                                        
            }        
        }                
        BitBlt (hdc, 0, 0, rect.right, rect.bottom, memdc, 0, 0, SRCCOPY);        
        break;


Под словом "затиралось" я имел в виду то, что при запуске программы окно отображается, но как только я вызываю обработчик сообщения USER_WM окно исчезает (это понятно потому что происходит копирование с контекста памяти memdc на контекст hdc без отсчения регионов)

Из тех вариантов, что вы привели сюда НЕ подходят:
- производится какое-либо долгосрочное вычисление, мещающее основной работе окна (в диспетчере задач при этом показана 100% загрузка CPU)

Ну и по поводу пакета "телепатия". Я и так по-моему достаточно хорошо все описал и изложил суть проблемы. Дело ведь не в том, что я что-то забыл написать в коде, а в том, что я не знаю как это делается в классическом варианте (это я про немодальное диалоговое окно сейчас), так как использую его в таком контексте впервые. А хамить не нужно.

Автор: GremlinProg 20.9.2009, 15:59
Цитата(PirateTigo @  20.9.2009,  16:20 Найти цитируемый пост)

в обработчике сообщения WM_PAINT находится следующий код:
Код

case WM_PAINT:        
        DefWindowProc (hWnd, message, wParam, lParam);
        SendMessage (hWnd, USER_WM, 0, 0);
        break;


так это и есть обработчик на немодальном диалоге, который "затирается"?
если так, то просто убери DefWindowProc, чтобы она не подтверждала регион коррекции
Цитата(PirateTigo @  20.9.2009,  17:07 Найти цитируемый пост)
А хамить не нужно.

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

Автор: PirateTigo 20.9.2009, 16:03
Убрал - программа зависла как только я попытался изобразить графический объект.

Добавлено через 5 минут и 1 секунду
Так... Кажется опять не понятно, что я хочу узнать от всех...

Мне в общем код не важен, мне нужен просто принцип. Как это делается? 
А если точнее, то какими средствами можно перерисовать немодальное диалоговое окно. Ну то есть как явно его обновить?

Автор: GremlinProg 20.9.2009, 16:24
Цитата(PirateTigo @  20.9.2009,  18:03 Найти цитируемый пост)
Убрал - программа зависла как только я попытался изобразить графический объект.

да, рисование в USER_WM организовано мягко говоря некорректно,
я расчитывал на более обыденную форму, с BeginPaint и EndPaint

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

на данном этапе, я предлагаю:
1. отвязаться от посылки USER_WM,
2. рисовать все в ответ на WM_PAINT
3. двойной буфер создавать прямо в WM_PAINT
4. пользоваться исключительно BeginPaint и EndPaint
5. если нужно отвязаться от создания второго буфера в WM_PAINT, это можно будет сделать в WM_SIZE, сразу как только будут решены текущие проблемы

на форуме много готовых примеров, выбирай наиболее подходящий: http://forum.vingrad.ru/act-Search/CODE/show/searchid-40cb68bda4aeef49e4564f727a049d43/search_in-posts/result_type/topics/flag/search/highlite/wm_paint+%25D0%25B4%25D0%25B2%25D0%25BE%25D0%25B9%25D0%25BD%25D0%25BE%25D0%25B9+%25D0%25B1%25D1%2583%25D1%2584%25D0%25B5%25D1%2580/index.html

Добавлено через 6 минут и 27 секунд
вот такой запрос немного точнее: http://forum.vingrad.ru/act-Search/CODE/show/searchid-1526993cb5a40a27a97bae001145b8f7/search_in-posts/result_type/topics/flag/search/highlite/wm_paint+%2522%25D0%25B4%25D0%25B2%25D0%25BE%25D0%25B9%25D0%25BD%25D0%25BE%25D0%25B9+%25D0%25B1%25D1%2583%25D1%2584%25D0%25B5%25D1%2580%2522/index.html

Автор: PirateTigo 20.9.2009, 17:33
В общем я нашел решение.

Нужно просто установить для главного окна стиль WS_CLIPCHILDREN, и/или для дочерних окон стиль WS_CLIPSIBLINGS.

Добавлено через 1 минуту и 45 секунд
Ответ найден.

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