Mdi - дочерние окна перетирают друг друга

antibot

Здравствуйте форумчане! Сталкнулся с небольшой проблемой для меня. А именно: Написал программу MDI,в каждом окне можно рисовать мышью, но стоит нарисовать в одном любую фигуру, а потом протащить это дочернее оено над всеми другими(пустыми или не пустыми), как в них появляется тот же рисунок что и в перетаскиваемом окне... Если обновить любое окно вручную, то первоначальный рисунок появится.Вот такая вот проблема...Как сделать чтобы в каждом окне было только то, что я нарисовал и это не зависело от наложения окон друг на друге или перетаскивание одно над другими...Заранее спасибо!
5 ответов

antibot

Эх...Неужели никто не знает как с этим разобраться...


antibot

Выложи исходник для начала хотябы


antibot

Спасибо, что откликнулись.Ниже приведу код:
#include "stdafx.h"
#include "lab6.h"
#include <windows.h>
#include <vector>
#include <math.h>
 
using namespace std;
 
#define MAX_LOADSTRING 100
 
struct point
{
    point(int X = 0, int Y = 0) : x(X), y(Y) {}
    int x;
    int y;
};
 
struct _CHILD_WINDOW
{
    CRITICAL_SECTION cs; 
    char *str;
};
 
typedef _CHILD_WINDOW *CHILD_WINDOW;
 
int x,y;
int CURRENT_INDEX=0;
bool left_button=false;
bool right_button=false;
vector<vector<point> >_POINTS;
vector<HWND>all_hwnd;
 
HINSTANCE hInst;
BOOL CALLBACK CloseEnumProc(HWND,LPARAM);
 
HWND MDI_client,main;
 
TCHAR szTitle[MAX_LOADSTRING];
TCHAR szMainClass[MAX_LOADSTRING];
TCHAR szChildClass[MAX_LOADSTRING];
 
ATOM                MyMainRegisterClass(HINSTANCE hInstance);
ATOM                MyChildRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);
 
LRESULT CALLBACK MainProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ChildProc(HWND, UINT, WPARAM, LPARAM);
 
int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);
 
    // TODO: разместите код здесь.
    MSG msg;
    HACCEL hAccelTable;
 
    // Инициализация глобальных строк
    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadString(hInstance, IDC_LAB6, szMainClass, MAX_LOADSTRING);
    LoadString(hInstance, IDC_LAB6_CHILD,szChildClass, MAX_LOADSTRING);
 
 
    MyMainRegisterClass(hInstance);
    MyChildRegisterClass(hInstance);
 
    // Выполнить инициализацию приложения:
    if(!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }
 
    hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_LAB6));
 
    // Цикл основного сообщения:
    while(GetMessage(&msg, NULL, 0, 0))
    {
        if(!TranslateMDISysAccel(MDI_client,&msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
 
    return (int) msg.wParam;
}
 
 
 
//
//  ФУНКЦИЯ: MyRegisterClass()
//
//  НАЗНАЧЕНИЕ: регистрирует класс окна.
//
//  КОММЕНТАРИИ:
//
//    Эта функция и ее использование необходимы только в случае, если нужно, чтобы данный код
//    был совместим с системами Win32, не имеющими функции RegisterClassEx'
//    которая была добавлена в Windows 95. Вызов этой функции важен для того,
//    чтобы приложение получило "качественные" мелкие значки и установило связь
//    с ними.
//
ATOM MyMainRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;
 
    wcex.cbSize = sizeof(WNDCLASSEX);
 
    wcex.style          = CS_HREDRAW|CS_VREDRAW;
    wcex.lpfnWndProc    = MainProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_LAB6));
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCE(IDC_LAB6);
    wcex.lpszClassName  = szMainClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
 
    return RegisterClassEx(&wcex);
}
 
ATOM MyChildRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;
 
    wcex.cbSize = sizeof(WNDCLASSEX);
 
    wcex.style          = CS_HREDRAW|CS_VREDRAW|CS_OWNDC;
    wcex.lpfnWndProc    = ChildProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_LAB6));
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCE(IDC_LAB6);
    wcex.lpszClassName  = szChildClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
    return RegisterClassEx(&wcex);
}
 
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // Сохранить дескриптор экземпляра в глобальной переменной
 
   main = CreateWindowEx(WS_EX_TRANSPARENT,szMainClass,"Многооконный графический редактор",WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT,0,CW_USEDEFAULT,0,NULL,NULL,hInstance,NULL);
 
    int width=700;
    int height=500;
    MoveWindow(main,(GetSystemMetrics(SM_CXSCREEN)-width)/2,(GetSystemMetrics(SM_CYSCREEN)-height)/2,width,height,false);
 
   if (!main)
   {
      return FALSE;
   }
 
   ShowWindow(main,nCmdShow);
   UpdateWindow(main);
 
   return TRUE;
}
 
