Winapi - Элемент управления (окно) "Матрица"

Задание

Написать собственный класс окна - "Матрица". Окно должно обладать следующими свойствами:

  1. клавиша Tab должна переключать фокус ввода на следующую ячейку;
  2. предоставлять возможность транспонирования и нахождения определителя матрицы;
  3. динамически изменять размеры матрицы.

Тестовая программа должна создать матрицу 4х4. При нажатии клавиши F1, транспонировать ее. При нажатии клавиши F2 - выводить на экран определитель матрицы, а при нажатии клавиши Escape, очищать матрицу.

Реализация

Скачать (download)

Содержание файла "MatrixEd.cpp" (тестовая программа):

/*
 * Square Matrix Editor testing program
 * (c) Slava Antonov, 2004
 */

#include 
#include 
#include "MatrixEd.h"


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


#define ID_CONTROL 1000

/* Идентификаторы горячих клавиш */
#define HK_PLUS 0
#define HK_MINUS 1
#define HK_F1 2
#define HK_F2 3


int** AllocItems(const int nSize);
void FreeItems(int** Items, const int nSize);


int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
  static char szAppName[] = "Matrix Editor";
  HWND        hwnd;
  MSG         msg;
  WNDCLASSEX  wndclass;

  wndclass.cbSize        = sizeof (wndclass);
  wndclass.style         = CS_HREDRAW | CS_VREDRAW;
  wndclass.lpfnWndProc   = WndProc;
  wndclass.cbClsExtra    = 0;
  wndclass.cbWndExtra    = 0;
  wndclass.hInstance     = hInstance;
  wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION);
  wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW);
  wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
  wndclass.lpszMenuName  = NULL;
  wndclass.lpszClassName = szAppName;
  wndclass.hIconSm       = LoadIcon (NULL, IDI_APPLICATION);

  RegisterClassEx (&wndclass);

  hwnd = CreateWindowEx(WS_EX_CONTROLPARENT | WS_EX_WINDOWEDGE,
      szAppName,
        // класс окна
      "Matrix Editor",
        // заголовок окна
      WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
        // стиль окна
      CW_USEDEFAULT,
      CW_USEDEFAULT,
      CW_USEDEFAULT,
      CW_USEDEFAULT,
      NULL,
      NULL,
      hInstance,
      NULL);

  ShowWindow (hwnd, iCmdShow) ;
  UpdateWindow (hwnd) ;

  while (GetMessage (&msg, NULL, 0, 0))
  {
    if (!IsDialogMessage(hwnd, &msg))
    {
      TranslateMessage (&msg);
      DispatchMessage (&msg);
    }
  }
  return msg.wParam;
} // WinMain()


LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
  static int cxClient, cyClient;
  static HWND hwndMatrix, hwndText;
  PAINTSTRUCT ps;
  HDC hdc;

  switch (iMsg)
  {
    case WM_CREATE:
      hwndText = CreateWindow("STATIC",
                     "Клавиши управления: +/-, Tab, Esc, F1, F2",
                     WS_VISIBLE | WS_CHILD,
                     10, 10, 300, 21,
                     hwnd,
                     NULL,
                     ((LPCREATESTRUCT) lParam)->hInstance,
                     NULL);

      hwndMatrix = CreateMatrix(((LPCREATESTRUCT) lParam)->hInstance,
                       hwnd,
                       0, 0, 0, 0,
                       0,
                       WS_CHILD | WS_VISIBLE | WS_TABSTOP,
                       0);
      SendMessage(hwndMatrix, MM_SETSIZE, 0, 4);
      
      RegisterHotKey(hwnd, HK_PLUS, 0, VK_ADD);
      RegisterHotKey(hwnd, HK_MINUS, 0, VK_SUBTRACT);
      RegisterHotKey(hwnd, HK_F1, 0, VK_F1);
      RegisterHotKey(hwnd, HK_F2, 0, VK_F2);
      return 0;  


    case WM_DESTROY:
      DestroyWindow(hwndMatrix);
      DestroyWindow(hwndText);
      PostQuitMessage(0);
      return 0; 


    case WM_COMMAND:
      switch(LOWORD(wParam))
      {
        case 2: /* ESCAPE */
          if (MessageBox(hwnd,
                  "Вы действительно хотите занулить все элементы матрицы?",
                  "Требудется подтверждение",
                  MB_OKCANCEL) == IDOK)
            SendMessage(hwndMatrix, MM_CLEAR, 0, 0);
          break;

        default:;
      }
      return 0;


    case WM_HOTKEY:
      switch(wParam)
      {
        case HK_PLUS:
          SendMessage(hwndMatrix,
              MM_SETSIZE,
              0,
              SendMessage(hwndMatrix, MM_GETSIZE, 0, 0) + 1);
          break;

        case HK_MINUS:
          {
            DWORD nSize = SendMessage(hwndMatrix, MM_GETSIZE, 0, 0);
            if (nSize > 0)
              SendMessage(hwndMatrix,
                  MM_SETSIZE,
                  0,
                 nSize - 1);
          }
          break;

        case HK_F1:
        /* Транспонирование матрицы */
          if(!SendMessage(hwndMatrix, MM_ISFILLED, 0, 0))
            MessageBox(hwnd,
                "Некоторые ячейки матрицы не заполнены",
                "Ошибка",
                MB_ICONERROR);
          else
            SendMessage(hwndMatrix, MM_TRANSPON, 0, 0);
          return 0;

        case HK_F2:
        /* Вычисление определителя матрицы */
          if(!SendMessage(hwndMatrix, MM_ISFILLED, 0, 0))
            MessageBox(hwnd,
                "Некоторые ячейки матрицы не заполнены",
                "Ошибка",
                MB_ICONERROR);
          else
          {
            int Det;
            SendMessage(hwndMatrix, MM_DETERM, 0, (LPARAM) &Det);
            char Buf[33];
            itoa(Det, Buf, 10);
            MessageBox(hwnd,
                Buf,
                "Определитель",
                MB_ICONINFORMATION);
          }
          return 0;

        defalult:
          break;
      }
      break;


    case WM_SIZE:
      cxClient = LOWORD(lParam);
      cyClient = HIWORD(lParam);
      MoveWindow(hwndMatrix, 10, 30, cxClient / 2, cyClient / 2, TRUE);
      return 0;
  }
  return DefWindowProc (hwnd, iMsg, wParam, lParam) ;
}

Содержание файла "MatrixEd.h"

/* Matrix Control
   (c) Slava Antonov, 2004 */


#ifndef _MATRIX_H
#define _MATRIX_H


#include 
#include 
#include "matrix.h"

const char* WNDCLASS_MATRIX = "Matrix";
const int MATRIX_ERROR = -1;
const char* PROPERTY_MATRIX = WNDCLASS_MATRIX;
const MMERR_EMPTYCELLS = -1;


/* Сообщения для окон класса "Матрица" */

const MM_SETSIZE = WM_USER + 1;
  /* Задает размер квадратной матрицы.
     Старые значения сохраняются, а новые
     забиваются нулями.
     lParam - новый размер
     result - MATRIX_ERROR в случае ошибки
              иначе, текущий размер матрицы */

const MM_GETSIZE = WM_USER + 3;
  /* Возвращает размер матрицы */

const MM_CLEAR = WM_USER + 4;
  /* Заменяет все элементы матрицы на нули */

const MM_GETITEMS = WM_USER + 2;
  /* Возвращает двумерный массив элементов матрицы
     lParam - указатель на двумерный массив N x N целых чисел
              где N - текущий размер матрицы
     Result - 0 если ошибок нет
              MMERR_EMPTYCELLS - если есть пустые ячейки */

const MM_ISFILLED = WM_USER + 5;
  /* Указаны ли все элементы матрицы
     Если результат - ноль, то указаны есть пустые ячейки */
   
const MM_TRANSPON = WM_USER + 6;
  /* Транспонирование матрицы */

