Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
консплекС++1к 2013.doc
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
667.14 Кб
Скачать

Лекція 9.Структури та об’єднання

План лекції (4 години)

  1. Структура (struct)

  2. Оголошення структури

  3. Доступ до членів структури

  4. Приклад створення простої структури

  5. Передавання структур як аргументів функції

  6. Вкладені структури

  7. Бітові поля

  8. Функції як елементи структури

  9. Оголошення об’єднання

  10. Спосіб збереження об’єднання у С++

  11. Використанні анонімних об’єднань у C++

Розглянемо додаткові типи даних, які використовуються в С та С++: структури, об’єднання, бітові поля та інші. Структури є важливим засобом, оскільки служать основою для побудови класів – фундаментального поняття об’єктно-орієнтованого програмування. Розуміння принципів створення структур полегшує розуміння функціонування класів у С++. .

Структура

Структура – це група змінних різних типів, поєднаних у єдине ціле. Вона відтворює таблицю даних різного типу.

Оголошення структури

Структура створюється за допомогою ключового слова struct, слідом за яким записується необов’язковий тег(ім’я), а потім – список членів структури. Тег буде використовуватися як ім’я нового типу даних для створення змінних вказаного типу. оголошення структури у загальному вигляді буде таким:

struct тег {тип1 ім’я1; тип2 ім’я2; тип3 ім’я3; …… тип n ім’я n;};

У прикладах програм використовується така структура:

struct stboat{ char szmodel [iSTRING15+iNULL_CHAR];

char szserial[iSTRING20+iNULL_CHAR];

int iyear;

long lmotor_hours;

float fsaleprice; };

У даному випадку створюється структура з іменем stboat, яка містить оголошення моторного човна. Масив szmodel зберігає назву моделі човна, а масив szserial – її реєстраційний номер. У змінній iyear записаний рік виробництва човна., а у змінній lmotor_hours – напрацьований ресурс мотора у годинах, у змінній fsaleprice – ціна.

Створити змінну на основі оголошеної структури можна таким чином:

struct stboat stused_boat;

У цьому виразі оголошується змінна stused_boat типу struct stboat. Допускається й таке оголошення:

struct stboat{ char szmodel [iSTRING15+iNULL_CHAR];

char szserial[iSTRING20+iNULL_CHAR];

int iyear; long lmotor_hours;

float fsaleprice; } stused_boat;

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

struct { char szmodel [iSTRING15+iNULL_CHAR];

char szserial[iSTRING20+iNULL_CHAR];

int iyear; long lmotor_hours;

float fsaleprice; } stused_boat;

Створена структура називається непоіменованою. Більше ніде у програмі не можна буде створювати її примірники, щонайменше прийдеться повторити оголошення структури. Проте при такому оголошенні структури можна оголосити одразу кілька змінних:

struct { char szmodel [iSTRING15+iNULL_CHAR];

char szserial[iSTRING20+iNULL_CHAR];

int iyear; long lmotor_hours;

float fsaleprice; } stboat1, stboat2, stboat3;

Компілятор зарезервує для членів структури потрібний об’єм пам’яті, подібно до оголошення звичайних змінних.

У С++ при створенні примірника структури, описаної раніше, ключове слово struct можна не вказувати:

У С та С++ можна оголошувати так:

struct stboat stused_boat;

Тільки у С++: stboat stused_boat;

Доступ до членів структур

Доступ до окремих членів структури можна отримати за допомогою оператора крапки:

ім’я_змінної.член_структури

Наприклад, у мові С запитати вміст поля szmodel описаної вище структури stused_boat можна за допомогою наступного виразу:

gets(stused_boat.szmodel);

Вивести отримане значення на екран можна так:

printf(“%s”, stused_boat. szmodel);

У С++ застосовується подібний синтаксис:

cin>> stused_boat.szmodel; cout<< stused_boat. szmodel;

Приклад створення простої структури

У наступному прикладі використовується структура stboat, оголошення якої розглядалось вище.

#define iSTRINGIS 15

#define iSTRING20 20

#define iNULL_CHAR 1

struct stboat {

char szmodel [iSTRINGIS15+iNULL_CHAR];

char szserial[iSTRING20+iNULL_CHAR];

int iyear; long lmotor_hours;

float fsaleprice; } stused_boat;

….

pDC->TextOut(25,25,“Введіть модель судна: “);

gets(stused_boat. szmodel);

pDC->TextOut(45,45,“Введіть реєстраційний номер судна: “);

gets(stused_boat. szserial );

pDC->TextOut(65,65,“Введіть рік виробництва судна: “);

scanf(“%d”, &stused_boat.iyear);

pDC->TextOut(85,85,“Введіть кількість мотогодин, напрацьованих двигуном:“);

scanf(“%d, &stused_boat.lmotor_hours”);

pDC->TextOut(105,105,“Введіть вартість судна: “);

scanf(“%а, &stused_boat.fsaleprice”);

s.Format(“Судно %s %d року випуску з реєстраційним номером #%s “,stused_boat. szmodel, stused_boat. iyear, stused_boat. Szserial);

pDC->TextOut(125,125,s); s.Format(“ яке відпрацювало %d мотогодин, “, stused_boat. lmotor_hours);

pDC->TextOut(125,145,s);s.Format(“ продане за $%8.2f. ”, stused_boat.fsaleprice);

pDC->TextOut(145,165,s); }

При виконанні цієї програми на екран виведеться інформація приблизно такого змісту:

Судно «Чайка» 1982 року випуску з реєстраційним номером #ХА1011, яке відпрацювало 34187 мотогодин, продано за $18132.00.

Передавання структур як аргументів функції

Часто виникає потреба передавати структуру у функцію. При цьому аргумент-структура передається за значенням, тобто у функції модифікуються лише копії початкових даних. У прототипі функції потрібно задати структуру як параметр (у С++ вказувати ключове слово struct необов’язково);

// синтаксис оголошення функції у С та С++

void vprint_data(struct stboat stused_boat);

//синтаксис, доступний лише у С++

void vprint_data(stboat stused_boat);

Вкладені структури

Структури можна вкладати одна в одну. Тобто деяка структура може містити змінні, які, у свою чергу, є структурами. Нехай оголошена така структура:

struct stowner{char cname[50];int iage;int isailling_experience;};

У наступному прикладі структура stowner баде вкладена у розглянуту раніше структуру stboat:

struct stboat{

char szmodel [iSTRINGIS15+iNULL_CHAR];

char szserial[iSTRING20+iNULL_CHAR];

char szcomment[80];struct stowner stowner_record;int iyear;

long lmotor_hours; float fsaleprice; } astBoats[iMAX_BOATS];;

Для , наприклад, виведення на екран віку хазяїна судна, потрібно скористатися таким виразом:

printf(“%d\n”, astBoats[0], stowner_record.iage);

Бітові поля

У С/С++ існує досить зручна можливість – «запакувати» набір бітових прапорців у єдину структуру, що називається бітовим полем та розташовану у системному слові. Нехай, наприклад, у програмі, яка читає дані з клавіатури, використовується група прапоців, що відображають стан спеціальних клавіш, таких як [Capslock],[NumLock], тощо.Ці прапорці можна організувати так:

struct stkeybits{ unsigned char rshift :1, Ctrl :1, alt :1, scroll :1, numlock :1, capslock :1, insert :1};

Після двокрапки вказана кількість бітів, відведених для прапорця. Їх може бути більше одного. Можна не вказувати ім’я прапорця, а лише двокрапку та ширину бітової комірки. Такі непоіменовані комірки призначені для пропуску потрібної кількості бітів у межах поля. Якщо вказана ширина 0, тоді наступний прапорець вирівняється по межі типу даних. Дозволяється створювати бітові поля цілого типу (char,short,int,long), причому бажано явно вказувати модифікатор unsigned, для того, щоб поле не розпізнавалось як знакове число.

При роботі з бітовими полями застосовується синтаксис структур. Наприклад, щоб встановити прапорець capslock, потрібно скористатися таким виразом:

struct stkeybits flags.capslock=1;

До бітових полів не можна застосовувати оператор отримання адреси (&).

Функції як елементи структури

Елементами структури можуть бути не тільки поля, тобто дані про деякий об’єкт, але й поєднані з такими полями функції, що оперують вміщеними у полях даними (вони називаються методами). Наприклад, наведена нижче програма містить елементи-функції (методи) структури, такі як: int geta();int getb();//читають вміст полів а та b

float f(float T);// обчислює значення Y за заданою формулою

void print();// друкує значення Y, передане функцією gety()

float gety()// читає значення Y із структури

#include “math.h”

struct c{int a;int b; float Y;int geta(); int getb();float f(float T);

void print(CDC*pDC); float gety(){return Y;}//вбудована inline функція

};

int c::geta(){return a;}

int c::getb(){return b;}

float c::f(float T){Y=geta()*getb()*T;return Y;}

void c::print(CDC*pDC){s.Format("a+b=%d",gety();}

CXXXView::OnDraw(CDC*pDC)

{ c w; //оголошення примірника структури

c*p; // оголошення вказівника на структуру

p=&w; // встановлення вказівника на задану структуру

w.a=2;w.b=3; // ініціювання полів структури

w.f(2); // виклик функції для обчислення значення Y

w.print(); // друкування результату обчислення

p->a=3; p->b=8; // введення значень полів структури з клавіатури

p->f(3);// обчислення значення Y з використанням вказівника

p->print(pDC);//друкування результату з використанням вказівника

}

Об’єднання

При написанні складних програм виникають потреби у різних способах перегляду деякого фрагменту інформації. Окрім того, програма може вимагати можливості працювати з двома чи кількома значеннями, використовуючи при цьому лише одне значення у кожну мить часу. У таких випадках для зберігання даних програма може використовувати об’єднання.

Оголошення обєднання

Для оголошення об’єднання використовується службове слово union:

union імя{тип імя_елементу1; тип імя_елементу2,… тип імя_елементуN.};

Основні концепції об’єднання:

  • об’єднання C++ схожі на структури, за винятком того, як C++ зберігає їх в пам’яті; також об’єднання може зберігати значення тільки для одного елементу у кожну мить часу.

  • об’єднання визначає шаблон, за допомогою якого програми далі оголошують змінні.

  • для звернення до визначеного елементу об’єднання програми використовують оператор C++ крапку.

  • для зміни значення елементу об’єднання всередині функції програма повинна передати змінну об’єднання у функцію за допомогою адреси.

  • анонімне об’єднання - це об’єднання, у якого немає імені (тегу).

Спосіб збереження об’єднання у С++

Наступна структура даних визначає об’єднання з іменем distance, яке містить два елементи:

union distance{int miles;long meters;};

Як і у випадку зі структурою, оголошення об’єднання не відводить пам’ят, а надає шаблон для майбутнього оголошення змінних. Для оголошення змінної об’єднання можна застосовувати довільний з наступних форматів:

union distance{ int miles; long meters;} japan, germany, franee; //одразу після оголошення

distance japan, germany, franee;// перед використанням

Як вказано вище, дане об’єднання містить два елементи: miles та meters. Таке оголошення створює змінні, які дозволяють зберігати відстань до вказаних країн. Можна надати значення довільному елементу. Проте на відміну від структури значення може надаватися лише одному елементу у кожну мить часу. При оголошенні об’єднання компілятор C++ розподіляє пам’ять для зберігання найбільшого елементу об’єднання. Для об’єднання distance компілятор розподіляє достатньо пам’яті для зберігання значення типу long.

Якщо у програмі надається значення елементу miles: japan.miles = 12123;

а потім надається значення елементу meters, тоді значення, надане елементу miles, втрачається.

Наступна програма USEUNION.CPP ілюструє використання об’єднання distance. Спочатку програма надає значення елементу miles і виводить це значення. Потім програма надає значення елементу meters. При цьому значення елементу miles втрачається:

#include <iostream.h>

union distance{int miles;long meters;} walk;

void main(void)

walk.miles = 5; s.Format("Пройдена відстань у мілях %d", walk.miles);

pDC->TextOut(30,30,s);

walk.meters = 10000;

s.Format("Пройденное расстояние в метрах %g",walk.meters);}

Використанні анонімних обєднань у C++

Анонімне об’єднання – це таке об’єднання, у якого немає імені. C++ надає анонімні об’єднання для того, щоб спростити використання елементів об’єднань, призначених для заощадження пам’яті чи створення псевдонімів для визначеного значення. Наприклад, нехай у програмі використовуються дві змінні miles та meters. Будемо вважати, що програма використовує тільки одну з них у кожну дану мить часу. У такому випадку програма може використовувати елементи об’єднання, подібного до distance, а саме name.miles та name.meters. Проте наступний оператор створює анонімне (безименне) об’єднання: union {int miles;long meters;};

Оголошення не використовує ім’я об’єднання і не оголошує змінну об’єднання. Програма звертатиметься до елементів з іменами miles та meters без допомоги крапки. Наступна програма ANONYM.CPP створює анонімне об’єднання, яке містить елементи miles та meters. Важливо, що програма розглядає елементи об’єднання як звичайні змінні. Протк різниця між елементами та звичайними змінними полягає у тому, що при наданні значення довільному з таких елементів, значення іншого елементу втрачається:

#include “afxwin.h”

CXXXView::OnDraw(CDC*pDC)

union {int miles;long meters;};

miles = 10000;s.Format("Значение в милях %d", miles);

pDC->TextOut(40,40,s);meters = 150000;

s.Format("Значение в метрах %g", meters);pDC->TextOut(60,60,s);}

РОЗДІЛ 4.ВВЕДЕННЯ ТА ВИВЕДЕННЯ ІНФОРМАЦІЇ У МОВІ С++

Лекція 10.Засоби введення та виведення у мовах С та С++

План лекції(4 години)

  1. Потоки введення-виведення.

  2. Стандартні потоки для базових типів

  3. Відображення тексту у додатку для середовища Windows

  4. Контекст пристрою

  5. Типи контекстів пристроїв

  6. Шрифти GDI та клас CFont

Засоби введення та виведення інформації, які розглядаються у пунктах

1-3 плану лекції, не використовуються у додатках для середовища Windows.

У мові C++ немає засобів для введення-виведення, вони створюються через бібліотеки потокового введення-виведення цілих, дійсних чисел та символьних рядків, яка поширюється на типи даних користувача. У програмах, написаних мовою С++ можна рівноправно використовувати дві бібліотеки введення-виведення: стандартну бібліотеку функцій мови С (стандарт ANSI C) та бібліотеку класів, спеціально розроблену для мови С++. Бібліотеку функцій мови С можна використовувати у програмі після приєднання заголовочного файла stdio.h, де оголошені прототипи функцій введення та виведення.

Заголовний файл <іostream.h> приєднується до програми, що компілюється, бібліотеки введення-виведення, яка побудована на основі класів і вміщена у всі компілятори С++.

Потоки введення-виведення.

Відповідно до назви файла iostream.h (stream –потік; “i”-скорочене від input –введення; “o”-скорочені від output-виведення) описані у цьому файлі засоби введення-виведення забезпечують програмiста механізмами для вилучення даних з потоків та для приєднання (внесення) даних у потоки. Потік визначається як послідовність байтів (символів) і з точки зору програми не залежить від тих конкретних пристроїв (файл на диску, принтер, клавіатура, монітор, стример), з якими ведеться обмін даними. При обміні з потоком часто використовується допоміжна дільниця основної пам’яті – буфер потоку. У буфер потоку вміщуються дані, що будуть виводитись програмою, перед тим, як передаватися до зовнішнього пристрою. При введенні даних вони спочатку вміщуються у буфер і лише потім передаються в область пам’яті програми, що виконується. Використання буфера як проміжкової пам’яті при обмінах з зовнішніми пристроями підвищує швидкість передавання даних, оскільки реальні пересилання виконуються лише тоді, коли буфер вже заповнений (при виведенні) чи порожній (при введенні).

Роботу по заповненню чи очищенню буферів введення-виведення операційна система виконує самостійно без втручання програмiста. Тому потік у прикладній програмі розглядаєтся як послідовність байтів. При цьому важливм є те, що ніякого зв’язку значень таких байтів з кодами деякого алфавіту не передбачається. Задача програмiста при введенні-виведенні через потоки - встановити відповідність типізованих об’єктів,що приймають участь у обміні, з послідовністю байтів потоку, де відсутні будь-які відомості при типи інформації, що передається.

Потоки, що використовуються у програмах, поділяються на три типи:

  • вхідні, з яких читається інформація;

  • вихідні, у які вводяться дані;

  • двонаправлені, які допускають як читання, так і запис.

Всі потоки бібліотеки введення-виведення послідовні, тобто у кожну мить для потоку визначені позиції запису та (або) читання, і ці позиції після обміну пересуваються по потоку на довжину переданої порції даних.

Відповідно до особливостей “пристрою”, до якого “приєднаний” потік, потоки поділяють на стандартні, консольні, рядкові та файлові.

З названих потоків не розглядаються лише консольні потоки, оскільки їх можна використовувати лише у MS DOS, і вони не входять до класичних реалізацій бібліотеки потокового введення-виведення. Консольні потоки забезпечують можливість роботи з дільницями екрану та екраном в цілому.

Якщо символи потоку у сукупності створюють символьний масив (рядок) в основній пам’яті, тоді це рядковий потік. Якщо при використанні потоку його символи розташовуються на зовнішньому носії даних (наприклад, на диску), тоді маємо файловий потік чи просто файл. Стандартні та консольні потоки відповідають передаванню даних від клавіатури і до екрану монітора.

Стандартні потоки для базових типів

Досить приєднати до тексту програми препроцесорну директиву #include <iostream.h> і можна через операції приєднання (запису) даних у потік << та вилучення (читання) даних з потоку >> обмінюватися даними з монітором та клавіатурою.

Це пояснюється тим, що заголовочний файл iostream.h не лише приєднує до програми оголошення класів ios, istream, ostream, stream, але і містить визначення стандартних потоків введення-виведення:

cin – об’єкт класу istream, поєднаний зі стандартним буферизованим вхідним потоком (клавіатурою);

cout – об’єкт класу ostream, поєднаний зі стандартним буферизованим вихідним потоком (монітор);

cerr – об’єкт класу ostream, поєднаний зі стандартним небуферизованим вихідним потоком (монітор), у який направляются повідомлення про помилки.

clog – об’єкт класу ostream, поєднаний зі стандартним буферизованим вихідним потоком (монітор), у який з буферизацією направляються повідомлення про помилки.

Після приєднання до програми файла iostream.h створюються об’єкти cin,cout,cerr,clog, тобто створюються відповідні стандартні потоки, і програмист може користуватися приєднаними засобами введення-виведення. Програміст може розірвати зв’язок довільного з перелічених об’єктів з консолью та приєднати його до того чи іншого файла, але стандартний (по замовчуванню) зв’язок встановлюється саме з клавіатурою ( потік cin ) та монітором (потоки cout,cerr,clog). У тому ж файлі iostream.h, де оголошені класи istream, ostream, для них визначені оригінальні операції введення та виведення даних. Операція введення класу istream називається вилученням (читанням) даних з потоку. Вона позначається символом операції зсуву вправо >>. Операція виведення класу ostream називається вставкою чи приєднанням (чи записом) даних у потік. Вона позначається символом операції зсуву вліво << . Роль операції вилучення та вставки конструкції << та >> грають по замовчуванні лише тоді, коли зліва від них знаходяться об'єкти, відповідно, класів iostream та ostream:

cin>>ім’я_об'єкта_базового типу

cout<<вираз_базового_типу

cerr<<вираз_базового_типу

clog<<вираз_базового_типу

Виконання операції >> (вилучення з потоку) полягає у перетворенні послідовності символів потоку на значення типізованого об’єкта, яким може бути змінна базового типу int, long, double, тощо. При виконанні операції << (приєднання до потоку) виконується зворотне перетворення – типізоване значення виразу (int, float, char) перетворюється на послідовність символів потоку.

Важливо пам’ятати, що зовнішнє (візуальне) відтворення даних не схоже на внутрішні коди, які застосовуються для їх збереження та обробки у ЕОМ. Зовні від ЕОМ це алфавітно-цифрові зображення (чисел чи символів), у ЕОМ – це двійкові коди, тобто послідовність бітів (двійкових розрядів), встановленої для кожного типу довжини. При виконанні програми операція виведення даних ( наприклад, на екран монітора) передбачає перетворення двійкових кодів на символи алфавіту, які зображуются на зовнішньому пристрої. В операції введення виконується перетворення сигналів від клавіш клавіатури на двійкові коди внутрішнього відтворення даних.