HWND CreateNewMDIChild(HWND client)
{
    MDICREATESTRUCT mcs;
    HWND file;
 
    mcs.szTitle = "Untitled";
    mcs.szClass = szChildClass;
    mcs.hOwner  = GetModuleHandle(NULL);
    mcs.x = CW_USEDEFAULT;
    mcs.y = CW_USEDEFAULT;
    mcs.cx=mcs.cy=300;
    mcs.style = MDIS_ALLCHILDSTYLES;
    file = (HWND)SendMessage(client,WM_MDICREATE,0,(LONG)&mcs);
    return file;
}
 
BOOL CALLBACK CloseEnumProc(HWND hwnd,LPARAM lParam)
{
    SendMessage(GetParent(hwnd),WM_MDIDESTROY,(WPARAM)hwnd,0);
    return true;
}
 
HANDLE mutex;
 
LRESULT CALLBACK MainProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;
    CHILD_WINDOW cw;
    HWND child;
    RECT rect;
    GetClientRect(hWnd,&rect);
 
    //child =(HWND)LOWORD(SendMessage(MDI_client,WM_MDIGETACTIVE,0,0));
    //if(IsWindow(child))SendMessage(child,WM_COMMAND,wParam,lParam);
 
    switch (message)
    {
    case WM_CREATE:
        mutex=CreateMutex(NULL,false,NULL);
        CLIENTCREATESTRUCT ccs;  
        ccs.hWindowMenu = GetSubMenu(GetMenu(hWnd),0);
        ccs.idFirstChild = 0; 
        MDI_client = CreateWindow("MDICLIENT","",
                                      WS_CHILD|WS_CLIPCHILDREN|WS_VSCROLL|WS_HSCROLL|WS_VISIBLE,
                                      0,0,0,0,hWnd,NULL,hInst,(LPSTR)&ccs);
        if (!MDI_client)
        {
            MessageBox(hWnd,"Невозможно создать окно администратора.","Ошибка",MB_OK);
            DestroyWindow(hWnd);
            break;
        }
        ShowWindow(MDI_client,SW_SHOW);
        MoveWindow(MDI_client,0,0,rect.right,rect.bottom,false);
    break;
    
    case WM_COMMAND:
        wmId    = LOWORD(wParam);
        wmEvent = HIWORD(wParam);
        switch (wmId)
        {
            case IDM_ABOUT:
                DialogBox(hInst,MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
            break;
 
            case IDM_INSERT_CHILD:
                {
                    child=CreateNewMDIChild(MDI_client);
 
                    if (!child)
                    {
                        MessageBox(hWnd,"Невозможно создать дочернее окно.","Ошибка",MB_OK);
                        DestroyWindow(child);
                        break;
                    }
                    //cw = (CHILD_WINDOW)malloc(sizeof(_CHILD_WINDOW));
                    //InitializeCriticalSection(&(cw->cs));
                    //cw->str="!\n";
                    //SetWindowLong(child,GWL_USERDATA,(LONG)cw);
                    ShowWindow(child,SW_SHOW);
                }
            break;
 
            case IDM_DELETE:
            {
                child = (HWND)SendMessage(MDI_client,WM_MDIGETACTIVE,0,0);
                if(child)SendMessage(child,WM_CLOSE,0,0);
            }
            break;
 
            case ID_CS:
                SendMessage(MDI_client,WM_MDICASCADE,0,0);
            break;
 
            case ID_HT:
                SendMessage(MDI_client,WM_MDITILE,0,0);
            break;
 
            case ID_CSALL:
                EnumChildWindows(MDI_client,&CloseEnumProc,0);
            break;
 
            case IDM_EXIT:
                DestroyWindow(hWnd);
            break;
 
            default:
                return DefWindowProc(MDI_client, message, wParam, lParam);
        }
 
        break;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        MoveWindow(MDI_client,0,0,rect.right,rect.bottom,false);
        EndPaint(hWnd, &ps);
    break;
    case WM_LBUTTONDOWN:
        left_button=true;
    break;
 
    case WM_LBUTTONUP:
        left_button=false;
        ReleaseCapture(); 
    break;
 
    case WM_DESTROY:
        PostQuitMessage(0);
    break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
 
HDC             _hdc; 
 
LRESULT CALLBACK ChildProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{   
    PAINTSTRUCT             ps;
    HDC                     hdc;
    CHILD_WINDOW            cw;     
 
    switch (message) 
    {
        case WM_CREATE:
            {
                _POINTS.push_back(vector<point>());
                all_hwnd.push_back(hWnd);
                CURRENT_INDEX=all_hwnd.size()-1;
            }
        break;
 
        case WM_MDIACTIVATE:
            {
                //cw = (CHILD_WINDOW)GetWindowLong(hWnd,GWL_USERDATA);
                //OutputDebugString(cw->str);
                int n=0;
                vector<HWND>::iterator it=all_hwnd.begin();
                for(;it!=all_hwnd.end();++it)
                {
                    if(*it==hWnd)CURRENT_INDEX=n;
                    n++;
                }
            }
        break;
 
        case WM_CLOSE:
            {
                int res=MessageBox(hWnd,"Вы уверены что хотите закрыть этот рисунок?","Предупреждение",MB_OKCANCEL);
                if(res==1)
                {
                    vector<HWND>::iterator it=all_hwnd.begin();
                    for(;it!=all_hwnd.end();++it)if(*it==hWnd)
                    {
                        all_hwnd.erase(it);
                        break;
                    }
                    DestroyWindow(hWnd);
                }
            }
        break;
 
        case WM_LBUTTONDOWN:
            WaitForSingleObject(mutex, INFINITE);
            _hdc=GetDC(hWnd);
            SetCapture(hWnd);
            SetCursor(LoadCursor(NULL,IDC_CROSS));
            ShowCursor(true);
            left_button=true;
            x = LOWORD(lParam);
            y = HIWORD(lParam);
            if(_POINTS[CURRENT_INDEX].size()==0)MoveToEx(_hdc,x,y,NULL);
            else
            {
                LineTo(_hdc,x,y);
                MoveToEx(_hdc,x,y,NULL);
            }
            _POINTS[CURRENT_INDEX].push_back(point(x,y));
            ReleaseMutex(mutex);
        break;
 
        case WM_LBUTTONUP:
            left_button=false;
            ReleaseCapture(); 
        break;
 
        case WM_MOUSEMOVE:
            //cw = (CHILD_WINDOW)GetWindowLong(hWnd,GWL_USERDATA);
            //EnterCriticalSection(&(cw->cs));
            WaitForSingleObject(mutex, INFINITE);
            if(left_button)
            {
                _hdc=GetDC(hWnd);
                SetCursor(LoadCursor(NULL,IDC_CROSS));
                ShowCursor(true);
                x = LOWORD(lParam);
                y = HIWORD(lParam);
                if(x>0 && y>0)
                {
                    LineTo(_hdc,x,y);
                    _POINTS[CURRENT_INDEX].push_back(point(x,y));
                }
            }
            ReleaseMutex(mutex);
            //LeaveCriticalSection(&(cw->cs));
        break;
 
        case WM_RBUTTONDOWN:
            _POINTS[CURRENT_INDEX].clear(); 
            InvalidateRect(hWnd,0,true);
        break;
 
        case WM_PAINT:
            {
                //cw = (CHILD_WINDOW)GetWindowLong(hWnd,GWL_USERDATA);
                //EnterCriticalSection(&(cw->cs));
                WaitForSingleObject(mutex,INFINITE);
 
                hdc = BeginPaint(hWnd,&ps);
                vector<point>::iterator it=_POINTS[CURRENT_INDEX].begin();
                if(_POINTS[CURRENT_INDEX].size()>0)MoveToEx(hdc,_POINTS[CURRENT_INDEX][0].x,_POINTS[CURRENT_INDEX][0].y,NULL);
                for(;it!=_POINTS[CURRENT_INDEX].end();++it)
                {
                    LineTo(hdc,it->x,it->y);    
                }
                EndPaint(hWnd,&ps);
                //LeaveCriticalSection(&(cw->cs));
                ReleaseMutex(mutex);
            }
        break;
 
        default:
          return DefMDIChildProc(hWnd, message, wParam, lParam);
    }
    return 0;
}
 
// Обработчик сообщений для окна "О программе".
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;
 
    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}
Вот ссылка на сырой проект:


antibot

Пробовал и критические секции и хранить уникальные данные для каждого HWND окна(с помощью setWindowLong)Вот исполняемый файл(.exe)


antibot

Спасибо, уже решил сам. Нужно было использовать функции setWindowLong,getWindowLong. Причем использовать для хранения данных исключительно для каждого окна. Это следовало уже из самого моего вопроса, но как то недодумался...