const MM_DETERM = WM_USER + 7;
  /* Возвращает определитель матрицы */

const MM_GETITEM = WM_USER + 8;
  /* Возвращает элемент матрицы
     wParam - номер строки
     lParam - номер столбца
     Result - элемент */

const MM_SETITEM = WM_USER + 9;
  /* Задает элемент матрицы
     LOWORD(wParam) - номер строки
     HIWORD(wParam) - номер столбца
     lParam         - новое значение
     Result         - старое значение */

struct STRUCT_MATRIX
{
  DWORD cxClient, cyClient;
    /* размеры клиентской области окна */

  HWND hwnd;
  HINSTANCE hInstance;

  DWORD nSize;
    /* размер квадратной матрицы */

  HFONT hFont;
    /* шрифт используемый для отображения матрицы */

  HWND** hwndCells;
    /* дескрипторы окон ячеек матрицы */
};

typedef STRUCT_MATRIX* PSTRUCT_MATRIX;


/* Объявления фукнций */

LRESULT CALLBACK MatrixWndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
  /* оконная процедура */

void CreateCells(PSTRUCT_MATRIX pData, DWORD nSize);
  /* выделяет память под массив ячеек и 
     создает окна для ячеек */

void FreeHandles(PSTRUCT_MATRIX pData);
  /* уничтожение окон ячеек и освобождение памяти */

BOOL MoveCells(const PSTRUCT_MATRIX pData);
  /* Изменение размеров и позиций ячеек в соотвествии
     с указанными шириной и высотой окна */

int** AllocItems(const int nSize);
void FreeItems(int** Items, const int nSize);


/* Оконная процедура */

