Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Как реализован двойной клик  (Прочитано 13095 раз)
0 Пользователей и 1 Гость смотрят эту тему.
yudjin
Помогающий

ua
Offline Offline
Пол: Мужской

« : 30-08-2010 09:29 » 

Собственно, сабж.
Сначала сделал по привязке ко времени. Все хорошо, но оказалось, что событие App.Instance.CurrentTool.OnMouseDown будет вызываться даже тогда, когда вызывается App.Instance.CurrentTool.OnDoubleClick. Работа с графикой, поэтому при двойном клике появляется лишняя точка, это плохо.

Код:
             if (DateTime.Now.Ticks - lastTicks < 2010000)
                {//Обработка двойного щелчка
                    Debug.WriteLine("Обработка двойного щелчка");

                    if (App.Instance.CurrentTool != null)
                        App.Instance.CurrentTool.OnDoubleClick(0, Convert.ToInt32(hostPoint.X), Convert.ToInt32(hostPoint.Y));
                }
                else
                {
                    Debug.WriteLine("Обработка щелчка");

                    if (App.Instance.CurrentTool != null)
                        App.Instance.CurrentTool.OnMouseDown(0, Convert.ToInt32(hostPoint.X), Convert.ToInt32(hostPoint.Y));
                }

                lastTicks = DateTime.Now.Ticks;

