Назад | Начало урока |
Содержание

День 4 (продолжение 2)

  • Фиксация формы указателя мыши
  • Резюме
  • Вопросы и ответы
  • Вопросы и упражнения

    Вверх

    Фиксация формы указателя мыши

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

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

    Выполните пошаговые инструкции :

    1. Добавить новую переменную к классу CMouseDlg, так же как вы добавляли переменные, хранящие координаты предыдущего положения указателя мыши. Имя переменной - m_bCursor, тип ее BOOL и private
    2. Инициализируйте эту переменную как показано в функции OnInitDialog в следующем листинге :

      //инициализировать курсор в виде стрелки

      m_bCursor = FALSE;

      Листинг 4.5 Функия OnInitDialog


      BOOL CMousDlg::OnInitDialog
      {
      CDialog::OnInitDialog();
      //Добавить пункт меню "About ... " к системному меню.
      //IDM_ABOUTBOX должен быть среди системных команд.
      ASSERT(IDB_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
      ASSERT(IDB_ABOUTBOX < 0xF000);
      CMenu* pSysMenu = GetSistemMenu(FALSE);//
      if(pSysMenu != NULL) //пустой указатель
      {
      CString strAboutMenu;
      strAboutMenu.LoadString(IDS_ABOUTBOX);
      if(!strAboutMenu.IsEmpty())
      {
      pSysMenu->AppendMenu(MF_SEPARATOR);
      pSysMenu->AppendMenu(MF_STRING,IDM_ABOUTBOX,strAboutMenu);
      }
      }
      //установить пиктограмму для этого диалога
      //Каркас делает это автоматически,
      //когда основное окно приложения не диалог

      SetIcon(m_hIcon,TRUE);//установить большой значек
      SetIcon(m_hIcon,FALSE);//установить маленький значек

      //инициализировать курсор в виде стрелки

      m_bCursor = FALSE;

      return TRUE;

      }


    3. Измените функцию OnKeyDown так, чтобы флагу m_bCursor было присвоено значение true,после того как форма указателя мыши изменилась.

      Листинг 4.6 Функция OnKeyDown


      void CMouseDlg::OnKeyDown(UINT nChar,UINT nRepCnt,UINT nFlags)
      {
      char cChar; //
      HCURSOR hCursor = 0;
      HCURSOR hPrevCursor = 0;

      cChar = char(nChar);

      if(cChar == 'A')

      hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);

      if(cChar == 'B')
      hCursor = AfxGetApp()->LoadStandardCursor(IDC_IBEAM);

      if(cChar == 'C')

      hCursor = AfxGetApp()->LoadStandardCursor(IDC_WAIT);

      if(cChar == 'X')
      {
      hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
      m_bCursor(TRUE);
      hPrevCursor = SetCursor(hCursor);
      if(hPrevCursor)
      DestroyCursor(hPrevCursor);

      OnOK();

      }

      else
      {

      if((hCursor)
      {
      hPrevCursor = SetCursor(hCursor);
      m_bCursor = TRUE;
      if(hPrevCursor)
      DestroyCursor(hPrevCursor);
      }
      }

      CDialog::OnKeyDown(nChar,nRepCnt,nFlags)

      }


    4. На вкладке Properties в режиме Message к объекту диалогового окна приложения добавьте функцию, обрабатывающую сообщение WM_SETCURSOR. Отредактируйте только что созданную функцию OnSetCursor добавив код указанный ниже

    Листинг 4.7


    BOOL CMouseDlg:: OnSetCursor(CWnd pWnd,UINT nHitTest,UINT message)
    {
    if(m_bCursor)
    return TRUE;

    return CDialog::OnSetCursor(pWnd,nHitTest,message);
    }

    Необходимо чтобы функция OnSetCursor() всегда возвращала значение TRUE или как то иначе вызывала основную функцию. Основная функция (АВ:имеется в виду функция OnKeyDown?) изменяет указатель мыши и ее не следует вызывать при запуске приложения.Поэтому переменной следует присвоить значение FALSE (АВ:в функции OnInitDialog)-благодаря чему до тех пор, пока пользователь не нажмет одну из клавиш, с помощью которых меняется форма указателей мыши, будет выполняться функция OnSetCursor, заданная по умолчанию.

    (АВ:Как видим как то иначе вызывать основную функцию мы не стали, а просто изменили код функции OnSetCursor, которая теперь всегда возвращает TRUE).

    После того как пользователь изменил форму указателя мыши, требуется обойти обработку по умолчанию и возвратить значение TRUE.(АВ:это и сделано в измененной нами функции OnSetCursor).Это позволит пользователю рисовать любым выбранным им указателем мыши, включая даже песочные часы.

    АВ:
    Сначала объявляем переменную m_bCursor типа BOOL,
    затем в функции OnInitDialog присваиваем ей значение FALSE.
    Затем в функции OnKeyDown в случаях,когда выбраны клавиши 'A', 'B' или 'C' вызывается функция SetCursor, которой передается дескриптор нового курсора,и одновременно переменной m_bCursor присваивается значение TRUE:

    hPrevCursor = SetCursor(hCursor);
    m_bCursor = TRUE;

    Это сделано затем.что функция OnSetCursor нами немного переделана таким образом, что если переменная m_bCursor имеет значение не ноль (а значит единица) ,то функция возвратит TRUE:

    BOOL CMouseDlg:: OnSetCursor(CWnd pWnd,UINT nHitTest,UINT message)
    {
    if(m_bCursor)
    return TRUE;

    return CDialog::OnSetCursor(pWnd,nHitTest,message);
    }

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

    При возвращении нашей функцией OnSetCursor значения TRUE без вызова функции OnSetCursor заданной по умолчанию, сохраняется тот курсор который имеется на экране в данный момент. А функция OnSetCursor вызывается постоянно с определенной частотой при перемещении курсора по экрану, так как курсор при этом постоянно надо перерисовывать, а благодаря именно этой функции система перерисовывает курсор заданный по умолчанию.

    Вверх
    Резюме
    Вы узнали :

  • как можно перехватывать сообщения о событиях мыши, и в зависимости от этих событий выполнять некоторые действия. Например используя события мыши вы рисуете фигуры в окне.
  • Вы научились так же перехватывать события клавиатуры,и определять какая клавиша была нажата.
  • Нажатие определенных клавиш вы связали с некоторыми действиями. Например при нажатии клавиши 'A' меняется форма курсора у мыши, при нажатии клавиши 'B' -форма курсора вновь меняется.
  • Перехватывая события клавиатуры можно запускать приложения.
  • Вам довелось познакомиться с принципами построения изображения в приложениях использующих MFC.
  • Затем создавая собственный код вы научились нужным образом корректировать поведение приложения.

    Вверх

    Вопросы и ответы
    1. Как изменить тип рисуемой линии? Необходимо нарисовать более толстую линию и изменить ее цвет.

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

      //получить контекст устройства
      CClientDC dc(this);

      //создать новое перо
      CPen lpen(PS_SOLID,16,RGB(255,0,0));

      //использовать новое перо
      dc.SelectObject(&lpen);

      //провести линию от предыдущей точки до текущей точки
      dc.MoveTo(m_iPrevX,m_iPrevY);
      dc.LineTo(point.x,point.y);

    2. Как определить исходя из полученного сообщения WM_KEYDOWN,была ли при этом так же нажата клавиша Shift или Ctrl ?

      Следует вызвать другую функцию - ::GetKeyState с ключом конкретной клавиши. Эта функция позволяет определить была ли нажата указанная вами клавиша. Если значение возвращаемое функцией ::GetKeyState отрицательно, то интересующая клавиши нажата.В противном случае клавиша не нажата. Например чтобы определить была ли нажата клавиша Shift, можно воспользоваться следующим кодом:

      if(::GetKeyState(VK_SHIFT)<0)
      MessageBox("Shift key is down");

      В Windows для всех специальных клавиш определены виртуальные ключи. Можно воспользоваться этими виртуальными ключами в функции ::GetKeyState или передать их функции OnKeyDown в качестве аргумента nChar. Список виртуальных ключей находится в документации Visual C++.

    Вверх
    Вопросы
    1. С какими сообщениями мыши можно связать функции?
    2. Предположим вы обрабатываете сообщение WM_ONMOUSEMOVE. Как определить была ли нажата левая кнопка мыши?
    3. Как предотвратить восстановление принятой по умолчанию формы указателя мыши после того,как его форма была изменена?
  • Ответы

    Упражнения
    1. Измените графическое приложение так, чтобы при нажатой левой кнопке мыши цвет рисуемого объекта был красным, а при нажатой правой - голубым.
    2. Усовершенствуйте функцию OnKeyDown, добавив в нее следующие стандартные указатели мыши:
      • IDC_CROSS
      • IDC_UPARROW
      • IDC_SIZEALL
      • IDC_SIZENWSE
      • IDC_SIZENESW
      • IDC_SIZEWE
      • IDC_SIZENS
      • IDC_NO
      • IDC_APPSTARTING
      • IDC_HELP
  • Ответы
  • Заметки

    Назад | Начало урока | Вверх |
    Содержание

    Hosted by uCoz