LRESULT CALLBACK MatrixWndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
  PSTRUCT_MATRIX pData;
  PAINTSTRUCT ps;
  HDC hdc;
  LRESULT lres;

  pData = (PSTRUCT_MATRIX) GetProp(hwnd, PROPERTY_MATRIX);
    // получаем указатель на стуктуру с данными окна

  switch (iMsg)
  {
    case WM_CREATE:
      pData = new STRUCT_MATRIX;
      pData->hwnd = hwnd;
      pData->hInstance = ((LPCREATESTRUCT) lParam)->hInstance;

      SetProp(hwnd, PROPERTY_MATRIX, (HANDLE) pData);
        /* запоминаем указатель на структуру с
           данными текущего окна */
      return 0;  


    case WM_DESTROY:
      FreeHandles(pData);
      RemoveProp(hwnd, PROPERTY_MATRIX);
      delete pData;
      return 0; 

    
    // говорим, что элемент управления
    // будет обрабатывать стрелки и символы
    case WM_GETDLGCODE:
      if (GetWindowLong(hwnd, GWL_STYLE) & ES_READONLY)
        return DLGC_WANTARROWS;
      else
        return DLGC_WANTARROWS | DLGC_WANTCHARS;

  
    case WM_SIZE:
      // пересчитываем положение и размеры
      // ячеек матрицы
      pData->cxClient = LOWORD(lParam);
      pData->cyClient = HIWORD(lParam);
      if (pData->nSize > 0)
        MoveCells(pData);
      return 0;


    case WM_SETFONT:
      pData->hFont = (HFONT) wParam;
      break;


    case WM_GETFONT:
      return (LRESULT) pData->hFont;


    case MM_CLEAR:
      if(pData->nSize > 0)
        for(int i = 0; i < pData->nSize; i++)
          for(int j = 0; j < pData->nSize; j++)
            SetWindowText(pData->hwndCells[i][j], "0");
      return 0;
    

    case MM_GETSIZE:
      return pData->nSize;


    /* Изменение размерности матрицы
       Старые значения сохраняются, новые приравниваюся 0 */
    case MM_SETSIZE:
      if((DWORD)lParam != pData->nSize)
      {
        lres = pData->nSize;
        int** OldItems = AllocItems(lres);
        SendMessage(hwnd, MM_GETITEMS, 0, (LPARAM) OldItems);

        FreeHandles(pData);
        CreateCells(pData, (DWORD) lParam);
          /* создает ячейки и запоминает новый размер */

        for(int i = 0; i < pData->nSize; i++)
          for(int j = 0; j < pData->nSize; j++)
            if ((i < lres) && (j < lres))
              SendMessage(hwnd,
                  MM_SETITEM,
                  MAKELONG(i, j),
                  OldItems[i][j]);
            else
              SendMessage(hwnd,
                  MM_SETITEM,
                  MAKELONG(i, j),
                  0);

        FreeItems(OldItems, lres);
        MoveCells(pData);
      } else
        lres = pData->nSize;
      return lres;
      

    case MM_GETITEM:
      {
        DWORD i = (DWORD) wParam;
        DWORD j = (DWORD) lParam;
        if((i < pData->nSize) || (j < pData->nSize))
        {
          char* a_ij;
          DWORD Len = GetWindowTextLength(pData->hwndCells[i][j]);
          a_ij = new char[Len + 1];
          GetWindowText(pData->hwndCells[i][j], a_ij, Len + 1);
          int Res = atoi(a_ij);
          delete []a_ij;
          return Res;
        } else
          return 0;
      }
    
    
    case MM_SETITEM:
      {
        DWORD i = LOWORD(wParam);
        DWORD j = HIWORD(wParam);

        if ((i < pData->nSize) && (j < pData->nSize))
        {
          char Buf[33];
          
          DWORD nLen = GetWindowTextLength(hwnd) + 1;
          char* pText = new char[nLen];
          GetWindowText(hwnd, pText, nLen);
          int OldValue = atoi(pText);
          delete[] pText;

          itoa(lParam, Buf, 10);
          SetWindowText(pData->hwndCells[i][j], Buf);

          return OldValue;
        } else
          return MATRIX_ERROR;
      }


    case MM_GETITEMS:
      if(pData->nSize > 0)
      {
        if(!SendMessage(hwnd, MM_ISFILLED, 0, 0)) return MMERR_EMPTYCELLS;
        int** Items = (int**) lParam;
        for(int i = 0; i < pData->nSize; i++)
          for(int j = 0; j < pData->nSize; j++)
            Items[i][j] = SendMessage(hwnd, MM_GETITEM, i, j);
      }
      return 0; 


    /* все ли ячейки заполнены? */
    case MM_ISFILLED:
      if(pData->nSize > 0)
      {
        for(int i = 0; i < pData->nSize; i++)
          for(int j = 0; j < pData->nSize; j++)
            if (GetWindowTextLength(pData->hwndCells[i][j]) == 0)
              return 0;
      }
      return !0;

    /* Транспонирование матрицы */
    case MM_TRANSPON:
      {
        if(pData->nSize == 0) return 0;

        char* a_ij;
        char* a_ji;
        for(int i = 0; i < pData->nSize; i++)
          for(int j = i + 1; j < pData->nSize; j++)
            {
              int nLen = GetWindowTextLength(pData->hwndCells[i][j]) + 1;
              a_ij = new char[nLen];
              GetWindowText(pData->hwndCells[i][j], a_ij, nLen);
         
              nLen = GetWindowTextLength(pData->hwndCells[j][i]) + 1;
              a_ji = new char[nLen];
              GetWindowText(pData->hwndCells[j][i], a_ji, nLen);

              if(strcmp(a_ij, a_ji) != 0)
              {
                SetWindowText(pData->hwndCells[i][j], a_ji);
                SetWindowText(pData->hwndCells[j][i], a_ij);
              }

              delete []a_ij;
              delete []a_ji;
            }
      }
      return 0;


    /* Вычисление определителя матрицы */
    case MM_DETERM:
      {
        if(pData->nSize <= 0) return 0;
        if(!SendMessage(hwnd, MM_ISFILLED, 0, 0)) return 0;

        CMatrix Matrix(pData->nSize, pData->nSize);
        for(DWORD i = 0; i < pData->nSize; i++)
          for(DWORD j = 0; j < pData->nSize; j++)
            Matrix[i][j] = SendMessage(hwnd, MM_GETITEM, i, j);
        *((int*) lParam) = Matrix.determinant();
      }
      return !0;
  }
  return DefWindowProc (hwnd, iMsg, wParam, lParam);
}


