Как написать программу диалог

      1. Диалог с компьютером

Напишем программу,
которая осуществляла бы такой диалог
человека с компьютером:

КОМПЬЮТЕР ВЫВОДИТ
НА ЭКРАН:
Здравствуй, я компьютер, а
тебя как зовут?

ЧЕЛОВЕК ВВОДИТ
С КЛАВИАТУРЫ:
Коля

КОМПЬЮТЕР ВЫВОДИТ
НА ЭКРАН:
Очень приятно, Коля. .Сколько
тебе лет?

ЧЕЛОВЕК ВВОДИТ
С КЛАВИАТУРЫ:
16

КОМПЬЮТЕР ВЫВОДИТ
НА ЭКРАН:
Ого!Целых 16 лет!Ты уже совсем
взрослый!

Вот программа:

VAR imya
:String;
vozrast :Integer;
BEGIN
WriteLn
(‘Здравствуй, я компьютер, а тебя как
зовут?’);
ReadLn (imya);
WriteLn (‘Очень приятно,
‘, imya, ‘ . Сколько тебе лет?’);
ReadLn
(vozrast);
WriteLn (‘Ого! Целых ‘ ,vozrast, ‘ лет! Ты
уже совсем взрослый!’)
END.

Диалог будет
отличаться только той информацией,
которую вводит человек. Так, в другой
раз по этой же программе будет осуществлен
следующий диалог:

КОМПЬЮТЕР: Здравствуй,
я компьютер, а тебя как зовут?
ЧЕЛОВЕК
:
Фантомас!
КОМПЬЮТЕР: Очень
приятно, Фантомас! . Сколько тебе
лет?
ЧЕЛОВЕК: 100
КОМПЬЮТЕР: Ого!
Целых 100 лет! Ты уже совсем взрослый!

Не
подумайте, что эта программа очень
умная. Она совершенно не анализирует,
какую информацию человек ввел с
клавиатуры. Поэтому с ней возможен и
такой диалог:

КОМПЬЮТЕР: Здравствуй,
я компьютер, а тебя как зовут?
ЧЕЛОВЕК: Сгинь
с моих глаз!
КОМПЬЮТЕР: Очень
приятно, Сгинь с моих глаз! . Сколько
тебе лет?
ЧЕЛОВЕК: -2
КОМПЬЮТЕР: Ого!
Целых -2 лет! Ты уже совсем взрослый!

Задание
17:
Напишите
программу для следующей задачи: Компьютер
спрашивает названия двух планет, радиусы
их орбит (в миллионах километров) и
скорости движения по орбите (в миллионах
километров в сутки). Компьютер вычисляет
продолжительность года на планетах и
выдает результат в таком виде:
Продолжительность
года на планете Земля – 365 суток, а на
планете Эоэлла – 12 суток.

      1. Константы

Кроме переменных
величин в тексте программы мы встречаем
константы. Это те значения, которые
или присванваются переменным, или
встречаются в выражениях, или сравниваются
с выражениями. Например:

x:=25 здесь числовая
константа — 25

slovo:=’Волга’ здесь
строковая константа — Волга

simvol:=’!’ здесь
символьная константа — !

y:=(x+1)
/ (200*x — 0.3) здесь числовые
константы — 1 и 200 и 0.3

    1. Разветвляющиеся программы

      1. Условный оператор if или как компьютер делает выбор

Идею разветвления
в программе я изложил в 1.8. Сейчас добавлю
только, что вся мыслительная
деятельность во всех программах (в
том числе и той, что выиграла в шахматы
у Каспарова) осуществляется только
при помощи ветвления (выбора).

Теперь посмотрим,
как писать разветвляющиеся программы
на Паскале.

Выучим сначала
три английских слова:

if

читается «иф»

переводится
«если»

then

читается «зэн»

переводится
«то»

else

читается «элз»

переводится
«иначе»

Теперь приведем
пример нового для вас оператора:

IF a=28 THEN WriteLn
(f) ELSE k:=44

Переводится он
так:

ЕСЛИ a=28 ТО печатай
f ИНАЧЕ присвой переменной k значение
44
.

Другими словами,
мы предлагаем компьютеру сначала
подумать, правда ли, что a=28 , и если
правда, то выполнить оператор WriteLn (f),
в противном случае выполнить оператор
k:=44
. Таким образом, мы с вами впервые написали
оператор, при выполнении которого
компьютер не просто выполняет, что
приказано, а сначала думает и делает
выбор (пока одного из двух).

Мы видим, что
оператор if
включает в себя другие операторы, которые
выполняются или не выполняются в
зависимости от какого-то условия. Чтобы
понять, зачем может пригодиться оператор
if,
рассмотрим следующую задачу.

Задача 1.
Компьютер должен перемножить два числа
— 167 и 121. Если их произведение превышает
2000, то компьютер должен напечатать текст
ПРОИЗВЕДЕНИЕ БОЛЬШОЕ, иначе текст
ПРОИЗВЕДЕНИЕ МАЛЕНЬКОЕ. После этого
компьютер в любом случае должен напечатать
само произведение.

Программа:

VAR a,b,y :Integer;

BEGIN
a:=167;

b:=121;

y:=a*b;

if
y>20000 then WriteLn (‘ПРОИЗВЕДЕНИЕ
БОЛЬШОЕ’)

else WriteLn
(‘ПРОИЗВЕДЕНИЕ МАЛЕНЬКОЕ’);

WriteLn (y)

END.

Пояснение: В
программе 5 операторов, последний –
WriteLn
(y)
. Поскольку эти 5 операторов
выполняются по порядку, то он выполнится
обязательно.

Задача 2. В
компьютер вводятся два произвольных
положительных числа — длины сторон двух
кубиков. Компьютер должен подсчитать
объем одного кубика — большего по размеру
.

Обозначим a1
— сторону одного кубика, a2
— сторону другого, bol
— сторону большего кубика, V
— объем кубика. Приведем три варианта
программы:

ВАРИАНТ 1

VAR a1,a2 : Real;

BEGIN

ReadLn (a1,a2);

if
a1>a2 then
WriteLn (a1*a1*a1 : 15:5)

else
WriteLn (a2*a2*a2 : 15:5)

END.

ВАРИАНТ 2

VAR a1,a2,V : Real;

BEGIN

ReadLn (a1,a2);

if
a1>a2 then V:=a1*a1*a1

else
V:=a2*a2*a2;

WriteLn
(V : 15:5)

END.

ВАРИАНТ 3

VAR a1,a2,bol,V :
Real;

BEGIN

ReadLn (a1,a2);

if
a1>a2 then
bol:=a1

else
bol:=a2;

V:=bol*bol*bol;

WriteLn (V : 15:5)

END.

Поясним последний
вариант. Программа состоит из четырех
операторов, которые выполняются в
порядке записи. Первым после запуска
выполняется оператор ReadLn (a1,a2),
который ждет от нас ввода двух чисел.
Пусть мы сегодня ввели числа 3 и 2.
Компьютер понимает, что a1
равно 3, a2
равно 2, и переходит к выполнению оператора
if.
Он видит, что 3>2, и поэтому выполняет
оператор bol:=a1,
а оператор bol:=a2
не выполняет. В результате в ячейке bol
оказывается число 3. Затем
компьютер переходит к следующему
оператору — V:=bol*bol*bol
и вычисляет V=3*3*3=27. Следующий оператор
WriteLn
(V : 15:5)
печатает число 27.00000 .

Если завтра мы
запустим эту же программу и введем числа
6 и 10, то компьютер увидит, что утверждение
6>10 ложно, и поэтому выполнит оператор
bol:=a2,
а оператор bol:=a1
выполнять не станет. В результате в
ячейке bol
окажется число 10 и будет напечатано
число 1000.00000 .

А теперь, дорогой
читатель, вам пришла пора освоить
пошаговый режим выполнения программы
на компьютере. В обычном режиме компьютер
выполняет программу настолько быстро,
что вы не успеваете заметить, в каком
порядке он выполняет отдельные операторы
программы, а без этого часто невозможно
понять ее логику. Пошаговый режим
заставляет компьютер при выполнении
программы задерживаться на каждой
строке программы столько, сколько нужно
человеку. Сейчас вам необходимо проделать
то, что сказано в части
IV
в пункте «Пошаговый режим» параграфа
«Исправление ошибок. Отладка программы».

Итак, если паровая
машина избавила человека от тяжелого
физического труда, то оператор if
избавил человека от тяжелого умственного
труда, в нашем случае — от необходимости
решать, какое из двух чисел больше
другого.

Оператор if
можно записывать и без части else.
Например, if s<t then w:=a+1.
Это означает, что если s<t,
то нужно выполнить оператор w:=a+1,
в противном случае ничего не делать, а
просто перейти к следующему оператору.

Для примера
рассмотрим простейшую задачу: В компьютер
вводится слово. Компьютер должен просто
распечатать его. Однако, если введенным
словом будет «колхозник», то
компьютер должен напечатать вместо
него слово «фермер».

Вот как будет
выглядеть наша программа-«цензор»:

VAR Slovo :
String;
BEGIN
ReadLn (Slovo); { переменная
Slovo будет иметь значением строку
символов, введенных с клавиатуры }
if
Slovo = ‘колхозник’ then Slovo :=
‘фермер’;
WriteLn (Slovo)
END.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]

  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #







Deutsch (de)
English (en)

español (es)

suomi (fi)
français (fr)



日本語 (ja)



polski (pl)


русский (ru)
slovenčina (sk)





中文(中国大陆)‎ (zh_CN)


Несколько полезных диалогов

Вот некоторые полезные диалоги, которых нет в палитре компонентов:

  • procedure ShowMessage (const Msg: string);
  • function MessageBox (Text, Caption : PChar; Flags: Word): Integer;
  • function MessageDlg (const Msg: string; AType: TMsgDlgType; AButtons: TMsgDlgButtons; HelpCtx: LongInt): Word;
  • function InputBox (const ACaption, APrompt, ADefault: string); string;
  • function InputQuery (const ACaption, APrompt: string; var Value: string): Boolean;
  • function PasswordBox(const ACaption, APrompt : String) : String;

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

Причина, по которой часто существует несколько очень похожих альтернатив, заключается в том, что разные методы могут вызывать компонент и получать данные обратно из процедуры или функции.
Эти диалоги могут быть «платформозависимыми», то есть они могут отображаться по-разному. Например, строки, которые полностью отображаются в Windows XP, могут быть усечены в Windows 7.

Диалоги сообщений

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

ShowMessage

procedure ShowMessage(const Msg: string);

{ Определено в Dialogs.pp }

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

Это модальный вызов процедуры, то есть окно отображается, получает фокус и не оставляет фокус, пока не будет нажата кнопка ОК или не выбрано что-либо иное.

Пример:

program LazMessage;
uses 
  Dialogs;
begin
  ShowMessage('Это сообщение от Lazarus');
end.

У вас есть возможность создавать многострочные сообщения, используя следующие разделители строк, все они будут работать:

  • sLineBreak
  • LineEnding
  • или символьный код: #13#10(Windows)/#10(Linux)/#13(macOS)

Пример из нескольких строк:

program LazMessage;
uses 
  Dialogs;
begin
  ShowMessage('Это - многострочное' + sLineBreak + 'сообщение!' );
end.

MessageBox

{ Определено в Forms.pp как часть TApplication; следовательно, должно вызываться как Application.Messagebox() 
или с использованием конструкции 'with Application do ...'}

function Application.MessageBox(Text, Caption: PChar; Flags: LongInt): Integer;

Параметры включают

  • Text: строка, которая отображается как приглашение или инструкция в поле;
  • Caption: строка заголовка в верхней части окна сообщения;
  • Flags: longint — целое число, построенное путем сложения различных констант, для определения содержимого и поведения блока, например, MB_ABORTRETRYIGNORE + MR_ICONQUESTION заставит приложение отображать значок запроса (?) в поле с тремя кнопками: ABORT RETRY IGNORE.

Функция возвращает целочисленное значение, соответствующее нажатой кнопке; его значение может быть определено с помощью констант[IDOK..IDHELP]
Она может быть вызвана как вызов процедуры (то есть как оператор ‘MessageBox()’, а не как вызов функции ‘Variable:= MessageBox()’ — см. Пример ниже)

Пример:

uses 
  Forms, Dialogs, LCLType;
 
procedure DisplayMessageBox;
var 
  Reply, BoxStyle: Integer;
begin
  BoxStyle := MB_ICONQUESTION + MB_YESNO;
  Reply := Application.MessageBox('Press either button', 'MessageBoxDemo', BoxStyle);
  if Reply = IDYES then Application.MessageBox('Yes       ', 'Reply',MB_ICONINFORMATION)
    else Application.MessageBox('No         ', 'Reply', MB_ICONHAND);
end;

Обратите внимание, что в этом примере строки ‘Yes’ и ‘No’ были дополнены пробелами; в противном случае поле не будет достаточно широким, чтобы правильно отображать заголовок

MessageBoxDemo.png
ReplyYes.png

MessageDLG

function MessageDlg(const aMsg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; HelpCtx: Longint): Integer;
function MessageDlg(const aCaption, aMsg: string; DlgType: TMsgDlgType; Buttons: TMsgDlgButtons; HelpCtx: Longint): Integer;

Две версии этой функции, то есть первый параметр ‘Caption’ является необязательным; если пропущено, заголовок отсутствует в поле

Это наиболее полный и продуманный диалог сообщений, который позволяет программисту значительно контролировать внешний вид диалогового окна.
Параметры, определяющие тип поля и его значка, являются типами, а не целочисленными константами, и кнопки можно указывать в виде набора в квадратных скобках, например [mbRetry, mbIgnore, mbAbort, mbCancel].
Параметр HelpCtx в настоящее время не реализован и должен быть установлен в ноль.
Возвращаемое значение из функции — это идентификатор нажатой кнопки, выраженный в виде целого числа (см. определения ниже, [mrNone..mrAll]).

Пример:

uses 
  Forms, Dialogs, LCLType, Controls;
 
procedure TryMessageDlg;
begin
  if MessageDlg('Question', 'Do you wish to Execute?', mtConfirmation, [mbYes, mbNo, mbIgnore],0) = mrYes
  then { выполнить оставшуюся часть программы };
end;

Question.png

QuestionDlg

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

Пример:

    case QuestionDlg ('Caption','Message',mtCustom,[mrYes,'Positive', mrNo, 'Negative', 'IsDefault'],'') of
        mrYes: QuestionDlg ('Caption','So you mean „Yes“',mtCustom,[mrOK,'That is right'],'');
        mrNo:  QuestionDlg ('Caption','Oh, you mean „No“',mtCustom,[mrOK,'Exactly'],'');
        mrCancel: QuestionDlg ('Caption','You canceled the dialog with ESC or close button.',mtCustom,[mrOK,'Exactly'],'');
    end;

QuestionDlg.png

Note-icon.png

Примечание: Если пользователь отменяет диалог, и кнопка ‘IsCancel’ не определена, возвращается mrCancel! Если вы хотите перенаправить ESC/закрыть на определенную кнопку, используйте параметр ‘IsCancel’ сразу после кнопки отмены

Note-icon.png

Примечание: Использование букв местного алфавита в типе UnicodeString в качестве заголовков кнопок может привести к ошибкам (замечено в V1.6.4).

Расширенные примеры для кнопок (из файла promptdialog.inc)

    [mrOk,mrCancel,'Cancel now',mrIgnore,300,'Do it','IsDefault']

Это приведет к отображению 4 кнопок:

  • ‘Ok’ возвращает mrOk
  • ‘Cancel now’ возвращает mrCancel
  • ‘Ignore’ возвращает mrIgnore
  • ‘Do it’ возвращает 300. Это будет кнопка по умолчанию (в фокусе)

Прим.переводчика: для Darwin имеет значение порядок указания кнопок диалога. Этот код:

  QuestionDlg('Caption',
              'Message',
              mtInformation,
              [mrOK,
              mrCancel,
              mrYes,
              mrNo],
              0);

даст такое расположение кнопок диалога

scr 084.png

а вот эти изменения кода

  QuestionDlg('Caption',
              'Message',
              mtInformation,
              [mrCancel,
              mrOK,
              mrNo,
              mrYes],
              0);

поменяют порядок расположения на более привычный

scr 085.png


Обычно кнопки в диалогах Lazarus имеют значки. Для предотвращения отображения значков можно использовать нестандартизированные значения для результатов сообщения. В настоящее время наибольшее стандартизированное значение равно 11. Например:

  case QuestionDlg ('Caption','Message',mtCustom,[20,'Positive', 21, 'Negative',22,'I do not know','IsCancel'],'') of
     20: QuestionDlg ('Caption','So you mean „Yes“',mtCustom,[20,'That is right'],'');
     21:  QuestionDlg ('Caption','Oh, you mean „No“',mtCustom,[21,'Exactly'],'');
     22:  QuestionDlg ('Caption','So, please find out!',mtCustom,[22,'Maybe'],'');
  end;

Для облегчения работы можно определить константы. Например:

const
  mrNoneNI=      20;
  mrOkNI=        mrNoneNI+1;
  mrCancelNI=    mrNoneNI+2;
  mrAbortNI=     mrNoneNI+3;
  mrRetryNI=     mrNoneNI+4;
  mrIgnoreNI=    mrNoneNI+5;
  mrYesNI=       mrNoneNI+6;
  mrNoNI=        mrNoneNI+7;
  mrAllNI=       mrNoneNI+8;
  mrYesToAllNI=  mrNoneNI+10;
  mrCloseNI=     mrNoneNI+11;
  mrLastNI=      mrCloseNI; 
begin
  case QuestionDlg ('Caption','Message',mtCustom,[mrYesNI,'Positive', mrNoNI, 'Negative',mrCancelNI,'I do not know','IsCancel'],'') of
    mrYesNI: QuestionDlg ('Caption','So you mean „Yes“',mtCustom,[mrYesNI,'That is right'],'');
    mrNoNI:  QuestionDlg ('Caption','Oh, you mean „No“',mtCustom,[mrNoNI,'Exactly'],'');
    mrCancelNI:  QuestionDlg ('Caption','So, please find out!',mtCustom,[mrCancelNI,'Maybe'],'');
  end; //case
end;

QuestionDlgNoButIcons.png


Прим.переводчика: Отображение значков на кнопках диалоговых окон зависит от системных настроек. Можно попытаться ими управлять из своего приложения, не меняя глобальных настроек, при помощи свойства TApplicationShowGlyphs компонента TApplicationProperties. Но, как говорится, «есть нюансы»  :)

  • Windows
    • для Win XP отображение значков зависит от значений этого свойства
    • для Win 7 и Win 10 значки не отображаются никогда вне зависимости от значений этого свойства
    • для Win 11 не проверял
  • Linux (проверялось для Debian GTK2 и Qt5)
    • значки отображаются всегда вне зависимости от значений этого свойства

scr 086.png

scr 087.png

  • Darwin
    • отображение значков зависит от значений этого свойства

scr 081.png

scr 082.png

scr 083.png

Диалоги ввода текста

InputBox

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

function InputBox(const ACaption, APrompt, ADefault: String): String;

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

Пример:

uses 
  Forms, LCLType, Dialogs, Controls;
 
procedure TryInputBox;
var 
  UserString: string;
begin
  UserString := InputBox('Get some text input','Please type in some information', 'Some sample text');
  ShowMessage(UserString)
end;

InputQuery

function InputQuery(const ACaption, APrompt : String; MaskInput : Boolean; var Value : String) : Boolean;
function InputQuery(const ACaption, APrompt : String; var Value : String) : Boolean;

Две версии этой функции, которая отображает подсказку и ожидает ввода пользователем текстовых данных; первый включает в себя логический параметр MaskInput, который определяет, маскируется ли пользовательский ввод звездочками в поле ввода текста (например, при вводе пароля), а второй пропускает это свойство. Текст, введенный пользователем, возвращается в переменном параметре ‘Value'(Значение); результатом функции является логическое значение, которое возвращает TRUE, если была нажата кнопка OK, или FALSE, если окно было закрыто любым другим механизмом (например, нажатием на значок ‘Close'(Закрыть) в верхней строке заголовка). Пропуск параметра MaskInput эквивалентен установке его в значение FALSE.

Пример:

uses 
  Forms, LCLType, Dialogs, Controls;
 
procedure TryInputQuery;
var 
  QueryResult: Boolean;
  UserString: string;
begin
  if InputQuery('Question', 'Type in some data', TRUE, UserString)
  then ShowMessage(UserString)
  else 
  begin
    InputQuery('Don''t be silly', 'Please try again', UserString);
    ShowMessage(UserString);
  end
end;

MessageDlgQuestion.png
DontBeSillly.png

PasswordBox

Function PasswordBox(const ACaption, APrompt : String) : String;

Ведет себя очень похоже на функцию InputQuery с MaskInput = TRUE; разница в том, что введенный пароль возвращается как результат функции (как в InputBox).

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

Несколько констант и типов, относящихся к использованию с диалоговыми окнами, предварительно определены в библиотеке LCL:

целочисленные константы для определения типов кнопок и иконки для отображения в MessageBox

const { Defined in LCLType.pp }

MB_OK = $00000000;
MB_OKCANCEL = $00000001;
MB_ABORTRETRYIGNORE = $00000002;
MB_YESNOCANCEL = $00000003;
MB_YESNO = $00000004;
MB_RETRYCANCEL = $00000005;

 
MB_ICONHAND = $00000010;
MB_ICONQUESTION = $00000020;
MB_ICONEXCLAMATION = $00000030;
MB_ICONASTERICK = $00000040;
MB_ICONWARNING = MB_ICONEXCLAMATION;
MB_ICONERROR = MB_ICONHAND;
MB_ICONINFORMATION = MB_ICONASTERICK;

целочисленные константы, определяющие возвращаемое значение из MessageBox в зависимости от того, какая кнопка была нажата

IDOK = 1; 	ID_OK = IDOK;
IDCANCEL = 2;	ID_CANCEL = IDCANCEL;
IDABORT = 3;	ID_ABORT = IDABORT;
IDRETRY = 4;	ID_RETRY = IDRETRY;
IDIGNORE = 5;	ID_IGNORE = IDIGNORE;
IDYES = 6;	ID_YES = IDYES;
IDNO = 7;	ID_NO = IDNO;
IDCLOSE = 8;	ID_CLOSE = IDCLOSE;
IDHELP = 9;	ID_HELP = IDHELP;

определяет, будет ли первая, вторая или третья кнопка по умолчанию

MB_DEFBUTTON1 = $00000000;
MB_DEFBUTTON2 = $00000100;
MB_DEFBUTTON3 = $00000200;
MB_DEFBUTTON4 = $00000300;

Параметр Flags MessageBox создается путем добавления константы кнопки [MB_OK..MB_RETRYCANCEL], необязательной константы значка [MB_ICONHAND..MB_ICONINFORMATION] и необязательной постоянной кнопки по умолчанию [MB_DEFBUTTON1..MB_DEFBUTTON3]

Типы для использования в MessageDlg, для которого требуются параметры AType TMsgDlgType и AButtons of TMSgDlgButtons

{ Defined in Dialogs.pp }
type
  TMsgDlgType    = (mtWarning, mtError, mtInformation,  mtConfirmation,
                    mtCustom);
  TMsgDlgBtn     = (mbYes, mbNo, mbOK, mbCancel, mbAbort, mbRetry, mbIgnore,
                   mbAll, mbNoToAll, mbYesToAll, mbHelp, mbClose);
  TMsgDlgButtons = set of TMsgDlgBtn;
  
 
const
  mbYesNoCancel = [mbYes, mbNo, mbCancel];
  mbOKCancel = [mbOK, mbCancel];
  mbAbortRetryIgnore = [mbAbort, mbRetry, mbIgnore];
  
 
  MsgDlgBtnToBitBtnKind: array[TMsgDlgBtn] of TBitBtnKind = (
   bkYes, bkNo, bkOK, bkCancel, bkAbort, bkRetry, bkIgnore,
    bkAll, bkNoToAll, bkYesToAll, bkHelp, bkClose
   );
 
 
  BitBtnKindToMsgDlgBtn: array[TBitBtnKind] of TMsgDlgBtn = (
    mbOk, mbOK, mbCancel, mbHelp, mbYes, mbNo,
    mbClose, mbAbort, mbRetry, mbIgnore, mbAll, mbNoToALl, mbYesToAll
    );
 
 
{ Defined in Controls.pp }
const
  mrNone = 0;
  mrOK = mrNone + 1;
  mrCancel = mrNone + 2;
  mrAbort = mrNone + 3;
  mrRetry = mrNone + 4;
  mrIgnore = mrNone + 5;
  mrYes = mrNone + 6;
  mrNo = mrNone + 7;
  mrAll = mrNone + 8;
  mrNoToAll = mrNone + 9;
  mrYesToAll = mrNone + 10;
  mrLast = mrYesToAll;

