Resize. Часть 1
В этом цикле статей будет разработана определенная «библиотека», позволяющая изменять размеры визуальных компонентов Builder во время работы программы. То есть вокруг компонента отрисовываются 8 маркеров, которые можно перетаскивать и вслед за ними будет меняться размер самого компонента. Подобное можно увидеть почти в любом WYSIWYG редакторе, в той же Delphi или Builder'e и т.п.

Рассмотрим основные требования:
- Отрисовка восьми маркеров, перетаскивая которые будет изменяться размер компонента.
- Возможность перетаскивать сам компонент.
- Не зависимость от конкретного типа компонента, главное, что бы был наследником TControl.
- Легкость встраивания в основную программу.
Для начала создадим в Builder'e новый VCL проект, и добавить новый unit. Назвать его можно, к примеру, Resize. В нем и будет писать весь дальнейший код.
Проектирование классов
Нам понадобиться всего два класса. Первый это класс, описывающий маркер, второй, это сам класс, отвечающий за изменение размера и контроль над компонентом. Назовем их TMarker и TResize соответственно.
TMarker
Класс, описывающий маркер, стоит для удобство наследовать от какого-нибудь визуального компонента, к примеру, от TPanel. Это позволить легко управлять внешним видом, и знать положение маркера относительно формы, при ресайзе это будет важно.
Поскольку, при перетаскивании за разные маркеры, размер компонента будет меняться по разному, то есть, грубо говоря, в разные стороны, то каждый маркер нужно как-то уникально идентифицировать. Для этого можно ввести скрытое целочисленное поле FNumber. Кроме того, объект TMarker должен знать об объекте типа TResize, с которым он будет связан, опять же введем скрытое поле FResize типа TResize. Поскольку класс TResize, объявлен далее, то тут нужно предопределение класса:
- class TResize;
- class TMarker : public TPanel {
- private:
- TResize *FResize;
- TControl *FObject; // Компонент, размеры которого нужно менять
- public:
- TMarker( TComponent *AOwner, int setNumber, TResize *setResize );
- };
Так же в этом классе будут находиться основные методы для изменения размеров, но к этому вернемся позже.
Рассмотрим его конструктор.
- TMarker::TMarker( TComponent *AOwner, int setNumber, TResize *setResize )
- : TPanel( AOwner ) {
- // Задаем "родителя"
- Parent = static_cast<TWinControl*>( AOwner );
- // Настройка основных свойств
- ParentColor = false;
- ParentBackground = false;
- Color = clBlack;
- Width = 6;
- Height = 6;
- BorderWidth = 0;
- BevelOuter = bvNone;
- DoubleBuffered = true;
- FResize = setResize;
- FNumber = setNumber;
- // При создании объект еще не задан
- FObject = 0;
- }
TResize
Основной класс, который, собственно, отвечает за взаимодействие между компонентом и маркерами, а так же за «перетаскивание» самого компонента.
Этот класс, как минимум должен содержать массив из восьми маркеров и сам компонент, с которым идет работа. Если массив маркеров можно сделать private полем, то компонент лучше сделать свойством, поскольку при задании нового компонента придется выполнять кое-какие действия.
Так же нужны следующие методы: позиционирование маркеров вокруг компонента, сокрытие и показ маркеров. Методы для перетаскивания объекта рассмотрим в следующей части.
Объявление класса TResize:
- class TResize {
- private:
- TControl *FObject;
- // Маркеры
- TMarker *FMarkers[ 8 ];
- public:
- // Компонент, с которым работаем
- __property TControl *Object = {
- read = FObject, write = SetObject
- };
- // Позиционирование маркеров вокруг компонента
- void PositionMarkers( );
- // Сокрытие маркеров
- void HideMarkers( );
- // Показ маркеров
- void ShowMarkers( );
- void SetObject( TControl *setObject );
- TResize( TComponent *AOwner );
- };
Рассмотрим методы этого класса.
Конструктор
Происходит создание восьми маркеров и их сокрытие (они будут скрыты, до тех пока не выбран компонент).
- TResize::TResize( TComponent *AOwner ) {
- // Создание маркеров
- // В качестве номера передается их порядковый номер в массиве
- for ( int i = 0; i < 8; i++ ) {
- FMarkers[ i ] = new TMarker( AOwner, i, this );
- }
- // Пока не выбран объект, маркеры стоит скрыть
- HideMarkers( );
- }
Метод SetObject
Метод при записи в свойство Object. Принимает в качестве параметра компонент, с которым нужно работать. Позиционирует маркеры вокруг объекта.
- void TResize::SetObject( TControl *setObject ) {
- // Сохраняем переданный объект в поле
- FObject = setObject;
- // Расстановка маркеров
- PositionMarkers( );
- }
Метод PositionMarkers
Метод, который расставляет маркеры вокруг объекта, согласно их номерам. Расставляются по часовой стрелке, маркер под номером ноль ставиться в левом верхнем углу компонента. Так же задается вид курсора над каждым маркером.
- void TResize::PositionMarkers( ) {
- // Отображаем маркеры
- ShowMarkers( );
- // Расставляем маркеры в зависимости от их номера
- FMarkers[ 0 ]->Left = FObject->Left - 3;
- FMarkers[ 0 ]->Top = FObject->Top - 3;
- FMarkers[ 0 ]->Cursor = crSizeNWSE;
- FMarkers[ 1 ]->Left = ( FObject->Left + Int( FObject->Width / 2 ) ) - 3;
- FMarkers[ 1 ]->Top = FObject->Top - 3;
- FMarkers[ 1 ]->Cursor = crSizeNS;
- FMarkers[ 2 ]->Left = FObject->Left + FObject->Width - 3;
- FMarkers[ 2 ]->Top = FObject->Top - 3;
- FMarkers[ 2 ]->Cursor = crSizeNESW;
- FMarkers[ 3 ]->Left = FObject->Left + FObject->Width - 3;
- FMarkers[ 3 ]->Top = ( FObject->Top + Int( FObject->Height / 2 ) ) - 3;
- FMarkers[ 3 ]->Cursor = crSizeWE;
- FMarkers[ 4 ]->Left = FObject->Left + FObject->Width - 3;
- FMarkers[ 4 ]->Top = FObject->Top + FObject->Height - 3;
- FMarkers[ 4 ]->Cursor = crSizeNWSE;
- FMarkers[ 5 ]->Left = ( FObject->Left + Int( FObject->Width / 2 ) ) - 3;
- FMarkers[ 5 ]->Top = FObject->Top + FObject->Height - 3;
- FMarkers[ 5 ]->Cursor = crSizeNS;
- FMarkers[ 6 ]->Left = FObject->Left - 3;
- FMarkers[ 6 ]->Top = FObject->Top + FObject->Height - 3;
- FMarkers[ 6 ]->Cursor = crSizeNESW;
- FMarkers[ 7 ]->Left = FObject->Left - 3;
- FMarkers[ 7 ]->Top = ( FObject->Top + Int( FObject->Height / 2 ) ) - 3;
- FMarkers[ 7 ]->Cursor = crSizeWE;
- }
Методы ShowMarkers и HideMarkers
Просто отображает или скрывает маркеры, используя методы Show() и Hide() панельки.
- void TResize::HideMarkers( ) {
- for ( int i = 0; i < 8; i++ ) {
- FMarkers[ i ]->Hide( );
- }
- }
- void TResize::ShowMarkers( ) {
- for ( int i = 0; i < 8; i++ ) {
- FMarkers[ i ]->Show( );
- }
- }
Тестовое приложение
Ну вот, начало положено, теперь можно создать приложение для демонстрации того, что у нас получилось.
Поскольку вначале мы создали проект с формой, то ее и можно использовать для демонстрации. Сначала в заголовочный файл формы подключим resize.h, потом в самой форме объявим закрытое поле Resize типа TResize, и выделим под него память в конструкторе.
- #include "StResize.h"
- class TMainForm : public TForm
- {
- __published: // IDE-managed Components
- TPanel *Panel1;
- TPanel *Panel2;
- void __fastcall Panel1Click(TObject *Sender);
- void __fastcall Panel2Click(TObject *Sender);
- private:
- TResize *Resize;
- public: // User declarations
- __fastcall TMainForm(TComponent* Owner);
- };
- __fastcall TMainForm::TMainForm(TComponent* Owner)
- : TForm(Owner)
- {
- Resize = new TResize( this );
- }
Но форму можно кинуть несколько визуальных компонентов. И в OnClick событиях для них прописать следующее (к примеру, если компонент это Panel1):
- Resize->Object = this->Panel1;
Теперь при клике на компонент, вокруг него появляются восемь маркеров. Правда, как вы, наверно, заметили :) их, как и сам, компонент, пока нельзя перетаскивать, но этим мы займемся в следующей части цикла статей.
builder, cpp
Комментарии (2)
хотелось бы узнать адрес оригинала
none,
адрес оригинала чего?) статьи?
все статьи выложенные на сайте, писались мной...
Добавить комментарий