void CreateCells(PSTRUCT_MATRIX pData, DWORD nSize)
{
  if (nSize == pData->nSize) return;
  pData->nSize = nSize;
  if (!nSize) return;
  pData->hwndCells = new HWND*[nSize];
  for (int i = 0; i < nSize; i++)
  {
    pData->hwndCells[i] = new HWND[nSize];
    for(int j = 0; j < nSize; j++)
      pData->hwndCells[i][j] = CreateWindowEx(0,
          "EDIT",
          NULL,
          WS_VISIBLE | WS_CHILD | WS_TABSTOP | ES_NUMBER | ES_CENTER,
          0,
          0,
          0,
          0,
          pData->hwnd,
          (HMENU) (i * nSize + j),
          pData->hInstance,
          0);
  }
}


void FreeHandles(PSTRUCT_MATRIX pData)
{
  if(!pData->nSize) return;
  for(int i = 0; i < pData->nSize; i++)
  {
    for(int j = 0; j < pData->nSize; j++)
      DestroyWindow(pData->hwndCells[i][j]);
    delete []pData->hwndCells[i];
  }
  delete []pData->hwndCells;
  pData->hwndCells = NULL;
}


BOOL MoveCells(const PSTRUCT_MATRIX pData)
{
  if (pData->nSize != 0)
  {
    int Space = 1; /* размер зазора между ячейками */
    int CellWidth = (pData->cxClient - (pData->nSize-1) * Space) / pData->nSize;
    int CellHeight = (pData->cyClient - (pData->nSize-1) * Space) / pData->nSize;
    for (int i = 0; i < pData->nSize; i++)
      for(int j = 0; j < pData->nSize; j++)
        MoveWindow(pData->hwndCells[i][j],
            j * CellWidth + j * Space, i * CellHeight + i * Space,
            CellWidth, CellHeight,
            TRUE);
  }
  return TRUE;
}


int** AllocItems(const int nSize)
{
  if(nSize <= 0) return NULL;

  int** Items = new int*[nSize];
  for (int i = 0; i < nSize; i++)
    Items[i] = new int[nSize];
  return Items;
}


void FreeItems(int** Items, const int nSize)
{
  if((!Items) || (nSize <= 0)) return;

  for (int i = 0; i < nSize; i++)
    delete []Items[i];
  delete []Items;
}


HWND CreateMatrix(HINSTANCE hInstance, HWND hwndParent,
         int x, int y, int width, int height, unsigned id,
         DWORD fStyle, DWORD fExStyle)
{
  WNDCLASSEX  wndclass;

  wndclass.cbSize        = sizeof(wndclass);
  wndclass.style         = CS_HREDRAW | CS_VREDRAW;
  wndclass.lpfnWndProc   = MatrixWndProc;
  wndclass.cbClsExtra    = 0 ;
  wndclass.cbWndExtra    = 0 ;
  wndclass.hInstance     = hInstance;
  wndclass.hIcon         = 0;
  wndclass.hCursor       = NULL;
  wndclass.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1) ;
  wndclass.lpszMenuName  = NULL ;
  wndclass.lpszClassName = WNDCLASS_MATRIX;
  wndclass.hIconSm       = 0;

  RegisterClassEx (&wndclass);

  HWND hwnd = CreateWindowEx(fExStyle | WS_EX_CONTROLPARENT,
                             WNDCLASS_MATRIX,
                             "",
                             fStyle | WS_CLIPCHILDREN,
                             x, y,
                             width, height,
                             hwndParent,
                             (HMENU) id,
                             hInstance,
                             NULL);
  return hwnd;
}

#endif
Слава Антонов © 2002 — August 13, 2008
Индекс цитирования 197-577-902 ICQ-статус
Hosted by uCoz