In this article, I’ll discuss how to use a dialog box as the main window for your program, step by step, from scratch. I’ll use Visual Studio 2008, but the steps should be similar for other Visual Studio versions, or even other IDEs.

1. Introduction

When writing pure Win32 programs, usually you see tutorials showing how to use “raw” windows, by filling a WNDCLASSEX structure, calling RegisterClassEx and then CreateWindowEx. This is explained in detail in Charles Petzold’s classic Programming Windows book – a must-have for any Win32 programmer, let me say.

But sometimes you don’t need to create a new window entirely from scratch, a simple dialog box would fit your needs.

In this article, I’ll discuss how to use a dialog box as the main window for your program, step by step, from scratch. A dialog box resource can be quickly created – with labels, editboxes, and buttons – using any resource editor. Here I’ll use Visual Studio 2008, but the steps should be similar for other Visual Studio versions, or even other IDEs.

I’ll use pure Win32 C code to keep things as simple as possible: no MFC, no ATL, no WTL, or whatever. I’ll also use the TCHAR functions (declared in tchar.h, more information here) to make the code portable with ANSI and Unicode, and only functions that are both x86 and x64 compatible.

1.1. Program Structure

Our program will be composed of three files:

  • C source file – the source code we’ll effectively write, and the central theme of this article;
  • RC resource script – describes the dialog box resources, easily created by Visual Studio or any resource editor, or even by hand, and compiled with a resource compiler; and
  • H resource header – simply the macro constants used in the RC file to identify the resources, usually created automatically together with the RC script.

2. The Dialog Box

Before writing the C source code, we’ll create an empty project and add a dialog box resource to it. When doing so, a resource script is created, containing the dialog box code. Let’s start a new project:

Image 1

Choose “Visual C++” and “Win32” from the tree in the left, then “Win32 project”, and give a name to it. Pay attention to the directory you are saving it. Then click OK:

Image 2

Now choose “Windows application” and “Empty project”. When creating an empty project, Visual Studio will create no files for us, and this is important because here we want to create a pure Win32 program, with no additional libraries. Then, click “Finish”:

Image 3

Now, let’s add the dialog box. In the Solution Explorer window – if you can’t see it, enable it in the “View” menu – right-click the project name and choose “Add”, “Resource”:

Image 4

Here you can see a couple of resource items whose script can be generated automatically by Visual Studio. We’ll use just the dialog box, so choose “Dialog” and click “New”:

Image 5

Once done, you should see your dialog in the resource editor, where you can add controls – like editboxes, buttons, and labels – by just using the mouse, positioning and arranging them really quick – much quicker than you would do with a “raw window” application, where you must deal with the code directly. My dialog looks like this:

Image 6

At this point, we have a resource script and a resource header, they can be seen in the Solution Explorer. Now it’s time to write the source code to bring this dialog box alive.

3. The Source Code

Let’s add an empty source file to our project. In the Solution Explorer, right-click the “Source Files” folder, then “Add”, “New Item”. Then give any name to the file, like “main.c”.

Image 7

In Visual Studio, by default, the source files will be compiled according to the file extension: C files compiled as plain C; and CPP, CXX (and some others) compiled as C++. Here we’ll write C code, but it can also be compiled as C++, so the file extension can be any of those cited. Particularly, I used the C extension, to make it clear it’s a plain C program.

Our C source will have only two functions:

  • WinMain – the program entry point, which will have the main program loop; and
  • DialogProc – the dialog box procedure, which will process the dialog messages.

Let’s start writing the code with the normal Win32 entry point function (the TCHAR version of it):

#include <Windows.h>
#include <tchar.h>


#include "resource.h"

int _tWinMain(HINSTANCE hInst, HINSTANCE h0, LPCTSTR lpCmdLine, int nCmdShow)
{
  return 0;
}

4. Dialog Creation and Message Loop

The dialog will be created inside the WinMain function with the CreateDialogParam function (instead of CreateWindowEx), and there is no window class registration. Then, we make it visible with a call to ShowWindow:

HWND hDlg;
hDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DIALOG1), 0, DialogProc, 0);
ShowWindow(hDlg, nCmdShow);

IDD_DIALOG1 is the resource identifier to our dialog box, declared in resource.h. DialogProc is our dialog box procedure, which will handle all dialog messages – I’ll show it later on.

Then it follows the main program message loop. It’s the heart of any Win32 program – see it as the bridge between the operational system and your program. It also exists in common “raw window” programs, although slightly different from this. Here, the message loop is specifically to deal with a dialog box as the main window:

BOOL ret;
MSG msg;
while((ret = GetMessage(&msg, 0, 0, 0)) != 0) {
  if(ret == -1) 
    return -1;

  if(!IsDialogMessage(hDlg, &msg)) {
    TranslateMessage(&msg); 
    DispatchMessage(&msg); 
  }
}

The IsDialogMessage function immediately forwards the message to our dialog box procedure if it belongs to it. Otherwise, the message enters regular handling. More information about the message loop can be found here.

There is a possibility to bypass this program loop (not writing it), as explained by Iczelion in the 10th lesson of his wonderful Win32 Assembly article series. However, by doing so, we have less control: we cannot put any verification in the loop, like accelerator handling, for example. So, let’s keep the loop in our code.

4.1. Enabling Visual Styles

In order to get the common controls 6 visual styles, introduced with Windows XP, you must not only call InitCommonControls (declared in CommCtrl.h), but also embed a manifest XML file into your code. Fortunately, there is a handy trick you can use in the Visual C++ compiler, which I learned from Raymond Chen’s blog. Just add this to your code:

#pragma comment(linker, 
  ""/manifestdependency:type='Win32' "
  "name='Microsoft.Windows.Common-Controls' "
  "version='6.0.0.0' "
  "processorArchitecture='*' "
  "publicKeyToken='6595b64144ccf1df' "
  "language='*'"")

This will generate and embed the XML manifest file automatically, and you’ll never worry about it again.

To call InitCommonControls, you must statically link your program to ComCtl32.lib, and this can be accomplished with a #pragma comment directive as well:

#pragma comment(lib, "ComCtl32.lib")

4.2. Our WinMain

So far, this is our complete WinMain function (without the dialog box procedure yet):

#include <Windows.h>
#include <CommCtrl.h>
#include <tchar.h>
#include "resource.h"

#pragma comment(linker, 
  ""/manifestdependency:type='Win32' "
  "name='Microsoft.Windows.Common-Controls' "
  "version='6.0.0.0' "
  "processorArchitecture='*' "
  "publicKeyToken='6595b64144ccf1df' "
  "language='*'"")

#pragma comment(lib, "ComCtl32.lib")

int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE h0, LPTSTR lpCmdLine, int nCmdShow)
{
  HWND hDlg;
  MSG msg;
  BOOL ret;

  InitCommonControls();
  hDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DIALOG1), 0, DialogProc, 0);
  ShowWindow(hDlg, nCmdShow);

  while((ret = GetMessage(&msg, 0, 0, 0)) != 0) {
    if(ret == -1)
      return -1;

    if(!IsDialogMessage(hDlg, &msg)) {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
  }

  return 0;
}

5. Dialog Box Procedure

The dialog procedure is responsible for handling all program messages, responding to all events. It starts like this:

INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  return FALSE;
}

Windows calls this function for every program message. If we return FALSE, it means Windows can carry out the default processing for the message, because we’re not interested in it; if we return TRUE, we tell Windows we’ve actually processed the message. This is slightly different from the “raw” window message handling through WndProc, where you return a call to the DefWindowProc function. Here, we must not call DefWindowProc, just return FALSE.

So, we’ll write only the handling of messages that are interesting to us. Among the most commonly used messages, we have WM_INITDIALOG, WM_COMMAND, and WM_SIZE. But to build a minimal functional program, we need only two:

switch(uMsg)
{
case WM_CLOSE: 
  return TRUE; 

case WM_DESTROY:
  return TRUE;
}

Notice we don’t need to handle the WM_PAINT message with dialog boxes.

5.1. The Minimal Message Handling

WM_CLOSE is called just prior to window closing. If you want to ask the user if he really wants to close the program, here is the place to put this check. To close the window, we call DestroyWindow – if we don’t call it, the window won’t be closed.

So here’s the message handling, also prompting the user. If you don’t need to prompt the user, just omit the MessageBox check and call DestroyWindow directly. And don’t forget to return TRUE here, whether you close the window or not:

case WM_CLOSE:
  if(MessageBox(hDlg,
    TEXT("Close the window?"), TEXT("Close"),
    MB_ICONQUESTION | MB_YESNO) == IDYES)
  {
    DestroyWindow(hDlg);
  }
  return TRUE;

Finally, we must handle the WM_DESTROY message, telling Windows we want to quit the main program thread. We do this by calling the PostQuitMessage function:

case WM_DESTROY:
  PostQuitMessage(0);
  return TRUE;

The WM_DESTROY message is also the best place to free resources that were allocated by the program and are still waiting to be deallocated – it’s final cleanup time. But don’t forget to do the cleanup before calling PostQuitMessage.

5.2. Closing on ESC

An interesting feature of the dialog boxes is that they can be easily programmed to be closed when the user hits the ESC key, and it can also be done when the dialog box is the main window as well. To do so, we must handle the WM_COMMAND message and wait for the IDCANCEL identifier, which comes in the low word of the WPARAM argument, and that’s what we do:

case WM_COMMAND:
  switch(LOWORD(wParam))
  {
  case IDCANCEL:
    SendMessage(hDlg, WM_CLOSE, 0, 0);
    return TRUE;
  }
  break;

The IDCANCEL identifier is declared in WinUser.h, which is included in Windows.h, so it’s always available.

Notice that when handling IDCANCEL, we send a WM_CLOSE message to our dialog window, which causes the dialog procedure to be called again with the WM_CLOSE message that we previously coded, so the user will be prompted if he wants to close the window (because that’s the way we coded it).

6. The Final Program

So here is our final program. It’s the C source code for a minimally functional Win32 dialog based program, with the message loop and visual styles properly enabled, just ready to go. You can keep this to use as the skeleton for any Win32 dialog based program.

#include <Windows.h>
#include <CommCtrl.h>
#include <tchar.h>
#include "resource.h"

#pragma comment(linker, 
  ""/manifestdependency:type='Win32' "
  "name='Microsoft.Windows.Common-Controls' "
  "version='6.0.0.0' "
  "processorArchitecture='*' "
  "publicKeyToken='6595b64144ccf1df' "
  "language='*'"")

#pragma comment(lib, "ComCtl32.lib")

INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  switch(uMsg)
  {
  case WM_COMMAND:
    switch(LOWORD(wParam))
    {
    case IDCANCEL:
      SendMessage(hDlg, WM_CLOSE, 0, 0);
      return TRUE;
    }
    break;

  case WM_CLOSE:
    if(MessageBox(hDlg, TEXT("Close the program?"), TEXT("Close"),
      MB_ICONQUESTION | MB_YESNO) == IDYES)
    {
      DestroyWindow(hDlg);
    }
    return TRUE;

  case WM_DESTROY:
    PostQuitMessage(0);
    return TRUE;
  }

  return FALSE;
}

int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE h0, LPTSTR lpCmdLine, int nCmdShow)
{
  HWND hDlg;
  MSG msg;
  BOOL ret;

  InitCommonControls();
  hDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DIALOG1), 0, DialogProc, 0);
  ShowWindow(hDlg, nCmdShow);

  while((ret = GetMessage(&msg, 0, 0, 0)) != 0) {
    if(ret == -1)
      return -1;

    if(!IsDialogMessage(hDlg, &msg)) {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
  }

  return 0;
}

7. Further Organization

