logo
Конспект по ООПиП ч

17. Использование элементов типа переключатель Статические поля (класс static). Окна редактирования Edit Box. Методы класса cEdit.

Можно так организовать программу, что по умолчанию будет выбран один из переключателей. Для выбора одного из переключателей в группе диалогового окна необходимо добавить следующий текст в функцию C<Имя>Dialog::0nInitDialog():

m_radio = 1; UpdateData(FALSE);

Членом-переменной является m_radio, с которым связана группа переключателей. Она (переменная) представляет собой индекс выбранного переключателя в этой группе элементов управления (как всегда, индекс начинается с 0). Значение индекса 1 соответствует второму переключателю в группе. Вызов функции UpdateData() в этом фрагменте обновляет содержимое элементов управления диалогового окна соответственно состоянию связанных с ними переменных-членов. Аргумент функции UpdateData() указывает направление передачи данных: UpdateData(TRUE) обновило бы содержимое переменных соответственно элементам управления, т.е. переписало бы в m_radio индекс выбранного в группе переключателя. В отличие от списка группа переключателей доступна и после того, как диалоговое окно убрано с экрана. Так что вам не придется добавлять что-либо в функции ОnОК() и OnCanceI(). Вместо этого у вас будет другая проблема – как преобразовать целое значение индекса в строковое выражение, которое нужно будет добавить в "хвост" текста сообщения в переменную msg. Существует множество ее решений, включая функцию-член Format() класса CString, но в данном случае можно поступить гораздо проще – использовать оператор switch, поскольку индекс может принимать лишь ограниченное множество значений. В конец текста функции C<Имя>App::InitInstance(), перед вызовом AfxMessageBox(), добавьте несколько строк, представленных в листинге.

Строки, которые следует включить в функцию C<Имя>App::InitInstance():

msg += "\г\п";

msg += "Radio Selection: ";

switch (dig.m_radio) { case 0: msg += "O"; break;

case 1: msg += "1"; break;

case 2: msg += "2"; break;

default: msg += "none"; break;

}

Первая из новых строк добавляет в сообщение два специальных символа – перевод каретки \r и перевод строки \n, которые в совокупности представляют маркер конца строки Windows. В результате дальнейшая часть сообщения msg начнется с новой строки. Флажки-переключатели. Флажки (check boxes) представляют собой маленькие квадратные окна с размещенным обычно справа от окна текстом (если при создании кнопки используется стиль BS_LEFTTEXT, то текст окажется слева). Флажки, как правило, действуют как двухпозиционные переключатели: один щелчок вызывает появление контрольной метки (состояние “включено”); другой щелчок приводит к исчезновению этой метки (состояние “выключено”). В приложениях флажки обычно объединяются, что дает пользователю возможность установить опции. Двумя наиболее используемыми стилями для флажков являются BS_CHECKBOX и BS_AUTOCHECKBOX. При использовании стиля BS_CHECKBOX приложение само должно устанавливать контрольную метку, посылая сообщение BM_SETCHECK. При стиле BS_AUTOCHECKBOX флажок самостоятельно включает и выключает контрольную метку, и оконная процедура родительского окна может игнорировать сообщения WM_COMMAND. Двумя другими стилями флажков являются BS_3STATE и BS_AUTO3STATE. Как показывают их имена, эти стили могут отображать третье состояние – серый цвет внутри окна флажка. Серый цвет показывает пользователю, что его выбор неопределен или не имеет отношения к делу. В этом случае флажок не может быть включен – т.е. он запрещает какой-либо выбор в данный момент. Однако флажок продолжает посылать сообщения родительскому окну, если щелкать на нем мышью. Радио-переключатели. Радио-переключатели (radio buttons, радио-кнопки) похожи на флажки, но их форма не квадратная, а круглая. Жирная точка внутри флажка показывает, что переключатель отмечен. Радио-кнопка может иметь стиль окна BS_RADIOBUTTON или BS_AUTORADIOBUTTON, но последний используется только в окнах диалога. В окнах диалога группы радио-переключателей, как правило, используются для индикации нескольких взаимоисключающих опций. В отличие от флажков, если повторно щелкнуть на радио-кнопке, то ее состояние не изменится.

Статическое окно управления - это окно, создаваемое на базе класса CStatic. Статические окна нельзя использовать для управления работой приложения: они не воспринимают щелчки мыши и не обрабатывают сообщения от клавиатуры, не посылает родительскому окну сообщение WM_COMMAND. Обычно этот орган управления используется для оформления внешнего вида диалоговых панелей или окон приложения. Все сообщения от мыши через “прозрачное” окно статического дочернего окна попадают в родительское окно. Рассмотрим некоторые стили статического окна. Статический класс окон включает в себя три стиля текста – SS_LEFT, SS_RIGHT и SS_CENTER. Они предназначены для выравнивания текста соответственно по левому краю, правому краю и центру. Текст задается в параметре текста окна функции SetWindowText.

