Visual C++: размещаем компоненты с помощью TableLayoutPanel
В основном, этот пример был мне нужен для демонстрации того, как выравнивать компоненты по ячейкам таблицы, не мучаясь с их "ручным" позиционированием. А приложение-калькулятор - всегда хороший пример программы с "нестандартным" размещением интерфейсных элементов.
Предположим, наш калькулятор должен выглядеть так:
Внешний вид приложения
Видно, что все компоненты уместились в сетку таблицы 5 на 5 ячеек, при этом некоторые компоненты занимают более одной ячейки. Мы разместим и растянем компоненты в стандартном контейнере TableLayoutPanel
, но сначала подготовим пустую форму и выставим ей некоторые нужные свойства:
MaximumSize: 600; 600 MinimumSize: 200; 200 Size: 240; 240 StartPosition: CenterScreen Text: Калькулятор
Как видно, мы не хотим делать окно не-масштабируемым, но некие на глазок выбранные пределы изменения его размеров всё же задаём.
Теперь добавляем на форму контейнер TableLayoutPanel
из списка "Контейнеры" Панели Элементов, ставим ему свойство Dock
в значение Fill
и с помощью встроенного инструмента "Задачи" переходим к правке строк и столбцов:
Правка строк и столбцов TableLayoutPanel
Сделаем 5 столбцов с шириной по 20% каждый и 5 строк, у которых высота задана как на картинке:
Высота строк в TableLayoutPanel
Заодно прочитаем, что написано на картинке о растягивании компонент, лежащих в ячейках таблицы, на несколько строк или столбцов с помощью свойств RowSpan
и ColumnSpan
.
В левую верхнюю ячейку перетаскиваем стандартный TextBox
, ставим ему свойства ColumnSpan
= 5
и Dock
= Fill
. Также поставим TextAlign
= Right
, чтобы результаты вычислений выравнивались по правому краю поля.
Перетаскиваем в нужные ячейки (см. первый рисунок) кнопки button1 ... button9
, подписывая их соответствующими цифрами 1 ... 9
(в свойстве Text
) и ставя каждой Dock
= Fill
. Кнопка button10
будет соответствовать цифре "ноль", с ней поступим так же, только не забудем выставить ColumnSpan
= 3
. Кнопка button11
будеми иметь подпись "=" и значение ColumnSpan
= 2
, таким образом, они с нулём займут всю нижнюю строку. Кнопки "+", "-", "*" и "/" у меня получились как button12 ... button15
, их свойства - такие же, как у кнопок с цифрами 1 ... 9
. Наконец, кнопка стирания button16
, подписанная C
, также имеет свойство ColumnSpan
= 2
.
Интерфейс, в общем, готов, осталось написать код. В приватной секции класса (например, сразу ниже директивы #pragma endregion
), предусмотрим следующие переменные:
// Внешние переменные, видимые из всех методов класса Form1: String^ Znak; // знак арифметической операции bool StartOfInput; // ожидание ввода double Number1, Number2; // Первый и второй операнды расчёта
Создадим обработчик события Load
формы и напишем в нём следующий код:
StartOfInput = true; Znak = nullptr; // Один обработчик для всех кнопок с цифрами button1->Click += gcnew EventHandler(this, &Form1::AddDigit); button2->Click += gcnew EventHandler(this, &Form1::AddDigit); button3->Click += gcnew EventHandler(this, &Form1::AddDigit); button4->Click += gcnew EventHandler(this, &Form1::AddDigit); button5->Click += gcnew EventHandler(this, &Form1::AddDigit); button6->Click += gcnew EventHandler(this, &Form1::AddDigit); button7->Click += gcnew EventHandler(this, &Form1::AddDigit); button8->Click += gcnew EventHandler(this, &Form1::AddDigit); button9->Click += gcnew EventHandler(this, &Form1::AddDigit); button10->Click += gcnew EventHandler(this, &Form1::AddDigit); //Второй - для операций button12->Click += gcnew EventHandler(this, &Form1::Operation); button13->Click += gcnew EventHandler(this, &Form1::Operation); button14->Click += gcnew EventHandler(this, &Form1::Operation); button15->Click += gcnew EventHandler(this, &Form1::Operation); //Отдельный "IsEqual" button11->Click += gcnew EventHandler(this, &Form1::IsEqual); //Отдельный "ClearMe" button16->Click += gcnew EventHandler(this, &Form1::ClearMe);
Как видно, отдельный обработчик каждой кнопке с цифрой не нужен, а показанный код служит примером того, как назначать обработчики событий программно (точно такие же примеры можно увидеть, разобрав автогенерируемый при работе в режиме конструктора код).
Под методом Form1_Load
можно реализовать коды обработчиков, в них полезно посмотреть, как получить текст, отображаемый на кнопке, это нужно, чтобы обработчик мог различать, от какой именно кнопки пришло событие.
private: System::Void AddDigit(System::Object^ sender, System::EventArgs^ e) { // Получить текст, отображаемый на кнопке Button^ MyButton = (Button^)sender; String^ Digit = MyButton->Text; if (StartOfInput == true) { // Ввод первой цифры числа: textBox1->Text = Digit; StartOfInput = false; return; } // Иначе "сцепляем" полученные цифры в новое число: if (StartOfInput == false) textBox1->Text = textBox1->Text + Digit; } private: System::Void Operation(System::Object^ sender, System::EventArgs^ e) { Number1 = Double::Parse(textBox1->Text); // Получить текст, отображаемый на кнопке можно таким образом: Button^ MyButton = (Button^)sender; Znak = MyButton->Text; StartOfInput = true; // ожидаем ввод нового числа } private: System::Void IsEqual(System::Object^ sender, System::EventArgs^ e) { // Обработка нажатия клавиши "IsEqual" double Result = 0; Number2 = Double::Parse(textBox1->Text); if (Znak == "+") Result = Number1 + Number2; if (Znak == "-") Result = Number1 - Number2; if (Znak == "*") Result = Number1 * Number2; if (Znak == "/") Result = Number1 / Number2; Znak = nullptr; // Отображаем Result в текстовом поле: textBox1->Text = Result.ToString(); Number1 = Result; StartOfInput = true; } private: System::Void ClearMe(System::Object^ sender, System::EventArgs^ e) { textBox1->Text = "0"; Znak = nullptr; StartOfInput = true; }
Разумеется, пример можно и нужно улучшать, например, добавив обработку событий от клавиатуры для textBox1
.
Ну а вопрос, заданный человеком, посмотревшим этот код - "как сделать, чтобы на при изменении размеров окна увеличивался шрифт на всех кнопках?", пожалуй лучше будет рассмотреть в отдельной заметке - потому что готового свойства "масштабировать всё" в .NET нету, а перебор всех компонентов в цикле - вещь неочевидная, особенно если компоненты могут содержать другие компоненты, а мы пишем на C++/CLI.
Этот проект в архиве .zip, проверен в Visual C++ 2010 Express (15 Кб)
11.09.2016, 18:07 [7007 просмотров]