Usually, when your program grows in complexity, you’ll end up with a huge DialogProc stuffed with code, and therefore very painful to maintain. A useful approach to this is the use of function calls to each message — the famous subroutines. It’s specially handy because it isolates the logic of the code, you can see clearly each part of the program, giving you the notion of responding to events. For example, our program could have two dedicated functions:

void onCancel(HWND hDlg)
{
  SendMessage(hDlg, WM_CLOSE, 0, 0);
}

void onClose(HWND hDlg)
{
  if(MessageBox(hDlg, TEXT("Close the program?"), TEXT("Close"),
    MB_ICONQUESTION | MB_YESNO) == IDYES)
  {
    DestroyWindow(hDlg);
  }
}

And it would allow us to rewrite our DialogProc like this:

INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  switch(uMsg) 
  {
  case WM_COMMAND:
    switch(LOWORD(wParam))
    {
    case IDCANCEL: onCancel(hDlg); return TRUE; 
    }
    break;

  case WM_CLOSE:   onClose(hDlg); return TRUE; 
  case WM_DESTROY: PostQuitMessage(0); return TRUE;
  }

  return FALSE;
}

History

  • 20th July, 2011: Initial version

This article, along with any associated source code and files, is licensed under A Public Domain dedication

This member has not yet provided a Biography. Assume it’s interesting and varied, and probably something to do with programming.

In this article, I’ll discuss how to use a dialog box as the main window for your program, step by step, from scratch. I’ll use Visual Studio 2008, but the steps should be similar for other Visual Studio versions, or even other IDEs.

1. Introduction

When writing pure Win32 programs, usually you see tutorials showing how to use “raw” windows, by filling a WNDCLASSEX structure, calling RegisterClassEx and then CreateWindowEx. This is explained in detail in Charles Petzold’s classic Programming Windows book – a must-have for any Win32 programmer, let me say.

But sometimes you don’t need to create a new window entirely from scratch, a simple dialog box would fit your needs.

In this article, I’ll discuss how to use a dialog box as the main window for your program, step by step, from scratch. A dialog box resource can be quickly created – with labels, editboxes, and buttons – using any resource editor. Here I’ll use Visual Studio 2008, but the steps should be similar for other Visual Studio versions, or even other IDEs.

I’ll use pure Win32 C code to keep things as simple as possible: no MFC, no ATL, no WTL, or whatever. I’ll also use the TCHAR functions (declared in tchar.h, more information here) to make the code portable with ANSI and Unicode, and only functions that are both x86 and x64 compatible.

1.1. Program Structure

Our program will be composed of three files:

  • C source file – the source code we’ll effectively write, and the central theme of this article;
  • RC resource script – describes the dialog box resources, easily created by Visual Studio or any resource editor, or even by hand, and compiled with a resource compiler; and
  • H resource header – simply the macro constants used in the RC file to identify the resources, usually created automatically together with the RC script.

2. The Dialog Box

Before writing the C source code, we’ll create an empty project and add a dialog box resource to it. When doing so, a resource script is created, containing the dialog box code. Let’s start a new project:

Image 1

Choose “Visual C++” and “Win32” from the tree in the left, then “Win32 project”, and give a name to it. Pay attention to the directory you are saving it. Then click OK:

Image 2

Now choose “Windows application” and “Empty project”. When creating an empty project, Visual Studio will create no files for us, and this is important because here we want to create a pure Win32 program, with no additional libraries. Then, click “Finish”:

Image 3

Now, let’s add the dialog box. In the Solution Explorer window – if you can’t see it, enable it in the “View” menu – right-click the project name and choose “Add”, “Resource”:

Image 4

Here you can see a couple of resource items whose script can be generated automatically by Visual Studio. We’ll use just the dialog box, so choose “Dialog” and click “New”:

Image 5

Once done, you should see your dialog in the resource editor, where you can add controls – like editboxes, buttons, and labels – by just using the mouse, positioning and arranging them really quick – much quicker than you would do with a “raw window” application, where you must deal with the code directly. My dialog looks like this:

Image 6

At this point, we have a resource script and a resource header, they can be seen in the Solution Explorer. Now it’s time to write the source code to bring this dialog box alive.

3. The Source Code

Let’s add an empty source file to our project. In the Solution Explorer, right-click the “Source Files” folder, then “Add”, “New Item”. Then give any name to the file, like “main.c”.

Image 7

In Visual Studio, by default, the source files will be compiled according to the file extension: C files compiled as plain C; and CPP, CXX (and some others) compiled as C++. Here we’ll write C code, but it can also be compiled as C++, so the file extension can be any of those cited. Particularly, I used the C extension, to make it clear it’s a plain C program.

Our C source will have only two functions:

  • WinMain – the program entry point, which will have the main program loop; and
  • DialogProc – the dialog box procedure, which will process the dialog messages.

Let’s start writing the code with the normal Win32 entry point function (the TCHAR version of it):

#include <Windows.h>
#include <tchar.h>


#include "resource.h"

int _tWinMain(HINSTANCE hInst, HINSTANCE h0, LPCTSTR lpCmdLine, int nCmdShow)
{
  return 0;
}

4. Dialog Creation and Message Loop

The dialog will be created inside the WinMain function with the CreateDialogParam function (instead of CreateWindowEx), and there is no window class registration. Then, we make it visible with a call to ShowWindow:

HWND hDlg;
hDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DIALOG1), 0, DialogProc, 0);
ShowWindow(hDlg, nCmdShow);

IDD_DIALOG1 is the resource identifier to our dialog box, declared in resource.h. DialogProc is our dialog box procedure, which will handle all dialog messages – I’ll show it later on.

Then it follows the main program message loop. It’s the heart of any Win32 program – see it as the bridge between the operational system and your program. It also exists in common “raw window” programs, although slightly different from this. Here, the message loop is specifically to deal with a dialog box as the main window:

BOOL ret;
MSG msg;
while((ret = GetMessage(&msg, 0, 0, 0)) != 0) {
  if(ret == -1) 
    return -1;

  if(!IsDialogMessage(hDlg, &msg)) {
    TranslateMessage(&msg); 
    DispatchMessage(&msg); 
  }
}

The IsDialogMessage function immediately forwards the message to our dialog box procedure if it belongs to it. Otherwise, the message enters regular handling. More information about the message loop can be found here.

There is a possibility to bypass this program loop (not writing it), as explained by Iczelion in the 10th lesson of his wonderful Win32 Assembly article series. However, by doing so, we have less control: we cannot put any verification in the loop, like accelerator handling, for example. So, let’s keep the loop in our code.

4.1. Enabling Visual Styles

In order to get the common controls 6 visual styles, introduced with Windows XP, you must not only call InitCommonControls (declared in CommCtrl.h), but also embed a manifest XML file into your code. Fortunately, there is a handy trick you can use in the Visual C++ compiler, which I learned from Raymond Chen’s blog. Just add this to your code:

#pragma comment(linker, 
  ""/manifestdependency:type='Win32' "
  "name='Microsoft.Windows.Common-Controls' "
  "version='6.0.0.0' "
  "processorArchitecture='*' "
  "publicKeyToken='6595b64144ccf1df' "
  "language='*'"")

This will generate and embed the XML manifest file automatically, and you’ll never worry about it again.

To call InitCommonControls, you must statically link your program to ComCtl32.lib, and this can be accomplished with a #pragma comment directive as well:

#pragma comment(lib, "ComCtl32.lib")

4.2. Our WinMain

So far, this is our complete WinMain function (without the dialog box procedure yet):

#include <Windows.h>
#include <CommCtrl.h>
#include <tchar.h>
#include "resource.h"

#pragma comment(linker, 
  ""/manifestdependency:type='Win32' "
  "name='Microsoft.Windows.Common-Controls' "
  "version='6.0.0.0' "
  "processorArchitecture='*' "
  "publicKeyToken='6595b64144ccf1df' "
  "language='*'"")

#pragma comment(lib, "ComCtl32.lib")

int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE h0, LPTSTR lpCmdLine, int nCmdShow)
{
  HWND hDlg;
  MSG msg;
  BOOL ret;

  InitCommonControls();
  hDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DIALOG1), 0, DialogProc, 0);
  ShowWindow(hDlg, nCmdShow);

  while((ret = GetMessage(&msg, 0, 0, 0)) != 0) {
    if(ret == -1)
      return -1;

    if(!IsDialogMessage(hDlg, &msg)) {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
  }

  return 0;
}

5. Dialog Box Procedure

The dialog procedure is responsible for handling all program messages, responding to all events. It starts like this:

INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  return FALSE;
}

Windows calls this function for every program message. If we return FALSE, it means Windows can carry out the default processing for the message, because we’re not interested in it; if we return TRUE, we tell Windows we’ve actually processed the message. This is slightly different from the “raw” window message handling through WndProc, where you return a call to the DefWindowProc function. Here, we must not call DefWindowProc, just return FALSE.

So, we’ll write only the handling of messages that are interesting to us. Among the most commonly used messages, we have WM_INITDIALOG, WM_COMMAND, and WM_SIZE. But to build a minimal functional program, we need only two:

switch(uMsg)
{
case WM_CLOSE: 
  return TRUE; 

case WM_DESTROY:
  return TRUE;
}

Notice we don’t need to handle the WM_PAINT message with dialog boxes.

5.1. The Minimal Message Handling

WM_CLOSE is called just prior to window closing. If you want to ask the user if he really wants to close the program, here is the place to put this check. To close the window, we call DestroyWindow – if we don’t call it, the window won’t be closed.

So here’s the message handling, also prompting the user. If you don’t need to prompt the user, just omit the MessageBox check and call DestroyWindow directly. And don’t forget to return TRUE here, whether you close the window or not:

case WM_CLOSE:
  if(MessageBox(hDlg,
    TEXT("Close the window?"), TEXT("Close"),
    MB_ICONQUESTION | MB_YESNO) == IDYES)
  {
    DestroyWindow(hDlg);
  }
  return TRUE;

Finally, we must handle the WM_DESTROY message, telling Windows we want to quit the main program thread. We do this by calling the PostQuitMessage function:

case WM_DESTROY:
  PostQuitMessage(0);
  return TRUE;

The WM_DESTROY message is also the best place to free resources that were allocated by the program and are still waiting to be deallocated – it’s final cleanup time. But don’t forget to do the cleanup before calling PostQuitMessage.

5.2. Closing on ESC

An interesting feature of the dialog boxes is that they can be easily programmed to be closed when the user hits the ESC key, and it can also be done when the dialog box is the main window as well. To do so, we must handle the WM_COMMAND message and wait for the IDCANCEL identifier, which comes in the low word of the WPARAM argument, and that’s what we do:

case WM_COMMAND:
  switch(LOWORD(wParam))
  {
  case IDCANCEL:
    SendMessage(hDlg, WM_CLOSE, 0, 0);
    return TRUE;
  }
  break;

The IDCANCEL identifier is declared in WinUser.h, which is included in Windows.h, so it’s always available.

Notice that when handling IDCANCEL, we send a WM_CLOSE message to our dialog window, which causes the dialog procedure to be called again with the WM_CLOSE message that we previously coded, so the user will be prompted if he wants to close the window (because that’s the way we coded it).

6. The Final Program

So here is our final program. It’s the C source code for a minimally functional Win32 dialog based program, with the message loop and visual styles properly enabled, just ready to go. You can keep this to use as the skeleton for any Win32 dialog based program.

#include <Windows.h>
#include <CommCtrl.h>
#include <tchar.h>
#include "resource.h"

#pragma comment(linker, 
  ""/manifestdependency:type='Win32' "
  "name='Microsoft.Windows.Common-Controls' "
  "version='6.0.0.0' "
  "processorArchitecture='*' "
  "publicKeyToken='6595b64144ccf1df' "
  "language='*'"")

#pragma comment(lib, "ComCtl32.lib")

INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  switch(uMsg)
  {
  case WM_COMMAND:
    switch(LOWORD(wParam))
    {
    case IDCANCEL:
      SendMessage(hDlg, WM_CLOSE, 0, 0);
      return TRUE;
    }
    break;

  case WM_CLOSE:
    if(MessageBox(hDlg, TEXT("Close the program?"), TEXT("Close"),
      MB_ICONQUESTION | MB_YESNO) == IDYES)
    {
      DestroyWindow(hDlg);
    }
    return TRUE;

  case WM_DESTROY:
    PostQuitMessage(0);
    return TRUE;
  }

  return FALSE;
}

