На этом шаге мы рассмотрим пример использования этого компонента.
Приведем пример приложения для домашнего телефонного справочника, построенного с использованием компонента CheckedListBox. Справочник должен содержать номера телефонов и специальный ящик (горячий ящик), в котором будут храниться самые необходимые из всего списка телефоны (чтобы ими можно было быстро воспользоваться). В ящик будут посылаться только те телефоны, которые в списке будут помечаться галочками (т. е. их флажки будут включены). Как только флажок выключается, номер телефона из горячего ящика удаляется. Однако строку из горячего ящика можно удалить и по щелчку мыши на ней.
При создании приложения возникли проблемы с переводом текста на русский язык и с методами записи в файл строк типа String. Одни методы читают только английский текст, другие читают и русский, но у них имеются недостатки с переходом от типа String к типу char*. Поэтому применение аппарата обычных функций работы с файлами, таких как fopen(), fgets(), fputs (), оказалось довольно затруднительным. Для упрощения проблем были выбраны два простейших метода чтения/записи одной строки типа String (см. по тексту примера). Ввиду того, что справочник имеет довольно мало строк, их можно сцепить в одну длинную, с которой можно работать - записывать и читать. Этим проблема преобразования типов от String к char* была снята.
Итак, приложение работает следующим образом: как только оно загружается для выполнения (фактически загружается форма), автоматически читаются два текстовых файла, в которых находятся сведения о предыдущей работе приложения (перед тем, как форме появиться на экране, срабатывает событие Load, в обработчик которого помещены операторы загрузки файлов). Содержимым этих файлов заполняется содержимое двух контейнеров: компонента ChekedListBox и компонента ComboBox. Далее приложение работает в обычном режиме: строки можно добавлявлять в оба контейнера и удалять из каждого в отдельности. Как только приложение завершит свою работу (кнопка Выход), содержимое контейнеров сохранится в соответствующих файлах (чтобы оно при выгрузке не исчезало).
Отсюда возникает проблема первоначального запуска приложения: надо вручную сформировать указанные два файла (их имена указаны в тексте приложения). Можно взять обыкновенный WordPad (Блокнот) и с его помощью создать пустые текстовые файлы в кодировке UTF-8. А далее в приложении вы сами введете те тексты, которые вам нужны.
Форма приложения приведена на рисунке 1, а текст - в примере ниже. На рисунках 2 и 3 показана работа с приложением.
Рис.1. Форма приложения "Домашний телефонный справочник"
Текст приложения:
#pragma once namespace My168_1 { using namespace System; using namespace System::ComponentModel; using namespace System::Collections; using namespace System::Windows::Forms; using namespace System::Data; using namespace System::Drawing; using namespace System::IO; // Добавлено для методов чтения/записи // строки . . . . . private: /// <summary> /// Требуется переменная конструктора. //--- Функции выгрузки в файл и загрузки из файла --- void LoadFromFile (String^ File, CheckedListBox^ lb) { // Этот метод открывает текстовый файл, читает все его строки // в строку String^ и закрывает файл. // Поскольку справочник небольшой, // то этот мето можно применять. // Это же касается и метода записи (см. ниже) String ^d, ^b = File::ReadAllText(File); //(надо будет выделять по разделителю "/") lb->Items->Clear(); //Разборка длинной строки на настоящие строки while(b->Length > 0) { int i = b->IndexOf("/"); //поиск 1-го вхождения //подстроки в строку if(i == -1) break; d = b->Substring(0,i); lb->Items->Add(d); b = b->Substring(i + 1, b->Length - d->Length - 1); } return; } // -------------------------------------------- void LoadFromFile(String ^File, ComboBox ^lb) { // Этот метод открывает текстовый файл, читает все его // строки в строку String^ и закрывает файл. String ^d, ^b = File::ReadAllText(File); //(надо будет вьделять по разделителю "/") lb->Items->Clear(); //Разборка длинной строки на настоящие строки while(b->Length > 0) { int i = b->IndexOf("/"); //поиск 1-го вхождения //подстроки в строку d = b->Substring(0, i); lb->Items->Add(d); b = b->Substring(i + 1, b->Length - d->Length - 1); } return; } // ============================================ void SaveToFile(String ^File, CheckedListBox ^lb) { String ^a, ^b; int j = lb->Items->Count; File::Delete(File); for(int i=0; i < j; i++) { // Чтение строк ChekedListBox в a и // формирование длинной строки в b a = lb->Items[i]->ToString(); b += a->Concat(a,"/"); //добавка разделителя строк // Этот тот метод открывает файл, добавляет к нему // строку типа String^, акрывает файл. Если файл // не существует, он создается. } //for File::AppendAllText(File, b); return; } // --------------------------------------------- void SaveToFile(String ^File, ComboBox^ lb) { String ^a, ^b; int j = lb->Items->Count; File::Delete(File); for(int i = 0; i < j; i++) { // Чтение строк ChekedListBox в a и формирование // длинной строки в b a = lb->Items[i]->ToString(); b += a->Concat(a, "/"); //добавка разделителя строк // Этот метод открывает файл, добавляет к нему строку // типа String^, закрывает файл. // Если файл не существует, он создается. } //for File::AppendAllText(File, b); return; } // ---------------------------------------------------- /// </summary> System::ComponentModel::Container ^components; . . . . . // Кнопка "Добавить в список" private: System::Void button2_Click(System::Object^ sender, System::EventArgs^ e) { String^ r = " "; // Формирование в строке r данных, введенных в поля ввода // для телефона и комментария r=r->Concat(textBox1->Text, r); r=r->Insert(35, textBox2->Text); checkedListBox1->Items->Add(r, 0); //состояние = 0 отключен textBox1->Text = ""; textBox2->Text = ""; textBox1->Focus(); } // Обработка нажатия клавиши <Enter> при вводе номера абонента private: System::Void textBox1_KeyDown(System::Object^ sender, System::Windows::Forms::KeyEventArgs^ e) { if (e->KeyCode == Keys::Enter) textBox2->Focus(); } // Обработка нажатия клавиши <Enter> при вводе комментария private: System::Void textBox2_KeyDown(System::Object^ sender, System::Windows::Forms::KeyEventArgs^ e) { if (e->KeyCode == Keys::Enter) button2->Focus(); } // Обработка кнопки "Выход" private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { // Когда приложение завершается, // надо сохранить данные ChekedListBox и ComboBox в файлах SaveToFile("d:\\file1.txt", checkedListBox1); SaveToFile("d:\\file2.txt", comboBox1); Close(); } // Обработка кнопки "Удалить из списка" private: System::Void button3_Click(System::Object^ sender, System::EventArgs^ e) { if (checkedListBox1->SelectedIndex == -1) // строку не отметили для удаления { MessageBox::Show("Отметьте строку для удаления", "Телефонный справочник", MessageBoxButtons::OK, MessageBoxIcon::Asterisk); return; } checkedListBox1->Items->Remove(checkedListBox1->SelectedItem); } // Обработка изменения состояния private: System::Void checkedListBox1_ItemCheck(System::Object^ sender, System::Windows::Forms::ItemCheckEventArgs^ e) { //Обработка выборки из списка //В зависимости от свойства CheckOnClick состояние флажка меняется //либо от одного щелчка, либо от повторного. //Здесь установлено, что от одного щелчка; //сюда попадаем, когда щелчком мыши выбираем строку из списка String ^str, ^tel, ^str1; int i = this->checkedListBox1->SelectedIndex; // здесь будет индекс выбранной строки после щелчка на ней str = dynamic_cast <String^>(checkedListBox1->SelectedItem); //перевод из типа Object^ в String^ // здесь будет выбранная строка после щелчка на ней tel = str->Substring(0, str->Length); //выделили номер телефона //добавка или удаление номера телефона в (из) ComboBox // поиск строки в ComboBox: если она найдена, то удаляется, // если не найдена, то после этого блока она добавляется int k=0, j=comboBox1->Items->Count; for (int i=0; i < j; i++) { str1 = dynamic_cast <String^>(comboBox1->Items[i]); if (System::String::Compare(str1, tel) != 0) //строки не сравнились continue; else { Object^ str2 = dynamic_cast <Object^> (str1); // Метод Remove() требует типа Object^, поэтому мы // перевели тип String^ в тип Object^ comboBox1->Items->Remove(str2); k = 1; break; } } //for() if(k == 1) //строку удалили return; // здесь ситуация, когда строки в ящике нет, поэтому ее надо в // него добавить if (comboBox1->Items->Count > 10) return; // если в ящике уже 10 строк, то добавлять не надо (он // будет содержать не более 10-ти строк comboBox1->Items->Add(tel); } // Обработка загрузки формы private: System::Void Form1_Load(System::Object^ sender, System::EventArgs^ e) { // Когда форма загружается, надо загрузить в // CheckedListBox и ComboBox их строки, сохраненные при выгрузке LoadFromFile("d:\\file1.txt", checkedListBox1); LoadFromFile("d:\\file2.txt", comboBox1); } // Обработка сворачивания CombоBox private: System::Void comboBox1_DropDownClosed(System::Object^ sender, System::EventArgs^ e) { //Удаление строки из ComboBox по щелчку на ней int i = comboBox1->SelectedIndex; comboBox1->Items->Remove(comboBox1->SelectedItem); }
Рис.2-3. Результат работы приложения
Пояснение:
Чтобы добавить новую строку в список, надо активизировать щелчком мыши поле ввода номера телефона (оно расположено над кнопкой Добавить в список). Затем нужно ввести в это поле текст и нажать клавишу Enter.
Фокус ввода перейдет к полю над кнопкой Удалить из списка (туда вводится второй текст (например, комментарий к первому введенному тексту) и снова нажимается клавиша Enter. Фокус ввода перейдет к кнопке Добавить в список, после чего надо снова нажать клавишу Enter. Обе введенные строки перенесутся в поле CheckedListBox.
Чтобы удалить строку из CheckedListBox, ее надо пометить, щелкнув на ней мышью, а затем нажать на кнопку Удалить из списка.
Чтобы удалить строку из ComboBox, надо открыть выпадающий список и щелкнуть на строке, которую требуется удалить.
На следующем шаге мы рассмотрим дополнение к вводу/выводу файлов.