Пробовал реализовать по примеру (http://silverlight.su/viewtopic.php?id=33), но тогда возникает следующая проблема - каждый клик идет с задержкой в 200 млсек, хотя лишних кликов уже нет.
Код:
       // время ожидания второго клика истекло
        void _doubleClickTimer_Tick(object sender, EventArgs e)
        {
            _doubleClickTimer.Stop();
            Debug.WriteLine("Обработка щелчка");
            if (App.Instance.CurrentTool != null)
                App.Instance.CurrentTool.OnMouseDown(0, Convert.ToInt32(hostPoint.X), Convert.ToInt32(hostPoint.Y));
        }

   
Код:
   
      protected void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            hostPoint = e.GetPosition(m_viewBox);
            hostPoint.X += offsetView.X - m_scrollViewer.HorizontalOffset;
            hostPoint.Y += offsetView.Y - m_scrollViewer.VerticalOffset;

            if (!doubleClickTimer.IsEnabled)
            {
                doubleClickTimer.Start();
            }

            else
            {
                // произошел двойной клик
                doubleClickTimer.Stop();

                {//Обработка двойного щелчка
                    Debug.WriteLine("Обработка двойного щелчка");

                    if (App.Instance.CurrentTool != null)
                        App.Instance.CurrentTool.OnDoubleClick(0, Convert.ToInt32(hostPoint.X), Convert.ToInt32(hostPoint.Y));
                }

        }
   
Подскажите, как это реализовано, допустим, в Windows (сообщение ON_MOUSE_DOUBLECLICK)
Записан
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #1 : 30-08-2010 09:58 » 

Что эта тема делает в Технологиях разработки?... Перенес пока сюда. Точнее не могу перенести, пока не пойму, с чем имеем дело и с какой средой - зацепиться не за что. Вроде и на Java похоже, и на C++.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
yudjin
Помогающий

ua
Offline Offline
Пол: Мужской

« Ответ #2 : 30-08-2010 10:36 » 

Среда не имеет значения. Допустим, это API ArcMap'а, где есть только OnMouseDown, а надо еще присобачить и двойной клик. В Silverlight'е такая же ситуация. Меня интересует общая схема, поэтому и отнес к технологии.
ЗЫ: использую язык C# и в API ArcMap'а, и в  Silverlight'е.
Записан
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 30-08-2010 11:51 » 

Ну, если взять утилитку Spy++ и поглядеть, что происходит при двойном клике, то можно увидеть, что происходит примерно следующее:
Код:
<00001> 000103FE P WM_LBUTTONDOWN fwKeys:MK_LBUTTON xPos:190 yPos:123
<00002> 000103FE P WM_LBUTTONUP fwKeys:0000 xPos:190 yPos:123
<00003> 000103FE P WM_LBUTTONDBLCLK fwKeys:MK_LBUTTON xPos:190 yPos:123
<00004> 000103FE P WM_LBUTTONUP fwKeys:0000 xPos:190 yPos:123
Стало быть, система не запаривается и посылает WM_LBUTTONUP всякий раз, когда происходит клик мышью. А вот прежде чем отправить WM_LBUTTONDOWN, проверяет, прошёл ли таймаут (например, 200 мс) с момента предыдущего WM_LBUTTONDOWN. Если прошёл - вместо него высылается WM_LBUTTONDBLCLK.
Собственно, если я всё правильно понимаю, LBUTTONDOWN vs. LBUTTONDBLCLK - и есть первичное отличие клика от дабл-клика.

Поскольку "тройной клик" в системе не реализован, то попытка выполнить что-то похожее даст:
Код:
<00001> 000103FE P WM_LBUTTONDOWN fwKeys:MK_LBUTTON xPos:77 yPos:467
<00002> 000103FE P WM_LBUTTONUP fwKeys:0000 xPos:77 yPos:467
<00003> 000103FE P WM_LBUTTONDBLCLK fwKeys:MK_LBUTTON xPos:77 yPos:467
<00004> 000103FE P WM_LBUTTONUP fwKeys:0000 xPos:77 yPos:467
<00005> 000103FE P WM_LBUTTONDOWN fwKeys:MK_LBUTTON xPos:77 yPos:467
<00006> 000103FE P WM_LBUTTONUP fwKeys:0000 xPos:77 yPos:467
То есть, клик+дабл-клик+клик.

А как это всё обрабатывать... Надо думать, здесь уже каждое окно реализует своё поведение, и есть стандартное поведение, уведомляющее о типе клика родителя. В любом случае, вручную такое реализовывать - задержка потребуется. Я не вижу другого способа заглянуть в будущее и убедиться, что данный клик не будет двойным.

ЗЫ. Да, кстати, задержка 200мс в случае Windows - именно с момента BUTTONDOWN, а не UP. Так что для пользователя она не будет слишком большой Улыбаюсь
ЗЗЫ. Кстати, именно поэтому (и не только) в первом твоём примере кода строчка
Код:
lastTicks = DateTime.Now.Ticks;
должна предварять всю остальную обработку.
« Последнее редактирование: 30-08-2010 11:58 от Вад » Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 30-08-2010 12:26 » 

Я бы решал по схеме:

Код: (Text) Псевдокод
class Clicks
{
  private const int N = ...;
  private int TIMEOUT = ...;
  private int queue[N] = { 0, TIMEOUT + 1, 2 * TIMEOUT + 2, ... };

  public void shift()
  {
    for(int i = 0; i < N - 1; ++I)
      self.queue[i] = self.queue[i + 1];
    self.queue[N - 1] = Time.ticks;
  }

  public int count()
  {
    for(int i = 0; i < N; ++i)
      if(self.queue[N - 1] - self.queue[i] < TIMEOUT)
        return N - i;
  }
}

Clicks clicks;

void on_click()
{
  clicks.shift();
  switch(clicks.count())
  {
    case 2:
      on_double_click();
      return;
    case 3:
      on_tri_click();
      return;
    ...
    default:
      on_single_click();
      return;
  }
}
« Последнее редактирование: 30-08-2010 12:28 от Dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #5 : 30-08-2010 15:59 » 

Вообще-то, в структуре сообщения есть штамп времени в миллисекундах.
Код: (Text)
struct MSG{
    HWND        hwnd;
    UINT        message;
    WPARAM      wParam;
    LPARAM      lParam;
    DWORD       time; // <<<<<<<<<<<<<<<<<<<<<<<<<<
    POINT       pt;
};
 

поэтому достаточно складировать очередь из N кликов ((WM_LBUTTONDOWN + WM_LBUTTONUP)*N), а затем анализировать очередь на наличие нужных таймаутов. Всё, что не уложилось или что обработано - удалять из очереди

Главное - подступиться к штампу времени )
Записан

Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #6 : 30-08-2010 19:05 » 

Граждане, у автора темы код на C# и упомянут Silverlight.

А почему?

А потому, что в Silverlight по меньшей мере до 3 версии включительно не было события двойного клика. Поэтому такая странная тема.

Посему писать сюда куски из WinAPI, конечно, дело хорошее, но совершенно бессмысленное.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #7 : 31-08-2010 03:32 » 

Dimka, это не куски кода на АПИ, это структура, которая почти так же будет выглядеть и на шарпе.  Затем, коли упомянуты C# , Spy++ и, собственно (автором) - Windows , то АПИ там есть. А значит - этот штамп времени из сообщения можно получить
Записан

Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #8 : 31-08-2010 06:26 » 

Алексей1153++, Silverlight работает внутри браузера со всеми вытекающими ограничениями на безопасность - это не оконное приложение. А про Spy++ Вад сказал, тем самым обозначив способ решения, которым пользуются "белые люди".
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #9 : 31-08-2010 06:45 » 

хорошо, вопрос снят ))
Записан

yudjin
Помогающий

ua
Offline Offline
Пол: Мужской

« Ответ #10 : 31-08-2010 07:22 » 

Всем спасибо, реализовал по схеме Dimkи.
Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines