Resize. Часть 1

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

 

Рассмотрим основные требования:

  • Отрисовка восьми маркеров, перетаскивая которые будет изменяться размер компонента.
  • Возможность перетаскивать сам компонент.
  • Не зависимость от конкретного типа компонента, главное, что бы был наследником TControl.
  • Легкость встраивания в основную программу.

Для начала создадим в Builder'e новый VCL проект, и добавить новый unit. Назвать его можно, к примеру, Resize. В нем и будет писать весь дальнейший код.

Проектирование классов

Нам понадобиться всего два класса. Первый это класс, описывающий маркер, второй, это сам класс, отвечающий за изменение размера и контроль над компонентом. Назовем их TMarker и TResize соответственно.

TMarker

Класс, описывающий маркер, стоит для удобство наследовать от какого-нибудь визуального компонента, к примеру, от TPanel. Это позволить легко управлять внешним видом, и знать положение маркера относительно формы, при ресайзе это будет важно.

Поскольку, при перетаскивании за разные маркеры, размер компонента будет меняться по разному, то есть, грубо говоря, в разные стороны, то каждый маркер нужно как-то уникально идентифицировать. Для этого можно ввести скрытое целочисленное поле FNumber. Кроме того, объект TMarker должен знать об объекте типа TResize, с которым он будет связан, опять же введем скрытое поле FResize типа TResize. Поскольку класс TResize, объявлен далее, то тут нужно предопределение класса:

  1. class TResize;
  2.  
  3. class TMarker : public TPanel {
  4. private:
  5.     TResize *FResize;
  6.     TControl *FObject; // Компонент, размеры которого нужно менять
  7. public:
  8.     TMarker( TComponent *AOwner, int setNumber, TResize *setResize );
  9. };

Так же в этом классе будут находиться основные методы для изменения размеров, но к этому вернемся позже.

Рассмотрим его конструктор.

  1. TMarker::TMarker( TComponent *AOwner, int setNumber, TResize *setResize )
  2.         : TPanel( AOwner ) {
  3.     // Задаем "родителя"
  4.     Parent = static_cast<TWinControl*>( AOwner );
  5.     // Настройка основных свойств
  6.     ParentColor = false;
  7.     ParentBackground = false;
  8.     Color = clBlack;
  9.     Width = 6;
  10.     Height = 6;
  11.     BorderWidth = 0;
  12.     BevelOuter = bvNone;
  13.     DoubleBuffered = true;
  14.  
  15.     FResize = setResize;
  16.     FNumber = setNumber;
  17.    
  18.     // При создании объект еще не задан
  19.     FObject = 0;
  20. }

TResize

Основной класс, который, собственно, отвечает за взаимодействие между компонентом и маркерами, а так же за «перетаскивание» самого компонента.

Этот класс, как минимум должен содержать массив из восьми маркеров и сам компонент, с которым идет работа. Если массив маркеров можно сделать private полем, то компонент лучше сделать свойством, поскольку при задании нового компонента придется выполнять кое-какие действия.

Так же нужны следующие методы: позиционирование маркеров вокруг компонента, сокрытие и показ маркеров. Методы для перетаскивания объекта рассмотрим в следующей части.

Объявление класса TResize:

  1. class TResize {
  2. private:
  3.     TControl *FObject;
  4.     // Маркеры
  5.     TMarker *FMarkers[ 8 ];
  6. public:
  7.     // Компонент, с которым работаем
  8.     __property TControl *Object = {
  9.         read = FObject, write = SetObject
  10.     };
  11.     // Позиционирование маркеров вокруг компонента
  12.     void PositionMarkers( );
  13.     // Сокрытие маркеров
  14.     void HideMarkers( );
  15.     // Показ маркеров
  16.     void ShowMarkers( );
  17.  
  18.     void SetObject( TControl *setObject );
  19.  
  20.     TResize( TComponent *AOwner );
  21. };

Рассмотрим методы этого класса.

Конструктор

Происходит создание восьми маркеров и их сокрытие (они будут скрыты, до тех пока не выбран компонент).

  1. TResize::TResize( TComponent *AOwner ) {
  2.     // Создание маркеров
  3.     // В качестве номера передается их порядковый номер в массиве
  4.     for ( int i = 0; i < 8; i++ ) {
  5.         FMarkers[ i ] = new TMarker( AOwner, i, this );
  6.     }
  7.     // Пока не выбран объект, маркеры стоит скрыть
  8.     HideMarkers( );
  9. }

Метод SetObject

Метод при записи в свойство Object. Принимает в качестве параметра компонент, с которым нужно работать. Позиционирует маркеры вокруг объекта.

  1. void TResize::SetObject( TControl *setObject ) {
  2.     // Сохраняем переданный объект в поле
  3.     FObject = setObject;
  4.     // Расстановка маркеров
  5.     PositionMarkers( );
  6. }

Метод PositionMarkers

Метод, который расставляет маркеры вокруг объекта, согласно их номерам. Расставляются по часовой стрелке, маркер под номером ноль ставиться в левом верхнем углу компонента. Так же задается вид курсора над каждым маркером.

  1. void TResize::PositionMarkers( ) {
  2.     // Отображаем маркеры
  3.     ShowMarkers( );
  4.  
  5.     // Расставляем маркеры в зависимости от их номера
  6.     FMarkers[ 0 ]->Left = FObject->Left - 3;
  7.     FMarkers[ 0 ]->Top = FObject->Top - 3;
  8.     FMarkers[ 0 ]->Cursor = crSizeNWSE;
  9.  
  10.     FMarkers[ 1 ]->Left = ( FObject->Left + Int( FObject->Width / 2 ) ) - 3;
  11.     FMarkers[ 1 ]->Top = FObject->Top - 3;
  12.     FMarkers[ 1 ]->Cursor = crSizeNS;
  13.  
  14.     FMarkers[ 2 ]->Left = FObject->Left + FObject->Width - 3;
  15.     FMarkers[ 2 ]->Top = FObject->Top - 3;
  16.     FMarkers[ 2 ]->Cursor = crSizeNESW;
  17.  
  18.     FMarkers[ 3 ]->Left = FObject->Left + FObject->Width - 3;
  19.     FMarkers[ 3 ]->Top = ( FObject->Top + Int( FObject->Height / 2 ) ) - 3;
  20.     FMarkers[ 3 ]->Cursor = crSizeWE;
  21.  
  22.     FMarkers[ 4 ]->Left = FObject->Left + FObject->Width - 3;
  23.     FMarkers[ 4 ]->Top = FObject->Top + FObject->Height - 3;
  24.     FMarkers[ 4 ]->Cursor = crSizeNWSE;
  25.  
  26.     FMarkers[ 5 ]->Left = ( FObject->Left + Int( FObject->Width / 2 ) ) - 3;
  27.     FMarkers[ 5 ]->Top = FObject->Top + FObject->Height - 3;
  28.     FMarkers[ 5 ]->Cursor = crSizeNS;
  29.  
  30.     FMarkers[ 6 ]->Left = FObject->Left - 3;
  31.     FMarkers[ 6 ]->Top = FObject->Top + FObject->Height - 3;
  32.     FMarkers[ 6 ]->Cursor = crSizeNESW;
  33.  
  34.     FMarkers[ 7 ]->Left = FObject->Left - 3;
  35.     FMarkers[ 7 ]->Top = ( FObject->Top + Int( FObject->Height / 2 ) ) - 3;
  36.     FMarkers[ 7 ]->Cursor = crSizeWE;
  37. }

Методы ShowMarkers и HideMarkers

Просто отображает или скрывает маркеры, используя методы Show() и Hide() панельки.

  1. void TResize::HideMarkers( ) {
  2.     for ( int i = 0; i < 8; i++ ) {
  3.         FMarkers[ i ]->Hide( );
  4.     }
  5. }
  6.  
  7. void TResize::ShowMarkers( ) {
  8.     for ( int i = 0; i < 8; i++ ) {
  9.         FMarkers[ i ]->Show( );
  10.     }
  11. }

Тестовое приложение

Ну вот, начало положено, теперь можно создать приложение для демонстрации того, что у нас получилось.
Поскольку вначале мы создали проект с формой, то ее и можно использовать для демонстрации. Сначала в заголовочный файл формы подключим resize.h, потом в самой форме объявим закрытое поле Resize типа TResize, и выделим под него память в конструкторе.

  1. #include "StResize.h"
  2.  
  3. class TMainForm : public TForm
  4. {
  5. __published:    // IDE-managed Components
  6.     TPanel *Panel1;
  7.     TPanel *Panel2;
  8.     void __fastcall Panel1Click(TObject *Sender);
  9.     void __fastcall Panel2Click(TObject *Sender);
  10. private:
  11.     TResize *Resize;
  12. public:     // User declarations
  13.     __fastcall TMainForm(TComponent* Owner);
  14. };
  15.  
  16. __fastcall TMainForm::TMainForm(TComponent* Owner)
  17.     : TForm(Owner)
  18. {
  19.     Resize = new TResize( this );
  20. }

Но форму можно кинуть несколько визуальных компонентов. И в OnClick событиях для них прописать следующее (к примеру, если компонент это Panel1):

  1. Resize->Object = this->Panel1;

Теперь при клике на компонент, вокруг него появляются восемь маркеров. Правда, как вы, наверно, заметили :) их, как и сам, компонент, пока нельзя перетаскивать, но этим мы займемся в следующей части цикла статей.

builder, cpp

Комментарии (2)

none | 17 декабря 2010 г. 22:34 Ответить

хотелось бы узнать адрес оригинала

Nodlik | 18 декабря 2010 г. 21:00 Ответить

none,
адрес оригинала чего?) статьи?
все статьи выложенные на сайте, писались мной...

Добавить комментарий

  • Допустимые html-теги:
    <b> </b> - жирный шрифт
    <em> </em> - наклонный
    <s> </s> - зачеркнутый
    <pre> </pre> - сохранение отступов (печать кода)
    [?]
Введите текст с картинки