int WINAPI _tWinMain(HINSTANCE hInst, HINSTANCE h0, LPTSTR lpCmdLine, int nCmdShow)
{
  HWND hDlg;
  MSG msg;
  BOOL ret;

  InitCommonControls();
  hDlg = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_DIALOG1), 0, DialogProc, 0);
  ShowWindow(hDlg, nCmdShow);

  while((ret = GetMessage(&msg, 0, 0, 0)) != 0) {
    if(ret == -1)
      return -1;

    if(!IsDialogMessage(hDlg, &msg)) {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
  }

  return 0;
}

7. Further Organization

Usually, when your program grows in complexity, you’ll end up with a huge DialogProc stuffed with code, and therefore very painful to maintain. A useful approach to this is the use of function calls to each message — the famous subroutines. It’s specially handy because it isolates the logic of the code, you can see clearly each part of the program, giving you the notion of responding to events. For example, our program could have two dedicated functions:

void onCancel(HWND hDlg)
{
  SendMessage(hDlg, WM_CLOSE, 0, 0);
}

void onClose(HWND hDlg)
{
  if(MessageBox(hDlg, TEXT("Close the program?"), TEXT("Close"),
    MB_ICONQUESTION | MB_YESNO) == IDYES)
  {
    DestroyWindow(hDlg);
  }
}

And it would allow us to rewrite our DialogProc like this:

INT_PTR CALLBACK DialogProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  switch(uMsg) 
  {
  case WM_COMMAND:
    switch(LOWORD(wParam))
    {
    case IDCANCEL: onCancel(hDlg); return TRUE; 
    }
    break;

  case WM_CLOSE:   onClose(hDlg); return TRUE; 
  case WM_DESTROY: PostQuitMessage(0); return TRUE;
  }

  return FALSE;
}

History

  • 20th July, 2011: Initial version

This article, along with any associated source code and files, is licensed under A Public Domain dedication

This member has not yet provided a Biography. Assume it’s interesting and varied, and probably something to do with programming.

Диалоги. Знакомство с элементами управления

Диалоги и элементы управления —
очень обширная тема. Например, для полного
освещения темы элементов управления
потребовалась бы целая книга. Поэтому в данных
методических указаниях мы рассмотрим сначала
основы, а затем только наиболее широко
используемые элементы управления. Это послужит
Вам хорошим фундаментом на пути к углубленному
изучению MFC.

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

Взаимодействие между диалогом и
пользователем

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

  • Обыкновенная кнопка (push button) — это
    кнопка, которую пользователь «нажимает» мышью
    или клавишей Enter,
    переместив предварительно на нее фокус ввода.
  • Контрольный переключатель (check box) может быть
    либо выбранным, либо нет. Если в диалоге есть
    несколько контрольных переключателей, то могут
    быть выбраны одновременно несколько из них.
  • Радиокнопка (radio button) — это почти то же самое, что и
    контрольный переключатель. Только при наличии
    нескольких кнопок в группе может быть выбрана
    только одна.
  • Список (list box) содержит
    набор строк, из которого можно выбрать одну или
    несколько. Широко используется при отображении
    имен файлов.
  • Поле ввода (edit box) — это
    элемент, позволяющий ввести строку текста.
  • Комбинированный список (combo box) представляет собой список со
    строкой ввода.
  • Статический элемент (static control) предназначен
    для вывода текста или графики, но не предназначен
    для ввода.

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

В MFC содержатся классы для всех
стандартных элементов управления. Эти классы
описывают сами элементы, а также содержат
функции для работы с ними. Их называют классами
управления. Они порождаются от класса CWnd.
Таким образом, все они обладают
характеристиками окна. Ниже приведены основные
классы управления:

Класс Элемент
управления
CButton Кнопки,
селекторные кнопки и контрольные переключатели
CEdit Поля
ввода
CListBox Списки
CComboBox Комбинированные
списки
CScrollBar Полосы
прокрутки
Cstatic Статические
элементы

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

Модальные и немодальные диалоги

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

Диалоги как ресурсы

Как уже было упомянуто выше, диалоги не
создаются программно. Вместо этого, при
необходимости из ресурсов загружаются описания
диалогов, и Windows по этому
описанию формирует окно и размещает на нем все
элементы управления.

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

Класс CDialog

В MFC все диалоги являются экземплярами
либо класса CDialog, либо
порожденных от него классов. Лишь самые простые
диалоги используют непосредственно класс CDialog. В общем же случае, необходимо
определять собственный класс. Класс CDialog имеет конструкторы со следующими
прототипами:

 
 	CDialog::CDialog(LPCSTR ResourceName, CWnd *Owner = 0);
 
 	CDialog::CDialog(UINT ResourceID, CWnd *Owner = 0);
 
 	CDialog::CDialog();
 
 

Параметр ResourceName или ResourceID определяет идентификатор диалога
в ресурсах, строковый или числовой. Параметр Owner — это указатель на
окно-собственник, если равен 0, то собственником
будет главное окно приложения. Последняя форма
конструктора предназначена для создания
немодальных диалогов, о которых будет сказано в
дальнейшем.

Обработка сообщений от диалогов

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

Каждый раз, когда элемент управления
диалога активизируется, диалогу посылается
сообщение WM_COMMAND. С этим
сообщением передается идентификатор элемента
управления. Для обработки сообщений в карту
сообщений диалога нужно поместить макрос ON_COMMAND(). Многие элементы управления
генерируют также идентификационный код,
который позволяет определить, какое действие
было произведено с элементом управления. Во
многих случаях по этому коду выбирается тот или
иной обработчик. Как будет показано далее, в MFC
имеется механизм, подобный макросу ON_COMMAND(), с помощью которого можно
связывать идентификационные коды с
обработчиками.

Вызов диалога

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

 
 	virtual int CDialog::DoModal();
 
 

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

Закрытие диалога

По умолчанию диалог закрывается при
получении сообщения с идентификатором либо IDOK, либо IDCANCEL. Они предопределены и обычно
связаны с кнопками подтверждения и отмены. Класс CDialog
содержит встроенные
обработчики для этих двух случаев, OnOK() и OnCancel().
Их не нужно включать в очередь сообщений диалога.
Но их можно переопределить, что дает возможность
программисту управлять закрытием диалога. Для
программного закрытия диалога нужно вызвать
член-функцию с прототипом:

 
 	void CDialog::EndDialog(int RetCode);
 
 

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

Пример программы с диалоговым
окном

Ниже приведены исходные тексты
примера программы с диалогом. Диалог выбирается
с помощью меню. Он имеет три элемента
управления — кнопки «Red», «Green» и «Cancel».
Также переопределена функция OnCancel(), что позволяет при попытке
закрытия диалога вывести окно с подтверждением.
Диалог закрывается программно, с возвратом кода
завершения 7, который затем возвращается
функцией DoModal() и
отображается в окне. Это сделано лишь для
демонстрации, реально же обычно возвращается IDCANCEL. Диалог создавался визуально в
среде Visual C++. Здесь
приводится также файл с идентификаторами,
сгенерированный средой. В дальнейшем этот файл
приводиться не будет, потому что, вообще говоря,
он не предназначен для чтения человеком. Так как
все идентификаторы в примерах имеют осмысленные
имена, то загрузив проект в среду IDE, Вы сможете сразу узнать, какие
идентификаторы каким элементам управления
соответствуют.

 	resource.h
 
 	//{{NO_DEPENDENCIES}}
 	// Microsoft Developer Studio generated include file.
 	// Used by Resources.rc
 
 	#define IDC_RED 1007
 	#define IDC_GREEN 1008
 	#define IDM_DIALOG 40001
 	#define IDM_HELP 40002
 	#define IDM_EXIT 40003
 
 	// Next default values for new objects
 	#ifdef APSTUDIO_INVOKED
 	#ifndef APSTUDIO_READONLY_SYMBOLS
 	#define _APS_NO_MFC 1
 	#define _APS_3D_CONTROLS 1
 	#define _APS_NEXT_RESOURCE_VALUE 106
 	#define _APS_NEXT_COMMAND_VALUE 40010
 	#define _APS_NEXT_CONTROL_VALUE 1008
 	#define _APS_NEXT_SYMED_VALUE 101
 	#endif
 	#endif
 
 	Dialogs.hpp
 	#include "stdafx.h"
 	#include "resource.h"
 
 	// Класс главного окна
 	class CMainWin: public CFrameWnd {
 	public:
 	// Конструктор немного изменен.
 	// Title -- заголовок окна, HowShow -- код показа окна 
 	CMainWin(CString Title, int HowShow); 
 	afx_msg void OnCommand_Dialog(); 
 	afx_msg void OnCommand_Exit();
 	afx_msg void OnCommand_Help();
 	afx_msg void OnPaint();
 	// Установка строки, отображаемой в верхней
 	// части окна
 	virtual void SetInfoStr(CString str);
 	private:
 	CString infoStr; 
 	// Строка, отображаемая в верхней части окна
 	DECLARE_MESSAGE_MAP()
 	};
 
 	// Класс приложения
 	class CApp: public CWinApp {
 	public:
 	BOOL InitInstance();
 	};
 	// Класс диалогового окна
 	class CSampleDialog: public CDialog {
 	public:
 	// DialogName -- идентификатор диалога в ресурсах,
 	// Owner -- окно-владелец (если NULL, то главное окно)
 	CSampleDialog(char *DialogName, CWnd *Owner = NULL);
 	afx_msg void OnCommand_Red();
 	afx_msg void OnCommand_Green();
 	afx_msg void OnCancel();
 	private:
 	DECLARE_MESSAGE_MAP()
 	};
 
 	Dialogs.cpp
 	#include "stdafx.h"
 	#include "Dialogs.hpp"
 	#include "resource.h"
 
 	CApp App;
 
 	//-------------------------------------------------------
 
 	CMainWin::CMainWin(CString Title, int HowShow)
 	:infoStr("")
 	{
 	RECT rect;
 	rect.top = 10; rect.left = 50;
 	rect.bottom = 460, rect.right = 630;
 	this->Create(0, Title, WS_OVERLAPPEDWINDOW, rect, 0, "DIALOGMENU");
 	this->ShowWindow(HowShow);
 	this->UpdateWindow();
 	this->LoadAccelTable("DIALOGMENU");
 	}
 	afx_msg void CMainWin::OnCommand_Dialog()
 	{
 	CSampleDialog sampleDialog("SAMPLEDIALOG", this);
 	int result = sampleDialog.DoModal();
 	char s[20];
 	sprintf(s, "%i", result);
 	this->SetInfoStr(infoStr + ". " +
 	"Функция CDialog::DoModal() возвратила " + CString(s));
 	}
 	afx_msg void CMainWin::OnCommand_Exit()
 	{
 	this->MessageBox("Завершение приложения.",
 			    "Dialogs", MB_ICONEXCLAMATION);
 	this->SendMessage(WM_CLOSE); 
 	}
 	afx_msg void CMainWin::OnCommand_Help()
 	{
 	this->MessageBox("Программа, использующая диалог.n"
 			    "Написана с помощью MFC 4.0.", 
 			    "Dialogs", MB_ICONINFORMATION);
 	}
 
 	afx_msg void CMainWin::OnPaint()
 	{
 	CPaintDC paintDC(this);
 	paintDC.TextOut(10, 10, infoStr);
 	}
 
 	void CMainWin::SetInfoStr(CString str)
 	{
 	infoStr = str;
 	this->InvalidateRect(0);
 	}
 
 	// Карта откликов на сообщения главного окна
 	BEGIN_MESSAGE_MAP(CMainWin, CFrameWnd)
 	ON_COMMAND(IDM_DIALOG, OnCommand_Dialog)
 	ON_COMMAND(IDM_HELP, OnCommand_Help)
 	ON_COMMAND(IDM_EXIT, OnCommand_Exit)
 	ON_WM_PAINT()
 	END_MESSAGE_MAP()

 	//---------------------------------------------------
 	BOOL CApp::InitInstance()
 	{
 	m_pMainWnd = new CMainWin("Dialogs - приложение с диалогом",
 				  SW_RESTORE);
 
 	return TRUE;
 	}
 
 	//---------------------------------------------------
 	CSampleDialog::CSampleDialog(char *DialogName, CWnd *Owner)
 	:CDialog(DialogName, Owner)
 	{
 	}
 
 	afx_msg void CSampleDialog::OnCommand_Red()
 	{
 	// Член-функция CWnd::GetOwner() возвращает указатель
         // на окно-собственник данного окна.
         // Так как в данном случае это главное окно,
         // мы проводим преобразование к CMainWin 
         // и вызываем метод SetInfoStr()
 	((CMainWin *) (this->GetOwner()))
 	->SetInfoStr("Нажата кнопка 'Red'");
 	}
 	afx_msg void CSampleDialog::OnCommand_Green()
 	{
 	// См. комментарий в CSampleDialog::OnCommand_Red()
 	((CMainWin *) (this->GetOwner()))
 	->SetInfoStr("Нажата кнопка 'Green'");
 	} 
 
 	afx_msg void CSampleDialog::OnCancel()
 	{
 	// См. комментарий в CSampleDialog::OnCommand_Red()
 
 	((CMainWin *) (this->GetOwner()))
 
 	->SetInfoStr("Нажата кнопка 'Cancel'");
 
 	// Закрываем диалог, только если пользователь
 	// подтвердил намерение. 
 
 	// Значение 7 будет возвращено DoModal().
 
 	int response = this->MessageBox("Вы уверены ?",
 					"Cancel", MB_YESNO);
 
 	if(response == IDYES)
 
 	this->EndDialog(7);
 
 	}
 
 	// Карта откликов на сообщения диалога
 	BEGIN_MESSAGE_MAP(CSampleDialog, CDialog)
 	ON_COMMAND(IDC_RED, OnCommand_Red)
 	ON_COMMAND(IDC_GREEN, OnCommand_Green)
 	END_MESSAGE_MAP()
 	//------------------------------------------------
 


