Так мені прийшла в голову думка повторити «подвиг», написавши калькулятор, але вже на D і Qt5!
Почну з того, що я взагалі не знайомий з Qt і його концепціями, хоч і колись намагався познайомитися з ним. Однак, я впевнений, що незнання Qt5 не перешкода, оскільки у Всесвітній Павутині є купа прикладів по цій чудовій тулкіта, а також є цілком вичерпна документація по API, доступна ось тут.
Насамперед, переконуємося, що libQtE5Widgets64.so (або QtE5Widgets64.dll) в наявності (передбачається, що у вас, також як і у мене 64-розрядна операційна система) і якщо це не так, то завантажуємо і збираємо ці бібліотеки.
Мені пощастило, в тому, що у мене виявилася абсолютно чиста Kubuntu 16.04 і один з наших гостей описав детальну процедуру по збірці QtE5 на 64-розрядному Linux, якої я скористався. Крім цього, перед тим, як виконати компіляцію довелося встановити дещо з додаткового програмного забезпечення за допомогою команди:
Далі, довелося трохи помучитися з компіляцією проекту в QtCreator, яка проходить по інструкції Віталія Коливанова, а ось установку компільованою libQtE5Widgets64.so.1.0.0 я провів трохи інакше: спочатку я її перейменував в libQtE5Widgets64.so, а потім просто скопіював в папку / lib системи - як це не дивно, але цього дії виявилося трохи більше ніж достатньо.
Тепер, все що нам потрібно - це файл qte5.d зі стандартної поставки QtE5 і чистий файл app.d.
Два цих файлу ми об'єднаємо в один простий проект в середовищі Monodevelop з MonoD, скориставшись опцією створення порожнього проекту (як це зробити, я вже описував в одній зі статей) і отримаємо тим самим можливість автоматичного доповнення коду і зручний список всіх функцій, який на даний момент міститися в QtE.
На цьому підготовка до розробки калькулятора закінчена і ми плавно переходимо до процесу його створення.
Для початку визначимося які елементи інтерфейсу нам буде потрібно, щоб втілити найпростіший калькулятор, який буде вважати тільки в цілих числах (в основному через чисто технічного обмеження, однак, це для нас не так уже й важливо).
Цілком очевидно, що для калькулятора потрібно дисплей, роль якого зіграє елемент QLCDNumber; кілька кнопок під числа і операції, які можна реалізувати за допомогою елемента управління QPushButton; а також буде потрібно кілька так званих «сайзер» або «вирівнювачів» для розміщення всередині них елементів: QVBoxLayout - для вертикального розміщення елементів усередині себе і QHBoxLayout - для горизонтального розміщення елементів.
Я дуже сподіваюся, що ви перед прочитанням цієї статті хоча б просто пробіглися очима по статті «QtE5 - вивчаємо D і Qt5 в комфортній графічному середовищі», оскільки дизайн програми в QtE5 дуже складний (по крайней мере, мені так до сих пір здається), а пояснити його в декількох словах я навряд чи зможу і крім того, далі йде досить таки складний код розміщення елементів ...
Крім самих елементів інтерфейсу, нам буде потрібно такий елемент, всередині якого ми могли б з упевненістю розміщувати потрібні елементи управління, такі як кнопки та ін. На щастя, в Qt5 є такий елемент і називається він QWidget, і саме від цього елемента нам і потрібно здійснити успадкування для того, щоб створити вікно зі своїми власними елементами GUI:
Приблизно таку заготовку ми будемо використовувати в нашому калькуляторі.
Спочатку ми створюємо псевдонім для QtE.WindowType чисто для спрощення коду та для простоти його прочитання, після чого визначаємо похідний від QWidget клас MainForm. У класі MainForm визначаємо стандартний конструктор, що приймає два параметри - елемент, який є «батьком» (батьком в плані системи викликів, а не успадкування) і тип вікна. Усередині конструктора теж не відбувається нічого незвичайного: клас MainForm звертається до батьківського конструктору за допомогою super, потім виставляє свій власний розмір (300 пікселів в довжину і 400 у висоту), а потім виводить в область заголовка деяку напис (в даному випадку, цим написом є напис - «QtE Calculator»). А ось така інструкція, а саме інструкція setStyleSheet (WHITE) вже є незвичною. Справа в тому, що ця інструкція однакова застосовна до більшості елементів графічного інтерфейсу QtE і дозволяє використовуючи знання HTML і CSS задавати зовнішній вигляд деякого елемента, в даному випадку - звичайного вікна. Перерахування WHITE також є одним їх елементів стратегії спрощення коду і задає звичайну строкову константу, яка містить інструкцію по фарбуванню фону в білий колір.
Тепер, ми можемо перейти до внутрішнього вмісту класу MainForm і для початку ми визначимо майже весь набір елементів інтерфейсу:
Майже весь (а це кнопки для чисел, операцій і кнопки обчислення), тому що один з елементів інтерфейсу ми визначимо як глобальну змінну (так, так, я знаю, що це недобре, але інших варіантів не було), а саме - QLCDNumber:
Після цього можна налаштувати елементи управління, згідно з нашим потребам, і почнемо ми мабуть, з LCD-дисплея, стилізувавши його під дисплей звичайних кишенькових калькуляторів:
Цей код повинен бути розміщений безпосередньо всередині конструктора класу MainForm, оскільки є кодом ініціалізації. Однак, потрібно трохи пояснити, що робить цей набір методів об'єкта lcd. Метод setMode встановлює режим відображення значень на LCD-індикаторі і приймає в якості аргументу константу (або перерахування, точно не скажу), яка розміщена прямо в цьому ж класі. В даному випадку, колнстанта QLCDNumber.Mode.Dec встановлюється десятковий режим відображення чисел, хоча заради інтересу можна поставити що-небудь більш інтригуюче, наприклад. шестнадцатеорічний режим відображення (константа QLCDNumber.Mode.Hex). Після установки правильного режиму відображення, ми налаштовуємо стиль самого дисплея за допомогою CSS (я ж казав, що метод setStyleSheet буде нам часто попадатися!), Після чого використовуємо найголовніший для нас метод - метод display, який дозволяє вивести на lcd деяке ціле число.
На жаль, саме через display наш калькулятор буде вважати тільки в цілих числах :(
LCD-дисплей, не єдиний елемент інтерфейсу, і це означає, що необхідно подумати про розміщення елементів у вікні програми.
Справа в тому, що елементи інтерфейсу в Qt5 можна розмістити у вікні програми за допомогою т.зв. сайзер (sizers) або, як їх називає розробник QtE5, вирівнювачів.
Сайзер в QtE5 два типи: QVBoxLayout - вертикальний і QHBoxLayout - горизонтальний вирівнювач. У них ми і будемо розміщувати кнопки, використовуючи для цього методи, визначені для обох типів сайзер: addWidget, размеющающій елементи управління, і addlayout, що розміщує вже самі сайзер.
Створимо самі елементи GUI і налаштуємо їх властивості, після чого створимо сайзер і помістимо в них один за іншим елементи (просто стежте за кодом, інакше ніяк це і не пояснити: D). Саме розміщення будемо проводити, використовуючи чудову конструкцію мови програмування D під назвою with:
Крім цього, після розміщення елементів і сайзер (робимо це послідовно!), Ми розміщуємо останній сайзер прямо в головному вікні за допомогою методу setLayout класу MainForm. За наведеним кодом, видно, що розміщення і настройка елементів дуже прості, як в загальному, і їх створення - в ході створення, ми просто передаємо потрібного об'єкту покажчик на головний елемент (parent, в нашому випадку, це форма MainForm) і деякий параметр- описатель, яким може бути текст кнопки або будь-якої іншої адекватний описатель.
Однак, наведений код ще не є завершеним, оскільки ми ще не описали логіку калькулятора і події, що зв'язують вже розміщені на формі кнопки і LCD-дисплей.
Визначимо кілька глобальних змінних, які будуть накопичувати цифри аргументів операцій додавання, віднімання, множення і ділення, а також визначимо рядок, що зберігає результат операції (необхідно для реалізації деякого поведінки звичайного кишенькового калькулятора) і числову змінну, яка збереже підсумок операції, придатний для відображення на екрані:
Тепер опишемо реакцію цифрових кнопок і кнопки зміни знака числа за допомогою подій, визначених в такий спосіб:
Працює це дуже просто: ми будемо причіплювати цифри до числа, відображеного в даний момент на калькуляторі за допомогою оператора конкатенації рядків. Допоміжні функції updateLCD і setOperationSign допоможуть грамотно вивести на дисплей число-результат і коректно встановити знак математичної операції.
Крім цього, функція setOperationSign і відповідні операції зможуть відстежити обрану користувачем математичну операцію (зберігаючи знак операції в змінної operationSign) або відстежити скидання поточного значення на дисплеї.
Тепер залишилося тільки впізнати математичну операцію, обрану користувачем, а також оновити значення на дисплеї, наприклад ось так:
Відповідно, необхідно наведений обробник події розмістити всередині блоку extern (C), для того, щоб Qt5 змогла правильно зреагувати на натискання кнопки «дорівнює». У цьому обробнику просто прооісходіт переклад строкового накопичувача цифр в ціле число, а потім використання його в якості другого аргументу в математичної операції (перший аргумент, як ви вже зрозуміли, це змінна result, вже містить введене число), позначення якої вже було поміщено в operationSign за допомогою соотвествующих кнопок процедур обробки.
Наступним кроком буде размешение в файлі наступної, трохи переробленої функції main:
Усередині main ми створюємо для зручності читання коду псевдонім на тип вікна QtE.WindowType.Window, а також проводимо перевірку того, наскільки успішно довантажити Qt5. Також ми створюємо екземпляр класу QApplication (екземпляр додатку на Qt, вхідні точка в додаток), здійснюємо захоплення переданих програмі аргументів (в разі, якщо такі підуть), після чого відбувається створення екземпляра MainForm (перший параметр - батьківський елемент, якого в даному випадку немає , оскільки вікно саме по собі буде першим в ієрархії елементів графічного інтерфейсу; другий параметр - той самий тип вікна).
Потім, ми просто відображаємо створене вікно і зберігаємо на нього покажчик для Qt5, і просто запускаємо.
Зберігаємо в файл і компілюємо, запускаємо, отримуючи ось такий результат:
Велике спасибі хочу сказати розробнику цієї воістину чудовою прив'язки до Qt5, Мохова Геннадію Володимировичу, за його допомогу при навчанні роботі з QtE5 і за дуже цінні поради, дані в ході написання цієї статті!