[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 2 из 2
  • «
  • 1
  • 2
Micro-Life Форум » Программирование » C и C++ » Уроки изучения Borland C++ Builder 5
Уроки изучения Borland C++ Builder 5
iBlackДата: Четверг, 15.10.2009, 18:42 | Сообщение # 16
Main Admin
Сообщений: 51
[ 3 ]
:-)
Шаг 16 - Функции Windows [MoveWindow, GetWindowRect]

Я всегда думаю, что вместо подробных объяснений лучше привести пример и потом откомментировать его.

Как пример использования функций можно привести программку, управляющую кнопкой Пуск. Ее форма:

А вот код:

Code
void* StartHandle=NULL;
TRect WinRect;
int left=0,width=0,height=0,top=0;
bool mousedown=false;
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
         : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
MoveWindow(StartHandle,CSpinEdit1->Value,
           CSpinEdit2->Value,width,height,true);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
Timer1->Enabled=!Timer1->Enabled;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
if(Timer2->Enabled)Timer2->Enabled=false;
else Timer2->Enabled=true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
if (left>Screen->Width) {left=1;return;};
left+=5;
MoveWindow(StartHandle,left,8,width,height,true);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer2Timer(TObject *Sender)
{
GetWindowRect(StartHandle,&WinRect);
if ((Mouse->CursorPos.x>WinRect.left)
                 &&
     (Mouse->CursorPos.x<WinRect.right)
                 &&
     (Mouse->CursorPos.y>WinRect.top)
                 &&
     (Mouse->CursorPos.y<WinRect.bottom))
   {
    left+=10;
    if(left>Screen->Width-5) left=0;
    MoveWindow(StartHandle,left,8,width,height,true);
   };
}
//-----Следующие три обработчика позволяют определить дескриптор Пуска
void __fastcall TForm1::Image1MouseDown(TObject *Sender,
       TMouseButton Button, TShiftState Shift, int X, int Y)
{
mousedown=true;
SetCaptureControl(Image1);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Image1MouseMove(TObject *Sender, TShiftState Shift,
       int X, int Y)
{
if(mousedown)
         ::SetCursor(LoadCursorFromFile("cursor.cur"));
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Image1MouseUp(TObject *Sender, TMouseButton Button,
       TShiftState Shift, int X, int Y)
{
StartHandle=WindowFromPoint(Mouse->CursorPos);
SendMessage(StartHandle,WM_SETFOCUS,0,0);
::SetCursor(LoadCursor(HInstance,IDC_ARROW));
mousedown=false;
ReleaseCapture();
GetWindowRect(StartHandle,&WinRect);
width=WinRect.Width();
height=WinRect.Height();
Button1->Enabled=true;
Button2->Enabled=true;
Button3->Enabled=true;
}
//---------------------------------------------------------------------------

Из новых компонентов на форме использован TTimer gif/16_2.gif (126 b) с палитры System. Обработчик события OnTimer() вызывается каждые Interval миллисекунд. В листинге обработчики представлены как Timer1Timer и Timer2Timer. Таймер можно отключить свойством Enabled.

Непонятный момент здесь только один - откуда я взял StartHandle? Во время работы программы пользователь перетаскивает инструмент на кнопку Пуск. Функция WindowFromPoint позволяет достать дескриптор окна по точке. Чтобы инструмент, изображенный на форме компонентом TImage, мог получать все "мышиные" сообщения, используется функция SetCaptureControl. Потом нужно применять ReleaseCapture(), для освобождения захвата.

Для разнообразия во время перетаскивания инструмента курсор меняется на нарисованный мной. Если Вам это не надо, вычеркните.

А так - функция GetWindowRect возвращает по дескриптору структуру TRect окна, содержащую его координаты и размеры. Функция MoveWindow перемещает соответствующее окно. Последний параметр отвечает за перерисовку. Общая логика кнопки "Побегаем" такова - по таймеру вызывается обработчик, передвигающий кнопку. Если кнопка выходит за пределы окна, то кнопка выходит с другого края. Логика "Поймай" - опять-таки по интервалу вызывается обработчик, который проверяет, находится ли курсор над кнопкой и при необходимости сдвигающий ее. Я думаю, объяснять "Передвинуть" уже не надо ;) .

iBlackДата: Четверг, 15.10.2009, 21:54 | Сообщение # 17
Main Admin
Сообщений: 51
[ 3 ]
:-)
Шаг 17 - Прокрутка области ввода [SendMessage, PostMessage, SCROLL]