Класс CEdit обеспечивает функционирование элемента управления «окно редактирования» (Edit box). Окно редактирования – это окно, в котором пользователь может вводить и редактировать текст. CEdit наследует методы от CWnd. Чтобы установить или получить текст из окна CEdit, можно пользоваться методами CWnd SetWindowText и GetWindowText. Даже в случае многострочного окна. А также, если окно многострочное, получать или устанавливать часть текста путем вызова методов GetLine, SetSel, GetSel, ReplaceSel. Если хотите обрабатывать уведомляющие сообщения Windows, посылаемые окном редактирования диалоговому окну, нужно добавить обработчики сообщений в класс диалога.

Список возможных сообщений от CEdit:

EN_CHANGE содержимое окна будет меняться. Так же как и EN_UPDATE сообщение посылается после того, как Windows обновит экран. EN_ERRSPACE – поле редактирования не имеет достаточно памяти. EN_HSCROLL – на горизонтальной полосе прокрутки был щелчок мышью. Родительское окно извещается прежде, чем экран обновится. EN_KILLFOCUS – окно редактирования потеряло фокус ввода. EN_MAXTEXT – текущая вставка превысила заданное число символов для окна редактирования и будет урезана. Также посылается, когда окно редактирования не имеет стиля ES_AUTOHSCROLL и число символов, которое должно быть вставлено превысит ширину окна. Также посылается, когда окно не имеет стиля ES_AUTOVSCROLL, и общее число строк будет превышать высоту окна редактирования. EN_SETFOCUS – посылается, когда окно редактирования получает входной фокус. EN_UPDATE – содержимое окна изменилось. Посылается после того, как окно отформатировало текст, но перед тем, как изобразить его на экране, так что размер окна может быть изменен, если необходимо. EN_VSCROLL – на вертикальной полосе прокрутки был щелчок мышью. Родительское окно извещается прежде, чем экран изменится. Если вы создаете объект CEdit внутри диалогового окна, он разрушается автоматически, когда пользователь закроет окно диалога.

Управляющие окна редактирования хранят текст в области памяти программы (в адресном пространстве программы). Содержимое управляющих полей редактирования ограничено примерно 32 килобайтами. Родительские окна также могут посылать окнам редактирования сообщения. Специфических сообщений, которые родительское окно может послать окну редактирования, достаточно много. Рассмотрим наиболее часто употребляемые:

WM_CUT - для удаления с пересылкой в буфер обмена; WM_COPY - копирования в буфер обмена; WM_CLEAR - очищения выделенной части текста из окна редактирования; WM_PASTE - для вставки текста из буфера обмена в окно редактирования; EM_GETSEL - для получения начальной и конечной позиции текущего выделения текста; EM_SETSEL - для выделения некоторого участка текста; EM_REPLACESEL - для замены текущего выделенного текста другим текстом; EM_GETLINECOUNT - для получения число строк многострочного редактора; EM_LINEINDEX - для получения смещения от начала буфера до некоторой строки; EM_LINELENGTH - для получения длины некоторой строки; EM_GETLINE - для копирования некоторой строки в буфер программы.

Некоторые методы класса CEdit.

Окна редактирования могут работать в режимах однострочного и многострочного редакторов. Приведем сначала методы, общие для обоих режимов, а затем методы для многострочного редактора.

1. Методы для получения первой и последней позиции выделенного фрагмента текста: DWORD GetSel() const;

void GetSel(int& nStartChar, int& nEndChar) const;

Для значения типа DWORD младшее слово содержит позицию первого, старшее - последнего символа.

2. Методы для установки нового выделения текста, задаваемого первым и последним выделенный символ:

void SetSel(DWORD dwSelection, BOOL bNoScroll=FALSE); или

void SetSel(int nStartChar, int nEndChar, BOOL bNoScroll=FALSE);

Значение FALSE параметра bNoScroll должно отключать перемещение курсора в область видимости.

3. Метод для замены выделенного фрагмента текста на строку, передаваемую в параметре lpszNewText:

void ReplaceSel(LPCTSTR lpszNewText);

4.Метод для удаления выделенного фр-та текста: void Clear();

5. Метод для копирования выделенного фрагмента текста в буфер Windows: void Copy();

6. Метод для переноса выд-го фрагмента текста в буфер обмена Windows (копирует в буфер и удаляет из текста): void Cut();

7. Метод для вставки текста из буфера обмена, начиная с позиции, в которой находится курсор: void Paste();

8. Метод для отмены последней операции, выполненной редактором: BOOL Undo();

Если редактор однострочный, возвращается всегда неотрицательное значение, иначе неотрицательное значение возвращается лишь в случае успешной замены.

9. Метод для определения того, можно ли отменить последнюю операцию редактора: BOOL CanUndo() const;

10. Метод для сброса флага undo (он сигнализирует о возможности отмены последней операции редактора), его вызов делает невозможным отмену: void EmptyUndoBuffer();

Этот флаг сбрасывается автоматически при выполнении методов SetWindowText и SetHandle.

11. Метод для определения значения флага модификации содержимого окна: BOOL GetModify() const;

Возвращает неотрицательное значение, если содержимое окна редактирования не модифицировалось. Информация о модификации поддерживается в специальном флаге, обнуляемом при создании окна редактирования и при вызове метода:

