Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.85/13: Рейтинг темы: голосов - 13, средняя оценка - 4.85
0 / 0 / 0
Регистрация: 13.02.2019
Сообщений: 3

Не могу создать кнопку, чтобы она закрывалась двойным нажатием левой кнопкой мыши. Как это сделать?

13.02.2019, 23:25. Показов 2917. Ответов 17
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Нужно создать кнопку и чтобы она закрывало окно Form1 двойным нажатием левой кнопкой мыши по ней. Хелп!
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
13.02.2019, 23:25
Ответы с готовыми решениями:

Рисование линий из центра экрана нажатием левой кнопкой мыши
Здравствуйте! Начала разбирать программу, рисующую линии нажатием левой кнопкой мыши из центра "окошка". Не очень понимаю как...

Как сделать редактирование записи в таблице DBgrid (база firebird) двойным нажатием кнопки мыши
Есть база данных Firebird (fdb), на форме Datasourse, IbTable, IBQuery, IBDatabase, IBTransaction. Как двойным нажатием mouse на записи в...

Как сделать клик левой кнопкой мыши без WinApi
Я не нашел, везде WinApi

17
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
 Аватар для volvo
33376 / 21500 / 8236
Регистрация: 22.10.2011
Сообщений: 36,896
Записей в блоге: 11
14.02.2019, 00:27
Лучший ответ Сообщение было отмечено volvo как решение

Решение

Пишешь вот такой класс-перехватчик в .h файл:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
namespace DblClick_Button
{
    class TButton : public Stdctrls::TButton
    {
    private:
        TNotifyEvent FOnDblClick;
        MESSAGE void __fastcall WmButtonDoubleClick(TMessage &Message)
        {
            Stdctrls::TButton::Dispatch(&Message);
            if(FOnDblClick)
            {
                FOnDblClick(this);
            }
        }
 
        BEGIN_MESSAGE_MAP
            MESSAGE_HANDLER(WM_LBUTTONDBLCLK, TMessage, WmButtonDoubleClick)
        END_MESSAGE_MAP(Stdctrls::TButton);
 
    public:
        __property TNotifyEvent OnDblClick = {read = FOnDblClick, write = FOnDblClick};
    };
}
#define TButton DblClick_Button::TButton
 
// тут - класс формы, все без изменений...
, и потом используешь OnDblClick как любой другой обработчик. Например, вот так:
C++
1
2
3
4
5
6
7
8
9
void __fastcall TForm1::MyCloseForm(TObject *Sender) // заголовок не забудь добавить в класс формы, в секцию public
{
    this->Close();
}
 
void __fastcall TForm1::FormCreate(TObject *Sender)
{
    Button1->OnDblClick = &MyCloseForm;
}
Вот и все...
5
2 / 2 / 0
Регистрация: 13.01.2019
Сообщений: 13
10.04.2020, 22:45
Пардон за некропостинг, но, перелопатив форум, нашел кучу похожих ситуаций, поэтому новую тему создавать не стал.

Цитата Сообщение от volvo Посмотреть сообщение
Пишешь вот такой класс-перехватчик в .h файл
Сделал, как вы советовали. Единственное, Билдер потребовал объявить конструктор, так как он не смог инициализировать конструктор предка. Объявил так:

C++
1
__fastcall virtual TButton(System::Classes::TComponent* AOwner) : Stdctrls::TButton(AOwner){};
Проблема в том, что сообщение двойного клика не перехватывается. Если воткнуть брейкпоинт в тело метода WmButtonDoubleClick, становится видно, что при двойном клике по кнопке активности там нет. Никак не могу понять, что я делаю неправильно, а сообразить двойной клик по кнопке все-таки хочется. Помогите, а?
0
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
 Аватар для volvo
33376 / 21500 / 8236
Регистрация: 22.10.2011
Сообщений: 36,896
Записей в блоге: 11
10.04.2020, 23:11
Странно. Не нужен там никакой конструктор, Билдер прекрасно обходится без него, проверено и на BCB6, и на rad 2009, и на xe2, и на xe4, и на xe8. Уже это наводит на мысли, что что-то не так делается...