К моему сожалению, не все возможности WinAPI воплощены в VCL. Поэтому иногда приходится прибегать к функциям WinAPI. Но иногда и в функциях не найдешь, то что нужно. Тогда последний вариант - сообщения.

Сообщения могут рассылаться функциями SendMessage и PostMessage. Отличия между ними в том, что первая не возвращает результат, пока сообщение не будет обработано, а вторая возвращается сразу же.

В этих функциях присутствуют параметры по порядку - оконный дескриптор, название сообщения, первый параметр, второй параметр. Параметры - указатели на структуры, или просто целые, в зависимости от типа сообщения.

Необходимо отметить, что почти то же самое предоставляет метод Perform объектов TControl, только он действует именно на сам объект.

Как пример. Иногда бывает необходимо послать окну сообщение покрутиться, например, если это Memo. Для осуществления этой задачи в WinAPI довольно много есть сообщений всяких разных. Но для областей ввода - Edit Controls - лучше всего подходит сообщения EM_SCROLL, EM_SCROLLCARET, EM_LINESCROLL. Первая прокручивает по линии или по странице, вторая до выделенного места (и убирает выделение), третья вверх-вниз влево-вправо по символам.

Форму лучше приготовить :) такую:

Все компоненты знакомые, новых свойств нет. В свойство Lines для TMemo я впечатал отрывок этого Шага, чтобы было, что прокручивать. А ScrollBars я установил в ssBoth, чтобы было, чем прокручивать ;) . Объекты я назвал соответственно их функции и написал такой код:

Code
void __fastcall TForm1::ScrollCaretClick(TObject *Sender)
{
SendMessage(Memo1->Handle,EM_SCROLLCARET,0,0);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::LeftClick(TObject *Sender)
{
SendMessage(Memo1->Handle,EM_LINESCROLL,-1,0);
}
void __fastcall TForm1::RightClick(TObject *Sender)
{
SendMessage(Memo1->Handle,EM_LINESCROLL,1,0);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::UpClick(TObject *Sender)
{
Memo1->Perform(EM_SCROLL,SB_LINEUP,0);
}
//---------------------------------------------------------------------------

void __fastcall TForm1::DownClick(TObject *Sender)
{
Memo1->Perform(EM_SCROLL,SB_LINEDOWN,0);
}
//---------------------------------------------------------------------------

Половину я оформил как Perform, а другую половину - как SendMessage. Как видно, они по действию одинаковы. Но Perform действует только на данный объект, а SendMessage на любой, чей HWND известен. Так что у каждого свои возможности. В листинге представлены варианты сообщений и аргументы к ним. Там, где значения wParam 1 и -1 - это прокрутка по горизонтали в разных направлениях.

С WinAPI мы вроде бы немного разобрались. Теперь нужно вернуться к не разобранным компонентам Палитры.

iBlackДата: Пятница, 16.10.2009, 16:21 | Сообщение # 18
Main Admin
Сообщений: 51
[ 3 ]
:-)
Шаг 18 - WinSight

Рассказать про WinSight я пообещал еще в позапрошлом Шаге, но сбился на функции WinAPI. Обещания нужно сдерживать, так что...

WinSight - программа отслеживания окон, аналогичная Spy++. Я бы сказал, что Spy удобнее, но он идет в поставке не с Builder'ом, а с MS Visual Studio. Также WinSight прилагается к Delphi. Откопать эту прогу можно в Пуске, там же, где и Builder лежит.

Что от такой программы нужно?

Возможность визуального поиска окон, отображение их свойств, отслеживание сообщений и все в том же духе. Это все в программе есть. Начнем с поиска окон.

Поиск окон

Для этого есть несколько возможностей:

Spy-FindWindow - в этом режиме при выделении окна в верхней части WinSight с помощью стрелок вверх-вниз оно (окно) обводится рамкой. Режим снимается при щелчке мышью.

Spy-Follow focus - когда этот пункт отмечен, при получении фокуса каким-нибудь окном оно автоматически выделяется в WinSight. По-моему, самый удобный способ. Именно так я нашел HWND пуска.

Просмотр свойств

Значит нужное окно нашли. Теперь нужно выяснить его свойства. Как и положено, для этого нужно два раза щелкнуть по окну в списке WinSight. После этого появляется окошко:

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

Просмотр сообщений

Просмотр сообщений можно включить командой Start! и отключить командой Stop. Настройки просмотра задаются в меню Messages. В нем можно настроить, какие процессы и сообщения будут трассироваться, и прочее. Я, правда, почти никогда этим не пользуюсь, обычно первого и второго хватает.

Вот вроде бы и все основное, на что способен WinSight. В следующем Шаге я намерен завершить рассмотрение WinAPI.

iBlackДата: Пятница, 16.10.2009, 21:40 | Сообщение # 19
Main Admin
Сообщений: 51
[ 3 ]
:-)
Шаг 19 - Таблицы откликов [MESSAGE_MAP, MESSAGE_HANDLER]

В VCL определены некоторые стандартные события для компонентов. Можно заметить, что эти события похожи на стандартные сообщения Windows. Однако не все сообщения Windows можно найти в VCL, и не все сообщения VCL реализованы в WinAPI. Например, в WinAPI нет сообщения, аналогичному OnClick, с другой стороны, в VCL нет события WM_DROPFILES, которое мы использовали в одном из предыдущих шагов.

Стандартные сообщения компонентов наследуются по иерархии. Изначально каждое из сообщений базируется все же на сообщениях Windows. Чтобы поймать такое сообщение, необходимо создать таблицу откликов. Тот, кто работал с другими версиями библиотек под Windows, например, OWL или MFC знаком с такими таблицами. Например, OWL приложение создает таблицу типа DEFINE_RESPONSE_TABLE1, а MFC приложение - BEGIN_MESSAGE_MAP...END_MESSAGE_MAP. Сходным образом создаются таблицы и в C++ Builder.

В данном классе создается секция protected и в нее вписывается таблица откликов:

Code
BEGIN_MESSAGE_MAP
...
MESSAGE_HANDLER(<сообщение Windows>, <тип сообщения>, <имя процедуры обработчика>)
...
END_MESSAGE_MAP(<класс-родитель>)

Процедура-обработчик должна быть перед этим определена как void <имя функции>(<тип сообщения>& Msg). Сообщения Windows можно посмотреть в MS SDK, а типы сообщений прописаны (если у Вас вариант Enterprise) в файле CBuilder5\Source\Vcl\messages.pas. В этой папке хранятся исходники VCL.

Как пример можно привести такой вариант. В компонентах VCL не описано стандартное событие на нажатие правой кнопкой мыши. Вместо этого рекомендуется использовать TPopupMenu и OnContextPopup. Однако иногда необходимо само событие. В примере будут описаны события нажатие правой кнопкой (RMouseDown), отпускание правой кнопки (RMouseUp), и собственно щелчок (RMouseClick).

Code
//unit1.h----------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
          TLabel *Label1;
private:
public:  // User declarations
          __fastcall TForm1(TComponent* Owner);

protected:
void __fastcall WmRButtonDown(TWMRButtonDown& Msg);
void __fastcall WmRButtonUp(TWMRButtonUp& Msg);
virtual void __fastcall RMouseClick(TObject* Sender);
virtual void __fastcall RMouseDown(TObject* Sender);
virtual void __fastcall RMouseUp(TObject* Sender);
bool fMouseDown;
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_RBUTTONDOWN,TWMRButtonDown,WmRButtonDown)
MESSAGE_HANDLER(WM_RBUTTONUP,TWMRButtonUp,WmRButtonUp)
E  ND_MESSAGE_MAP(TForm);
};

//unit1.cpp----------------
void __fastcall TForm1::WmRButtonDown(TWMRButtonDown& Msg)
{
fMouseDown=true;
RMouseDown(this);
}
void __fastcall TForm1::WmRButtonUp(TWMRButtonUp& Msg)
{
if(fMouseDown)
    {
    RMouseClick(this);
    fMouseDown=false;
    };
RMouseUp(this);
}
void __fastcall TForm1::RMouseClick(TObject* Sender)
{
Application->MessageBox("Right button clicked","Test",MB_OK);
}

void __fastcall TForm1::RMouseDown(TObject* Sender)
{
Label1->Caption="Right Button down";       //TODO: Add your source code here
}

void __fastcall TForm1::RMouseUp(TObject* Sender)
{
Label1->Caption="Right Button up";        //TODO: Add your source code here
}

Здесь приведены и заголовочный и кодовый файлы. Таким образом разработчики компонентов определяют события для своих творений. Сначала вызывается WinAPI связанный метод объекта, который,в свою очередь, вызывает один из виртуальных методов, которые могут быть переопределены в потомках. В данном случае чисто демонстрационный пример выводит по щелчку окно сообщения, а Label1 отображает текущее состояние правой кнопки.

На этом заканчивается обзор WinAPI. В следующих Шагах будут рассматриваться не разобранные компоненты палитры Standard.

Micro-Life Форум » Программирование » C и C++ » Уроки изучения Borland C++ Builder 5
  • Страница 2 из 2
  • «
  • 1
  • 2
Поиск: