Рейтинговые книги
Читем онлайн Программирование на Visual C++. Архив рассылки - Алекс Jenter

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 129 130 131 132 133 134 135 136 137 ... 156

// Сохранить копию таблицы цветов.

// Сохранить маску.

for (every color in the color table) {

 if (color == rgbTransparent) color = white;

 else color = black;

}

// Подготовить приемник с помощью переноса маски.

StretchDIBits(hdcDest, lpDIB, SRCAND);

// (Да, там есть еще параметры)

// Теперь подготовим "зачерненный" источник для маскированного переноса.

for (every color in the color table) {

 if (color == white) // (мы его изменяли ранее)

  color = black;

 else color = original color from color table;

}

// Выведем приемник с эффектом прозрачности.

StretchDIBits(hdcDest, lpDIB, SRCPAINT); // (Да, там есть еще параметры)

// Восстановим первоначальную таблицу цветов.

Заметьте, что в данном способе требуется только одна копия растра – и для источника, и для маски прозрачности, так как используется преимущество в виде таблицы цветов. Однако остаются дополнительные расходы по преобразованию DIB в аппаратно-зависимый растр. 

ВОПРОС – ОТВЕТ 

Как обработать нажатие Enter в edit box'е?

Автор: Игорь Вартанов 

Начнем с того, что для обработки нажатия Enter необходимо, чтобы (в общем случае) окно редактирования ожидало этого нажатия (т.е. имело стиль ES_MULTILINE). В противном случае система выполнит трансляцию этого нажатия в нажатие кнопки родительского окна, имеющей в текущий момент стиль BS_DEFAULTPUSHBUTTON. Кстати, это довольно неплохая методика для диалога, содержащего единственное окно ввода и имеющего кнопку по-умолчанию OK. Если же диалог (или окно) имеет несколько окон ввода, и логика работы приложения подразумевает, что нажатие Enter означает окончание ввода в выбранном окне и перевод фокуса на следующее, то скорее всего вам подойдет нижеследующая методика.

Основной вариант

Демонстрационный проект EditDlg

WinAPI

ПРИМЕЧАНИЕ

Обратите внимание, окно редактирования должно иметь стиль ES_MULTILINE.

Основная идея состоит в подмене стандартной процедуры окна редактирования (т.н. subclassing) при инициализации окна диалога, и выполнение в новой процедуре обработки нажатия клавиши. В нашем примере при обнаружении нажатия Enter выполняется копирование текста окна в буфер текста и перевод фокуса на следующий контрол диалогового окна. Если же была нажата иная клавиша, выполняется вызов стандартной оконной процедуры для окон класса "edit".

#include <windows.h>

#include "resource.h"

WNDPROC oldEditProc = NULL;

LRESULT CALLBACK newEditProc(HWND hEdit, UINT msg, WPARAM wParam, LPARAM lParam) {

 switch(msg) {

 case WM_KEYDOWN:

  {

   if (VK_RETURN == wParam) {

    HWND hParent = GetParent(hEdit);

    SendMessage(hParent, msg, wParam, lParam);

    SetFocus(GetNextDlgTabItem(hParent, hEdit, FALSE));

    return 0; // запрет обработки по-умолчанию

   }

  }

  break;

 case WM_CHAR:

  if (VK_RETURN == wParam) return 0; // запрет обработки по-умолчанию

  break;

 }

 return CallWindowProc(oldEditProc, hEdit, msg, wParam, lParam);

}

BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) {

 static char m_edText[256] = "";

 switch (msg) {

 case WM_INITDIALOG:

  oldEditProc = (WNDPROC) SetWindowLong(

   GetDlgItem(hDlg, IDC_EDIT1), GWL_WNDPROC, (LONG)newEditProc);

  break;

 case WM_COMMAND:

  if (wParam == IDCANCEL) EndDialog(hDlg, 0);

  break;

 case WM_KEYDOWN:

  if (VK_RETURN == wParam)

   GetDlgItemText(hDlg, IDC_EDIT1, m_edText, 256);

  break;

 }

 return 0;

}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {

 DialogBox(hInstance, "MAINDLG", HWND_DESKTOP, (DLGPROC)DlgProc);

 return 0;

}

Обратите внимание на то, что обработчики сообщений при обнаружении нажатия Enter возвращают из оконной процедуры нуль. Это делается для того, чтобы сообщения не передавались обработчику по-умолчанию (и, следовательно, не выполнялось нажатие кнопки по-умолчанию).

MFC

ПРИМЕЧАНИЕ

Обратите внимание, окно редактирования должно иметь стиль ES_MULTILINE.

Для реализации поведения приложения, аналогичного только что описанному, необходимо создать класс, производный от CEdit, имеющий собственные обработчики сообщений WM_KEYDOWN и WM_CHAR (при создании класса и добавлении обработчиков используйте ClassWizard).

// .h-файл класса ////////////////////////////////////////////////

...

class CEnterEdit : public CEdit {

public:

 CEnterEdit();

public:

 virtual ~CEnterEdit();

protected:

 //{{AFX_MSG(CEnterEdit)

 afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);

 afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);

 //}}AFX_MSG

 DECLARE_MESSAGE_MAP()

};

// .cpp-файл класса //////////////////////////////////////////////

...

BEGIN_MESSAGE_MAP(CEnterEdit, CEdit)

 //{{AFX_MSG_MAP(CEnterEdit)

 ON_WM_KEYDOWN()

 ON_WM_CHAR()

 //}}AFX_MSG_MAP

END_MESSAGE_MAP()

void CEnterEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) {

 if (nChar == VK_RETURN) {

  // Предполагаем, что родительское окно эдит-бокса -

  // диалог класса CEditDlgDlg, который имеет буфер хранения

  // введенного текста m_edText типа CString.

  CEditDlgDlg* pDlg = (CEditDlgDlg*) GetParent();

  GetWindowText(pDlg->m_edText);

  pDlg->GetNextDlgTabItem(this)->SetFocus();

  return; // запрет обработки по-умолчанию

 }

 CEdit::OnKeyDown(nChar, nRepCnt, nFlags);

}

void CEnterEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) {

 if (nChar == VK_RETURN) return; // запрет обработки по-умолчанию

 CEdit::OnChar(nChar, nRepCnt, nFlags);

}

ПРИМЕЧАНИЕ

Подмена оконной процедуры – универсальный метод для получения необходимой функциональности. Если же есть возможность получить доступ к циклу сообщений, то можно воспользоваться альтернативной методикой – обработкой сообщения WM_KEYDOWN в самом цикле (см. далее – Альтернативный вариант).

Пример EditDlg демонстрирует обработку нажатия клавиши Enter. Он содержит два проекта – WinAPI и MFC.

Альтернативный вариант

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

Необходимо помнить, что цикл обработки сообщений модального диалога реализуется самой системой и недоступен для программиста. В этом случае остается единственное средство – подмена оконной процедуры окна редактирования, описанная выше (см. Основной вариант).

Детали реализации этого метода очень сильно зависят от постановки задачи, среды разработки и организации цикла обработки сообщений. Общая схема такова:

1. До выполнения DispacthMessage(&msg) необходимо проанализировать поле msg.message на приход сообщения WM_KEYDOWN.

2. Если получено сообщение WM_KEYDOWN, и поле msg.wParam содержит VK_RETURN, то выполнить вызов функции-диспетчера нажатия enter. При этом обычно необходимо избегать передачи полученного сообщения в функцию DispatchMessage(), чтобы не выполнялась обработка по-умолчанию.

3. Для всех иных сообщений выполнить стандартную обработку.

MFC

Для программ, использующих MFC, все необходимые проверки выполняются в методе PreTranslateMessage() класса приложения или окна.

BOOL CMyWinApp::PreTranslateMessage(MSG* pMsg) {

 if ((WM_KEYDOWN == pMsg->message) && (VK_RETURN  == pMsg->wParam)) {

  OnEnterPressed(); // вызов диспетчера нажатия Enter

  return TRUE; // запрет дальнейшей обработки

 }

 // стандартная обработка сообщения

 return CWinApp::PreTranslateMessage(pMsg);

}

WinAPI

Для приложений WinAPI реализация цикла обработки сообщений может выглядеть таким образом:

...

while (GetMessage(&msg, NULL, 0, 0)) {

 if ((WM_KEYDOWN == pMsg->message) && (VK_RETURN  == pMsg->wParam)) {

  OnEnterPressed(); // вызов диспетчера нажатия Enter

  continue; // запрет дальнейшей обработки

 }

 // стандартная обработка сообщения

 TranslateMessage(&msg);

 DispatchMessage(&msg);

}

...

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

1 ... 129 130 131 132 133 134 135 136 137 ... 156
На этой странице вы можете бесплатно читать книгу Программирование на Visual C++. Архив рассылки - Алекс Jenter бесплатно.
Похожие на Программирование на Visual C++. Архив рассылки - Алекс Jenter книги

Оставить комментарий