- •О.С. Зеленський
- •Розділ 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.6. Лінійний регулятор, лінійний індикатор, інкриментний регулятор
Приклад роботи знаходиться у папці DISK\dialog\dialog6.
Створимо програму з такими елементами керування як: лінійний регулятор (CSliderCtrl), лінійний індикатор (CProgressCtrl) та інкрементний регулятор (CSpinCtrl). Уявимо що ця програма використовується для регулювання напруги у деякому пристрої. Створимо структуру napr у якій буде зберігатись напруга та швидкість її зміни:
struct napr
{
int volt;
int skor;
};
У класі діалогу додамо змінну створену на основі цієї структури:
class CDialDoc : public CDocument
{
.............................................................
public:
napr vol;
.............................................................
};
Створимо клас Dia, у якому буде розміщено зазначені вище елементи керування. Результат роботи програми приведено на рис. 8.11:
class Dia : public CDialog
{
// Construction
public:
Dia(); // standard constructor
CDialDoc* doc;
// Dialog Data
//{{AFX_DATA(Dia)
enum { IDD = IDD_DIALOG1 };
CSliderCtrl m_slid;
CProgressCtrl m_prog;
CString m_edit;
CString m_edit_zn;
//}}AFX_DATA
.............................................................
};
Рис. 8.11. Результат роботи програми
Змінна m_edit буде містити числове значення для автоматичної зміни напруги. Значення напруги буде виводитись у змінну m_edit_zn. У діалозі будемо періодично змінювати положення елементів керування. Для цього створимо таймер функцією SetTimer (для видалення таймера використовується функція KillTimer). Таймер закріплюється за певним вікном, а операційна система генерує події WM_TIMER для вікон з таймерами. Додамо функцію OnTimer, яка буде реагувати на періодично створювані системою події WM_TIMER:
void Dia::OnTimer(UINT nIDEvent)
{
m_slid.SetPos(m_slid.GetPos() + 10);
CDialog::OnTimer(nIDEvent);
SendMessage(WM_HSCROLL);
}
У функції ми змінюємо позицію лінійного регулятора через вказівку m_slid. Функція GetPos із класу CSliderCtrl повертає позицію елемента, а SetPos встановлює нову позицію. Для синхронізації зміни лінійного регулятора із іншими елементами керування розташованими у вікні діалогу ми викликаємо функцію SendMessage із параметром WM_HSCROLL для виклику функції OnHScroll:
void Dia::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
CString vrem;
vrem.Format("%d вольт",m_slid.GetPos());
SetWindowText("Напряжение = " + vrem);
m_edit_zn = vrem;
UpdateData(false);
CRect rec, rec_tec;
CClientDC client(this);
CBrush br(RGB(255,0,0));
CBrush br_os(RGB(255,255,255));
m_prog.SetPos(m_slid.GetPos());
::GetWindowRect(::GetDlgItem(m_hWnd,IDC_PICTURE),&rec);
ScreenToClient(&rec);
rec_tec = rec;
rec_tec.right = rec.left + rec.Width() * m_slid.GetPos() / m_slid.GetRangeMax();
client.FillRect(rec,&br_os);
client.FillRect(rec_tec,&br);
if(m_slid.GetPos() > 0)
((CButton*)GetDlgItem(IDC_CHECK1))->SetCheck(0);
CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}
У змінній vrem формується заголовок для вікна діалогу. Встановлення заголовку для вікна робиться функцією SetWindowText. Позиція лінійного індикатора змінюється через вказівку m_prog функцією SetPos із класу CProgressCtrl. У елементі керування IDC_PICTURE ми намалюємо позицію самостійно. Прямокутник rec буде займати всю область вікна елемента IDC_PICTURE а rec_tec лише область, що буде показувати рівень напруги. Створимо пензлик br_os для малювання фону а також пензлик br для малювання рівня поточної напруги. Функцією FillRect малюються 2 прямокутника rec і rec_tec. Функція SetCheck з параметром 0 очищує прапорець IDC_CHECK1.
Як зазначалось вище автоматична зміна напруги за таймером буде виконуватись в залежності від значення m_edit. Створимо елемент керування інкриментний регулятор для зміни значення m_edit, додамо функцію OnDeltaposSpin1 для контролю за цим елементом:
void Dia::OnDeltaposSpin1(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR;
int a = atoi(m_edit);
a = a - pNMUpDown->iDelta*10;
if (a > -1 && a < 110)
{
m_edit.Format("%d",a);
UpdateData(0);
}
KillTimer(1);
if(a)SetTimer(1,10000/a,0);
*pResult = 0;
}
Спочатку ми перетворюємо значення змінної m_edit у число a типу int. Потім змінюємо значення a. Якщо значення a знаходиться у допустимих межах тоді перетворюємо його у текстовий вид функцією Format та записуємо результат у змінну m_edit. Виклик функції UpdateData призводить до оновлення значення текстового поля. Функція SetTimer створює новий таймер, який потрібен для періодичного виклику функції OnTimer.
У вікні діалогу є кнопка IDC_BUTTON1 для зупинки автоматичної зміни напруги. Створимо для цієї кнопки функцію відгуку OnButton1:
void Dia::OnButton1()
{
m_edit = "0";
UpdateData(false);
KillTimer(1);
}
Спочатку у m_edit записуємо число 0, потім оновлюємо текстові поля через виклик функції UpdateData. На випадок якщо у вікна існує таймер відключаємо його функцією KillTimer.
При натисненні на прапорець IDC_CHECK1 (з написом "Сброс напряжения") викликається функція OnCheck1:
void Dia::OnCheck1()
{
m_edit = "0";
UpdateData(false);
KillTimer(1);
m_slid.SetPos(0);
SendMessage(WM_HSCROLL);
}
Спочатку виконуються ті самі дії що і в функції OnButton1. А далі обнуляється позиція лінійного регулятора через вказівку m_slid. Як зазначалось вище функцію SendMessage викликаємо для синхронізації зміни лінійного регулятора із іншими елементами керування розташованими у вікні діалогу.
Виклик вікна діалогу зробимо у класі документа CDialDoc в функції OnDialog:
void CDialDoc::OnDialog()
{
Dia dial;
dial.doc = this;
if (dial.DoModal() == IDOK)
{
vol.volt = atoi((dial.m_edit_zn.Mid(0,4)).GetBuffer(1));
vol.skor = atoi(dial.m_edit);
SetModifiedFlag();
}
}
Після вдалого виклику вікна діалогу і натиснення кнопки OK ми записуємо нові значення напруги та швидкості її зміни у об’єкт структури vol. Викликаємо функцію SetModifiedFlag для фіксації факту зміни даних класу CDialDoc. Запис та зчитування параметрів об’єкту структури vol робиться у функції Serialize. Детально серіалізація даних розглядалась у п. 7.4, тому наводити код функції Serialize не будемо.