Засоби виведення, що застосовуються у мові, повинні мати можливість розпізнавати тип даних, що виводяться, і у вказаному прикладі помістити у вихідний потік або код зовнішнього відтворення цілого числа, або два коди розташованих поряд символів. Для забезпечення такої можливості операція << приєднання до стандартного вихідного потоку перевантажена. Існують варіанти для типів chаr, unsigned short, signed short, signed int,unsigned int, signed long, unsigned long, float double, long double, char*, void *. Всі вони доступні після приєднання до програми файла iostream.h. Операція приєднання визначена лише для вказівників двох типів, оскільки всі вказівники, відмінні від char *, приводяться до типу void *.

Функції: printf для виведення та scanf для введення надають можливість перетворювати числові величини на символьне відтворення та навпаки, також дають змогу створювати та інтерпретувати форматні рядки. Наприклад, функція printf(control, arg1, arg2, ...) перетворює, визначає формат та друкує задані аргументи у стандартний потік виведення під керуванням рядка control, що містить: звичайні символи, що копіюються у вихідний потік, та специфікації перетворень, що спонукають перетворення та друкування аргументів printf.

Специфікація перетворення починається символом % і закінчується символом перетворення. Між % та символом перетворення можна записувати:

  • знак мінус означає вирівнювання аргумента по лівому краю поля.

  • рядок цифр, вказує мінімальну ширину поля, перетворене число надрукується у полі принаймні цієї ширини, а при потребі, і в ширшому. Якщо перетворений аргумент має менше символів, ніж вказана ширина поля, тоді він доповниться зліва (чи з правого боку, коли вказувалось вирівнювання по лівому краю) заповнюючими символами до цієї ширини. Заповнюючим символом найчастіше є пробіл, а коли ширина поля вказується з початковим нулем, тоді таким символом буде нуль (лідуючий нуль у даному випадку не означає вісімкової ширини поля).

  • крапка, що відокремлює ширину поля від наступного рядка цифр.

  • рядок цифр (точність), що вказує максимальну кількість символів рядка, які повинні друкуватися, або кількість дкукованих праворуч від десяткової крапки цифр для змінних типу float чи double.

  • модифікатор довжини l, що вказує на те, що відповідний елемент даних має тип long, а не int. Нижче наведені символи перетворення та їх суть:

d - аргумент перетворюється до десяткового вигляду.

о - аргумент перетворюється на беззнакову вісімкову форму(без початкового 0).

x-аргумент перетворюється на беззнакову 16-кову форму (без початкових 0x).

u - аргумент перетворюється на беззнакову десяткову форму.

c- аргумент розглядається як окремий символ.

s - рядок: символи рядка друкуються доти, доки не зустрінеться нульовий символ, чи не надрукується кількість символів, вказана у специфікації точності.

e - аргумент, змінна типу float чи double, перетворюється на 10-кову форму у вигляді [-]m.nnnnnnE[+-]xx, де довжина n визначається з точністю 6.

f - аргумент, змінна типу float чи double, перетворюється на 10-кову форму в вигляді [-]mmm.nnnnn, де довжина n визначається точністю 6.

g - застосовується формат чи коротший %f; незначущі нулі не друкуються.

Якщо записаний за % символ не символ перетворення, тоді друкується власне цей символ; значить, символ % можна надрукувати, вказавши %%.

Функція scanf виконує введення, це аналог printf та виконує у зворотному напрямі багато з названих вище перетворень. Функція

scanf(control, arg1, arg2, ...) читає символи зі стандартного потоку введення, інтерпретує їх відповідно до формату, вказаного в аргументі control, та вміщує результати в наступні аргументи. Керуючий аргумент описується нижче; інші аргументи, кожен з яких повинен бути вказівником, визначають, куди потрібно вмістити відповідним чином перетворене введення. Керуючий рядок найчастіше містить специфікації перетворення, які застосовуються для безпосередньої інтерпретації вхідних послідовностей. Керуючий рядок може містити:

  • пробіли, табуляції, символи нового рядка;

  • звичайні символи (не %), які не співпадають з наступними;

  • специфікації перетворення, що містять символ, необов’язкове число, що вказує максимальну ширину поля та символ перетворення.

При нормальному завершенні результат вміщується у змінну, яка вказується відповідним аргументом. Поле - рядок символів. Дозволяються символи перетворення (аргументи-вказівники на тип вводимого числа):

d - при введенні очікується десяткове ціле;

o - при введенні очікується вісімкове ціле (з початковим нулем чи без нього);

x - при введенні очікується шістнадцяткове ціле (з початколвим 0x чи без них);

h - при введенні очікується ціле типу short;

c - очікується окремий символ, вводимий символ вміщується у вказане місце.

s - очікується символьний рядок; вказівник вказує на масив символів, достатній для прийняття рядка та доданого в конці символа \0.

f - очікується число з плаваючою крапкою;

Е - символ перетворення e є синонімом для f. Формат введення змінної типу float містить необов’язковий знак, рядок цифр такий, що, можливо містить десяткову крапку та необов’язкове поле експоненти, що складається з букви e, за якою записане ціле, можливо таке, що містить знак.

Перед символами перетворення d, o та x можна записувати l, що означає, що у списку аргументів повинен знаходитись вказівник на змінну типу long, а не типу int. Також букву l можна записувати перед символами перетворення e чи f, повідомляючи про те, що у списку аргументів повинен знаходитися вказівник на змінну типу double, а не типу float. Наприклад, звернення int 1; float x; char name [50]; scanf ("&d %f %s", &i, &x, name); з рядком при введенні 25 54.32e-1 thompson надає i значения 25, x - 432 і name - "thompson", що, відповідно до правил, закінчиться символом \0. Ці три поля введення можна відокремити пробілами, табуляцією та символами переведення на новий рядок. Звернення: int i; float x; char name [50]; scanf("%2d%f%*d%2s", &i, &x, name); з введенням 56789 0123 45a72 надасть i значення 56, x - 789.0, пропустить 0123 та вмістить у name рядок "45". При наступному зверненні до довільної процедури введення прочитається буква a. В наведених прикладах name є вказівник і тому перед ним не записується &.

Для форматного перетворення в пам’яті використовуються функції sscanf та sprintf, що виконують подібні перетворення, але працюють з рядком, а не з файлом. Звернення до них має вигляд: sprintf(string, control, arg1, arg2, ...)

sscanf(string, control, arg1, arg2, ...)

Відображення тексту у додатку для середовища Windows

Додатки використовують екран для відображення даних, якими вони керують. Windows забезпечує універсальність представлення інформації на екрані, застосовуючи для цього одні й ті ж примітиви відображення. Система сама розпізнає цільовий пристрій та активізує відповідний йому модуль. Кожен пристрій виведення у Windows має набір поточних параметрів, з використанням яких і відбувається власне виведення. До того ж у кожну мить часу тільки одному додатку відповідає деякий логічний пристрій виведення, що усуває одночасний доступ до останнього - перед початком процесу виведення додаток змінює параметри виведення, налагоджуючи їх для себе.

Система Windows забезпечує зберігання потрібних параметрів у спеціальній структурі, що називається контекстом пристрою.

Контексти пристроїв

Контекст пристрою – це структура, що визначає набір графічних об’єктів та поєднаних з ними атрибутів та графічних режимів, які, власне, і діють на виведення. Графічні об’єкти містять олівці для рисування ліній, пензлі для фарбування та заповнення, бітові образи для копіювання чи прокрутки частин екрану, колірні палітри для визначення набору доступних кольорів, області для відтинання та інших операцій, а також контури для операцій рисування та фарбування.

Зрозуміло, що додаток не має прямого доступу до контексту пристрою, тому налагодження виконується викликом спеціальних функцій.

Використовуючи контекст пристрою, додаток може виконувати такий набір операцій:

  • перелік графічних об’єктів;

  • встановлення нових графічних об’єктів;

  • видалення графічних об’єктів;

  • збереження графічних об’єктів, їх атрибутів та параметрів графічних режимів;

  • відновлення графічних об’єктів, їх атрибутів та параметрів графічних режимів.

До того ж, додаток може використовувати контекст пристрою для визначення процесу графічного виведення, переривання тривалих графічних операцій, початих іншим потоком багатопоточного додатку, а також ініціювати принтер.

Типи контекстів пристроїв

У Windows визначені чотири основні типи контекстів пристроїв:

  • для екрану - забезпечує операції рисування безпосередньо на екрані;

  • для принтера - забезпечує операції рисування на принтері чи плоттері;

  • для об’єктів в пам’яті - забезпечує операції рисування без безпосереднього виведення на екран;

  • інформаційний - забезпечує отримання даних про пристрій.

Контексти екрану

Win32 API надає три типи контексту пристрою для екрану: контекст класу, загальний та приватний контексти. Контекст класу та приватний контекст пристрою застосовуються у додатках, які виконують багаторазові операції рисування. Це, наприклад, програми автоматизованого проектування та настільні видавничі системи, тобто такі додатки, які самостійно та постійно виводять інформацію і, відповідно, час, що витрачається на ці операції, є критичним з точки зору продуктивності додатку. Загальні контексти пристрою використовуються у додатках, які лише іноді виконують операції рисування, і де час, що витрачається на цей процес, не є суттєвим. Додаток отримує контекст пристрою екрану, викликаючи функцію Begin-Paint чи GetDC та ідентифікуючи вікно, у яке відповідно виводитиметься інформація. До того ж тип контексту пристрою залежить від того, як додаток зареєстрував клас вікна. Найчастіше додаток отримує контекст пристрою екрану безпосередньо перед виконанням операцій виведення. По завершенні виведення додаток повинен обов’язково звільнити контекст пристрою викликом функції EndPaint чи ReleaseDC, відповідно.

Контекст класу

Контекст класу підтримується тільки для сумісності з попередніми версіями Windows. При створенні Win32-додатку замість контекстів класу застосовуються приватні контексти.

Загальний контекст

Загальний контекст пристрою – це контекст пристрою екрану, поєднаний з компонентом керування вікна Win32 API та розташований в області адміністратора вікна. Додаток отримує загальний контекст пристрою, викликаючи функцію GetDC, GetDCEx чи BeginPaint. Система Windows ініціює загальні контексти пристрою значеннями по замовчуванню, які можна змінювати при потребі за допомогою спеціальних функцій. Кількість загальних контекстів у системі обмежена і тому після завершення операції виведення потрібно повідомити систему про це викликом функції ReleaseDC чи EndPaint. В результаті виклику однієї з вказаних функцій ті зміни параметрів контексту, які вносились додатком, відміняться. Кожного разу параметри потрібно встановлювати саме таким чином.

Приватний контекст

Приватні контексти пристрою відрізняються від загальних тим, що зберігають довільні зміни для заданих за замовчуванням даних навіть після виклику функції ReleaseDC чи EndPaint. Приватні контексти приустрою не є частиною області адміністратора вікна і тому лише одноразово ініціюються значеннями за замовчуванням. Адміністратор вікна автоматично видаляє приватний контекст пристрою тільки після того, як останнє вікно класу зруйнується.

Додаток створює приватний контекст пристрою, визначаючи стиль CS_OWNDC для класу вікна при ініціюванні структури WNDCLASS з наступною реєстрацією класу вікна. Для отримання приватних контекстів вікон, що мають стиль CS_OWNDC, застосовуються ті ж функції: GetDC, GetDCEx чи BeginPaint.

Контекст принтера

Win32 API надає однаковий тип контексту пристрою як для принтера, який може бути матричним, струменевим чи лазерним, так і для графобудувача. Додаток створює контекст пристрою принтера, викликаючи функцію CreateDC. При цьому задаються потрібні параметри, такі як ім’я драйверу принтера, ім’я принтера, файла чи іншого пристрою виведення. Після завершення друку додаток повинен викликати функцію DeleteDC для видалення створеного контексту. Просте звільнення контексту за допомогою функції ReleaseDC недостаточнє та недопустиме.

Об’єкт в пам’яті

Для покращення характеристик виведення зображень, наприклад, усунення мигтіння, Win32 API надає можливість додаткам повністю підготовляти зображення в пам’яті перед його виведенням на екран дисплея і тільки після цього виводити. Для цього призначений контекст пристрою пам’яті, який зберігає растрове зображення для специфічного пристрою. Додаток створює контекст пристрою пам’яті, викликаючи функцію CreateCompatibleDC. Результатом виконання цієї функції є растрове зображення (або растр), яке має колірний формат, сумісний з форматом початкового пристрою (звідси й назва функції).

Початкове зображення у контексті пристрою пам’яті має розмір один на один піксел. Перед початком роботи додатку з зображенням, воно повинне встановити бітовий масив з відповідною шириною та висотою у контексті пристрою, викликаючи функцію SelectObject.

Інформаційний контекст

Win32 API підтримує інформаційний контекст пристрою, який використовується для відновлення чи отримання заданих за замовчуванням параметрів пристрою. Для стврення інформаційного контексту додаток повинен викликати функцію Create1С. Для отримання інформації про об’єкти, задані за замовчуванням для пристрою, яке цікавить програміста, використовуються функції GetCurrentObject та GetObject. Використання інформаційного контексту пристрою ефективніше, ніж контекстів інших типів, оскільки Win32 API працює з інформаційним контекстом на нижчому рівні і не створює структури, потрібні для їх роботи.

По завершенні роботи з інформаційним контекстом потрібно викликати функцію DeleteDC для видалення створеного контексту.

Графічні об’єкти

Система Windows забезпечує додаток набором графічних об’єктів, які надають можливість керування виведенням. Для цього застосовуються:

  • бітові масиви (bitmaps) - прямокутні масиви точок, які формують растрові зображення;

  • олівці (pens) - для задання параметрів рисування ліній, таких як товщина, колір та стиль (суцільна, переривчаста та ін.);

  • пензлі (brushes) - для задання параметрів заливання замкнених контурів, таких як колір та стиль;

  • регіони (regions) - області вікна, які можуть обмежуватися прямокутником, многокутником, еліпсом чи їх комбінацією для виконання операцій заповнення, заливання, інверсії і т. п.; окрім того, служать для визначення місцезнаходження курсору;

  • логічні палітри (logical palettes) - для забезпечення інтерфейсу додатку та кольорового пристрою виведення, такого як дисплей; містять список кольорів, потрібних додатку;

  • контури (paths) - з метою заповнення чи виділення контуру різних фігур;

  • шрифти (fonts) - для задання параметрів виведення тексту, серед яких ім’я шрифту, розмір символів та ін.

Графічні режими

Система Windows підтримує п’ять різних графічних режимів, які дають змогу додаткам визначати тип змішування кольорів, місце та параметри виведення і т. д.

Режим налагодження фону. Визначає те, як змішуються кольори фону текстових об’єктів та растрових зображень та фону поля виведення (вікна чи екрану).

Режим відображення (рисування). Визначає, як змішується колір олівців (pens), пензлів (brushes), текстових об’єктів та растрових зображень з кольором фону поля виведення (вікна).

Режим масштабування. Визначає перетворення логічних координат при графічному виведенні у вікна чи на принтер.

Режим заливання контурів. Визначає використання шаблонів пензлів при заливанні складних контурів.

Режим стиснення. Визначає, яким чином відбувається перетворення кольорів растрових зображень при їх збільшенні (зменшенні). Як і у випадку графічних об’єктів, контекст пристрою ініціюється значеннями за замовченням і для графічних режимів.

Робота зі шрифтами. Шрифти TrueType

Не дивлячись на те, що шрифти є графічними об’єктами, їх застосування має власні суттєві особливості. Операційна система Windows може працювати зі шрифтами таких трьох типів:

  • Растрові

  • Векторні

  • Шрифти TrueType

Відмінність між видами шрифтів полягає у способі зберігання параметрів накреслення символів у спеціальних шрифтових файлах. У випадку растрових шрифтів кожен символ зберігається у вигляді растру (бітового масиву). Векторні шрифти зберігають для кожного символу відносні координати кінців відрізків, з яких складається відповідний символ. Шрифти TrueType містять інформацію про лінії та команди згибу, а також налагоджувальну інформацію (hints) для точного відображення символу, яка використовується при зменшенні чи збільшенні масштабу відображення.

Растрові шрифти мають задані розміри і, відповідно, якість їх відображення залежить від пристрою виведення. Навпаки, векторні шрифти незалежні від пристрою виведення, проте потрібний для їх відображення час більший, ніж для растрових чи шрифтів TrueType. Останні ж забезпечують прийнятну швидкість виведення і можуть масштабуватися зі збереженням початкового вигляду символів.

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

Класи графічного інтерфейсу

Win32 API має велику кількість функцій графічного виведення та налагодження режимів рисування, проте їх використання потребує дотримання визначеного набору правил, оскільки у противному випадку можуть виникнути помилки під час виконання програми, збої при рисуванні, втрата частини вмісту вікон та поступове вичерпання системних ресурсів, що вплине на роботу не тільки власне неправильно створеного додатку, але й інших додатків і всієї системи в цілому. У 32-розрядних версіях таке може статися, якщо невірно написаний додаток продовжує використовуватися, проте після його завершення, навіть аварійного, система (за рідким винятком) самостійно звільнює захоплені раніше ресурси. Реалізація роботи з графікою на мові C++ з використанням класів бібліотеки MFC дає змогу у більшості випадків гарантувати правильне використання ресурсів (захват та звільнення) у неявному для розробника вигляді. Бібліотека надає програмісту потужні засоби графічного виведення у вигляді функцій віповідних класів, а також бібліотечні класи виконують створення, ініціювання та коректне звільнення графічних ресурсів для ефективної реалізації графічного виведення.

Класи контекстів пристроїв

  • CDC - базовий клас для всіх класів, які інкапсулюють контексти пристроїв Windows. Об’єкти цього класу використовуються для роботи з усім екраном дисплея чи з принтером. До того ж, саме вказівник на базовий клас передається у такі функції, як, наприклад, СView:: On Draw, маючи фактичну можливість вказувати на об’єкти інших похідних класів контекстів пристроїв. (Параметр CDC *pDC функції CView::OnDraw насправді вказує на об’єкт класу CPaintDC, створений у функції CView::OnPrepareDC, яка викликається бібліотечними функціями MFC).

  • CPaintDC – об’єкти цього класу використовуються лише у обробнику повідомлення WM_PAINT, яке генерується у відповідь на виклик функцій UpdateWindow чи RemоwWindow. Обробником цього повідомлення найчастіше служить перевизначувана функція вікна CWnd::OnPaint. При створенні об’єкту класу CPaintDC у конструкторі викликається функція Win32 API BeginPaint, а при руйнуванні, у деструкторі, функція EndPaint, також з Win32 API, забезпечуючи таким чином потрібні операції для підготовки та завершення процесу графічного виведення. За створення об’єкту класу CPaintDC відповідає розробник додатку.

  • CClientDC – об’єкти цього класу забезпечують доступ до клієнтської частини вікна. Використовуються для графічного виведення у довільній функції, на відміну від об’єктів класу CPaintDC. При створенні об’єкту класу CClientDC у конструкторі викликається функція Win32 API GetDC, а при руйнуванні, у деструкторі, функція ReleaseDC, также з Win32 API, забезпечуючи потрібні операції для підготовки та завершення процесу графічного виведення саме і тільки у клієнтську частину вікна. За створення об’єкту класу CClientDC відповідає розробник додатку.

  • CWindowDC – об’єкти цього класу забезпечують доступ до всього вікна. При створенні об’єкту класу CWindowDC у конструкторі викликається функція Win32 API GetWindowDC, а при руйнувванні, у деструкторі, функція ReleaseDC, також з Win32 API, забезпечуючи потрібні операції для підготовки та завершення процесу графічного виведення як у клієнтську, так і у неклієнтську частини вікна. За створення об’єкту класу CWindowDC відповідає розробник додатку.

  • CMetaFileDC – об’єкти цього класу забезпечують доступ до метафайлів Windows. Виклики функцій-членів класу CMetaFileDC записуються у поєднаному в відповідним об’єктом файлі. Можна створити два типи об’єктів класу CMetaFileDC. Об’єкти першого типу підтримують тільки функції, які виконують винятково графічне виведення. Такі метафайли є контекстно-залежними, оскільки пізніше можливе виведення їх вмісту тільки з урахуванням налагоджень контексту того пристрою, на який виконується власне виведення. Метафайли другого типу (контекстно-незалежні) можуть містити, на додаток до функцій графічного виведення, і функції налагодження параметрів рисування. Природно, що інформація з таких файлів може відображатися на різних пристроях однаково. (Метафайли, на відміну від інших графічних файлів, містять команди рисування. Виведення вмісту файла полягає у виконанні записаних команд. За замовчуванням імена метафайлів мають розширення .WMF (від Windows MetaFile), а розширених метафайлів - Enhanced MetaFiles - розширення .EMF. На відміну від класу CpaintDC, для об’єктів класу CMetaFileDC автоматичний виклик функції OnPrepareDC не відбувається - відповідальність за її виклик лежить на розробнику додатку.

Графічні обєкти

Налагодження параметрів графічного виведення виконується двома шляхами. Одні параметри налагоджуються викликом функцій Win32 API чи функцій класу CDC та похідних від нього, інші - шляхом заміни так званих графічних об’єктів.

Бібліотека MFC надає розробникам всі потрібні класи, які інкапсулюють відповідні графічні об’єкти Windows. До того ж, бібліотека має у складі додаткові класи, які не мають безпосереднього відношення до графіки, але значно полегшують вирішення деяких задач (класи CPoint, CSize, CRect, CRectTracker). Всі класи мають один і той же базовий клас, який дає змогу уніфікувати роботу з графічними об’єктами як такими (CGdiObject). Нижче наводиться огляд наявних класів.

  • CGdiObject - базовий клас для всіх класів, які забезпечують інтерфейс з графічними об’єктами Windows. Не дивлячись на те, що цей клас не є абстрактним, немає потреби у безпосередньому створенні його об’єктів, оскільки він не асоційований ні з яким графічним об’єктом Windows.

  • CPen - інкапсулює об’єкт Windows "олівець", який може призначатися для контекст пристрою і застосовуватися для визначення типу та кольору ліній чи границь фігур.

  • CBrush - інкапсулює об’єкт Windows "пензель", який може призначатися для контексту пристрою та застосовуватися для визначення типу та кольору заливки внутрішніх областей замкнених фігур.

  • CFont - інкапсулює об’єкт Windows "шрифт", який може призначатися для контексту пристрою та застосовуватися при операціях виведення текстової інформації.

  • CBitmap - інкапсулює об’єкт Windows "бітовий масив", який забезпечує додаток рядом функцій. Застосовується також для роботи з контекстами пристроїв, розташованих в пам’яті.

  • CPalette - інкапсулює об’єкт Windows "колірна палітра" (чи просто "палітра"), який забезпечує інтерфейс між додатком та колірним пристроєм виведення, таким як екран дисплея. Цей інтерфейс дає змогу додатку повністю використати можливості пристрою виведення, не порушуючи при цьому роботу (графічне виведення) інших додатків. "Палітра" служить у Windows для визначення використовуваних додатком кольорів з набору доступних у системі.

  • CRgn - інкапсулює об’єкт Windows "регіон", який хоч і відноситься до графічних об’єктів, насправді є швидше додатковим об’єктом або, точніше, засобом керування графічним виведенням, визнакчаючи складні (не тільки прямокутні) області.

Як і ті функції Win32 API, які працюють з різними об’єктами Windows, функції графічного виведення використовують відповідні дескриптори. Функції класів графічних об’єктів та контекстів пристроїв працюють також з дескрипторами. У таблиці показана відповідність представлених класів бібліотеки MFC та типів дескрипторів об’єктів Windows.

Таблиця Відповідність дескрипторів об’єктів Windows та класів MFC

Клас MFC

Об’єкт Windows

Тип дескриптора

СРеп

"олівець"

HPEN

CBrush

"пензель"

HBRUSH

CFont

"шрифт"

HFONT

CBitmap

"бітовий масив"

HBITMAP

CPalette

"палітра"

HPALETTE

CRgn

"регіон"

HRGN

Окрім того, що кожен з вищеперелічених класів має конструктор, що є природним, в ньому також визначена спеціальна функція (функції) ініціювання, що має префікс Create.

Створення графічного об’єкту довільного класу, наприклад СРеn чи СBrush. можна двома способами. Перший спосіб полягає у використанні конструктора як для створення власне об’єкту, так і для його ініціювання. Другий спосіб, окрім використання конструктора, який тільки створює об’єкт класу, додатково вимагає виклику ініціюючої функції.

З сказаного можна зрозуміти, що другий спосіб має перевагу, оскільки неможливість ініціювання, наприклад, у випадку вичерпання відповідних системних ресурсів, легше визначити при виклику саме функції ініціювання. У противному випадку, для гарантії захисту від помилок, вірніше, своєчасного їх виявлення, потрібно використовувати механізм обробки винятків.

При використанні графічного об’єкту для налагодження відповідних параметрів рисування потрібно виконати наступні дії:

  • стврити графічний об’єкт одним з двох описаних способів:

  • замінити у контексті пристрою поточний об’єкт новим створеним графічним об’єктом, зберігши при цьому вказівник на останній;

При використанні функцій Win32 API додаток маніпулює не вказівниками, а дескрипторами, які не мають, деструктора. Звільнення ресурсу потрібно проводити у явному вигляді викликом відповідної функції API.

  • закінчивши операції рисування, відновити графічний об’єкт у контексті пристрою за допомогою збереженого вказівника;

  • забезпечити видалення створеного об’єкту після виходу з області видимості, що відбувається автоматично для об’єктів, створених у стеці додатку.

У випадку, коли один і той же об’єкт використовується додатком досить часто, так що його створення і потім видалення суттєво впливає на продуктивність додатку в цілому, можливе створення та збереження такого об’єкту на весь час його багаторазового використання. Проте перед завершенням роботи додатку потрібно забезпечити його коректне видалення, і, як наслідок, звільнення ресурсу, так як конкретного графічного об’єкту Windows.

У наступному прикладі ілюструється методика створення та використання графічних об’єктів за допомогою класів та функцій бібліотеки MFC.

void CSunView::OnDraw(CDC* pDC)

{ // Створення з одночасним ініціюванням

CPen pen_l (PS__DOT, 1, RGB(0, 0, 0));

try

{ // Створення з одночасним ініціюванням

CBrush brush(HS_CROSS, RGB(0, 0, 0));

// Створення

CPen pen_2;

// Ініціювання

if (pen_2.CreatePen(PS_SOLID, 2, RGB(192, 192, 192))).

{ // Встановлюємо новий олівець, зберігаючи вказівник на поточний

CPen* pOldPen = pDC->SeiectObject(&pen_2);

// Рисування з використанням нового олівця  pDC->Rectangle(...);

// Відновлюємо старий олівець pDC->SelectObject(pOldPen);

}

else (

// Обробка неможливості ініціювання реп_2

 } 

}

catch (CResourceException *e) 

{

// Обробка неможливості ініціювання brush

}

Зверніть увагу на те, що після завершенння виконання функції всі створені об’єкти класів CBrush та СРеn автоматично знищаться, і їх деструктори виконають дії, потрібні для звільнення захоплених ресурсів. Окрім того, у прикладі не виконується ніяка діагностика можливої помилки при ініціюванні об’єкту реn_1, а для об’єкту brush перевіряється виникнення виняткової ситуації, яка спонукається при неможливості створенні об’єкту та має тип вказівника на об’єкт CResourceException. До того ж при виникненні виняткової ситуації одразу ж після виконання конструктора керування передається на оператор catch, а проміжкові оператори ігноруються.

Функція CDC::DrawText: вимагає вказати прямокутник, всередині якого виводиться текст, та прапорці, що вказують, як саме розташувати текст всередині прямокутника. Наприклад, для виведення тексту у вигляді одного рядка по центру прямокутника rect використовується виклик:

dc.DrawText( "Hello, MFC", -1, &rect, DT_SINGLELINE ¦ DT_CENTER ¦ DT_VCENTER );

Функція TextOut - виводить текст подібно до DrawText, але потребує значень координати точки початку виведення тексту чи використовує для цього поточну позицію. Оператор: dc.TextOut( 0, 0, "Hello, MFC" ); виведе рядок "Hello, MFC", починаючи від лівого верхнього кута вікна, поєднаного з контекстом dc.

Функція TabbedTextOut при виведенні рядка замінює символи табуляції на пробіли (масив позицій табуляції передається як параметр).

За замовчуванням, координати, передані у TextOut, TabbedTextOut та ExtTextOut, вважаються лівим верхнім кутом описуючого прямокутника для першого символа рядка. Проте інтерпретацію координат можна змінити, задавши у контексті пристрою властивість вирівнювання тексту. Для цього використовується функція CDC::SetTextAlign, наприклад, для вирівнювання тексту по правій границі: dc.SetTextAlign( TA_RIGHT );

Для того, щоб функція TextOut замість явно вказаних координат користувалась поточною позицією, потрібно викликати SetTextAlign з вказуванням стилю та встановленням прапорця TA_UPDATECP. Тоді TextOut після виведення кожного рядка змінюватиме поточну позицію. Так можна вивести кілька рядків підряд зі збереженням коректної відстані між ними.

Функції-члени CDC для виведення тексту

Функція

Опис

DrawText

Виводить текст с заданим форматуванням всередині описуючого прямокутника

TextOut

Виводить символьний рядок у поточну чи задану позиціюї

TabbedTextOut

Виводить символьний рядок, який містить табуляції

ExtTextOut

Виводить символьний рядок з можливим заповненням описуючого прямокутника фоновим кольором чи зміною міжсимвольної відстані

GetTextExtent

Обчислює ширину рядка з урахуванням параметрів поточного шрифту

GetTabbedText

Обчислює ширину рядка з табуляціями з урахуванням поточного шрифту Extent

GetTextMetrics

Повертає властивості поточного шрифту (висоту символу, середню ширину символу та ін.)

SetTextAlign

Задає параметр вирівнювання для функції TextOut та деяких інших функцій виведення

SetTextJustification

Задає додаткову ширину, потрібну для вирівнювання символьного рядка

SetTextColor

Задає у контексті пристрою колір виведення тексту

SetBkColor

Задає у контексті пристрою колір фону, яким заповнюється область між символами при виведенні тексту

Функції GetTextMetrics та GetTextExtent призначені для отримання властивостей поточного шрифту, вибраного у контексті пристрою. GetTextMetrics повертає ці властивості у вигляді структури TEXTMETRIC. GetTextExtent (чи GetTabbedTextExtent) обчислює у логічних одиницях ширину заданого рядка з урахуванням поточного шрифту. Приклад використання GetTextExtent – обчислення ширини проміжка між словами, щоб рівномірно розподілити текст за заданою шириною. Нехай потрібно вивести рядок у дільницю шириною nWidth. Для вирівнювання рядка по обох границях можна використати наступні виклики:

CString string = "Рядок з трьома пробілами ";

CSize size = dc.GetTextExtent( string );

dc.SetTextJustification( nWidth - size.cx, 3 );

dc.TextOut( 0, y, string );

Другий параметр SetTextJustification задає кількість символів-відокремлювачів у рядку. За замовчуванням символом-відокремлювачем є пробіл. Після виклику SetTextJustification, всі наступні виклики TextOut та інших текстових функцій розподілятимуть простір, заданий першим параметром SetTextJustification, рівномірно між всіма символами-відокремлювачами.

Шрифти GDI та клас CFont

Всі текстові функції-члени CDC використовують поточний шрифт, вибраний у контексті пристрою. Шрифт – це набір символів визначеного розміру (висоти) та накремлення, у яких є загальні властивості, наприклад, товщина символу (нормальна чи груба). У типографії розмір шрифту вимірюється у спеціальних одиницях – пунктах. 1 пункт приблизно дорівнює 1/72 дюйма. Висота символу шрифту 12 пт дорівнює приблизно 1/6 дюйма, але у Windows реальна висота дещо залежито від властивостей пристрою виведення. Термін "накреслення" визначає загальний стиль шрифту. Наприклад, Times New Roman та Courier New є різними накресленнями.

Шрифт – один з типів об’єктів модуля GDI. У MFC для роботи зі шрифтами є клас CFont. Спочатку потрібно створити об’єкт цього класу, а потім за допомогою однієї з його функцій-членів CreateFont, CreateFontIndirect, CreatePointFont чи CreatePointFontIndirect створити шрифт у модулі GDI. Функціям CreateFont та CreateFontIndirect можна задавати розмір шрифту у пікселях, а CreatePointFont та CreatePointFontIndirect – у пунктах. Наприклад, для створення 12-пунктного екранного шрифту Times New Roman функцією CreatePointFont потрібно виконати виклики (розмір задається у 1/10 пункта): CFont font;

font.CreatePointFont( 120, "Times New Roman" );

Зробити те ж саме за доп0омогою CreateFont дещо складніше, оскільки потрібно дізнатися, скільки у контексті пристрою логічних одиниць припадає на один дюйм по вертикалі і потім перевести висоту з пунктів у пікселі:

CClientDC dc(this);

int nHeight = -((dc.GetDeviceCaps(LOGPIXELSY)*12)/72);

CFont font;

font.CreateFont( nHeight, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH ¦ FF_DONTCARE, "Times New Roman" );

Серед великої кількості параметрів CreateFont є товщина, признак курсиву та ін. властивості. Ці ж властивості шрифту можна зберігати у спеціальній структурі LOGFONT і передавати її для створення шрифту у CreatePointFontIndirect, наприклад:

LOGFONT lf;

memset( &lf, 0, sizeof(lf) );

lf.lfHeight = 120;

lf.lfWeight = FW_BOLD;

lf.lfItalic = TRUE;

strcpy( lf.lfFaceName, "Times New Roman" );

CFont font;

font.CreatePointFontIndirect( &lf );

Якщо спробувати створити шрифт, не встановлений у системі, тоді GDI спробує підібрати наближений схожий шрифт із встановлених. Не дивлячись на те, що внутрішній механізм перетворення шрифтів GDI і спробує це зробити, не завжди результати будуть хорошими. Принаймні текст на екран не виводитиметься.

}

void CMainWindow::OnPaint()

{ CPaintDC dc( this );

CRect rect;

GetClientRect( &rect );

dc.DrawText("Hello, MFC", -1, &rect, DT_SINGLELINE ¦ DT_CENTER ¦ DT_VCENTER );}

CString strMessage;

if (aCD.DoModal() == IDOK)

{ strMessage.Format("a=%d b=%d", aCD.m_a,aCD.m_b);

AfxMessageBox(strMessage);}

void CMyAppView::OnDraw(CDC* pDC)

{ CMyAppDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

CString s;

s.Format("a=%d с=%d",pc.m_a,pc.m_с);

pDC->TextOut(20,40,s);

}

ДОДАТОК. Ключові слова мови С++