Диалози. Въведение в контролите - MFC

Диалозите и контролите са много обширна тема. Например, ще е необходима цяла книга, за да се покрие напълно темата за контролите. Затова в този урок първо ще разгледаме основите, а след това само най-често използваните контроли. Това ще ви даде добра основа по пътя ви към задълбочено изучаване на MFC.

Диалогът (диалогов прозорец) е специален вид прозорец, който е предназначен да взаимодейства с потребителя. Те обикновено се използват за промяна на настройките на приложението и въвеждане на информация. Много често се използват диалози. Например почти всички прозорци с настройки на Microsoft Word са диалогови прозорци.

Взаимодействие между диалог и потребител Взаимодействието между диалог и потребител се осъществява с помощта на контроли. Това е специален тип прозорец за вход или изход. Контролата принадлежи на прозореца, който я притежава, в този случай диалоговият прозорец. Всички версии на Windows поддържат някакъв набор от стандартни контроли, които включват бутони, контролни превключватели, бутони за избор, списъчни полета, полета за въвеждане, комбинирани полета, ленти за превъртане и статични елементи. Трябва да сте запознати с всички тези елементи. Нека разгледаме накратко всеки от тях:
  • Обикновен бутон (бутон) е бутон, който потребителят "натиска" с мишката или клавиша Enter, като преди това е преместил фокуса на въвеждане върху него.
  • Квадратчето за отметка може да бъде избрано или не. Ако има няколко квадратчета за отметка в диалоговия прозорец, няколко от тях могат да бъдат избрани едновременно.
  • Радио бутонът е почти същият като радио бутон. Само ако има няколко бутона в група, само един може да бъде избран.
  • Списъчното поле съдържа набор от редове, от които могат да бъдат избрани един или повече. Широко използван при показване на имена на файлове.
  • Полето за редактиране е елемент, който ви позволява да въведете ред текст.
  • Разгъващото се поле е списък с ред за въвеждане.
  • Статичната контрола е предназначена за показване на текст или графики, но не и за въвеждане.
Контролите могат както да генерират съобщения в отговор на действията на потребителя, така и да ги получават от приложението. В последния случай съобщенията всъщност са команди, на които управлението трябва да отговори.

MFC класове за контроли

MFC съдържа класове за всички стандартни контроли. Тези класове описват самите елементи и също така съдържат функции за работа с тях. Те се наричат ​​контролни класове. Те са извлечени от класа CWnd. Следователно всички те имат характеристиките на прозорец. Следват основните контролни класове:

Модални и безмоделни диалози

Има два типа диалогови прозорци: модални и немодални. Първите са най-често срещаните. В случай на модални диалогови прозорци, когато диалоговият прозорец е активиран, главният прозорец на приложението става пасивен и спира да отговаря на действията на потребителя, докато потребителят не затвори диалоговия прозорец. В случай на безмоделни диалогови прозорци, диалоговият прозорец съществува независимо от другите прозорци и главният прозорец също може да бъде активиран. Програмирането на безмоделни диалози е малко по-трудно. Ще разгледаме и двата вида диалози.

Диалозите като ресурси

Както бе споменато по-горе, диалоговите прозорци не се създават програмно. Вместо това, ако е необходимо, описанията на диалоговите прозорци се зареждат от ресурси и Windows, според това описание, формира прозорец и поставя всичко в него.контроли.

Клас CDialog

В MFC всички диалогови прозорци са екземпляри или на класа CDialog, или на класове, извлечени от него. Само най-простите диалогови прозорци използват директно класа CDialog. В общия случай е необходимо да дефинирате свой собствен клас. Класът CDialog има конструктори със следните прототипи:

Параметърът ResourceName или ResourceID указва идентификатора на разговора в ресурси, низ или число. Параметърът Owner е указател към прозореца на собственика, ако е равен на 0, тогава главният прозорец на приложението ще бъде собственик. Последната форма на конструктора е за създаване на безмоделни диалози, за които ще стане дума по-късно.

Обработка на съобщения от диалогови прозорци

Всички диалози са вид прозорци. Следователно те използват същия механизъм за съобщения като основния прозорец. Всеки диалогов прозорец има своя собствена опашка от съобщения, точно както основния прозорец.

Всеки път, когато се активира диалогов контрол, към диалога се изпраща съобщение WM_COMMAND. Идентификационният номер на контролата се предава с това съобщение. За да обработвате съобщения, макросът ON_COMMAND() трябва да бъде поставен в картата на съобщенията на диалоговия прозорец. Много контроли също генерират идентификационен код, който ви позволява да определите какво действие е извършено върху контролата. В много случаи този код избира един или друг манипулатор. Както ще бъде показано по-късно, MFC предоставя механизъм, подобен на макроса ON_COMMAND(), който може да се използва за свързване на идентификационни кодове с манипулатори.

