Как узнать какая кнопка нажата???
От: Аноним  
Дата: 25.09.02 16:58
Оценка:
Нужно сделать калькулятор и препод требует сделать, чтобы все кнопки на онклик запускали одну прцедуру... И вот у меня проблема как узнать на какую именно кнопку нажал пользователь??
Re: Как узнать какая кнопка нажата???
От: Кодт Россия  
Дата: 25.09.02 17:07
Оценка:
Здравствуйте Аноним, Вы писали:

А>Нужно сделать калькулятор и препод требует сделать, чтобы все кнопки на онклик запускали одну прцедуру... И вот у меня проблема как узнать на какую именно кнопку нажал пользователь??


1) вопрос не в тот форум. Наверное, тебе более подходит WinAPI

2) какими средствами ты пишешь этот калькулятор:
— консольное досовское приложение (а вдруг?)
— приложение на Windows API
— Visual C и библиотека MFC
— Borland C Builder
— ...

от этого много зависит.
Например, с чистым WinAPI, все события проходят через одну процедуру (обработчик событий окна).
На MFC — есть несколько способов (назначение общего обработчика для нескольких событий, субклассирование кнопок и т.д.)

Сформулируй точнее, пожалуйста.
Перекуём баги на фичи!
Re[2]: Как узнать какая кнопка нажата???
От: Cyber_Girl  
Дата: 25.09.02 17:27
Оценка:
Здравствуйте Кодт, Вы писали:

К>Здравствуйте Аноним, Вы писали:




К>1) вопрос не в тот форум. Наверное, тебе более подходит WinAPI

Почему winApi? В процедуру же предается Sender через него можно как-то узнать.... но как?

А компилятор Borland С Builder


К>от этого много зависит.

К>Например, с чистым WinAPI, все события проходят через одну процедуру (обработчик событий окна).
К>На MFC — есть несколько способов (назначение общего обработчика для нескольких событий, субклассирование кнопок и т.д.)
По-моему ты усложняешь... в дельфи такое пишется в одну строчку :
Label1.Caption := (Sender as TButton).Name;

Как такое сделать в си????
Re[3]: Как узнать какая кнопка нажата???
От: Кодт Россия  
Дата: 25.09.02 18:09
Оценка:
Здравствуйте Cyber_Girl, Вы писали:

К>>1) вопрос не в тот форум. Наверное, тебе более подходит WinAPI

CG>Почему winApi? В процедуру же предается Sender через него можно как-то узнать.... но как?

CG>А компилятор Borland С Builder


Ага! Это был BCB! Я зналь, я зналь!

Тогда — прямая дорога в форум "Delphi & Builder"

К>>от этого много зависит.

К>>Например, с чистым WinAPI, все события проходят через одну процедуру (обработчик событий окна).
К>>На MFC — есть несколько способов (назначение общего обработчика для нескольких событий, субклассирование кнопок и т.д.)
CG>По-моему ты усложняешь... в дельфи такое пишется в одну строчку :

CG>Label1.Caption := (Sender as TButton).Name;


CG>Как такое сделать в си????

Сделай различие между языком C++, программным интерфейсом виндов (WinAPI) и средой программирования BCB.

К сожалению, по Билдеру я не специалист (в Дельфях еще более-менее... а в Билдере просто не знаю тонкостей).

Ставлю на нашей беседе бомбочку "Перевести в форум Дельфи & Билдер"
Перекуём баги на фичи!
Re: Как узнать какая кнопка нажата???
От: Anatolix Россия https://www.linkedin.com/in/anatolix/
Дата: 26.09.02 06:12
Оценка:
Вот ответ из FAQ который я написал для конференции http://www.softforum.ru/cbuilder
Что-то у него сегодня проблемы с коннектами прямой сейчас поэтому закину сюда.
Ответ на твой вопрос гдето в середине.
Через пол часа можешь залесть вот сюда http://www.softforum.ru/cbuilder.faq и прочитать остальные, тебе поможет.

Q: Как динамически создать кнопку и поставить ее на панель?

   TButton* B=new TButton(this);
   B->Parent=Panel1;

Q: Нужно ли ее потом удалять самостоятельно?

В данном примере кнопка будет удалена автоматически это сделает 
либо Owner либо Parent(кто первый успеет) В данном примере в 
качестве Owner кнопки передан this который указывает на форму 
в чьем методе создается кнопка, а в качестве Parent присвоен 
Panel1. Когда один из этих объектов будет удален он удалит 
вместе с собой кнопку.

Q: Все ли объекты удаляются автоматически?

Нет. VCL умеет удалять удаляет только потомков TComponent. 
Для этого им при конструировании надо передать в качестве 
параметра Owner тот объект который будет ответственен за их 
удаление. Все остальные объекты надо удалять руками.

Кроме того иногда бывает полезно удалить объект когда он больше 
не нужен, а не ждать когда это сделает VCL

Q: Как удалить объект?

Надо воспользоваться оператором delete. Для того чтобы удалить 
объект надо иметь указатель на него. В первом примере указатель 
хранится в переменной B. И теряется при выходе из процедуры. 
Для того чтобы нормально удалить объект надо сохранить указатель 
в какой-нибудь переменной.

TButton* B;

void __fastcall Form1::ButtonCreateClick(TObject* Sender)
{
     B=new TButton(this);
     B->Parent=Panel1;
}

void __fastcall Form1::ButtonDestroyClick(TObject* Sender)
{
     delete B;
}

Q: Как в обработчике различать для какого компонента он был вызван 
и как работать с этим компонентом?

Например есть кнопка, у нее обработчик OnClick в обработчик кнопка 
приходит как TObject. Но на самом деле это есть указатель на кнопку. 
Просто компилятор не знает об этом. Поэтому его надо в этом убедить.

Простейший метод:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
     ((TButton*)Sender)->Caption="qwe";
     ((TButton*)Sender)->Tag=3;
     ((TButton*)Sender)->Name="asd";
}

Если обработчик будет вызван не кнопкой а чем нибудь еще то будет 
Access Violation. Чтобы этого избежать нуобходимо уметь проверять 
является обработчик кнопкой(чем нибудь другим) или нет.

Если у нас вполне конечное кол-во объектов можно просто сравнивать 
указатели

if (Sender==TForm1->Button12)
{
      ((TButton*)Sender)->Caption="qwe";
}

Если у нас не вполне понятное количество компонентов то этот метод 
неподходит. Необходимо научиться определять настоящий тип объектов.
Первое что приходит в голову новичкам это проверить ClassName

if (Sender->ClassName()="TButton")
{
      ((TButton*)Sender)->Caption="qwe";
}

Метод работает но у него есть несколько недостатоков:
1) Медленно работает т.к. создаются и сравниваются строки
2) Работает только с потомками TObject(в Delphi все классы 
наслендуются от TObject, а в C++ Builder нет)
3) Не подходит для определения промежуточных классов.

Например мы хотим изменить у Sender свойство Tag. Tag есть у всех 
TComponent А Sender может быть, например, TButton, TBitBtn, TPanel итп
(в более более тяжелом случае мы можем, например что это визуальный 
компонент лежащий на форме(т.е это TControl) и т.к. он наследуется 
от TComponent св-во Tag у него есть, но это все что мы про него знаем)

В этом случае нам поможет RTTI(RunTime Type Identification). 
Дело в том что в Объектах содержится указатель на, так называемую, 
VTBL (таблица виртуальных методов). На самом деле VTBL есть не у 
всех объектов, а только у тех у которых есть виртуальные функции
(т.е. полиморфных классов) и их потомков(TObject полиморфный тип)

Для этого есть ключевое слово dynamic_cast.

синтаксис выглядит так:

     dynamic_cast<CastType>(Pointer)

если приведение типа удалось dynamic_cast возвратит ненулевой 
указатель того типа, которого нужно, если не удалось нулевой. 
Например(как в предыдущем примере) мы хотим изменить(или посмотреть) Tag.

Делаем так:

if (TComponent* C=dynamic_cast<TComponent*>(Sender))
{
      switch(C->Tag)
      {
            ...
      }
}
else
{
      throw Exception("В наш обработчик пришел не TComponent");
}


Q: Как назначать/отрывать обработчики событий в Runtime?

Событие это просто указатель на функцию, специального типа. 
Его можно присваивать и отрывать в Runtime.

    Button1->OnClick=0;

больше событие не выполнится, т.к. оно теперь не назначено.

    Button1->OnClick=Button2Click;

теперь первая кнопка при нажатии вызывает событие которое должна 
вызывать вторая кнопка.

Если ты хочешь присвоить события компонентам созданным в 
динамике - вперед. С непривычки бывает сначала сложно описать 
функцию с правильными параметрами Я рекомендую сделать так: 
например есть массив кнопок им всем надо присвоить OnClick.

1) Ставим на форму кнопку
2) Делаем ей событие OnClick, переименовываем функцию как надо.
3) Пишем внутрь какой-нибудь комментарий(т.к. Builder удаляет 
   пустые обработчики)
4) Удаляем саму кнопку

Теперь у нас есть правильно описанный обработчик события который 
можно присвоить как

   ArrayOfTButton[i]->OnClick=...
Любая проблема дизайна может быть решена введением дополнительного абстрактного слоя, за исключением проблемы слишком большого количества дополнительных абстрактных слоев
Re: Как узнать какая кнопка нажата???
От: sensimon  
Дата: 26.09.02 08:54
Оценка:
Здравствуйте Аноним, Вы писали:

А>Нужно сделать калькулятор и препод требует сделать, чтобы все кнопки на онклик запускали одну прцедуру... И вот у меня проблема как узнать на какую именно кнопку нажал пользователь??


Я бы сделал примерно так.

void __fastcall Form1::Button1Click(TObject* Sender)
{
     TButton *B=dynamic_cast<TButton *>(Sender);
     if (!B) return;
     switch (B->Tag) {
        case 1:....
     };
     B=NULL; 
}



Можно конечто проверять и B->Name, но лучше немного потрудиться и каждой кнопке добавить свой tag
Re: Как узнать какая кнопка нажата???
От: IgorVer  
Дата: 27.09.02 02:14
Оценка:
Здравствуйте Аноним, Вы писали:

А>Нужно сделать калькулятор и препод требует сделать, чтобы все кнопки на онклик запускали одну прцедуру... И вот у меня проблема как узнать на какую именно кнопку нажал пользователь??


Создать 4 кнопки (Button1,Button2,Button3,Button4).



void __fastcall TForm1::FormCreate(TObject *Sender)
{
  Button1->Tag=1;
  Button2->Tag=2;
  Button3->Tag=3;
  Button4->Tag=4;
  Button1->OnClick=Button1Click;
  Button2->OnClick=Button1Click;
  Button3->OnClick=Button1Click;
  Button4->OnClick=Button1Click;
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
 TButton *a;  
 a=(TButton *)Sender;
 switch(a->Tag)
 {
  case 1:ShowMessage("Button #1");break;
  case 2:ShowMessage("Button #2");break;
  case 3:ShowMessage("Button #3");break;
  case 4:ShowMessage("Button #4");break;
 };
}
Re: Как узнать какая кнопка нажата???
От: Олег Куликов США  
Дата: 27.09.02 07:56
Оценка:
Здравствуйте Аноним, Вы писали:

А>как узнать на какую именно кнопку нажал пользователь??




void __fastcall TFormXXX::ButtonClick(TObject *Sender)
{
  if (Sender == Button1)
  {
    //    
  }
  else if (Sender == Button2)
  {
    //
  }
  //и т.д.
}
И немедленно выпил...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.