- •О.С. Зеленський
- •Розділ 1. Загальні відомості створення додатку windows
- •1.1. Створення додатку Windows за допомогою майстра AppWizard
- •1.2. Варіанти майстрів для різних проектів
- •1.3. Короткий опис sdi програми
- •1.4. Короткий опис mdi програми
- •1.5. Короткий опис простого діалогового додатку
- •Контрольні питання
- •Розділ 2. Повідомлення і команди
- •2.1. Обробка повідомлень
- •2.2. Цикли обробки повідомлень
- •2.3. Карти повідомлень
- •Контрольні питання
- •Розділ 3. Документи та види
- •3.1. Клас додатку
- •3.2. Клас головного вікна
- •3.3. Клас документа
- •3.4. Класи виду
- •Контрольні питання
- •Розділ 4. Робота з клавіатурою, мишею і меню
- •4.1. Робота з клавіатурою
- •4.2. Робота з мишею
- •4.3. Робота з меню
- •Контрольні питання
- •Розділ 5. Виведення на екран
- •5.1. Класи графічних об'єктів
- •5.2. Робота зі шрифтами
- •5.3. Робота з пензликами та малювання графічних фігур
- •5.4. Робота з пензликом
- •5.5. Робота зі скролінгом
- •5.6. Приклад роботи з таблицями
- •5.7. Малювання на екрані маніпулятором "миша"
- •5.8. Завантаження та виведення на екран бітових зображень
- •5.9. Копіювання бітових образів
- •5.10. Малювання графічних об'єктів з використанням резинових контурів та метафайлів
- •5.11. Виділення графічних об'єктів у прямокутній області
- •5.12. Універсальний приклад роботи з двовимірною графікою з використанням резинового контуру
- •5.13. Запис на диск та зчитування з диску графічних об'єктів
- •5.14. Побудова кругових діаграм і гістограм
- •5.15. Користувацький режим роботи з графікою на прикладі малювання годинника Clock
- •Контрольні питання
- •Завдання
- •Розділ 6. Друк і попередній перегляд документів
- •6.1. Вибір і налаштування параметрів друку
- •6.2. Створення контекста пристрою
- •6.3. Друк документів і бібліотека mfc
- •6.4. Масштабування
- •6.5. Друк багатосторінкового документа
- •Контрольні питання
- •Розділ 7. Робота з файлами
- •7.1. Приклад роботи з файлами на основі класів cFile, cStdioFile та потоку fstream
- •7.1.1. Робота з класом cFile
- •7.1.2. Робота з потоком fstream
- •Можливі режими доступу
- •7.1.3. Робота з класом cStdioFile
- •7.2. Серіалізація даних, клас cArchive
- •7.3. Використання реєстру в додатках
- •Контрольні питання
- •Завдання
- •Розділ 8. Діалогові вікна
- •8.1. Створення діалогового вікна та простіші елементи керування
- •8.2. Робота зі списками і комбінованими полями
- •8.3. Ускладнений приклад зі списками
- •8.4. Робота з повзунками
- •8.5. Виведення бітових матриць в діалозі та у вікні виду
- •8.6. Лінійний регулятор, лінійний індикатор, інкриментний регулятор
- •8.7. Стандартні діалоги вибору файлів, шрифтів та кольору
- •8.8. Взаємоз'вязок діалога, документа та виду при розробці додатку
- •8.8.1. Клас cDialDoc
- •8.8.2. Клас cDialView
- •8.8.3. Клас Cdlg
- •8.9. Формування вхідного документа на основі діалогу
- •Контрольні питання
- •Завдання Робота з типовими елементами керування
- •Робота зі списками і комбінованими полями
- •Список літератури
8.2. Робота зі списками і комбінованими полями
Приклад роботи знаходиться у папці DISK\dialog\dialog2.
Наступною темою при роботі з діалогами є комбіновані поля. Наступна програма містить комбіноване поле і текстове поле, в якому відображається обраний користувачем рядок.
Коли користувач клацає на стрілці поруч з комбінованим полем, в діалоговому вікні розкривається список.
Коли користувач вибирає один з рядків списку – він виводиться у текстовому полі.
За допомогою AppWizard необхідно створити програму combos на базі діалогового вікна. Все готово до заповнення комбінованого поля даними.
Ініціалізація комбінованого поля
Комбіновані поля ініціалізуються в методі OnInitDialog():
BOOL CCombosDlg::OnInitDialog()
{
CDialog::OnInitDialog();
.............................................................
}
Тепер можна переходити до ініціалізації комбінованого поля. Вона виконується практично так само, як і в попередньому прикладі. За допомогою ClassWizard створюється змінна, що представляє комбіноване поле, і має назву m_combo. Вона повинна належати до класу CComboBox. Методи класу CComboBox перераховані в табл. 8.1.
Таблиця 8.1.
Методи класу CComboBox
Метод |
Призначення |
AddString |
Додає рядок в кінець списку комбінованого поля |
CComboBox |
Конструює об'єкт класу CComboBox |
Clear |
Видаляє поточний виділений фрагмент у текстовому полі |
CompareItem |
Викликається для визначення положення нового рядка в відсортованому комбінованому полі з нестандартним промальовуванням |
Copy |
Копіює поточний виділений фрагмент в буфер обміну |
Create |
Створює комбіноване поле як елемент Windows і пов'язує його з об'єктом CComboBox |
Cut |
Видаляє поточний виділений фрагмент і поміщає його в буфер обміну |
DeleteItem |
Викликається при видаленні користувачем рядка з комбінованого поля з нестандартним промальовуванням |
DeleteString |
Видаляє рядок зі списку |
Dir |
Включає в список комбінованого поля імена файлів |
DrawItem |
Викликається, коли виникає необхідність у нестандартному промальовуванні комбінованого поля |
FindString |
Шукає у списку перший рядок із заданим префіксом |
FindStringExact |
Шукає у списку перший рядок, який точно співпадає із заданим |
GetCount |
Повертає кількість рядків у списку |
Продовження таблиці 8.1
Метод |
Призначення |
GetCurSel |
Отримує індекс поточного вибраного рядка списку (якщо він є) |
GetDroppedControlRect |
Отримує екранні координати видимої частини списку, що розкривається |
GetDroppedState |
Визначає, чи видно в даний момент список, що розкривається |
GetDroppedWidth |
Отримує мінімальну допустиму ширину списку, що розкривається |
GetEditSel |
Визначає позицію першого і останнього символів поточного виділеного фрагмента |
GetExtendedUI |
Визначає, який користувацький інтерфейс має комбіноване поле – стандартний або розширений |
GetHorizontalExtent |
Повертає кількість пікселів, на яку список може прокручуватися по горизонталі |
GetItemData |
Повертає 32-розрядну величину, пов'язану з рядком списку |
GetItemDataPtr |
Повертає 32-розрядну величину, пов'язану з рядком списку у вигляді вказівки |
GetItemHeight |
Визначає висоту рядків у списку |
GetLBText |
Отримує текст рядка зі списку |
GetLBTextLen |
Отримує довжину рядка в списку |
GetLocale |
Отримує ідентифікатор локального контексту для комбінованого поля |
GetTopIndex |
Повертає перший індекс відображаємого рядка списку |
InitStorage |
Виділяє блоки пам'яті для зберігання рядків списку |
InsertString |
Вставляє рядок у список |
LimitText |
Обмежує довжину тексту, який може вводитися користувачем в текстове поле |
MeasureItem |
Викликається при створенні комбінованого поля з нестандартним промальовуванням для визначення його розмірів |
Paste |
Вставляє в текстове поле вміст буфера обміну |
ResetContent |
Видаляє весь вміст списку і текстового поля |
SelectString |
Шукає і вибирає рядок у списку |
SetCurSel |
Вибирає рядок у списку |
SetDroppedWidth |
Задає мінімальну допустиму ширину списку, що розкривається |
SetEditSel |
Виділяє символи в текстовому полі |
SetExtendedUI |
Визначає користувацький інтерфейс комбінованого поля – стандартний або розширений |
SetHorizontalExtent |
Визначає кількість пікселів, на яку список може прокручуватися по горизонталі |
SetItemData |
Задає значення 32-розрядної величини, пов'язаної з рядком списку |
SetItemDataPtr |
Задає значення 32-розрядної величини, пов'язаної з рядком списку у вигляді вказівки |
SetItemHeight |
Задає висоту рядків списку або висоту текстового поля |
SetLocale |
Задає ідентифікатор локального контексту для комбінованого поля |
SetTopIndex |
Визначає індекс першого відображаємого рядка списку |
ShowDropDown |
Відображає або приховує список |
Підказка. Ви також можете зв'язати змінну зі значенням комбінованого поля – ним вважається поточний зміст текстового поля.
Як і в попередньому прикладі, для занесення до списку необхідних рядків («Рядок 01» - «Рядок 12») ми скористаємося методом AddString():
BOOL CCombosDlg::OnInitDialog()
{
CDialog::OnInitDialog();
m_combo.AddString("Рядок 01");
m_combo.AddString("Рядок 02");
m_combo.AddString("Рядок 03");
m_combo.AddString("Рядок 04");
m_combo.AddString("Рядок 05");
m_combo.AddString("Рядок 06");
m_combo.AddString("Рядок 07");
m_combo.AddString("Рядок 08");
m_combo.AddString("Рядок 09");
m_combo.AddString("Рядок 10");
m_combo.AddString("Рядок 11");
m_combo.AddString("Рядок 12");
// Додати команду "About ..." в системне меню.
.............................................................
}
Крім того, необхідно вибрати зі списку перший рядок («Рядок 01»), щоб при першій появі комбінованого поля на екрані в текстовому полі відображався його зміст (у протилежному випадку текстове поле виявиться порожнім):
BOOL CCombosDlg::OnInitDialog()
{
CDialog::OnInitDialog();
m_combo.AddString("Рядок 01");
m_combo.AddString("Рядок 02");
m_combo.AddString("Рядок 03");
m_combo.AddString("Рядок 04");
m_combo.AddString("Рядок 05");
m_combo.AddString("Рядок 06");
m_combo.AddString("Рядок 07");
m_combo.AddString("Рядок 08");
m_combo.AddString("Рядок 09");
m_combo.AddString("Рядок 10");
m_combo.AddString("Рядок 11");
m_combo.AddString("Рядок 12");
m_combo.SetCurSel(0);
// Додати команду "About ..." в системне меню.
.............................................................
}
Перейдемо до обробки можливих дій користувача.
Визначення вибраного рядка
Наша програма повинна повідомляти, який рядок списку вибрав користувач. У цій ситуації комбіноване поле посилає програмі повідомлення CBN_SELCHANGE. Префікс CBN означає «Combo Box Notification», тобто «повідомлення від комбінованого поля». Це сімейство складається з повідомлень CBN_CLOSEUP, CBN_DBLCLICK, CBN_DROPDOWN, CBN_EDITCHANGE, CBN_EDITUPDATE, CBN_ERRSPACE, CBN_KILLFOCUS, CBN_SELCHANGE, CBN_SELENDCANCEL, CBN_SELENDOK і CBN_SETFOCUS. За допомогою ClassWizard зв’яжемо обробник з повідомленням CBN_SELCHANGE.
Підказка. Всі можливі повідомлення перераховані в ClassWizard на вкладці Message Maps у списку Messages.
ClassWizard пропонує присвоїти новому методу ім'я OnSelchangeCombo1(). Підтвердіть запропоноване ім'я та відкрийте код методу:
void CCombosDlg::OnSelchangeCombo1()
{
// ЗРОБИТИ: додайте код для обробки повідомлень
// від елемента
}
Виклик цього методу означає, що користувач вибрав зі списку комбінованого поля новий рядок; ми хочемо повідомити про це в текстовому полі, використовуючи змінну m_text. Робиться це так само, як і у випадку зі списком, – слід викликати метод GetCurSel(), після чого оновити вміст текстового поля методом UpdateData():
void CCombosDlg::OnSelchangeCombo1()
{
m_combo.GetLBText(m_combo.GetCurSel(), m_text);
UpdateData(false);
}
Підказка. Щоб перехопити зміни, що вносяться до вмісту текстової частини комбінованого поля, слід за допомогою ClassWizard організувати в програмі обробку повідомлення CBN_EDITCHANGE.
Запустимо програму. При виборі нового пункту вміст відповідного рядка з’являється в текстовому полі (рис. 8.4). Наша програма успішно працює і дозволяє вибирати з комбінованого поля нові рядки.
Рис. 8.4. Програма combos дозволяє вибирати рядки з комбінованого поля
Вихідний текст програми combos міститься у файлах combosDlg.h/combosDlg.cpp.
combosDlg.h і combosDlg.cpp
// CombosDlg.h: заголовочний файл
//
# if !defined(AFX_COMBOSDLG_H__ED674083_9309_11D0_8860_444553540000__INCLUDED_)
#define AFX_COMBOSDLG_H__ED674083_9309_11D0_8860_444553540000__INCLUDED_
#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
/////////////////////////////////////////////////////////////////////////
// Діалогове вікно CCombosDlg
class CCombosDlg: public CDialog
{
// Створення
public:
CCombosDlg(CWnd* pParent = NULL); // Стандартний конструктор
// Дані діалогового вікна
//{{AFX_DATA(CCombosDlg)
enum { IDD = IDD_COMBOS_DIALOG };
CComboBox m_combo;
CString m_text;
//}}AFX_DATA
// Перевизначення віртуальних функцій, згенерованих ClassWizard
//{{AFX_VIRTUAL(CCombosDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // Підтримка DDX/DDV
//}}AFX_VIRTUAL
// Реалізація
protected:
HICON m_hIcon;
// Згенеровані функції схеми повідомлень
//{{AFX_MSG(CCombosDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand (UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnSelchangeCombo1();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
// {{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ буде вставляти додаткові
// оголошення перед попереднім рядком.
#endif
// !defined(AFX_COMBOSDLG_H__ED674083_9309_11D0_8860_444553540000__INCLUDED_)
// combosDlg.cpp: файл реалізації
//
#include "stdafx.h"
#include "combos.h"
#include "combosDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
////////////////////////////////////////////////// ///////////////////////
// Діалогове вікно CAboutDlg, виведене за командою About
class CAboutDlg: public CDialog
{
public:
CAboutDlg();
// Дані діалогового вікна
//{{AFX_DATA(CAboutDlg)
enum {IDD = IDD_ABOUTBOX};
//}}AFX_DATA
// Перевизначення віртуальних функцій, згенеровані ClassWizard
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // Підтримка DDX/DDV
//}}AFX_VIRTUAL
// Реалізація
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// Обробники повідомлень відсутні
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////
// Діалогове вікно CCombosDlg
CCombosDlg::CCombosDlg(CWnd* pParent /*=NULL*/)
: CDialog(CCombosDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CCombosDlg)
m_text = _Т("");
//}}AFX_DATA_INIT
// Зверніть увагу на те, що в Win32 LoadIcon
// не вимагає подальшого виклику DestroyIcon
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CCombosDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CCombosDlg)
DDX_Control(pDX, IDC_COMBO1, m_combo);
DDX_Text(pDX, IDC_EDIT1, m_text);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CCombosDlg, CDialog)
//{{AFX_MSG_MAP(CCombosDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_CBN_SELCHANGE(IDC_COMBO1, OnSelchangeCombo1)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////
// Обробники повідомлень CCombosDlg
BOOL CCombosDlg::OnInitDialog()
{
CDialog::OnInitDialog();
m_combo.AddString("Рядок 01");
m_combo.AddString("Рядок 02");
m_combo.AddString("Рядок 03");
m_combo.AddString("Рядок 04");
m_combo.AddString("Рядок 05");
m_combo.AddString("Рядок 06");
m_combo.AddString("Рядок 07");
m_combo.AddString("Рядок 08");
m_combo.AddString("Рядок 09");
m_combo.AddString("Рядок 10");
m_combo.AddString("Рядок 11");
m_combo.AddString("Рядок 12");
m_combo.SetCurSel(0);
// Додати команду "About ..." в системне меню.
// Значення IDM_ABOUTBOX має перебувати в діапазоні
// системних команд.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING,
IDM_ABOUTBOX, strAboutMenu);
}
}
// Поставити значок для діалогового вікна. Бібліотека
// робить це автоматично, якщо головне вікно програми
// не є діалоговим.
SetIcon(m_hIcon, TRUE); // Встановити великий значок
SetIcon(m_hIcon, FALSE); // Встановити малий значок
// ЗРОБИТИ: додайте додаткову ініціалізацію
return TRUE; // повернути TRUE, якщо тільки ви
// не передаєте фокус елементу
}
void CCombosDlg::OnSysCommand(UINT nID, LPARAM IParam)
{
if ((nID & OxFFFO) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, IParam);
}
}
// Якщо в діалоговому вікні присутня кнопка згортання,
// наведений нижче код знадобиться для малювання значка.
// У додатках MFC, які використовують модель документ / вид,
// це робиться автоматично.
void CCombosDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // контекст пристрою
// для малювання
SendMessage(WM_ICONERASEBKGND,
(WPARAM) dc.GetSafeHdc(), 0);
// Вивести значок у центрі клієнтського
// прямокутника
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
Cflect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Намалювати значок
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// Викликається системою для отримання курсору,
// який відображається при перетягуванні згорнутого вікна.
HCURSOR CCombosDlg::OnQueryDragIcon()
{
return (HCURSOR) m.hIcon;
}
void CCombosDlg::OnSelchangeCombo1()
{
m_combo.GetLBText(m_combo.GetCurSel(), m_text);
UpdateData(false);
}
На наступному етапі розглянемо ускладнений приклад зі списками.