Диалогово повикване

След като обектът на диалоговия клас е създаден, трябва да се извика членската функция DoModal(). Резултатът ще бъде модален дисплей на диалоговия прозорец. Прототипът на функцията е следният:

Функцията връща кода за изход, генериран от диалоговия прозорец, когато се затвори, или -1, ако прозорецът не може да бъде показан. Ако възникне грешка при показване на диалоговия прозорец, се връща IDABORT. Функцията не завършва, докато диалоговият прозорец не бъде затворен.

Затваряне на диалоговия прозорец

По подразбиране диалоговият прозорец се затваря, когато се получи съобщение с IDOK или IDCANCEL. Те са предварително дефинирани и обикновено са свързани с бутоните за потвърждение и отказ. Класът CDialog съдържа вградени манипулатори за тези два случая, OnOK() и OnCancel(). Не е необходимо да бъдат включени в опашката със съобщения на диалоговия прозорец. Но те могат да бъдат отменени, което дава на програмиста контрол върху затварянето на диалоговия прозорец. За да затворите програмно диалоговия прозорец, трябва да извикате членска функция с прототип:

Параметърът определя стойността, върната от функцията DoModal(). Обикновено стойностите IDOK или IDCANCEL се връщат, други стойности се използват рядко.

Примерна програма за диалогов прозорец

По-долу са изходните текстове на примерна програма с диалогов прозорец. Диалогът се избира с помощта на менюто. Разполага с три контроли - бутони "Червен", "Зелен" и "Отказ". Функцията OnCancel() също е предефинирана, което ви позволява да показвате прозорец за потвърждение, когато се опитате да затворите диалоговия прозорец. Диалоговият прозорец се затваря програмно, връщайки изходен код 7, който след това се връща от функцията DoModal() и се показва в прозореца. Това е само за демонстрационни цели, в действителност обикновено се връща IDCANCEL. Диалоговият прозорец е създаден визуално в средата на Visual C++. Тук също има файл с идентификатори, генерирани от средата. По-нататък този файл няма да бъде даден, тъй като най-общо казано не е предназначен за четене от хора. Тъй като всички идентификатори в примерите имат смислени имена, като качите проекта в IDE, можете веднага да разберете коиидентификатори на какви контроли съответстват.

Инициализация на диалогов прозорец

Често различните променливи и контроли, свързани с диалоговия прозорец, трябва да бъдат инициализирани преди диалоговият прозорец да бъде показан. За да позволи на диалогов прозорец да извършва такива действия, Windows автоматично му изпраща съобщение WM_INITDIALOG по време на създаването. Когато се получи такова съобщение, MFC автоматично извиква членската функция OnInitDialog(), която е стандартен манипулатор, дефиниран в класа CDialog. Тази функция трябва да бъде предефинирана в програмата, ако е необходимо да се извършват различни действия по инициализация. Прототипът на функцията е:

Тази функция се извиква преди да се покаже диалоговият прозорец. Трябва да върне TRUE, така че Windows да може да даде фокус на въвеждането (т.е. да го направи активен) на първата контрола в прозореца.

Първото действие в заменената функция трябва да бъде извикване на функцията CDialog::OnInitDialog().

В бъдеще ще използваме тази функция в примерите.

Списъчното поле е един от най-често срещаните контроли. В MFC работата със списъка се извършва чрез класа CListBox.

Основи на списъка

Списъците са контроли, които изискват двупосочно взаимодействие между тях и програмата. Тоест списъкът може както да изпраща, така и да получава съобщения. По-специално, съобщенията се изпращат до списъка, когато той се инициализира. Това включва предаване на набор от низове, които ще бъдат показани в списъчното поле (по подразбиране списъкът се създава празен). Когато списъкът се инициализира, той изпраща съобщения за действията, извършени върху него от потребителя.

Получаване на идентификатор на списък

Списъкът може да генерира съобщения от различен тип. Например съобщенията се изпращат, когатодвойно щракване върху елемент от списък, когато списъкът загуби фокуса на въвеждане и когато друг елемент е избран от списъка. Всяко такова събитие се описва с идентификационен код. Този код е част от съобщението WM_COMMAND. Някои други елементи също използват идентификационни кодове.

Единственият код, който ще използваме, се нарича LBN_DBLCLK. Изпраща се, когато потребителят щракне два пъти върху елемент в списъка. (Когато дефинирате списък, ресурсите трябва да имат зададена опция Уведомяване, за да могат да генерират това съобщение.) Когато се направи избор, списъкът трябва да бъде запитан, за да разбере кой елемент е избран.

За да обработите съобщението LBN_DBLCLK, трябва да поставите неговия манипулатор в картата на съобщенията. Но това няма да бъде макрос ON_COMMAND(). Вместо това в този случай се използват специални макроси. За нашето съобщение това ще бъде ON_LBN_DBLCLK(). Изглежда така:

Много съобщения се обработват по този начин. Имената на всички макроси за такива съобщения започват с префикса ON_LBN_.

Изпращане на съобщения до списък

В традиционните програми на Windows съобщенията се изпращат до контролите с помощта на API функции като SendDlgItemMessage(). Но в MFC програмите за тази цел се използват съответните членски функции. Те автоматично изпращат правилното съобщение до управлението. Това е предимството на MFC пред традиционния метод на програмиране.

В списъка могат да бъдат изпратени няколко различни съобщения. За всеки клас CListBox съдържа отделна членска функция. Например, разгледайте следните функции:

Получаване на указател към списък

Функциите CListBox работят върху CListBox обекти. Това означава, че трябва да получите указател към списък обект, което се прави с помощта на функциятаGetDlgItem(), който е член на класа CWnd:

Тази функция връща указател към обекта, чийто идентификатор е предаден като параметър. Ако такъв обект не съществува, тогава се връща 0. Трябва да се разбере, че указателят, върнат от функцията, е временен. Той е валиден само в рамките на текущия манипулатор.

Стойността, върната от функцията, трябва да бъде прехвърлена към указател към конкретен контролен клас. Например в нашия случай това е типът CListBox*.

Инициализация на списъка

Тъй като списъкът е създаден празен по подразбиране, той трябва да се инициализира всеки път, когато се показва диалоговият прозорец. За да направите това, трябва да замените функцията OnInitDialog(), в която низовете ще бъдат добавени към списъка. Ако при добавяне на елементи към списъка техният брой надвишава този, който се побира в списъчното поле, тогава в този прозорец автоматично ще се появи вертикална лента за превъртане.

Примерна програма

Поле за въвеждане

Това е последната контрола, която ще разгледаме като въведение в диалоговите прозорци и контролите. Полетата за въвеждане се използват много широко, тъй като ви позволяват да въведете низ по ваша преценка. Дори да знаете как да създавате само полета за въвеждане и списъци, вече можете да пишете полезни програми.

Полетата за въвеждане приемат много съобщения и сами могат да генерират няколко вида съобщения. Обикновено обаче не е необходимо да се отговаря на повечето от тях. Както скоро ще видите, полетата за въвеждане изпълняват повечето от функциите за редактиране сами. Това не изисква взаимодействие с програмата. Просто трябва да решите кога да поискате съдържанието на полето за въвеждане.

За да получите текущото съдържание на водното поле, което се състои от един ред, се използва функцията GetWindowText(). Неговият прототип е:

В момента на създаване полето за въвежданепразно е. За инициализиране на съдържанието му се използва друга членска функция на класа CWnd, SetWindowText(). Той показва низ в контролата, която е извикала тази функция. Ето неговия прототип:

Примерна програма с поле за въвеждане

Безмоделни диалози

Безмоделните диалогови прозорци получават съобщения успоредно с главния прозорец на приложението. Тоест поне два прозореца ще бъдат активни едновременно. Следователно работата с безмоделни диалози изисква малко повече усилия, трябва да се извършат допълнителни операции.

Има две стъпки за създаване на безмоден диалог. Първо, трябва да създадете „празен“ диалогов обект, тоест да не е свързан с шаблон от ресурси. Свързването към ресурси се извършва чрез функцията Create(). Нека разгледаме този процес по-подробно.

За да създадете безмоден диалогов обект, използвайте конструктора CDialog::CDialog() без параметри. Той е деклариран като защитен член на класа. Това означава, че може да бъде извикан само от функция член на производен клас. Това се прави, така че програмистът да дефинира свой собствен производен клас за немодалния диалог и да дефинира допълнителни операции за немодалния диалог в него.

След като екземплярът бъде създаден, той се свързва с ресурси с помощта на функции:

Първият параметър дефинира идентификатора на диалоговия прозорец в ресурси. Вторият параметър, както обикновено, указва собственика на прозореца за диалоговия прозорец.

Трябва да се помни, че безмоделният диалогов обект трябва да съществува през цялото време, докато се използва диалоговият прозорец. Функцията Create() показва прозореца и излиза веднага след това. И обектът прозорец трябва да съществува.

За да затворите немодален диалог, използвайте функцията DestroyWindow(). Това означава, че OnCancel() функционираи/или OnOK() трябва да бъдат отменени.