БГУ Пособие - Программирование в C++ Builder. Учебное пособие по курсу методы программирования для студентов специальностей
Скачать 1.24 Mb.
|
public. 1.8. Объявления обработчиков событий C++Builder использует модификатор _closure для объявления функ- ций обработчиков событий: <тип> (_closure * 24 Это ключевое слово определяет указатель функции с именем name. В отличие от 4-байтового указателя обычной функции, 8-байтовый указа- тель _closure передает еще и скрытый указатель this на экземпляр клас- са. Введение 8-байтовых указателей делает возможным вызывать неко- торую функцию определенного класса, а также обращаться к функции в определенном экземпляре этого класса. 1.9. Право владения Любой компонент может находиться во владении (ownership) других компонентов. Свойство компонента Owner (Владелец) содержит ссылку на компонент, который им владеет. Владелец отвечает за освобождение тех компонентов, которыми владеет, когда сам разрушается. Так, в про- цессе конструирования формы она автоматически становится владельцем всех компонентов, размещенных на ней, даже если часть их размещена на другом компоненте, например, таком как TPanel. Владение примени- мо не только к видимым, но и к невидимым (TTimer, TDataSource) ком- понентам. Когда компонент не переносится на форму, а создается динамически в процессе выполнения программы, конструктору компонента передает- ся ее владелец в качестве параметра. В следующем примере неявный владелец (например, форма) передается конструктору компонента TButton как параметр. Конструктор TButton выполнит присваивание зна- чения переданного параметра свойству Owner кнопки MyButton: MyButton = new TButton(this); Когда форма, уничтожается, автоматически уничтожается и кнопка MyButton. Можно создать компонент, у которого нет владельца, передавая зна- чение параметра 0 конструктору компонента. Его уничтожение выполня- ется с помощью оператора delete. Свойство Components класса Tcomponent содержит перечень компо- нентов, которыми владеет данный компонент. Ниже приводится фраг- мент кода обработчика события OnClick с циклом отображения имен классов всех компонентов, которыми владеет некоторая форма. void __fastcall TForm1::Button1Click(TObject *Sender) { for (int i=0; i ShowMessage(Components[i]->ClassParent()->ClassName()) ; } 25 } Метод ClassParent() возвращает родительские классы для находящих- ся на форме классов. 1.10. Родительское право Понятие родительского права (parentship) отличается от права владе- ния и применимо только к видимым компонентам. В качестве родитель- ских компонент могут выступать форма, панель, groupbox, на которых располагаются объекты – потомки. Родительские компоненты обраща- ются к соответствующим внутренним функциям, чтобы вызвать отобра- жение компонентов-потомков. Родитель также отвечает за освобождение своих потомков, когда сам родитель уничтожается. Свойство компонента Parent (Родитель) содержит ссылку на компонент, который является его родителем. Многие свойства видимых компонентов (например, Left, Width, Top, Height) относятся к родительским элементам управления. Другие свойства (например, ParentColor и ParentFont) позволяют потом- кам использовать свойства родителей. Компоненту надо присвоить родителя, ответственного за отображе- ние. Это присваивание выполняется автоматически на стадии проектиро- вания при перетаскивании компонента из Палитры компонентов на форму. При создании компонента во время выполнения программы не- обходимо явно записать это присваивание, иначе компонент не будет отображен: void __fastcall TForm1::FormCreate(TObject *Sender) { MyEdit = new TEdit(this); // Передать this как владельца MyEdit->Parent = this; // Передать this как родителя } В качестве примера приведем объявление компонента с единственным свойством IsTrue, имеющим значение по умолчанию true, а также конструктор, который устанавливает это значение при инициализации компонентного объекта. Заметим, что если свойство имеет значение по умолчанию false, то не нужно явно устанавливать его в конструкторе, поскольку все объекты (включая компоненты) всегда инициализируют свои члены данных значением 0, т.е. false. class TMyComponent : public TComponent { private: Boolean FIsTrue; public: __fastcall TMyComponent(TComponent* Owner); __published: 26 __property Boolean IsTrue = { read=FIsTrue, write=FIsTrue, default=true }; }; __fastcall TMyComponent:: TMyComponent (TComponent* Owner) : TComponent (Owner) { FIsTrue = true; } Вопросы 1. Каким образом, и в каких файлах можно создать собственный класс, динамический объект и вызвать методы класса? 2. Что представляют собой свойства компонентов? Приведите приме- ры нескольких свойств формы. 3. Что представляют собой события компонентов? Приведите приме- ры. 4. Каким образом можно изменить значения свойств компонентов? 5. Объявить класс MyClass, содержащий некоторую строку, и метод swap(), заменяющий строку другой строкой. Выполнить тестирование. 6. Объявить класс и определить размерность объектов данного клас- са. 7. Чем отличаются оператор-функции, объявленные как friend, от оператор-функций членов класса C++ и можно ли их использовать в C++Builder? 8. На каком этапе происходит выделение памяти под объекты компо- нентных классов? 9. Что представляет собой общедоступное свойство класса и его опубликованное свойство? 10. Что поизойдет в результате выполнения следующего кода? void __fastcall TForm1::Button1Click(TObject *Sender) { TForm * newForm= new TForm(this); TButton* button=new TButton(Application); button->Parent=newForm; button->Caption="New Button"; button->Left=10; button->Top=15; button->Show(); newForm->Caption="newForm"; newForm->ShowModal(); button->Click(); delete newForm; } 12. Как распознать нажатые функциональные клавиши? 27 13. Куда поступают события клавиатуры? Какое свойство формы влияет на то, куда поступают события клавиатуры? 14. В следующем коде какой из объектов отвечает за удаление кноп- ки? TButton* B=new TButton(this); B->Parent=Panel1; 2. КОМПОНЕНТЫ БИБЛИОТЕКИ VCL 2.1. Стандартные компоненты Компоненты вкладки Standard Палитры компонентов осуществляют включение в программу стандартных управляющих элементов Windows. Компонент TLabel отображает статический текст, являющийся значением свойства Caption. Например: Label1->Caption="Это Метка"; Компонент TEdit отображает область редактируемого ввода строки. Содержимое области редактирования определяется значением свойства Text. Например: double r1=Form1->Edit1->Text.ToDouble(), y=0, r2=Form1->Edit2->Text.ToDouble(); y=r1+r2; ShowMessage(FloatToStr(y)); Компонент TButton создает кнопку с надписью. Нажатие на кнопку инициирует некоторое событие. Кнопка, выбранная со значением true свойства Default, запускает обработчик события OnClick для кнопки всякий раз, когда нажимается клавиша Enter в окне диалога. Кнопка прерывания, выбранная со значением true свойства Cancel, запускает обработчик события OnClick для кнопки всякий раз, когда нажимается клавиша Escape. Ниже приводится пример использования рассматриваемых компонентов Label1-Label4, Edit1-Edit6 и Button1 при решении квадратного уравнения. //Uni1.cpp #include #pragma hdrstop #include #include "Unit1.h" #pragma package(smart_init) #pragma resource "*.dfm" 28 TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) {} void __fastcall TForm1::Button1Click(TObject *Sender) { try{ double a=StrToFloat(Edit1->Text); double b=StrToFloat(Edit2->Text); double c=StrToFloat(Edit3->Text); if(a==0){ShowMessage("Уравнение не квадратное");return;} double d = b * b - 4 * a * c; String str=""; if( d < 0) { str += ( - b ) / ( 2 * a); str += " + i * "; str += sqrt( - d ) / ( 2 * a); Edit4->Text = str; str = ""; str += ( - b ) / ( 2 * a); str += " - i * "; str += sqrt( - d ) / ( 2 * a); Edit5->Text = str; } else { Edit4->Text = ( - b + sqrt( d ) ) / ( 2 * a); Edit5->Text = ( - b - sqrt( d ) ) / ( 2 * a); } Edit6->Text=d; } catch(...) {ShowMessage("Input Error");} } На рис. 10 показана форма приложения в процессе выполнения. 29 Рис. 10. Форма в процессе выполнения Можно использовать кнопку с картинкой вместо кнопки типа TButton. Для этого можно применить компонент TBitBtn со вкладки Additional Палитры компонентов. Компонент ТMеmо отображает прямоугольную область ввода множества строк. Содержимое области редактирования определяет массив строк, являющийся значением свойства Lines. Например: void __fastcall TForm1::Edit1Change(TObject *Sender) { Memo1->Lines->Add(Edit1->Text); } Компонент TСheckBox создает квадратный флажок с двумя состояниями. Состояние check флажка соответствует выбору некоторого варианта (отмечается перечеркиванием квадрата), а состояние uncheck соответствует снятию выбора. При этом свойство компонента Checked меняется с true на false и возникает событие OnClick. Описательный текст флажка хранится в свойстве Caption. Компонент TRadioButton cоздает круглую кнопку (радиокнопку) с двумя состояниями и описательным текстом. Радиокнопки представляют набор взаимоисключающих вариантов выбора: только одна кнопка может быть выбрана в данный момент времени (отмечается внутренним черным кружком), а с ранее выбранной кнопки выбор автоматически снимается. При нажатии радиокнопки свойство компонента Checked меняется и возникает событие OnClick. Обычно радиокнопки размещаются внутри предварительно установленного на форме группового контейнера. Если выбрана одна кнопка, выбор всех прочих кнопок в той же группе автоматически снимается. Например, две радиокнопки на форме могут быть выбраны одновременно только в том случае, когда они размещены в разных 30 контейнерах. Если группировка радиокнопок явно не задана, то по умолчанию все они группируются в одном из оконных контейнеров (TForm, TGroupBox или TPanel). Компонент TListBox отображает прямоугольную область списка текстовых вариантов для выбора, добавления или вычеркивания. Если все элементы списка не умещаются в отведенную область, то список можно просматривать с помощью линейки прокрутки. Элементы списка содержатся в свойстве Items, а номер элемента, который будет выбран во время выполнения программы, – в свойстве ItemIndex. Окно текстового редактора элементов списка открывается кнопкой в графе значений свойства Items. Можно динамически добавлять, вычеркивать, вставлять и перемещать элементы списка с помощью методов Add, Append, Delete и Insert объекта Items. Например: ListBoxl->Items->Add("Последний элемент списка"); Значение true свойства Sorted устанавливает сортировку элементов списка по алфавиту. Рассмотрим пример приложения, позволяющего вводить текст в ре- дактируемое поле и добавлять этот текст к списку при нажатии на кноп- ку. Выберем пункт меню File|New Application для создания проекта и со- храним его главную форму под именем samp1.cpp, а сам проект под име- нем samp.bpr. Поместим на форму компоненты TButton, TEdit, TRadioButton и TListBox со страницы Standard Палитры компонентов. После этого выберем на форме компонент Edit1 и удалим текущее значе- ние свойства Text. Затем установим свойство Caption для RadioButton1 равным "Добавить", для RadioButton2 – "Удалить", для кнопки Button1 – "Выполнить", а для кнопки Button2 – "Выход". Чтобы добавить обработчик события OnClick для кнопки «Выпол- нить», нужно выбрать эту кнопку на форме, открыть страницу событий в Инспекторе объектов и дважды щелкнуть мышью на колонке справа от события OnClick. В соответствующей строке ввода появится имя функ- ции. C++ Builder сгенерирует прототип обработчика события и покажет его в редакторе кода. После этого следует ввести следующий код в тело функции: void __fastcall TForm1::Button1Click(TObject *Sender) { if(RadioButton1->Checked) { if (!(Edit1->Text == "")) { ListBox1->Items->Add(Edit1->Text); Edit1->Text = "" ; 31 } } else { if(RadioButton2->Checked){ if (!(ListBox1->ItemIndex == -1)) ListBox1->Items->Delete(ListBox1->ItemIndex); } } } В обработчик события OnClick для кнопки "Выход" добавим вызов функции Close(). Для компиляции приложения в меню Run выберем пункт Run. На рис. 11 показано окно приложения в процессе выполнения. Рис. 11. Окно приложения в процессе выполнения Компонент TСomboBox создает комбинацию области редактирования и выпадающего списка текстовых вариантов для выбора. Значение свойства Text заносится непосредственно в область редактирования. Элементы списка, которые может выбирать пользователь, содержатся в свойстве Items, номер элемента, который будет выбран во время выполнения программы, – в свойстве ItemIndex, а сам выбранный текст – в свойстве SelText. Свойства SelStart и SelLength позволяют установить выборку части текста или обнаружить, какая часть текста выбрана. Можно динамически добавлять, вычеркивать, вставлять и перемещать элементы списка с помощью методов Add, Append, Delete и Insert объекта Items. Например: ComboBoxl->Items->Insert(0, "Первый элемент списка"); Компонент TScrollBar создает линейку прокрутки с бегунком для просмотра содержимого окна. Поведение прокручиваемого объекта определяется обработчиком события OnScroll. Значение свойства LargeChange определяет насколько должен продвинуться бегунок, когда 32 пользователь щелкает мышью на самой линейке (по обеим сторонам от бегунка). Значение свойства SmallChange определяет насколько должен продвинуться бегунок, когда пользователь щелкает мышью по кнопкам со стрелками (на концах линейки) или нажимает клавиши позиционирования. Рассмотрим пример взаимодействия компонентов TScrollBar и TComboBox, которое происходит следующим образом: изменение по- ложения бегунка компонента TScrollBar вызывает изменение соответствующего ему элемента списка компонента TComboBox и на- оборот. Ниже приводится листинг программы, содержащий обработчики событий компонентов: //Unit1.cpp #include #pragma hdrstop #include "desyat.h" //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- void __fastcall TForm1::ComboBox1Change(TObject *Sender) { ScrollBar1->Position=ComboBox1->ItemIndex+1; } //--------------------------------------------------------------------------- void __fastcall TForm1::ScrollBar1Change(TObject *Sender) { ComboBox1->ItemIndex=ScrollBar1->Position-1; ComboBox1->Items->Add(ScrollBar1->Position-1); } //--------------------------------------------------------------------------- На рис. 12 показано окно программы в процессе выполнения. Компонент TGroupВох создает контейнер в виде прямоугольной рам- ки, визуально объединяющий на форме логически связанную группу не- которых интерфейсных элементов. Этот компонент представляет собой инкапсуляцию одноименного объекта Windows. Компонент TRadioGroup создает контейнер в виде прямоугольной рамки, визуально объединяющий на форме группу логически взаимоис- ключающих радиокнопок. 33 Рис. 12. Окно программы Радиокнопки образуют группу при помещении их в один и тот же контейнер. Только одна кнопка из данной группы может быть выбрана. Добавление кнопок к компоненту TRadioGroup выполняется редактированием свойства Items. Присвоение названия радиокнопки очередной строке свойства Items приводит к появлению этой кнопки в группирующей рамке. Значение свойства ItemIndex определяет, какая радиокнопка выбрана в настоящий момент. Можно группировать радиокнопки в несколько столбцов, устанавливая соответствующее значение свойства Columns. Компонент TPanel создает пустую панель (контейнер), которая может содержать другие компоненты. Можно использовать компонент TPanel для создания на форме панелей инструментов или строк состояния (од- нако для этого лучше использовать специальные компоненты TToolBar, TPageScroller, TStatusBar). Компонент TMainMenu создает панель команд главного меню и соответствующие им выпадающие меню для формы. В качестве примера приведем создание простейшего текстового ре- дактора с возможностью открытия и сохранения текстовых файлов. Бу- дем использовать компоненты TMainMenu, TOpenDialog, TSaveDialog, TMemo. На рис. 13 показан процесс проектирования меню с помощью редактора меню. Рис. 13. Редактирование меню 34 Далее приводятся обработчики событий для соответствующих пунк- тов меню: void __fastcall TForm1::Open1Click(TObject *Sender) { // Программная установка свойств компонента OpenDialog1 OpenDialog1->Options.Clear(); OpenDialog1->Options << ofFileMustExist; OpenDialog1->Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*"; OpenDialog1->FilterIndex = 2; if (OpenDialog1->Execute()) Memo1->Lines-> LoadFromFile (OpenDialog1->FileName); } //--------------------------------------------------------------------------- void __fastcall TForm1::Save1Click(TObject *Sender) { // Программная установка свойств компонента SaveDialog1 SaveDialog1->Options.Clear(); SaveDialog1->Options << ofFileMustExist; SaveDialog1->Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*"; SaveDialog1->FilterIndex = 2; if (SaveDialog1->Execute()) Memo1-> Lines->SaveToFile(SaveDialog1->FileName); } void __fastcall TForm1::Exit1Click(TObject *Sender) { exit(0); } На рис. 14 показано окно приложения после запуска приложения и открытия в полученном текстовом редакторе файла модуля формы. Компонент TPopupMenu создает всплывающее меню для формы или для другого компонента. Если необходимо, чтобы специальное меню появлялось при нажатии правой кнопки мыши на элемент, которому приписан данный компонент (свойство PopupMenu содержит имя компонента всплывающего меню), установите значение true свойства AutoPopup. Если всплывающее меню относится к форме, то свойство формы PopupMenu следует установить в имя всплывающего меню, на- пример, PopupMenu1. |