12. Метод для установки или сброса флага модификации (см. предыдущий метод): void SetModify(BOOL bModified=TRUE);

Флаг сбрасывается при вызове метода с параметром FALSE и устанавливается при модификации содержимого окна редактирования или при вызове SetModify с параметром TRUE.

13. Метод для установки режима просмотра (bReadOnly=TRUE) или редактирования (bReadOnly=FALSE):

BOOL SetReadOnly(BOOL bReadOnly=TRUE);

14. Метод для определения символа, который при выводе пароля будет появляться на экране вместо символов, набираемых пользователем: TCHAR GetPasswordChar() const;

Если такой символ не определен, возвращается 0.

15. Метод для установки максимальной длины (в байтах) текста, который может ввести пользователь: void LimitText(int nChars=0);

Если значение параметра равно 0, длина текста устанавливается равной UINT_MAX.

18. Потоки в Visual C++. Работа с исключающим семафором и критической секцией.

Процесс - это программа, или задача, которая выполняется.

Поток - это часть выполняющегося процесса.

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

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

В MFC определены два типа потоков: интерфейсные и рабочие.

Интерфейсный поток способен принимать и обрабатывать сообщения. Говоря языком MFC, интерфейсные потоки содержат канал сообщений. Главный поток MFC-программы (начинающийся при объявлении объекта класса CWinApp) является интерфейсным потоком. Рабочие потоки обеспечивают дополнительные пути выполнения задачи внутри интерфейсного потока.

В MFC потоковая многозадачность реализуется с помощью класса CWinThread. Кстати, производным от него является класс CWinApp, формирующий поток приложения.

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

При помощи критических секций можно запрещать выполнение определенных участков кода программы несколькими потоками одновременно. Для этого данные участки должны быть объявлены как критический раздел (critical section). Когда в этот раздел входит один поток, другим потокам запрещается делать то же самое до тех пор, пока первый поток не выйдет из данного раздела.

Критические разделы, в отличие от других типов объектов синхронизации,

применяются только для синхронизации потоков внутри одного процесса. Другие

же типы объектов могут быть использованы для синхронизации потоков внутри

процесса или для синхронизации процессов.

В MFC механизм синхронизации, обеспечиваемый интерфейсом Win32,

поддерживается с помощью следующих классов, порожденных от класса

CSyncObject:

CCriticalSection - реализует критический раздел;

CEvent - реализует объект события;

CMutex - реализует исключающий семафор;

CSemaphore - реализует классический семафор.

Использование критических секции

Критическая секция (Critical Section) – это участок кода, в котором поток

получает доступ к ресурсу (переменной), который доступен из других

потоков.

Критические секции (разделы или секции кода, требующие монопольного

доступа к разделяемым данным) удобны для управления доступом к данным.

Создавая критическую секцию, вы передаете потокам объект, который

они должны использовать совместно. Любой поток, владеющий объектом

критической секции, получает доступ к защищенным данным. Остальные

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

Доступ к защищенным данным может получить не более одного потока

одновременно.

Для создания в программе, использующей библиотеку MFC, объекта

критической секции необходимо создать экземпляр объекта класса ССritical Section, как это показано ниже:

CCriticalSection criticalSection;

Когда в программе необходимо получить доступ к данным, защищенным

критической секцией, вызывается метод Lock() объекта этой критической

секции, как показано ниже:

criticalSection.Lock();

Если объект критической секции в данный момент не захвачен другим

потоком, функция Lock() передаст этот объект во владение данному потоку.

Теперь поток может получить доступ к защищенным данным. Завершив

обработку данных, поток должен вызвать метод Unlock() объекта

критической секции:

criticalSection.Unlock();

Функция Unlock() освобождает объект критической секции. В

результате другой поток сможет его захватить и получить доступ к

защищенным данным.

Лучшим способом реализации механизма защиты данных является

размещение критической секции в том же классе, где объявлены данные. Если это сделать, то основной программе не придется беспокоиться о синхронизации работы потоков — методы этого класса возьмут все на себя.

Использование исключающего семафора

Исключающие семафоры или мьютексы (mutex) во многом похожи на

критические секции, но являются несколько более сложными объектами, так как обеспечивают безопасное разделение ресурсов не только потоками одного приложения, но также потоками различных приложений.

Для получения доступа к объекту мьютекс необходимо создать объект

класса CSingleLock для объекта mutex, как показано ниже:

CSingleLock singleLock(&mutex);

Аргумент конструктора является указателем на обеспечивающий

синхронизацию потоков объект, с помощью которого и осуществляется

управление. Затем для получения доступа к мьютексу вызывается метод Lock()

объекта класса CSingleLock:

singleLock.Lock();

Если мьютекс еще не захвачен, то вызывающий поток становится его

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

Для освобождения мьютекса необходимо вызвать метод Unlock() класса

CSingleLock. Но поскольку вы создали экземпляр класса CSingleLock в стеке (а не в куче с помощью оператора new), то вызывать Unlock() вообще нет необходимости. Когда функция SetArray() завершит свою работу, объект выйдет из области видимости, что приведет к вызову его деструктора, который автоматически освободит объект.