Рис. 7. Пример приложения с диалогом

Инициализация диалога

Часто различные переменные и элементы
управления, связанные с диалогом, должны быть
инициализированы до того, как диалог будет
отображен. Чтобы позволить диалогу выполнить
подобные действия, Windows автоматически
посылает ему сообщение WM_INITDIALOG в момент создания. При получении
такого сообщения MFC автоматически вызывает
член-функцию OnInitDialog(), которая
является стандартным обработчиком, определенным
в классе CDialog. Эта
функция должна переопределяться в программе,
если необходимо выполнение различных
инициализационных действий. Прототип функции
такой:

 	virtual BOOL CDialog::OnInitDialog();
 

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

Первым действием в переопределенной
функции должен быть вызов функции CDialog::OnInitDialog().

В дальнейшем мы будем использовать эту
функцию в примерах.

Списки

Список является одним из наиболее
распространенных элементов управления. В MFC
работа со списком осуществляется через класс CListBox.

Основы работы со списками

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

Прием идентификационных кодов
списка

Список может генерировать сообщения
различных типов. Например, сообщения посылаются
при двойном щелчке на элементе списка, при потере
списком фокуса ввода и при выборе другого
элемента из списка. Каждое такое событие
описывается идентификационным кодом. Этот код
является частью сообщения WM_COMMAND. Некоторые другие элементы также
используют идентификационные коды.

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

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

 	ON_LBN_DBLCLK(ИдентификаторСписка,
 		      ИмяОбработчика)
 

Многие сообщения обрабатываются
подобным образом. Названия всех макросов для
таких сообщений начинаются с префикса ON_LBN_.

Передача сообщений списку

В традиционных Windows-программах сообщения посылаются
элементам управления с помощью API-функций, например SendDlgItemMessage(). Но в программах на MFC для этих
целей применяются соответствующие
функции-члены. Они автоматически посылают нужное
сообщение элементу управления. В этом
заключается преимущество MFC по сравнению с
традиционным методом программирования.

Списку может быть послано несколько
разных сообщений. Для каждого класс CListBox содержит отдельную член-функцию.
Например, рассмотрим следующие функции:

 	int CListBox::AddString(LPCSTR StringToAdd);
 	int CListBox::GetCurSel() const;
 	int CListBox::GetText(int Index, LPCSTR StringVariable);
 

Функция AddString() вставляет указанную строку в
список. По умолчанию она вставляется в конец
списка. Начало списка имеет индекс 0. Функция GetCurSel()
возвращает индекс текущего
выделенного элемента. Если ни один элемент не
выбран, возвращает LB_ERR.
Функция GetText() получает строку, связанную с
указанным индексом. Строка копируется в
символьный массив по адресу StringVariable.

Получение указателя на список

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

 СWnd *CWnd::GetDlgItem(int ItemIdentifier) const;
 

Эта функция возвращает указатель на
объект, чей идентификатор передан как параметр.
Если такой объект не существует, то возвращается
0. Необходимо понимать, что указатель,
возвращаемый функцией, является временным. Он
действителен только в пределах текущего
обработчика.

Значение, возвращенное функцией,
должно быть приведено к типу указателя на
конкретный класс управления. Например, в нашем
случае это тип CListBox*.

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

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

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

Мы расширим предыдущий пример
программы и добавим в диалог список. Выбор
элемена списка осуществляется либо с помощью
двойного щелчка на элементе, либо при нажатии на
кнопку «Выбери фрукт». Обратите внимание, что в
обоих случаях вызывается один и тот же
обработчик, который сначала получает адрес
объекта списка, затем получает номер выделенного
пункта, а по номеру получает выделенную строку.
Строка печатается в окне.

 
 	Listbox.hpp
 
 	#include "stdafx.h"
 	#include "resource.h"
 	// Класс основного окна
 	class CMainWin: public CFrameWnd {
 	public:
 	CMainWin(CString Title, int HowShow);
 	afx_msg void OnCommand_Dialog();
 	afx_msg void OnCommand_Exit();
 	afx_msg void OnCommand_Help();
 	afx_msg void OnPaint();
 	virtual void SetInfoStr(CString str);
 	private:
 	CString infoStr;
 	DECLARE_MESSAGE_MAP()
 	};
 
 	// Класс приложения
 	class CApp: public CWinApp {
 	public:
 	BOOL InitInstance();
 	};
 
	// Класс диалога
 	class CSampleDialog: public CDialog {
 	public:
 	CSampleDialog(char *DialogName, CWnd *Owner = NULL);
 	BOOL OnInitDialog();
 	afx_msg void OnCommand_Red();
 	afx_msg void OnCommand_Green();
 	afx_msg void OnSelectFruit();
 	afx_msg void OnCancel();
 	private:
 	DECLARE_MESSAGE_MAP()
 	};
 
 	Listbox.cpp
 
 	#include "stdafx.h"
 	#include <stdlib.h>
 	#include "Listbox.hpp"
 	#include "Resource.h"
 	//------------------------------------------------
 	// Реализация CMainWin
 	 
 	CMainWin::CMainWin(CString Title, int HowShow)
 	:infoStr("")
 	{
 	RECT rect;
 	rect.top = 10; rect.left = 50;
 	rect.bottom = 460, rect.right = 630;
 	this->Create(0, Title, WS_OVERLAPPEDWINDOW, rect, 0,
 			"MENU");
 	this->ShowWindow(HowShow);
 	this->UpdateWindow();
 	this->LoadAccelTable("DIALOGMENU");
 	}

 	afx_msg void CMainWin::OnCommand_Dialog()
 	{
 	CSampleDialog sampleDialog("SAMPLEDIALOG");
 	sampleDialog.DoModal();
 	this->SetInfoStr("Диалог закрыт.");
 	}
 
 	afx_msg void CMainWin::OnCommand_Exit()
 	{
 	this->SendMessage(WM_CLOSE);
 	}
 
 	afx_msg void CMainWin::OnCommand_Help()
 	{
 	this->MessageBox("Демонстрация элемента управления Listbox", 
 	"Listbox", MB_ICONINFORMATION);
 	}
 
 	afx_msg void CMainWin::OnPaint()
 	{
 	CPaintDC paintDC(this);
 	paintDC.TextOut(10, 10, infoStr, infoStr.GetLength());
 	}
 
 	void CMainWin::SetInfoStr(CString str)
 	{
 	infoStr = str;
 	this->InvalidateRect(0);
 	}
 
	BEGIN_MESSAGE_MAP(CMainWin, CFrameWnd)
 	ON_COMMAND(IDM_DIALOG, OnCommand_Dialog)
 	ON_COMMAND(IDM_HELP, OnCommand_Help)
 	ON_COMMAND(IDM_EXIT, OnCommand_Exit)
 	ON_WM_PAINT()
 	END_MESSAGE_MAP()
 	//----------------------------------------------
 
	BOOL CApp::InitInstance()
 	{
 	m_pMainWnd = new CMainWin("Listbox", SW_RESTORE);
 	return TRUE;
 	}

 	//----------------------------------------------
 	CSampleDialog::CSampleDialog(char *DialogName, CWnd *Owner)
 	:CDialog(DialogName, Owner)
 	{
 	}
 
 	afx_msg void CSampleDialog::OnCommand_Red()
 	{
 	((CMainWin *) (this->GetOwner()))
 	->SetInfoStr("Нажата кнопка 'Red'");
 	}
 
 	afx_msg void CSampleDialog::OnCommand_Green()
 	{
 	((CMainWin *) (this->GetOwner())) 
 	->SetInfoStr("Нажата кнопка 'Green'");
 	} 

 	// Инициализация диалога
 	BOOL CSampleDialog::OnInitDialog()
 	{
 	CDialog::OnInitDialog();
	// Вызвать метод базового класса
 	// Получить объект списка Listbox
 
 	CListBox *listBoxPtr = (CListBox *) 
 		(this->GetDlgItem(IDC_LB1));
 
 	// Добавить строки в список
 	listBoxPtr->AddString("Яблоко");
 	listBoxPtr->AddString("Слива");
 	listBoxPtr->AddString("Груша");
 	listBoxPtr->AddString("Апельсин");
 	listBoxPtr->AddString("Мандарин");
 	listBoxPtr->AddString("Абрикос");
 	listBoxPtr->AddString("Персик");
 	listBoxPtr->AddString("Ананас");
 	return TRUE;
 	}
 
 	// Обработчик сообщения выбора элемента
 
 	// (двойной щелчок на списке или нажатие
 	// специальной кнопки)
 
 	afx_msg void CSampleDialog::OnSelectFruit()
 	{
 	CListBox *listBoxPtr = (CListBox *) (this->GetDlgItem(IDC_LB1));
 	// Получить номер текущего выделенного элемента списка
 	int index = listBoxPtr->GetCurSel();
 	// Если результат LB_ERR, то ни один элемент еще не выделен
 	if(index == LB_ERR) {
 	((CMainWin *) (this->GetOwner())) 
 	->SetInfoStr("Ни один фрукт не выделен");
 	}
 
 	else {
 	char s[100];
 	// Получить текст выделенного элемента
 	listBoxPtr->GetText(index, s);
 	CString infoStr;
 	infoStr.Format("Выбран фрукт %s с индексом %i", s,
	       index);
 	// Вывести сообщение
 	((CMainWin *) (this->GetOwner())) 
 	->SetInfoStr(infoStr);
 	}
 	}
 
 	afx_msg void CSampleDialog::OnCancel()
 	{
 	((CMainWin *) (this->GetOwner())) 
 	->SetInfoStr("Нажата кнопка 'Cancel'");
 	this->EndDialog(TRUE);
 	}
 
 	BEGIN_MESSAGE_MAP(CSampleDialog, CDialog)
 	ON_COMMAND(IDC_RED, OnCommand_Red)
 	ON_COMMAND(IDC_GREEN, OnCommand_Green)
 	ON_COMMAND(IDC_SELFRUIT, OnSelectFruit)
 	ON_LBN_DBLCLK(IDC_LB1, OnSelectFruit) // Сообщение от списка
 	END_MESSAGE_MAP()
 	//------------------------------------------------
 
 	CApp App;
 


Рис. 8. Пример приложения со списком

Поле ввода

Это последний элемент управления,
который мы рассмотрим в качестве введения в
диалоги и элементы управления. Поля ввода
используются очень широко, так как дают
возможность ввести строку по своему усмотрению.
Даже зная, как создавать только поля ввода и
списки, уже можно писать полезные программы.

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