А насчет того, что не работает - единственное, что приходит на ум - это то, что #define, который после описания класса-перехватчика, куда-то запропастился, или был посчитан за бесполезный комментарий и выброшен. Ещё раз проверено, нормально ловится двойное нажатие...
0
2 / 2 / 0
Регистрация: 13.01.2019
Сообщений: 13
11.04.2020, 20:29
Цитата Сообщение от volvo Посмотреть сообщение
Не нужен там никакой конструктор, Билдер прекрасно обходится без него
Ругается на конструктор только, если я создаю кнопку в рантайме, типа TButton *btn = new TButton(this). Для дизайн-тайм кнопок сборка проходит нормально. Однако событие все равно не ловится.

Объявлял так: в хидере формы вставил описание перехватчика между подключением заголовков и объявлением класса формы. #define на месте, указан до класса формы. Может, дело в среде? Юзаю Builder 10.3.3 Rio.
0
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
 Аватар для volvo
33376 / 21500 / 8236
Регистрация: 22.10.2011
Сообщений: 36,896
Записей в блоге: 11
11.04.2020, 20:52
Может и в среде. например, заморочки нового 64-битного компилятора. У них все время руки чешутся что-нибудь испортить, вот и получается, портят среду все больше и больше... Мне проверять негде, ничего сказать не могу по этому поводу...

Добавлено через 8 минут
Цитата Сообщение от рейтар Посмотреть сообщение
Ругается на конструктор только, если я создаю кнопку в рантайме
Это да, так и должно быть, при динамическом создании надо конструктор описывать. А вот все остальное - непонятно. ОС какая? Может, это в самой ОСи какие-нибудь заморочки? MS тоже любит портить все хорошее... Я тестировал вышеприведенный код под WinXP/Win7/Win8 в свое время, на Win10 он не тестировался никогда.
0
2 / 2 / 0
Регистрация: 13.01.2019
Сообщений: 13
11.04.2020, 21:24
Цитата Сообщение от volvo Посмотреть сообщение
заморочки нового 64-битного компилятора
Не, я сборку под 32-бита создаю, в теории разрядность нового компилятора не должна играть роли.

Не по теме:

Но насчет заморочек - согласен, есть такое. Например, пока в настройках проекта не включишь использование классического компилятора, code insight напрочь отказывается работать. Причем в первой 10.1 такой фигни не было.



Винда у меня 10-ка. Попробую на 7-ке проверить.

Ну и если не выгорит, может есть другой вариант? Например, попадался мне тут на форуме совет, переопределить оконную процедуру компонента и там отлавливать событие двойного клика. Вроде бы работает, но у меня получилось так, что определенное ранее событие OnClick срабатывает раньше, чем перехват сообщения двойного клика. Подумать, так логично, но как-то ж отлавливают двойной клик наравне с одинарным?

Цитата Сообщение от volvo Посмотреть сообщение
при динамическом создании надо конструктор описывать
А почему компилятор не использует конструктор предка, если я описываю его пустым, типа {}? И пардон за тупой вопрос: достаточно ли мне будет в своем конструкторе написать что-нибудь типа AOwner = owner, чтобы остальные поля инициализировались конструктором предка?
0
 Аватар для Lelik-pahan
1703 / 899 / 207
Регистрация: 25.11.2009
Сообщений: 1,848
12.04.2020, 11:57
рейтар, а может для созданной динамически кнопки забываете назначить обработчик?
C++
1
Button1->OnDblClick = &MyCloseForm;
Добавлено через 15 минут
Цитата Сообщение от рейтар Посмотреть сообщение
получилось так, что определенное ранее событие OnClick срабатывает раньше, чем перехват сообщения двойного клика.
Так будет в любом случае, даже если у Вас заработает пример volvo.
А как иначе? Если назначен обработчик двойного клика, кнопка после первого клика должна выждать временной интервал, который даётся на двойной клик, и только после этого, если не было второго клика, вызвать событие одиночного клика? Это не так.

Добавлено через 5 минут
Цитата Сообщение от рейтар Посмотреть сообщение
А почему компилятор не использует конструктор предка, если я описываю его пустым, типа {}?
А как вы определили, что не использует? Перейдите к его описанию в Vcl.StdCtrls.hpp и поставьте точку останова. Должна сработать.
0
2 / 2 / 0
Регистрация: 13.01.2019
Сообщений: 13
13.04.2020, 09:43
Цитата Сообщение от Lelik-pahan Посмотреть сообщение
а может для созданной динамически кнопки забываете назначить обработчик?
К сожалению - нет.

