15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту


Как изменить курсор мышки для окна в MFC

В приложениях Windows, окно всегда создаётся на основе оконного класса. Оконный класс содержит несколько характеристик, на которых основывается создаваемое окно, вклучая и курсор мышки поумолчанию. В некоторых случаях, приложению необходимо изменить курсор, связанный с окном, которое оно создаёт. Данная статья описывает три метода, при помощи которых MFC приложение может отображать различные курсоры в различное время.

Ниже приведены некоторые ситуации, в которых MFC приложению необходимо менять курсор мышки:

  • Например, когда Вы создаёте текстовый редактор, то I-образный курсор больше подходит для ввода текста, нежели стрелка. Это влечёт замену курсора мышки на весь период работы приложения.

  • Например, когда производится длительная операция, такая как считывание или запись на диск. В данном случае пользователю желательно показать песочные часы. Это влечёт замену курсора мышки на ограниченный период времени.

Три метода

Давайте кратко рассмотрим три метода замены стандартного курсора мышки в окне:

  • Переопределяем функцию CWnd::OnSetCursor(). Вызываем API функцию SetCursor() для изменения курсора.

  • Регистрируем собственный класс окна с желаемым курсором мышки, переопределяем функцию CWnd::PreCreateWindow() и используем вновь-зарегистрированный класс для создания окна.

  • Чтобы показать стандартные песочные часы, приложение может вызвать CCmdTarget::BeginWaitCursor(), а затем CmdTarget::EndWaitCursor() чтобы обратно вернуть стандартный курсор. Эта схема работает только на протяжении одного сообщения. Если мышка будет сдвинута до вызова EndWaitCursor, то Windows пошлёт окну сообщение WM_SETCURSOR. Дефолтовый обработчик этого сообщения изменит курсор на тот, который зарегистрирован в классе. Поэтому необходимо переопределить CWnd::OnSetCursor() для этого окна, чтобы при изменении курсора на дефолтовый опять показывало песочные часы.

Пример кода, илюстрирующий все три метода

Следующий код, показывает три способа, как изменить курсор мышки оконного класса, наследованного от CView. m_ChangeCursor это переменна член класса CMyView, ей присвоен тип BOOL. Она показывает, надо ли показать другой тип курсора.

Первый метод

Изменяем курсор мышки для объекта CMyView путём переопределения функции CWnd::OnSetCursor(). Используем ClassWizard, чтобы в карте сообщений для сообщения WM_SETCURSOR добавить функцию CMyView::OnSetCursor(). В тело функции добавляем следующий код:

      BOOL CMyView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
      {
            if ( m_ChangeCursor )
              {
                  ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_WAIT));
                  return TRUE;
              }

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

Второй метод

При помощи функции AfxRegisterClass() или AfxRegisterWndClass() регистрируем собственный оконный класс, содержащий желаемый курсор мышки. Затем создаём окно вида, основанное на зарегистрированном оконном классе. Более подробнее о регистрации оконного класса в MFC, см. MFC Tech Note 1, "Window Class Registration."

      BOOL CMyView::PreCreateWindow(CREATESTRUCT& cs)
      {
          cs.lpszClass = AfxRegisterWndClass(
            CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW, // используем желаемые
                                                  // стили окна
            AfxGetApp()->LoadStandardCursor(IDC_WAIT),
            (HBRUSH) (COLOR_WINDOW + 1));         // кисть фона

          return CView::PreCreateWindow(cs)
      } 

Третий метод

Для изменения курсора мышки вызываем функции BeginWaitCursor() и EndWaitCursor().

ЗАМЕЧАНИЕ: CWinApp::DoWaitCursor(1) и CWinApp::DoWaitCursor(-1) работают аналогично BeginWaitCursor() и EndWaitCursor(), соответственно.

      void CMyView::PerformLengthyOperation()
      {
            BeginWaitCursor();  // или AfxGetApp()->DoWaitCursor(1)

            //...

            EndWaitCursor();    // или AfxGetApp()->DoWaitCursor(-1)
      } 

 

ЗАМЕЧАНИЕ: Если вызовы BeginWaitCursor() и EndWaitCursor() делаются не в том же самом обработчике, то необходимо переопределить OnSetCursor как показано ниже:

      BOOL CMyView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
      {
            if (m_ChangeCursor)
              {
                  RestoreWaitCursor();
                  return TRUE;
              }

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

В этом примере, m_ChangeCursor устанавливается в TRUE перед вызовом BeginWaitCursor(), и обратно в FALSE после вызова EndWaitCursor().