Для получения текущего содержимого
поля вода, состоящего из одной строки,
используется функция GetWindowText(). Ее прототип таков:

 	int CWnd::GetWindowText(LPSTR StringVariable,
 				int MaxStringLen) const;
 

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

В момент создания поле ввода является
пустым. Для инициализации его содержимым
используется еще одна функция-член класса CWnd —
SetWindowText(). Она отображает
строку в элементе управления, который вызвал эту
функцию. Вот ее прототип:

 	void CWnd::SetWindowText(LPCSTR String);
 

Пример программы с полем ввода

 	edbox.hpp
 
 	#include "stdafx.h"
 	#include "resource.h"
 
 	// Класс основного окна
 	class CMainWin: public CFrameWnd {
 	public:
 	CMainWin(CString Title, int HowShow);
 	afx_msg void OnCommand_Dialog();
 	afx_msg void OnCommand_Exit();
 	afx_msg void OnCommand_Help();
 	afx_msg void OnPaint();
 	virtual void SetInfoStr(CString str);
 	private:
 	CString infoStr;
 	DECLARE_MESSAGE_MAP()
 	};
 
 	// Класс приложения
 	class CApp: public CWinApp {
 	public:
 	BOOL InitInstance();
 	};
 
 	// Класс диалога
 	class CSampleDialog: public CDialog {
 	public:
 	CSampleDialog(char *DialogName, CWnd *Owner);
 	BOOL OnInitDialog();
 	afx_msg void OnCommand_Red();
 	afx_msg void OnCommand_Green();
 	afx_msg void OnCommand_EditOK();

 	// Здесь читаются данные поля ввода
 	afx_msg void OnSelectFruit();
 	afx_msg void OnCancel();
	private:
 	DECLARE_MESSAGE_MAP()
 	};
 
 	edbox.hpp

 	#include "stdafx.h"
 	#include <stdlib.h>
 	#include "Edbox.hpp"
 	#include "resource.h"
 	// Реализация
 	//-------------------------------------------
 	CMainWin::CMainWin(CString Title, int HowShow)
 	:infoStr("")
 	{
 	RECT rect;
 	rect.top = 10; rect.left = 50;
 	rect.bottom = 460, rect.right = 630;
 	this->Create(0, Title, WS_OVERLAPPEDWINDOW, rect, 0,
 			"DIALOGMENU");
 	this->ShowWindow(HowShow);
 	this->UpdateWindow();
 	this->LoadAccelTable("DIALOGMENU");
 	}
 
 	afx_msg void CMainWin::OnCommand_Dialog()
 	{
 	CSampleDialog sampleDialog("SAMPLEDIALOG", this);
 	sampleDialog.DoModal();
 	this->SetInfoStr("Диалог закрыт");
 	}
 
 	afx_msg void CMainWin::OnCommand_Exit()
 	{
 	this->SendMessage(WM_CLOSE);
 	}
 
 	afx_msg void CMainWin::OnCommand_Help()
 	{
 	this->MessageBox("Программа, использующая Editboxn",
 	"Editbox", MB_ICONINFORMATION);
 	}
 
 	afx_msg void CMainWin::OnPaint()
 	{
 	CPaintDC paintDC(this);
 	paintDC.TextOut(10, 10, infoStr);
 	}
 
 	void CMainWin::SetInfoStr(CString str)
 	{
 	infoStr = str;
 	this->InvalidateRect(0);
 	}
 
 	BEGIN_MESSAGE_MAP(CMainWin, CFrameWnd)
 	ON_COMMAND(IDM_DIALOG, OnCommand_Dialog)
 	ON_COMMAND(IDM_HELP, OnCommand_Help)
 	ON_COMMAND(IDM_EXIT, OnCommand_Exit)
 	ON_WM_PAINT()
 	END_MESSAGE_MAP()

 	//----------------------------------------------
 	BOOL CApp::InitInstance()
 	{
 	m_pMainWnd = new CMainWin("Editbox", SW_RESTORE);
 	return TRUE;
 	}

 	//----------------------------------------------
 	CSampleDialog::CSampleDialog(char *DialogName, CWnd *Owner)
 	:CDialog(DialogName, Owner)
 	{
 	}
 
 	BOOL CSampleDialog::OnInitDialog()
 	{
 	CDialog::OnInitDialog();
 	CListBox *listBoxPtr = (CListBox *) (this->GetDlgItem(IDC_LB1));
 	listBoxPtr->AddString("Яблоко");
 	listBoxPtr->AddString("Слива");
 	listBoxPtr->AddString("Груша");
 	listBoxPtr->AddString("Апельсин");
 	listBoxPtr->AddString("Мандарин");
 	listBoxPtr->AddString("Абрикос");
 	listBoxPtr->AddString("Персик");
 	listBoxPtr->AddString("Ананас");

 	// Получить объект Editbox
 	CEdit *editBoxPtr = (CEdit *) (this->GetDlgItem(IDC_EDIT1));

 	// Установить текст в Editbox
 	editBoxPtr->SetWindowText("Вася");
 	return TRUE;
 	}
 
 	afx_msg void CSampleDialog::OnCommand_Red()
 	{
 	((CMainWin *) (this->GetOwner()))
 		->SetInfoStr("Нажата кнопка 'Red'");
 	}
 
 	afx_msg void CSampleDialog::OnCommand_Green()
 	{
 	((CMainWin *) (this->GetOwner()))
 		->SetInfoStr("Нажата кнопка 'Green'");
 	} 
 
 	// Здесь читается текст из Editbox
 	afx_msg void CSampleDialog::OnCommand_EditOK()
 	{
 	// Получить объект Editbox
 	CEdit *pCEdit = (CEdit *) (this->GetDlgItem(IDC_EDIT1));
 	char s[1024];
 	// Прочитать текст из Editbox
 	pCEdit->GetWindowText(s, sizeof(s) / sizeof(s[0]) - 1);
 	// Вывести информацию в окно
 	((CMainWin *) (this->GetOwner()))
 		->SetInfoStr(CString("Введена строка "") 
 				+ s + """);
 	}
 
 	afx_msg void CSampleDialog::OnSelectFruit()
 	{
 	CListBox *listBoxPtr = (CListBox *) (this->GetDlgItem(IDC_LB1));
 	int index = listBoxPtr->GetCurSel();
 	if(index == LB_ERR) {
 	((CMainWin *) (this->GetOwner()))
 		->SetInfoStr("Ни один фрукт не выделен");
 
 	}
 	else {
 	char s[100];
 	listBoxPtr->GetText(index, s);
 	CString infoStr;
 	infoStr.Format("Выбран фрукт %s с индексом %i", s,
 		       index);
 	((CMainWin *) (this->GetOwner()))->SetInfoStr(infoStr);
 	}
 	}
 	afx_msg void CSampleDialog::OnCancel()
 	{
 	this->EndDialog(TRUE);
 	}
 
 	BEGIN_MESSAGE_MAP(CSampleDialog, CDialog)
 	ON_COMMAND(IDC_RED, OnCommand_Red)
 	ON_COMMAND(IDC_GREEN, OnCommand_Green)
 	ON_COMMAND(IDC_EDITOK, OnCommand_EditOK)
 	ON_COMMAND(IDC_SELFRUIT, OnSelectFruit)
 	ON_LBN_DBLCLK(IDC_LB1, OnSelectFruit)
 	END_MESSAGE_MAP()
 	//-------------------------------------------------
 	CApp App;
 


Рис. 9. Приложение со строкой редактирования в
диалоге

Немодальные диалоги

Немодальные диалоги получают
сообщения параллельно с основным окном
bприложения. То есть, как минимум два окна будут
одновременно активными. Поэтому работа с
немодальными диалогами требует чуть больше
усилий, должны быть выполнены дополнительные
операции.

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

Для создания объекта немодального
диалога нужно использовать конструктор CDialog::CDialog()
без параметров. Он объявлен
как protected-член класса. Это
означает, что он может быть вызван только изнутри
член-функции порожденного класса. Это сделано
для того, чтобы программист обязательно
определял свой порожденный класс для
немодального диалога, и определял в нем
дополнительные операции для немодального
диалога.

Когда экземпляр создан, он
привязывается к ресурсам с помощью функций:

 	BOOL CDialog::Create(LPCSTR ResourceName, CWnd *Owner = 0);
 	BOOL CDialog::Create(UINT ResourceId, CWnd *Owner = 0);
 

Первый параметр определяет
идентификатор диалога в ресурсах. Второй
параметр, как обычно, определяет
окно-собственник для диалога.

Необходимо помнить о том, что объект
немодального диалога должен существовать в
течение всего времени использования диалога.
Функция Create() отображает
окно и после этого немедленно завершается. А
объект окна должен существовать.

В отличие от модальных окон,
немодальные не становятся автоматически
видимыми при вызове. Чтобы диалог сразу был
видимым, нужно в ресурсном редакторе установить
опцию Visible. Или можно
использовать функцию ShowWindow().

Для закрытия немодального диалога
нужно использовать функцию DestroyWindow(). Это означает, что функции OnCancel()
и/или OnOK() должны быть переопределены.

Пример программы с немодальным
диалогом

 	ModelessDialog.hpp
 
 	#include "stdafx.h"
 	#include "resource.h"
 
 	class CMainWin;
 	// Класс немодального диалога
 	class CSampleDialog: public CDialog {
 	public:
 	CSampleDialog();
 	// Функция привязки диалога к ресурсам
 
 	BOOL Create(LPCSTR DialogName, CWnd *Owner = 0);
 	BOOL OnInitDialog();
 	afx_msg void OnCommand_Red();
 	afx_msg void OnCommand_Green();
 	afx_msg void OnCommand_EditOK();
 	afx_msg void OnSelectFruit();
 	afx_msg void OnCancel();
 	private:
 
 	// Переменная, показывающая, используется ли в
 	// данный момент диалог
 
 	BOOL inUse;
 	CMainWin *owner;
 	DECLARE_MESSAGE_MAP()
 	};
 
 	class CMainWin: public CFrameWnd {
 	public:
 	CMainWin(CString Title, int HowShow);
 	afx_msg void OnCommand_Dialog();
 	afx_msg void OnCommand_Exit();
 	afx_msg void OnCommand_Help();
 	afx_msg void OnPaint();
 	virtual void SetInfoStr(CString str);
 	private:

 	// Экземпляр объекта диалога -
 
 	// существует все время, пока существует
 	// основное окно
 
 	CSampleDialog dialog;
 	CString infoStr;
 	DECLARE_MESSAGE_MAP()
 	};
 	class CApp: public CWinApp {
 	public:
 	BOOL InitInstance();
 
 	};
 
 	ModelessDialog.cpp
 
 	#include "stdafx.h"
 	#include <stdlib.h>
 	#include "ModelessDialog.hpp"
 	#include "resource.h"
 
 	static CApp App;
 	//--------------------------------------------------
 
 	CMainWin::CMainWin(CString Title, int HowShow)
 	// Вызываем конструктор без параметров класса диалога
 	:dialog(), infoStr("")
 	{
 	RECT rect;
 	rect.top = 10; rect.left = 50;
 	rect.bottom = 460, rect.right = 630;
 	this->Create(0, Title, WS_OVERLAPPEDWINDOW, rect, 0,
 			"DIALOGMENU");
 	this->ShowWindow(HowShow);
 	this->UpdateWindow();
 	this->LoadAccelTable("DIALOGMENU");
 	}
 
 	afx_msg void CMainWin::OnCommand_Dialog()
 	{
 	dialog.Create("SAMPLEDIALOG", this);
 	}

 	afx_msg void CMainWin::OnCommand_Exit()
 	{
 	this->SendMessage(WM_CLOSE);
 	}
 
 	afx_msg void CMainWin::OnCommand_Help()
 	{
 	this->MessageBox("Программа, использующая немодальный диалог.",
                             "О программе", MB_ICONINFORMATION);
 	}
 
 	afx_msg void CMainWin::OnPaint()
 	{
 	CPaintDC paintDC(this);
 	paintDC.TextOut(10, 10, infoStr);
 	}
 
 	void CMainWin::SetInfoStr(CString str)
 	{
 	infoStr = str;
 	this->InvalidateRect(0);
 	}
 
 	BEGIN_MESSAGE_MAP(CMainWin, CFrameWnd)
 	ON_COMMAND(IDM_DIALOG, OnCommand_Dialog)
 	ON_COMMAND(IDM_HELP, OnCommand_Help)
 	ON_COMMAND(IDM_EXIT, OnCommand_Exit)
 	ON_WM_PAINT()
 	END_MESSAGE_MAP()
 	//----------------------------------------------------
 
 	BOOL CApp::InitInstance()
 	{
 	m_pMainWnd = new CMainWin("Приложение с немодальным
 				  диалогом", SW_RESTORE);
 	return TRUE;
 	}
 
 	//----------------------------------------------------
 	CSampleDialog::CSampleDialog()
 	:CDialog()
 	{
 	// Объект создан, но пока не используется
 	inUse = FALSE;
 	}

 	BOOL CSampleDialog::Create(LPCSTR DialogName, CWnd *Owner)
 	{
 	// Если диалог уже используется (был отображен),
 	// то только отобразить его
 	if(inUse) {
 	this->ShowWindow(SW_SHOW);
 	return TRUE;
 	}
 
 	inUse = TRUE; // Диалог используется
 	// Создать диалог и получить результат создания
 	BOOL success = (CDialog::Create(DialogName, Owner) != FALSE);
 	owner = (CMainWin *) Owner; // Собственник
 	return success;
 	}
 
 	BOOL CSampleDialog::OnInitDialog()
 	{
 	CDialog::OnInitDialog();
 	CListBox *listBoxPtr = (CListBox *) (this->GetDlgItem(IDC_LB1));
 	listBoxPtr->AddString("Яблоко");
 	listBoxPtr->AddString("Слива");
 	listBoxPtr->AddString("Груша");
 	listBoxPtr->AddString("Апельсин");
 	listBoxPtr->AddString("Мандарин");
 	listBoxPtr->AddString("Абрикос");
 	listBoxPtr->AddString("Персик");
 	listBoxPtr->AddString("Ананас");
 	CEdit *editBoxPtr = (CEdit *) (this->GetDlgItem(IDC_EDIT1));
 	editBoxPtr->SetWindowText("Вася");
 	return TRUE;
 	}
 
 	afx_msg void CSampleDialog::OnCommand_Red()
 	{
 	owner->SetInfoStr("Нажата кнопка 'Red'");
 	}
 
 	afx_msg void CSampleDialog::OnCommand_Green()
 	{
 	owner->SetInfoStr("Нажата кнопка 'Green'");
 	} 
 
 	afx_msg void CSampleDialog::OnCommand_EditOK()
 	{
 	CEdit *pCEdit = (CEdit *) (this->GetDlgItem(IDC_EDIT1));
 	char s[1024];
 	pCEdit->GetWindowText(s, sizeof(s) / sizeof(s[0]) - 1);
 	owner->SetInfoStr(CString("Введена строка "") 
 			     + s + """);
 	}
 
 	afx_msg void CSampleDialog::OnSelectFruit()
 	{
 
 	CListBox *listBoxPtr = (CListBox *) 
 			(this->GetDlgItem(IDC_LB1));
 	int index = listBoxPtr->GetCurSel();
 	if(index == LB_ERR) {
 	owner->SetInfoStr("Ни один фрукт не выделен");
 	}
 
 	else {
 	char s[100];
 	listBoxPtr->GetText(index, s);
 	CString infoStr;
 	infoStr.Format("Выбран фрукт %s с индексом %i", s,
 		       index);
 	owner->SetInfoStr(infoStr);
 	}
 	}
 
 	afx_msg void CSampleDialog::OnCancel()
 	{
 	owner->SetInfoStr("Нажата кнопка 'Cancel'");
 	// Удалить диалог
 	this->DestroyWindow();
 	// Больше диалог не используется
 	inUse = FALSE;
 	}
 
 	BEGIN_MESSAGE_MAP(CSampleDialog, CDialog)
 	ON_COMMAND(IDC_RED, OnCommand_Red)
 	ON_COMMAND(IDC_GREEN, OnCommand_Green)
 	ON_COMMAND(IDC_EDITOK, OnCommand_EditOK)
 	ON_COMMAND(IDC_SELFRUIT, OnSelectFruit)
 	ON_LBN_DBLCLK(IDC_LB1, OnSelectFruit)
 	END_MESSAGE_MAP()
 


Рис. 10. Пример приложения с немодальным диалогом

Пример программы на условные операторы if в Си.

Программа провдит диалог с человеком, узнает его интересы Программа запрашивает имя пользователя, приветствует его по имени.Запрашивает и анализирует возраст.(молодой, средних лет или пожилой) . Задает вопросы  о любимом цвете,  стиле музыки, типах книг и другие. Проверяет схожесть интересов, выводит информацию о схожести интересов. При написании программы полезными будут уроки Вывод информации на экран в Си  Условия в Си
Описание алгоритма программы на Си для диалога  скомпьютером
На этом уроке мы напишем программу на Си анкета, диалог с компьютером. Вначале программы определяются  ответы по каждому вопросу, для этого  вводятся для каждого вопроса своя переменная и присваивается ей нужное значение.Например:
int age=40;// возраст
int cvet=1;// номер любимого цвета 1 –зеленый  2-красный 3-синий 4-желтый 5-черный 6 — другой
int music=1;// номер стиля музыки  1 — рок 2 — поп  3 — классика 4 — джаз  5 -металл  6 — реп 7 – другой

Программа должна задавать вопросы  с различными вариантами ответов. Пользователь вводит номер ответа. Ответ пользователя  сравнивается с  определенным ответом в начале программы.
printf(«Какой Ваш любимый цвет? 1 -зеленый 2-красный 3-синий 4-желтый 5-черный 6 — другойn»);
// запрашиваем ответ
scanf(«%d», &a);
// проверяем правильность ответа
if (a==cvet)
{
  k=k+1;// увеличиваем счетчик правильных ответов      
         }

Чтобы подсчитать количество совпавших ответов  используется специальная переменная счетчик ответов k.
В конце теста производится проверка количества совпавших ответов, если количество больше  заданного параметра, то выводится сообщение о схожести интересов.
// анализ количества совпавших ответов
if (k>2)
{
   printf («У нас  с Вами %s очень много схожего. Мы сможем подружиться n»,n);     
         }   
else
{
  printf («Мы с Вами %s очень разные n», n); 
    }

Пример полного решения программа на си диалог с компьютером,анкетирование
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
main()
{
char n[50];// объявляем строковую переменную n для имени
int k; // счетчик совпадающих ответов
int a; // номер текущего ответа
int age=40;// возраст
int cvet=1;// номер любимого цвета 1 -зеленый 2-красный 3-синий 4-желтый 5-черный 6 — другой
int music=1;// номер стиля музыки  1 — рок 2 — поп  3 — классика 4 — джаз  5 -металл  6 — реп 7 — другой
int book=2;// номер вида книг 1 — детективы 2-фантастика 3- классика 4 — научная литература 5 -развлекательные журналы 6 — другие
int film=2;// номер типа фильмов 1 — боевики 2-фантастика 3-детективы 4-исторические 5-сериалы  6 -другие
 k=0;// обнуление счетчика совпавших ответов
// приветствие
printf(«Как Ваше имя ?n «);
scanf(«%s», n); // ввод строки  n имени
printf(«Здравствуйте,  %s! Очень хотелось бы узнать тебя получше. Ответьте пожалуйстаn», n); // форматированный вывод Здравствуйте, n !

// 1 вопрос
printf(«Каков Ваш возраст?n»);
// запрашиваем ответ
scanf(«%d», &a);

// проверяем правильность ответа
if (abs(a-age)<5)
{
  printf(«Здорово! мы  ровесники «);
  k=k+1;// увеличиваем счетчик правильных ответов      
         }

// 2 вопрос
printf(«Какой Ваш любимый цвет? 1 -зеленый 2-красный 3-синий 4-желтый 5-черный 6 — другойn»);
// запрашиваем ответ
scanf(«%d», &a);
// проверяем правильность ответа
if (a==cvet)
{
  k=k+1;// увеличиваем счетчик правильных ответов      
         }

// 3 вопрос
printf(«Какой Ваш любимый стиль музыки?   1 — рок 2 — поп  3 — классика 4 — джаз  5 -металл  6 — реп 7 — другойn»);
// запрашиваем ответ
scanf(«%d», &a);
// проверяем правильность ответа
if (a==music)
{
  k=k+1;// увеличиваем счетчик правильных ответов      
         }

// 4 вопрос
printf(«Какой Вы любите читать книги? 1 – детективы  2-фантастика 3- классика 4 — научная литература 5 -развлекательные журналы 6 — другиеn»);
// запрашиваем ответ
scanf(«%d», &a);
// проверяем правильность ответа
if (a==book)
{
  k=k+1;// увеличиваем счетчик правильных ответов      
         } 

// 5 вопрос
printf(«Какой Вам нравятся фильмы?  1 — боевики 2-фантастика 3-детективы 4-исторические 5-сериалы  6 -другиеn»);
// запрашиваем ответ
scanf(«%d», &a);
// проверяем правильность ответа
if (a==film)
{
  k=k+1;// увеличиваем счетчик правильных ответов      
         }

// анализ количества совпавших ответов
if (k>2)
{
   printf («У нас  с Вами %s очень много схожего. Мы сможем подружитьсяn»,n);     
         }   
else
{
  printf («Мы с Вами %s очень разныеn», n); 
    }

getch();      
}

На заметку:
1. В программе введен счетчик  правильных ответов переменная k . В начале программы она обнуляется k=0.  Если ответ пользователя совпадает с  заданным в программе, то счетчик увеличивается k=k+1.
Задания для самостоятельной работы:
1 В диалоге добавьте несколько  своих вопросов. Не забудьте ввести для них переменные с правильными ответами в начале программы.
2. Напишите программу   тест по любимому предмету. Программа  задает и запрашивает ответы  по  избранной теме. Подсчитывает количество верных ответов. В конце теста выставляет оценку исходя из количества правильных ответов.
Возможный вариант реализации тест на си
#include <stdio.h>
#include <conio.h>
main()
{
char n[50];// объявляем строковую переменную n для имени
int k; // счетчик правильных ответов
int a; // номер ответа
k=0;
// приветствие
printf(«Как Ваше имя ?n»);
scanf(«%s», n); // ввод строки  n имени
printf(«Здравствуйте,  %s! Вам предлагается тест по географииn», n); // форматированный вывод Здравствуйте, n !
// 1 вопрос теста
printf(«Столица Антигуа и Барбуда? Введите номер правильного ответаn»);
printf(«1. Сент-Джонс 2. Сукре 3. Бужумбура 4. Банжул 5. Бисауn»);
// запрашиваем ответ
scanf(«%d», &a);
// проверяем правильность ответа
if (a==1)
{
  printf(«Правильно «);
  k=k+1;// увеличиваем счетчик правильных ответов      
         }

else{
 printf(«Не правильно «);
     }

// 2 вопрос теста
printf(«Лидер по добыче каменного угля? Введите номер правильного ответаn»);
printf(«1. Россия 2. Индия 3. США 4. Китай 5. Австралияn»);
// запрашиваем ответ
scanf(«%d», &a);
// проверяем правильность ответа
if (a==4)
{
  printf(«Правильноn»);
  k=k+1;// увеличиваем счетчик правильных ответов      
         }
else{
 printf(«Не правильноn»);
     }

// 3 вопрос теста
printf(«Самая высокая гора? Введите номер правильного ответаn»);
printf(«1. Чогори 2. Канченджанга 3. Эверест 4. Джомолунгма 5. Эльбрусn»);
// запрашиваем ответ
scanf(«%d», &a);
// проверяем правильность ответа
if (a==4)
{
  printf(«Правильноn»);
  k=k+1;// увеличиваем счетчик правильных ответов      
         }
else{
 printf(«Не правильноn»);
     }

Вернуться к содержанию

Полезно почитать по теме условия в си
Условия в Си
Решение линейного уравнения на Си

Поделиться

Нет комментариев. Ваш будет первым!

Понравилась статья? Поделить с друзьями:
  • Как написать программу джарвиса
  • Как написать программу генератор случайных чисел
  • Как написать программу вычисляющую значение функции
  • Как написать программу вычисления площади круга
  • Как написать программу вычисления наименьшего общего кратного