Цитата Сообщение от Lelik-pahan Посмотреть сообщение
Так будет в любом случае, даже если у Вас заработает пример volvo.
А как иначе?
Ммм, как в других компонентах? Или там сообщение о кликах отлавливаются на уровне оконной процедуры?

Цитата Сообщение от Lelik-pahan Посмотреть сообщение
А как вы определили, что не использует?
Хотел было написать, что по сообщению компилятора "[bcc32 Error] Unit4.cpp(19): E2125 Compiler could not generate default constructor for class 'DblClick_Button::TButton'", но потом подумал, что это вовсе не означает, что конструктор предка не был вызван.

В общем, я хз, с чего я не могу отловить двойной клик. Использую альтернативный способ: буду поднимать флаг при одинарном клике и опускать его при втором одинарном клике по этому же Sender-у. В любом случае, спасибо за дискуссию
0
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
 Аватар для volvo
33376 / 21500 / 8236
Регистрация: 22.10.2011
Сообщений: 36,896
Записей в блоге: 11
13.04.2020, 16:14
А, вот оно что... Хочется и одинарный и двойной клик обрабатывать одновременно? Ну, тогда вот так:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
namespace DblClick_Button
{
    class TButton : public Stdctrls::TButton
    {
    private:
        TNotifyEvent FOnDblClick;
        MESSAGE void __fastcall WmButtonDoubleClick(TMessage &Message)
        {
            Stdctrls::TButton::Dispatch(&Message);
            if(FOnDblClick)
            {
                FOnDblClick(this);
            }
        }
        MESSAGE void __fastcall WmButtonClick(TMessage &Message)
        {
            TMsg msg;
            long tm = ::GetTickCount() + ::GetDoubleClickTime(); // время для реакции на двойной клик
            while(::GetTickCount() < tm) // ждем возможного получения WM_LBUTTONDBLCLK компонентом
                if(::PeekMessage(&msg, Handle, WM_LBUTTONDBLCLK,
                                 WM_LBUTTONDBLCLK, PM_NOREMOVE)) return; // Дождались - двойной клик, здесь делать нечего
 
            Stdctrls::TButton::Dispatch(&Message);
            if(OnClick)
            {
                OnClick(this);
            }
        }
 
        BEGIN_MESSAGE_MAP
            MESSAGE_HANDLER(WM_LBUTTONDBLCLK, TMessage, WmButtonDoubleClick);
            MESSAGE_HANDLER(WM_LBUTTONDOWN, TMessage, WmButtonClick)
        END_MESSAGE_MAP(Stdctrls::TButton);
 
