Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Создание компонента

1.9K
29 октября 2004 года
Volly
57 / / 18.10.2003
Нужно создать визуальный компонент, который мог бы обрабатывать события, типа OnMouseMove, OnMouseDown и так далее. Как это сделать (желательно, как можно подробнее)? Как узнать координаты курсора мыши?
5.7K
30 октября 2004 года
Andrdandr
29 / / 17.09.2004
1) скачай парочку примеров с CodeProject.com
2) CPoint CWnd::GetCursorPos()
1.9K
30 октября 2004 года
Volly
57 / / 18.10.2003
Спасибо. А как динамически поместить на форму, допустим, кнопку?
3
31 октября 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by Volly
Спасибо. А как динамически поместить на форму, допустим, кнопку?



Компоненты... формы...
Человек явно переползает с Delphi или BCB.
Совет: разберитесь с оконной концепцией ОС Windows и не будет проблем с "динамическим помещением".
Можно начать с метода Win32API CreateWindow.

1.9K
31 октября 2004 года
Volly
57 / / 18.10.2003
Green
Во-первых, не на BCB, а на VS.NET. Во-вторых, и в BCB, и в Delphi динамически поместить компонент на форму - раз плюнуть. Пусть тот спец, кто верит что BCB и Delphi создан не для ламеров, кинет в меня камнем.

Andrdandr
На сайте codeproject.com я не нашел чего-то такого, что могло бы мне помочь. Я хочу написать компонент БЕЗ использования MFC с определением своего окна, с созданием класса и т.д. Только что пытался написать процедуру регистрации класса типа WNDCLASS. Там нужно указывать обработчик сообщений, так? Так. Вот я и занес в класс компонента функцию: LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam). А компилятор ругается, мол не могу сконвертировать процедуру в WNDPROC. Ладно. Вынес обработчик за пределы класса, попытался скомпилировать, но опять компилятор ругается, что невозможно вызвать неопределенную процедуру OnClick, которая в классе определена как virtual OnClick(). Так как же можно определить обработчик сообщений, чтобы он был членом класса компонента, и мог бы нормально работать с WNDCLASS? Вот исходный текст последней попытки:

#include "stdafx.h"

TCHAR MCButton_Class[] = TEXT("dv_button_class");

LRESULT CALLBACK MCBSendMessage(HWND, UINT, WPARAM, LPARAM);

typedef struct nRect
{
int left;
int top;
int width;
int height;
} nmRect;

class MCButton
{
public:
HWND hWnd;
BOOL Create(HWND wParent, nRect choord);
BOOL RegisterButtonClass(HINSTANCE hInstance);
virtual OnClick();
};

BOOL MCButton::RegisterButtonClass(HINSTANCE hInstance)
{
WNDCLASS wc;

wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = MCBSendMessage;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszClassName = MCButton_Class;
wc.lpszMenuName = NULL;

if (!RegisterClass(&wc)) return FALSE;
else return TRUE;
}


LRESULT CALLBACK MCBSendMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_LBUTTONDOWN:
MCButton::OnClick(); // ТУТ возникает ошибка
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
3
31 октября 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by Volly

Я хочу написать компонент БЕЗ использования MFC с определением своего окна, с созданием класса и т.д.


Похвально (если для изучения), но для начала определимся с понятиями.
В оконной системе ОС Windows нет такого понятия, как "компонент". Есть более обобщенное понятие "окно" и понятие "элемент управления" ("контрол").
Думаю, изучени программирования пользовательских приложений можно начать с сайта firststeps.ru
(раздел Visual C++ -> WinAPI)

Цитата:
Originally posted by Volly

Только что пытался написать процедуру регистрации класса типа WNDCLASS. Там нужно указывать обработчик сообщений, так? Так. Вот я и занес в класс компонента функцию: LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam). А компилятор ругается, мол не могу сконвертировать процедуру в WNDPROC.


Давай говорить вместо "компонент" словосочетание "оконный класс" (не путать с "классом окна").
Дело в том, что Windows не объектно-ориентированная ОС, а процедурно-ориентированная.
Т.о. в качестве обработчика сообщений можно указывать лишь глобальные и статические методы.

Цитата:
Originally posted by Volly

Ладно. Вынес обработчик за пределы класса, попытался скомпилировать, но опять компилятор ругается, что невозможно вызвать неопределенную процедуру OnClick, которая в классе определена как virtual OnClick().


Ты недавно программируешь на С++ ?
Вызывать нестатические методы класса можно только в контексте конкретного экземпляра.
В твоем коде ты пытаешься вызвать нестатический метод OnClick без указания контекста, т.е как статический метод.
Обычно контекст указывается указанием имени экземпляра (через точку) или при помощи разыменования указателя (через стрелочку).

Цитата:
Originally posted by Volly

Так как же можно определить обработчик сообщений, чтобы он был членом класса компонента, и мог бы нормально работать с WNDCLASS?


Объявить его статическим членом.
А далее посмотреть эту ветку форума:
http://forum.codenet.ru/showthread.php?s=&threadid=18954

430
31 октября 2004 года
craftyfox
157 / / 20.02.2000
Когда-то скачал tutorials как раз по этой теме,
но никак теперь не найду, откуда...
конечно способ, который там, не единственный,
и может быть, не самый лучший, но для начала,
думаю, сгодится.Есть кое что полезное и по другим вопросам.

rar, 93 kB (на русском)
1.9K
31 октября 2004 года
Volly
57 / / 18.10.2003
craftyfox и Green, большое спасибо. Кое-что уже проясняется :) Будут вопросы, задам. Кстати, туториалы классные.
430
31 октября 2004 года
craftyfox
157 / / 20.02.2000
Цитата:
Originally posted by Volly
craftyfox и Green, большое спасибо. Кое-что уже проясняется :) Будут вопросы, задам. Кстати, туториалы классные.


Если попадутся где-нибудь в сети кинь ссылку.
а то неудобно как-то...

1.9K
01 ноября 2004 года
Volly
57 / / 18.10.2003
Теперь обработчик сообщений прекрасно работает, однако есть еще одна проблема. Предполагается, что программист должен задать обработчик нажатия кнопки мыши, который будет вызываться из обработчика сообщений при обработке сообщения WM_LBUTTONDOWN. Вызывать не статическую процедуру, которая является членом оконного класса, он не желает (компилятор ругается), а, как бы это выразиться, перезаписать статическую процедуру я не знаю как. Может подскажете? Или другими словами: можно ли (и как, если можно) перезаписать какую-то процедуру в классе, которая была определена статически в классе предка? Если что, изучаю C++ я почти год.
3
01 ноября 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by Volly
Теперь обработчик сообщений прекрасно работает, однако есть еще одна проблема. Предполагается, что программист должен задать обработчик нажатия кнопки мыши, который будет вызываться из обработчика сообщений при обработке сообщения WM_LBUTTONDOWN. Вызывать не статическую процедуру, которая является членом оконного класса, он не желает (компилятор ругается), а, как бы это выразиться, перезаписать статическую процедуру я не знаю как. Может подскажете? Или другими словами: можно ли (и как, если можно) перезаписать какую-то процедуру в классе, которая была определена статически в классе предка? Если что, изучаю C++ я почти год.



Если я правильно понял, то ты реализуешь оконную процедуру в некотором базовом классе, а непосредственные обработчики в классах-наследниках. Естественно, что базовый класс не знает об обработчиках объявленных в наследниках. Так?

Решение проблемы зависит от того, что тебе нужно в конечном итоге и какими методами её решать.

Решение 1. Не определять в базовом классе оконную процедуру. Точнее заново определять её в каждом классе наследнике, добавляя что-то новое и ссылаясь на базовую оконную процедуру:

Код:
struct A
{
  void proc()
  {
    ........
  }
};

struct B :public A
{
  void proc()
  {
    ........   // something new
    A::proc(); // base proc called
  }
};

Для удобства обычно такие вещи оборачиваются в макрос. См. BEGIN_MSG_MAP, MESSAGE_HANDLER и т.п.

Решение 2. В конечном итоге все-равно нужно будет, чтоб обработчики вызывались в контексте конкретного экземпляра. Эта проблема решается несколькими совершенно различными способами. Один из них мы обсуждали в теме приведенной мною выше.
Я знаю три способа:
1) SetWindowLongPtr(GWLP_USERDATA);
2) HWND Map (как в MFC);
3) Thunk (как в WTL).

Все это не раз реализовывалось. Думаю, не стоит изобретать велосипед, а посмотреть, как уже было сделано. Тем более, что написание подобных механизмов имеет смысл только для изучения данной тематики, а для реализации "для дела" в них нет смысла.
1.9K
01 ноября 2004 года
Volly
57 / / 18.10.2003
Думаю, ты меня немного не так понял. Вот базовый класс:

[COLOR=blue]class MCButton
{
public:
static HWND hWnd;
static BOOL Create(HWND wParent, HINSTANCE hInstance, nRect choord, int CmdShow);
static BOOL RegisterButtonClass(HINSTANCE hInstance);
static void OnClick();
static LRESULT CALLBACK MCBSendMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
};[/COLOR]

При обработке сообщения WM_LBUTTONDOWN обработчик сообщений (MCBSendMessage) должен вызвать процедуру OnClick, определенную в классе. Если процедура определена без 'static', то компилятор ругается, что типа присутствует вызов нестатичной функции. Пробовал определить эту функцию в конечном классе:

[COLOR=blue]class MyButton1: public MCButton
{
public:
static void OnClick();
}[/COLOR]

Проект компилировался, однако при сообщении WM_LBUTTONDOWN все равно вызывалась процедура OnClick(), определенная в базовом классе. Что же делать?

Код, где определен базовый класс и конечные классы я приаттачил.
3
01 ноября 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by Volly
Думаю, ты меня немного не так понял. Вот базовый класс:

[COLOR=blue]class MCButton
{
public:
static HWND hWnd;
static BOOL Create(HWND wParent, HINSTANCE hInstance, nRect choord, int CmdShow);
static BOOL RegisterButtonClass(HINSTANCE hInstance);
static void OnClick();
static LRESULT CALLBACK MCBSendMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
};[/COLOR]

При обработке сообщения WM_LBUTTONDOWN обработчик сообщений (MCBSendMessage) должен вызвать процедуру OnClick, определенную в классе. Если процедура определена без 'static', то компилятор ругается, что типа присутствует вызов нестатичной функции. Пробовал определить эту функцию в конечном классе:

[COLOR=blue]class MyButton1: public MCButton
{
public:
static void OnClick();
}[/COLOR]

Проект компилировался, однако при сообщении WM_LBUTTONDOWN все равно вызывалась процедура OnClick(), определенная в базовом классе. Что же делать?

Код, где определен базовый класс и конечные классы я приаттачил.



Я все правильно понял, смотри"Решение 1".
Вызывать статические методы дочернего класса из родительского просто так не получится.
Проще всего переопределять в дочерних классах не только обработчики, но и саму оконную процедуру.
Т.к. оконная процедура в общем случае представляет собой switch, то её поще реализовать с помощью макросов (см. BEGIN_MESSAGE_MAP и т.п.)

Немного основ С++.
Для того чтобы родительский класс мог вызывать методы описанные в классе потомке есть несколько методов:
1) виртуальные методы, но они не могут быть статическими),
2) передавать класс потомка базовому, как параметр шаблона (как в WTL).

Код:
template<class T>
class MCButton
{
public:
  static HWND hWnd;

  static void OnClick()
  {
    T::OnClick();
  }
};

class MyButton1: public MCButton<MyButton1>
{
public:
  static void OnClick();
}
1.9K
01 ноября 2004 года
Volly
57 / / 18.10.2003
Подожди, давай по порядку (сразу прошу на меня не обижаться, т.к. с программированием на C++ под Windows я имею весьма посредственный опыт). Цель - создать базовый класс кнопки, на котором будет лежать задача отрисовки этой кнопки и обработки сообщений. При этом надо сделать так, чтобы в дочернем классе можно было определить обработчик нажатия. С BEGIN_MESSAGE_MAP ничего не получается, хотя я руководствовался примером из MSDN. Т.е. программа запускается, но исполняться ничего не исполняется.
Проще всего переопределять в дочерних классах не только обработчики, но и саму оконную процедуру.
Что имеешь в виду под оконной процедурой? Если этот самый обработчик сообщений (типа LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)), то тогда придется регистрировать столько классов окон (через RegisterClass()), сколько и кнопок в программе, т.к. в WNDCLASS всегда указывается обработчик сообщений, а для каждой кнопки, в таком случае, он должен быть свой.
Если не сложно, покажите пример создания "того, что я описал" на конкретном примере.
3
01 ноября 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by Volly

Цель - создать базовый класс кнопки, на котором будет лежать задача отрисовки этой кнопки и обработки сообщений. При этом надо сделать так, чтобы в дочернем классе можно было определить обработчик нажатия.


Сначала вопрос (1): для чего тебе это надо?
Просто, для тренировки?
Или для конкретного проекта?
Еще один вопрос (2): все обработчики могут быть статическими? Т.е. в них ты не будешь использовать что-либо из нестатических членов этого класса?

Цитата:
Originally posted by Volly

С BEGIN_MESSAGE_MAP ничего не получается, хотя я руководствовался примером из MSDN. Т.е. программа запускается, но исполняться ничего не исполняется.


BEGIN_MESSAGE_MAP это макрос, который имеет смысл в контексте MFC или WTL. Если уж ты хочешь все сделать сам, то посмотри, как устроен этот макрос, а не используй его напрямую. Посмотри и создай свою систему подобных макросов.

Цитата:
Originally posted by Volly

Что имеешь в виду под оконной процедурой? Если этот самый обработчик сообщений (типа LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)), то тогда придется регистрировать столько классов окон (через RegisterClass()), сколько и кнопок в программе, т.к. в WNDCLASS всегда указывается обработчик сообщений, а для каждой кнопки, в таком случае, он должен быть свой.


Да, под оконной процедурой я понимаю WndProc (Window Procedure - оконная процедура).
Оконную процедуру не обязательно задавать регистрацией нового класс, её можно указать для конкретного экземпляра, не говоря уж о конкретном классе. Смотри SetWindowLongPtr.

Видимо, ты не совсем ясно представляешь всю схему.
Дела в том, что в общем случае схема такая:
есть базовый класс (например кнопки), есть дочерний класс для какого-то определенного вида кнопок, а есть ещё экземпляры этого класса.
Обычно мало бывает создать механизм вызова обработчиков для конкретного класса, необходимо ещё чтобы эти обработчики могли работать с нестатическими членами данного класса. Это понятно? Поэтому и возникает вопрос (2).

Цитата:
Originally posted by Volly

Если не сложно, покажите пример создания "того, что я описал" на конкретном примере.


Ответь на вопрос (2) и я нарисую пример.
Кстати, почему бы не посмотреть примеры, приведенные по указанной мною выше ссылке?

1.9K
01 ноября 2004 года
Volly
57 / / 18.10.2003
Отвечаю. (1): это нужно для конкретного проекта. (2): если ты имеешь в виду под словом "обработчики" обработчики сообщений, то думаю, что они должны будут использовать нестатические члены класса, а точнее, hWnd, так как понадобится узнать DC (Device Context, что ли) окна для отрисовки кнопки.

Смотри SetWindowLongPtr
А что фактически делает эта процедура?

Видимо, ты не совсем ясно представляешь всю схему
Так и есть. На то я и программирую под Windows на C++ недолго :)

есть базовый класс (например кнопки), есть дочерний класс для какого-то определенного вида кнопок, а есть ещё экземпляры этого класса
Кстати, если я, допустим, определил в каком-то классе переменную с типом 'static' (допустим, int), создал экземпляр класса и присвоил какое-то значение этой переменной в экземпляре класса, то оно запишется в какую-то определенную область памяти или в область, принадлежащую только этому экземпляру?

Кстати, почему бы не посмотреть примеры, приведенные по указанной мною выше ссылке?
Сейчас скачаю, посмотрю. Просто я понимаю в программировании на C++ под Windows, наверно, еще меньше чем тот человек, кто создал ту тему.
3
01 ноября 2004 года
Green
4.8K / / 20.01.2000
Цитата:
Originally posted by Volly

Отвечаю. (1): это нужно для конкретного проекта.


Тогда, может не париться, не тратить время, а сразу использовать готовые оконные библиотеки (MFC, WTL)?

Цитата:
Originally posted by Volly

(2): если ты имеешь в виду под словом "обработчики" обработчики сообщений, то думаю, что они должны будут использовать нестатические члены класса, а точнее, hWnd, так как понадобится узнать DC (Device Context, что ли) окна для отрисовки кнопки.


Тогда тебе точно надо посмотреть указанное мной обсуждение.

Цитата:
Originally posted by Volly

Смотри SetWindowLongPtr
А что фактически делает эта процедура?


В MSDN же написано.

Цитата:
Originally posted by Volly

Кстати, если я, допустим, определил в каком-то классе переменную с типом 'static' (допустим, int), создал экземпляр класса и присвоил какое-то значение этой переменной в экземпляре класса, то оно запишется в какую-то определенную область памяти или в область, принадлежащую только этому экземпляру?


Это уже вопрос по С++, а не по программированию под Windows.
Static на то и статик, чтоб быть одним во всех экземплярах. Изменение значения в одном экземпляре приведет к изменению во всех.

430
02 ноября 2004 года
craftyfox
157 / / 20.02.2000
Цитата:
Originally posted by Green

Тогда, может не париться, не тратить время, а сразу использовать готовые оконные библиотеки (MFC, WTL)?


Только как бы потом такая "экономия времени" боком не вышла...

Может стоит все-таки посмотреть предложенные примеры, т.е. создать тестовый проект, скопировать туда код, просмотреть его под отладчиком, понять что там происходит, попытаться модифицировать его для собственных нужд...
А то ведь сказка про белого бычка получается.
Вот еще с codeproject:
http://www.codeproject.com/win32/win32windowwrapperclass.asp
Ссылка, которую как-то давал Green о WTL, тоже можно рассматривать как "tutorial по данной теме":
http://rsdn.ru/summary/255.xml

Только что толку в примерах, если в них все равно не заглядывают?

1.9K
02 ноября 2004 года
Volly
57 / / 18.10.2003
Тогда, может не париться, не тратить время, а сразу использовать готовые оконные библиотеки (MFC, WTL)?
Как однажды сказал мой учитель информатики, кто-то любит булку с маслом, а кто-то - с хреном. Я в данном случае выбрал хрен. Да и изучение MFC и WTL займет время. Так не лучше ли изучать сразу азы C++ и при этом делать проект, чем пользоваться библиотеками, в которых сало чего понимаешь? Кстати, а где можно взять WTL?

Тогда тебе точно надо посмотреть указанное мной обсуждение.
Посмотрел тот проект. Классно. Все красиво и понятно. Только подправил там кое-что. А с отрисовкой 3-ей кнопки действительно что-то странное: если все оставить как есть, то окно этой кнопки постоянно перерисовывается, а если вместо "break" поставить "return 0", то не исполняется процедура при нажатии на кнопку.
527
03 ноября 2004 года
pavor
275 / / 28.09.2003
Цитата:
Originally posted by Volly
Green
Во-первых, не на BCB, а на VS.NET. Во-вторых, и в BCB, и в Delphi динамически поместить компонент на форму - раз плюнуть. Пусть тот спец, кто верит что BCB и Delphi создан не для ламеров, кинет в меня камнем.
}


«И был бой, и была победа, и возвращались они, и подбирали камни свои. И последним шел Тамерлан. И поднимал он тяжелые камни, и говорил с ними, называя их имена». (Всемирная история. Банк «Империал»)
Таких "спецов" в нете куча:)

430
04 ноября 2004 года
craftyfox
157 / / 20.02.2000
Цитата:
Originally posted by Volly
А с отрисовкой 3-ей кнопки действительно что-то странное: если все оставить как есть, то окно этой кнопки постоянно перерисовывается, а если вместо "break" поставить "return 0", то не исполняется процедура при нажатии на кнопку.


Да дело там не в третьей кнопке.
Почитай в тех же tutorials об особенностях обработки WM_PAINT. (альтернатива - ValidateRect).
Хотя, вообще говоря, в случае BUTTON одним WM_PAINT'ом чтобы "типа самому рисовать" не обойдешься, и без BS_OWNERDRAW, боюсь, что это будет сложнее, чем создать кнопку, "с нуля", из Static, например.

1.9K
04 ноября 2004 года
Volly
57 / / 18.10.2003
Я сегодня еще раз пересмотрел тот код - ужас. Было даже странно удивляться тому, что кнопка перерисовывалась как стандартная виндовская. Создал свой класс, так теперь текст на кнопке показывается только после того, как окно занесешь за границы экрана, а потом затащишь обратно. Идиотизм... Прекрасный повод, чтобы использовать MFC.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог