Делаем ListBox с редактированием элементов
Вообще-то, элементы базового списка ListBox
"на месте" не редактируются, для этого можно использовать ListView или табличные компоненты. Тем не менее, можно, например, выводить текстовое поле в том месте, где находится выбранный элемент списка и выполнять редактирование непосредственно в TextBox
, по завершении редактирования передавая информацию обратно в список.
На форму добавлен TableLayoutPanel из 2 столбцов и 1 строки,
относительная ширина столбцов равна 75% и 25%, выравнивание Dock = Fill
.
В левую ячейку поместили список ListBox
, а в правую - панель для кнопок Panel
, также поставив им свойство Dock=Fill
.
Кроме того, у ListBox
установлено свойство ScrollAlwaysVisible=True
(полоса прокрутки).
На панель поместим 3 кнопки Button
с именами Name = addButton
, deleteButton
, editButton
, у всех них установлено Dock = Top
.
Вот вид формы в конструкторе:
вид формы приложения
Нам понадобится пара новых свойств класса формы, как обычно, опишем их под директивой #pragma endregion
файла MyForm.h
:
private: int Cnt, //номер очередной строки EditIndex; //номер редактируемого элемента TextBox ^textBox1; //текстовое поле
На загрузку формы программно создадим и спрячем TextBox
, пока не позиционируя его:
private: System::Void MyForm_Load(System::Object^ sender, System::EventArgs^ e) { Cnt = 0; textBox1 = gcnew TextBox(); textBox1->Location = System::Drawing::Point(0, 0); textBox1->Size = System::Drawing::Size(0, 0); textBox1->Parent = this; textBox1->Hide(); textBox1->Text = ""; textBox1->BackColor = Color::Beige; textBox1->ForeColor = Color::Blue; textBox1->Font = gcnew System::Drawing::Font("Microsoft Sans Serif", 10, FontStyle::Regular | FontStyle::Underline, GraphicsUnit::Pixel); textBox1->BorderStyle = BorderStyle::FixedSingle; textBox1->KeyPress += gcnew System::Windows::Forms::KeyPressEventHandler(this, &MyForm::textBox_KeyPress); textBox1->LostFocus += gcnew System::EventHandler(this, &MyForm::textBox_LostFocus); this->Controls->Add(textBox1); }
Из кода видно, как "украсить" поле ввода.
Код также программно добавил созданному текстовому полю обработчики событий "нажатие клавиши" и "потеря фокуса", оба метода просто будут переписывать значение из поля ввода в список а потом вызывать ещё не написанный метод hideTextEditor
, который передаст управление из поля ввода снова в список.
private: System::Void textBox_KeyPress(System::Object ^sender, System::Windows::Forms::KeyPressEventArgs^ e) { if (e->KeyChar == 13) { listBox1->Items[EditIndex] = textBox1->Text; hideTextEditor(); } } private: System::Void textBox_LostFocus(System::Object ^sender, System::EventArgs ^e) { listBox1->Items[EditIndex] = textBox1->Text; hideTextEditor(); }
Самому списку можно добавить обработчики событий через конструктор форм, мы будем отслеживать двойной щелчок с списке, а также нажатие клавиш Enter или F2, все эти действия будут вызывать ещё не написанный метод CreateEditBox
, ответственный за переход к редактированию элемента.
private: System::Void listBox1_DoubleClick(System::Object^ sender, System::EventArgs^ e) { CreateEditBox(sender); } private: System::Void listBox1_KeyPress(System::Object^ sender, System::Windows::Forms::KeyPressEventArgs^ e) { if (e->KeyChar == 13) CreateEditBox(sender); } private: System::Void listBox1_KeyDown(System::Object^ sender, System::Windows::Forms::KeyEventArgs^ e) { if (e->KeyData == Keys::F2) CreateEditBox(sender); }
Кнопки "Добавить", "Удалить" и "Править" выполнят несложную работу по управлению элементами списка, причём, последняя также лишь вызывает метод CreateEditBox
.
private: System::Void addButton_Click(System::Object^ sender, System::EventArgs^ e) { String ^Str = gcnew String("Строка " + ++Cnt); listBox1->Items->Add(Str); } private: System::Void deleteButton_Click(System::Object^ sender, System::EventArgs^ e) { int n = listBox1->SelectedIndex; if (n == -1) { MessageBox::Show("Сначала выберите строку", "Ошибка", MessageBoxButtons::OK); return; } listBox1->Items->RemoveAt(n); } private: System::Void editButton_Click(System::Object^ sender, System::EventArgs^ e) { CreateEditBox(listBox1); }
Наконец, нам остаётся написать собственные методы класса, которые ранее мы неоднократно вызывали.
private: System::Void CreateEditBox (System::Object ^sender) { ListBox ^listBox1 = (ListBox ^)sender; int n = listBox1->SelectedIndex; if (n < 0) { MessageBox::Show("Сначала выберите строку", "Ошибка", MessageBoxButtons::OK); return; } Rectangle ^r = listBox1->GetItemRectangle(n); String ^itemText = (String ^)listBox1->Items[n]; int delta = 2; //Смещение от позиции элемента списка textBox1->Location = System::Drawing::Point(r->X + delta, r->Y + delta); textBox1->Size = System::Drawing::Size(r->Width - 10, r->Height - delta); showTextEditor(); textBox1->Text = itemText; textBox1->Focus(); textBox1->SelectAll(); EditIndex = n; } private: System::Void showTextEditor(System::Void) { listBox1->SendToBack(); textBox1->BringToFront(); textBox1->Show(); } private: System::Void hideTextEditor() { textBox1->Hide(); textBox1->SendToBack(); listBox1->BringToFront(); }
Текстовое поле появляется прямо поверх списка, это достигается сменой переднего/заднего планов списка и текстового поля.
Скачать этот пример в архиве .zip, внутри - папка с решением Visual Studio 2015 (7 Кб)
Ниже показана немного "улучшенная" версия приложения с таким же интерфейсом, в частности, в ней всё можно делать с клавиатуры нажатиями Enter, Insert и Delete. Это вся часть файла MyForm.h
(или Form.h
) после директивы #pragma endregion
#pragma endregion private: int Cnt; //Счетчик строк int editIndex; //Индекс последнего выбранного элемента TextBox ^textBox1; //Поле для редактирования выбранного элемента private: System::Void MyForm_Load(System::Object^ sender, System::EventArgs^ e) { //Загрузка формы Cnt = 0; editIndex = -1; //Создаём и настраиваем TextBox для редактирования элементов списка textBox1 = gcnew TextBox(); textBox1->Parent = this; textBox1->Text = ""; textBox1->BackColor = Color::Yellow; textBox1->KeyPress += gcnew KeyPressEventHandler(this, &MyForm::textBox1_KeyPress); textBox1->LostFocus += gcnew EventHandler(this, &MyForm::textBox1_LostFocus); hideTextEditor(); this->Controls->Add(textBox1); } private: System::Void addButton_Click(System::Object^ sender, System::EventArgs^ e) { //Нажатие кнопки "Добавить" String ^str = gcnew String(L"Строка "+ ++Cnt); listBox1->Items->Add(str); editIndex = listBox1->Items->Count - 1; listBox1->SelectedIndex = editIndex; } private: System::Void deleteButton_Click(System::Object^ sender, System::EventArgs^ e) { //Нажатие кнопки "Удалить" int n = listBox1->SelectedIndex; if (n < 0) { MessageBox::Show(L"Сначала выберите строку"); return; } editIndex = n; listBox1->Items->RemoveAt(n); int cnt = listBox1->Items->Count; if (cnt < 1) return; if (editIndex >= cnt) editIndex = cnt - 1; listBox1->SelectedIndex = editIndex; } private: System::Void textBox1_KeyPress(System::Object^ sender, KeyPressEventArgs^ e) { //Обработчик нажатия клавиш при редактировании строки списка if (e->KeyChar == (int)Keys::Enter) { listBox1->Items[editIndex] = textBox1->Text; hideTextEditor(); } } private: System::Void textBox1_LostFocus(System::Object^ sender, EventArgs^ e) { //Обработчик смены фокуса при редактировании строки списка listBox1->Items[editIndex] = textBox1->Text; hideTextEditor(); } private: System::Void editButton_Click(System::Object^ sender, System::EventArgs^ e) { //Нажатие кнопки "Править" createActiveTextBox(listBox1); } private: System::Void createActiveTextBox(System::Object^ sender) { //Метод для позиционирования поля редактирования и его показа ListBox ^list = (ListBox ^)sender; int n = list->SelectedIndex; if (n < 0) { MessageBox::Show(L"Сначала выберите строку"); return; } Rectangle ^R = list->GetItemRectangle(n); //Место выбранного элемента на экране textBox1->Location = Point(R->X,R->Y); textBox1->Size = System::Drawing::Size(R->Width,R->Height); //Можно попробовать позиционировать точнее, применяя list->Margin textBox1->Text = (String ^)list->Items[n]; editIndex = n; showTextEditor(); } private: System::Void showTextEditor() { //Метод "активировать редактор строки списка" listBox1->SendToBack(); textBox1->BringToFront(); textBox1->Show(); textBox1->SelectAll(); textBox1->Focus(); } private: System::Void hideTextEditor() { //Метод "убрать редактор строки списка" textBox1->Hide(); textBox1->SendToBack(); listBox1->BringToFront(); if (editIndex >= 0 && editIndex < listBox1->Items->Count) listBox1->SelectedIndex = editIndex; } private: System::Void listBox1_DoubleClick(System::Object^ sender, System::EventArgs^ e) { //Редактор также можно вызвать двойным щелчком по элементу списка createActiveTextBox(listBox1); } private: System::Void listBox1_KeyPress(System::Object^ sender, System::Windows::Forms::KeyPressEventArgs^ e) { //или нажатием клавиш. При этом: //KeyPress "ловит" только ASCII-коды клавиш if (e->KeyChar == (unsigned int)Keys::Enter) { createActiveTextBox(listBox1); } } private: System::Void listBox1_KeyDown(System::Object^ sender, System::Windows::Forms::KeyEventArgs^ e) { //А в KeyDown можно отслеживать и другие клавиши switch (e->KeyCode) { case Keys::F2: createActiveTextBox(listBox1); break; case Keys::Delete: this->deleteButton_Click(sender, e); break; case Keys::Insert: this->addButton_Click(sender, e); break; } } //Ниже закрывающие скобки класса и namespace
08.10.2017, 16:30 [5710 просмотров]