    public:
         __fastcall virtual TButton(System::Classes::TComponent* AOwner) : Stdctrls::TButton(AOwner)
         {
         }
        __property TNotifyEvent OnDblClick = {read = FOnDblClick, write = FOnDblClick};
    };
}
#define TButton DblClick_Button::TButton
+
C++
1
2
3
4
5
6
7
8
9
10
11
12
void __fastcall TForm1::FormCreate(TObject *Sender)
{
    TButton *btn = new TButton(this);
    btn->Parent = this;
    btn->OnDblClick = &MyDblClick;
    btn->OnClick = &MyClick;
 
    btn->Top = 10;
    btn->Left = 10;
    btn->Visible = true;
    btn->Caption = "Test";
}
3
2 / 2 / 0
Регистрация: 13.01.2019
Сообщений: 13
13.04.2020, 17:12
Цитата Сообщение от volvo Посмотреть сообщение
Ну, тогда вот так
Понимаю, это уже не смешно, но не работает( Причем брейкпоинт на строке с макросом BEGIN_MESSAGE_MAP срабатывает, т.е. сообщения ходят через компонент, но вот на MESSAGE_HANDLER(WM_LBUTTONDBLCLK, TMessage, WmButtonDoubleClick); срабатывание не происходит.

Поковырявшись и поэкспериментировав, пришел к такому варианту:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
namespace DblClick_Button
{
  class TButton : public Stdctrls::TButton
  {
    private:
      TNotifyEvent FOnDblClick;
 
      MESSAGE void __fastcall WmButtonClick(TMessage &Message)
      {
        TMsg msg;
        long tm = ::GetTickCount() + ::GetDoubleClickTime(); // время для реакции на двойной клик
 
        while(::GetTickCount() < tm) // ждем возможного получения WM_LBUTTONDBLCLK компонентом
          {
            if (::PeekMessage(&msg, Handle, WM_LBUTTONDBLCLK,
                             WM_LBUTTONDBLCLK, PM_NOREMOVE))
              {
                if (FOnDblClick)
                  FOnDblClick(this);
 
                return; // Дождались - двойной клик, здесь делать нечего
              }
          }
 
        Stdctrls::TButton::Dispatch(&Message);
 
        if (OnClick)
           OnClick(this);
      }
 
      BEGIN_MESSAGE_MAP
        MESSAGE_HANDLER(WM_LBUTTONDOWN, TMessage, WmButtonClick)
      END_MESSAGE_MAP(Stdctrls::TButton);
 
    public:
      __fastcall virtual TButton(System::Classes::TComponent* AOwner) : Stdctrls::TButton(AOwner)
      {
      }
 
      __property TNotifyEvent OnDblClick = {read = FOnDblClick, write = FOnDblClick};
  };
}
#define TButton DblClick_Button::TButton
Так - работает. Наверное, вы были правы: таки Эмбаркадеро что-то поменяли в компиляторе, относительно старых версий.
0
 Аватар для Lelik-pahan
1703 / 899 / 207
Регистрация: 25.11.2009
Сообщений: 1,848
15.04.2020, 00:03
рейтар, проверьте 2 вещи:
1. проверьте перехват WM_LBUTTONDBLCLK в чистом проекте
2. переопределите в классе формы метод CreateParams, поставьте точку останова и посмотрите значение Params.WindowClass.style
C++
1
2
3
4
5
    virtual void __fastcall CreateParams(Vcl::Controls::TCreateParams& Params)
    {
        TForm::CreateParams(Params);
        //Params.WindowClass.style
    };
0
Практикантроп
 Аватар для nick42
4841 / 2726 / 534
Регистрация: 23.09.2011
Сообщений: 5,798
15.04.2020, 01:11
Если одиночный клик не катастрофичен (всё равно по двойному форма закрывается), то можно применить старый дедовский способ, что-то наподобие такого__
C++
1
2
3
4
5
6
7
8
9
10
void __fastcall TForm1::Button1Click(TObject *Sender) 
{
   static TDateTime tLast=0;
   if((double)tLast && (double)fabs(Time()-tLast)>43935.9999971)
     Close();    // Caption = "double";
   else {
     Caption = "Form1";   // something else
   }
   tLast=Now();
}
0
2 / 2 / 0
Регистрация: 13.01.2019
Сообщений: 13
15.04.2020, 11:28
Цитата Сообщение от Lelik-pahan Посмотреть сообщение
1. проверьте перехват WM_LBUTTONDBLCLK в чистом проекте
Это и есть чистый проект.

Цитата Сообщение от Lelik-pahan Посмотреть сообщение
2. переопределите в классе формы метод CreateParams, поставьте точку останова и посмотрите значение Params.WindowClass.style
65001
0
 Аватар для Lelik-pahan
1703 / 899 / 207
Регистрация: 25.11.2009
Сообщений: 1,848
15.04.2020, 11:56
Цитата Сообщение от рейтар Посмотреть сообщение
65001
а если сделать так, перехват не заработает?
C++
1
2
3
4
5
    virtual void __fastcall CreateParams(Vcl::Controls::TCreateParams& Params)
    {
        TForm::CreateParams(Params);
        Params.WindowClass.style = CS_DBLCLKS;
    };
И проверьте, срабатывает ли событие OnDblClick у самой формы.
0
2 / 2 / 0
Регистрация: 13.01.2019
Сообщений: 13
15.04.2020, 13:23
Цитата Сообщение от Lelik-pahan Посмотреть сообщение
И проверьте, срабатывает ли событие OnDblClick у самой формы.
Срабатывает.

Цитата Сообщение от Lelik-pahan Посмотреть сообщение
а если сделать так, перехват не заработает?
Неа, все равно, на MESSAGE_HANDLER(WM_LBUTTONDOWN, TMessage, WmButtonClick) срабатывает, а на обработчике сообщения двойного клика - нет.
0
Супер-модератор
Эксперт Pascal/DelphiАвтор FAQ
 Аватар для volvo
33376 / 21500 / 8236
Регистрация: 22.10.2011
Сообщений: 36,896
Записей в блоге: 11
15.04.2020, 14:24
Кликните здесь для просмотра всего текста
Название: mice.jpg
Просмотров: 70

Размер: 10.5 Кб
0
2 / 2 / 0
Регистрация: 13.01.2019
Сообщений: 13
15.04.2020, 15:24

Не по теме:

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



Добавлено через 8 минут
Му-ха-ха, я нашел причину несрабатывания. В свойствах проекта, на вкладке Appearance в разделе Custom Styles біл вібран стиль под Win10. Стоило вернуться к "родному" для винды оформлению - все заработало. Жаль, переключение стилей "на лету" классная фишка, планировал ее юзать и дальше.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
15.04.2020, 15:24
Помогаю со студенческими работами здесь

Как сделать чтобы при нажатии на кнопку в форме2 эта форма закрывалась и открывалась форма1(основная, т.к. на
Как сделать чтобы при нажатии на кнопку в форме2 эта форма закрывалась и открывалась форма1(основная, т.к. на ней у меня меню программы)

Как сделать так чтобы меню вызывалось правой кнопкой мыши?
Как сделать так чтобы меню вызывалось правой кнопкой мыши? Ниже приведено меню и функция обработки правой кнопки Не могу связать одно с...

Как нарисовать точки в zed graph левой кнопкой мыши?
Как нарисовать точки в zed graph левой кнопкой мыши?

Разместить еще одну кнопку button2 чтобы она было ровно кнопкой Button1
Здравствуйте! Я создал одну кнопку Button1 в jFrame разместил сверху окна. Вот код: but = new JButton(&quot;Рассчитать...

Как отследить вход в PictureBox курсора мыши с нажатой левой кнопкой
Проблема такая. Необходимо сделать так, чтобы PictureBox меняла картинку при входе курсора мыши с нажатой левой кнопкой (например, с sap0...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
Новые блоги и статьи
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 28.01.2026
Содержание блога SDL3 имеет собственные средства для загрузки и отображения PNG-файлов с альфа-каналом и базовой работы с ними. В этой инструкции используется функция SDL_LoadPNG(), которая. . .
Загрузка PNG с альфа-каналом на SDL3 для Android: с помощью SDL3_image
8Observer8 27.01.2026
Содержание блога SDL3_image - это библиотека для загрузки и работы с изображениями. Эта пошаговая инструкция покажет, как загрузить и вывести на экран смартфона картинку с альфа-каналом, то есть с. . .
влияние грибов на сукцессию
anaschu 26.01.2026
Бифуркационные изменения массы гриба происходят тогда, когда мы уменьшаем массу компоста в 10 раз, а скорость прироста биомассы уменьшаем в три раза. Скорость прироста биомассы может уменьшаться за. . .
Воспроизведение звукового файла с помощью SDL3_mixer при касании экрана Android
8Observer8 26.01.2026
Содержание блога SDL3_mixer - это библиотека я для воспроизведения аудио. В отличие от инструкции по добавлению текста код по проигрыванию звука уже содержится в шаблоне примера. Нужно только. . .
Установка Android SDK, NDK, JDK, CMake и т.д.
8Observer8 25.01.2026
Содержание блога Перейдите по ссылке: https:/ / developer. android. com/ studio и в самом низу страницы кликните по архиву "commandlinetools-win-xxxxxx_latest. zip" Извлеките архив и вы увидите. . .
Вывод текста со шрифтом TTF на Android с помощью библиотеки SDL3_ttf
8Observer8 25.01.2026
Содержание блога Если у вас не установлены Android SDK, NDK, JDK, и т. д. то сделайте это по следующей инструкции: Установка Android SDK, NDK, JDK, CMake и т. д. Сборка примера Скачайте. . .
Использование SDL3-callbacks вместо функции main() на Android, Desktop и WebAssembly
8Observer8 24.01.2026
Содержание блога Если вы откроете примеры для начинающих на официальном репозитории SDL3 в папке: examples, то вы увидите, что все примеры используют следующие четыре обязательные функции, а. . .
моя боль
iceja 24.01.2026
Выложила интерполяцию кубическими сплайнами www. iceja. net REST сервисы временно не работают, только через Web. Написала за 56 рабочих часов этот сайт с нуля. При помощи perplexity. ai PRO , при. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru