- •Управление курсором при редактировании текста
- •Задание 3. Реализация процесса управления курсором при редактировании
- •Подведение итогов
- •Глава 10. Интерфейс графических устройств
- •Контексты устройств и объекты gdi
- •Объекты контекста устройства и выбор инструментов рисования
- •Идентификаторы стандартных инструментов рисования
- •Создание инструментов рисования
- •Некоторые стили пера
- •Значения, передаваемые в макрос rgb() для генерации стандартных чистых цветов vga
- •Режим отображения
- •Установка графических атрибутов
Задание 3. Реализация процесса управления курсором при редактировании
С целью получения отображения мигающего курсора при вводе текста можно выполнить модификацию программы Echo Для управления курсором в программе нужно определить несколько новых функций обработки сообщений. Выполните такие действия.
Откройте проект Echo, если вы закрыли его после выполнения задание 2. Для этого выполните команду FileOpenProject… в Developer Studio.
В класс CEchoView добавьте переменные-члены: m_CaretPos для хранения текущей позиции курсора, m_XCaret и m_YCaret для его ширины и высоты. Добавление выполните с помощью команды AddAdd Variable… контекстного меню для класса CEchoView. В окне Add Member Variable Wizard введите тип переменной POINT и ее имя m_CaretPos и нажмите кнопку Finish. Повторите вызов мастера добавления переменных для инкапсуляции в класс переменных m_XCaret и m_YCaret типа int. В файл EchoView.h интерфейса класса представления CEchoView добавятся следующие объявления:
class CEchoView : public CView { protected: // create from serialization only CEchoView(); DECLARE_DYNCREATE(CEchoView) // Attributes public: CEchoDoc* GetDocument() const; // Overrides public: virtual void OnDraw(CDC* pDC); //overridden to draw this view virtual BOOL PreCreateWindow(CREATESTRUCT& cs); public: virtual ~CEchoView(); virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; // Generated message map functions protected: DECLARE_MESSAGE_MAP() public: afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); afx_msg void OnEditClear(); POINT m_CaretPos; int m_XCaret; int m_YCaret; };
Одновременно с добавлением переменных-членов класса CEchoView происходит их инициализация в конструкторе. Если задать нулевые значения этим переменным, то курсор первоначально появится в левом верхнем углу окна представления. Для исключения синтаксических ошибок измените список инициализации, удалив из него инициализацию структуры m_CaretPos. Поля структуры m_CaretPos проинициализируйте в теле конструктора с помощью операции присваивания. В результате вы получите такой код:
CEchoView::CEchoView() : m_XCaret(0) , m_YCaret(0) { // TODO: add construction code here m_CaretPos.x = m_CaretPos.y = 0; }
Добавьте обработчик сообщения WM_CREATE для определения параметров инициализации окна перед его отображением. В окне Properties класса CEchoView разверните список сообщений (кнопка Messages), выберите сообщение WM_CREATE и выполните. команду <Add> OnCreate. Вы получите объявление функции CEchoView::OnCreate() в файле интерфейса класса CEchoView, определение функции в файле его реализации и соответствующие макрос ON_WM_CREATE() в карте сообщения класса представления.
Вычислите ширину и высоту курсора, используя метрики текста. Получить метрику текста можно в объекте контекста устройства с помощью функции CDC::GetTextMetrtics(). Требуемые ширину и высоту можно определить с помощью полей tmAveCharWidth, tmHeight и tmExternalLeading структуры TEXTMETRIC. Для выполнения описанных вычислений добавьте в функцию CEchoView::OnCreate() следующий код, который представлен далее полужирным шрифтом:
int CEchoView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; // TODO: Add your specialized creation code here CClientDC ClientDC(this); TEXTMETRIC TM; ClientDC.GetTextMetrics(&TM); m_XCaret = TM.tmAveCharWidth / 3; m_YCaret = TM.tmHeight + TM.tmExternalLeading; return 0; }
Добавьте обработчик сообщения WM_SETFOCUS для создания курсора и установки его в указанную позицию. Для этого в списке сообщений класса CEchoView выберите сообщение WM_ SETFOCUS и с помощью команды. <Add> OnSetFocus добавьте в код функцию и макрос обработки сообщения ON_WM_SETFOCUS().
В функцию CEchoView::OnSetFocus() добавьте код, который создает курсор указанного размера, вызывая функцию CWnd::CreateSolidCaret(), устанавливает его в левый верхний угол окна, используя функцию CWnd::SetCaretPos(), отображает его, вызывая функцию CWnd::ShowCaret(). Добавленный код представлен полужирным шрифтом.
void CEchoView::OnSetFocus(CWnd* pOldWnd) { CView::OnSetFocus(pOldWnd); // TODO: Add your message handler code here CreateSolidCaret(m_XCaret, m_YCaret); SetCaretPos(m_CaretPos); ShowCaret(); }
Добавьте обработчик сообщения WM_ KILLFOCUS для удаления курсора в случае потери окном фокуса ввода. Для этого в окне Properties класса CEchoView выберите сообщение WM_ KILLFOCUS и выполните команду <Add> OnKillFocus. После выполнения этих операций в карту сообщения добавляется макрос ON_WM_KILLFOCUS(), в файл EchoView.h — объявление функции, ее шаблон — в файл реализации EchoView.cpp
В функцию CEchoView::OnKillFocus() необходимо добавить вызов функции ::DestroyCaret() для удаления курсора всякий раз, когда окно теряет фокус ввода.
void CEchoView::OnKillFocus(CWnd* pNewWnd) { CView::OnKillFocus(pNewWnd); // TODO: Add your message handler code here ::DestroyCaret(); }
Для управления курсором необходимо модифицировать функцию CEchoView::OnChar(). В ее код нужно включить операторы, обеспечивающие добавление символа в конец строки текста, скрытие курсора, отображение текста, определения новой длины строки и позиции курсора, установку курсора в эту позицию и отображение его. Добавьте операторы, выделенные полужирным шрифтом, в функцию CEchoView::OnChar() в файл EchoView.cpp:
void CEchoView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { // TODO: Add your message handler code here and/or call default if (nChar < 32) { ::MessageBeep(MB_OK);//звонок return; //конец работы функции } //демонстрация ввода символов при нажитии управляющих клавиш CEchoDoc* pDoc = GetDocument(); //PDoc->m_TextLine.AppendChar(nChar); CString str; //альтернативные AppendChar() операторы str.Format("%c",nChar); pDoc->m_TextLine +=str; //nChar; //operator is ambiguous CClientDC ClientDC(this); ClientDC.SetTextColor(::GetSysColor(COLOR_WINDOWTEXT)); ClientDC.SetBkMode(TRANSPARENT); HideCaret(); ClientDC.TextOut(0, 0, pDoc->m_TextLine); CSize Size = ClientDC.GetTextExtent (pDoc->m_TextLine, pDoc->m_TextLine.GetLength()); m_CaretPos.x = Size.cx; SetCaretPos(m_CaretPos); ShowCaret(); //pDoc->UpdateAllViews(NULL);//альтернативное отображение строки CView::OnChar(nChar, nRepCnt, nFlags); }
Обработчик командного сообщения, вызванного командой меню EditClear, удаляет текст из окна представления. После удаления текста курсор должен оказаться в верхнем левом углу окна представления. Для реализации этого действия добавьте следующий код в функцию CEchoView::OnEditClear():
void CEchoView::OnEditClear() { // TODO: Add your command handler code here CEchoDoc* pDoc = GetDocument(); pDoc->m_TextLine.Empty(); pDoc->UpdateAllViews(NULL); m_CaretPos.x = 0; SetCaretPos(m_CaretPos); }
В заключение откройте файл Echo.cpp и добавьте вызов функции SetWindowText() класса CWnd в функцию InitInstance() класса CEchoApp с целью изменения заголовка главного окна.
BOOL CEchoApp::InitInstance() { CWinApp::InitInstance(); // операторы инициализации не показаны // The one and only window has been initialized, so show and //update it m_pMainWnd->ShowWindow(SW_SHOW); m_pMainWnd->UpdateWindow(); // call DragAcceptFiles only if there's a suffix // In an SDI app, this should occur after ProcessShellCommand m_pMainWnd->SetWindowText("Echo"); return TRUE; }
Теперь программу Echo можно скомпилировать и выполнить. Окно программы с курсором показано на рис. 9.7.
Рис. 9.7. Окно программы Echo с курсором в конце строки
При тестировании программы Echo вы можете отображать символы в окне программы, нажимая символьные клавиши. Вы заметили, что при нажатии клавиши Enter курсор не переводится на новую строку. Удаление символов не происходит, если вы нажимаете клавишу Backspace. Предлагаем вам самостоятельно реализовать эти операции.
