Почему в GroupBox нет события MouseMove? - PullRequest
3 голосов
/ 10 ноября 2009

Элемент управления WinForms GroupBox не поддерживает MouseMove (или, по крайней мере, не всегда), и я не понимаю, почему.

Так как он происходит от Control, у него есть событие MouseMove, но GroupBox явно вводит его с Browsable(false), поэтому он не отображается в таблице свойств. Вы можете перехватить событие MouseMove во время выполнения, и иногда оно работает - до тех пор, пока FlatStyle остается в Standard. Если для FlatBtyle GroupBox установлено значение System, то события MouseMove вообще не запускаются.

Отражатель не дал мне никаких подсказок. Кажется, что конструктор GroupBox не устанавливает какие-то странные стили элементов управления, а GroupBox не делает глупостей, таких как переопределение MouseMove и не вызывает base.

Это также представляется ограничением, специфичным для WinForms, поскольку групповые блоки Delphi прекрасно поддерживают OnMouseMove. Исправление: сравнение с Delphi недопустимо. Групповые блоки Delphi на самом деле не являются стандартными элементами управления BM_GROUPBOX; они просто окрашены в , выглядят как групповые блоки, фактически не наследуя странное поведение групповой коробки, подобное этому. Так что это вполне может быть ограничением для элемента управления групповыми окнами Windows, хотя я нигде не видел его документированного.

Почему WinForms GroupBox не поддерживает MouseMove?

Ответы [ 4 ]

4 голосов
/ 01 января 2010

В соответствии с этой цепочкой стандартная групповая коробка Windows (т. Е. Элемент управления BUTTON со стилем BS_GROUPBOX) появляется для возврата HTTRANSPARENT в ответ на WM_NCHITTEST. Поскольку элемент управления считается прозрачным, Windows отправляет события перемещения мыши в родительское окно.

Поток подтверждает, что, если вы обработаете WM_NCHITTEST самостоятельно и вернете HTCLIENT, тогда групповое окно получит события перемещения мыши. Они используют MFC, но, вероятно, это работает и для WinForms.

Что не ясно, так это , почему Windows возвращает HTTRANSPARENT по умолчанию, но, по крайней мере, проблема была подтверждена независимо.

2 голосов
/ 10 ноября 2009

Это можно увидеть с помощью Reflector, ключевым свойством является CreateParams и внутреннее свойство OwnerDraw. GroupBox обычно работает с OwnerDraw = true, кроме случаев, когда вы устанавливаете FlatStyle = System. Затем вы получаете старомодный групповой блок Windows, окно с именем класса BUTTON с включенным битом стиля BS_GROUPBOX.

Если вы посмотрите на Spy ++, вы увидите, что элемент управления вообще не получает сообщений мыши. Не уверен, почему это так, документы SDK не упоминают об этом. Я предполагаю, что это восходит к Windows 2.x, где учитывается каждый цикл. Но это объясняет, почему событие MouseMove скрыто, оно не может срабатывать при выборе стиля системы. То же самое для клика и вверх / вниз. Установщик свойства FlatStyle действительно ограничивает его, также отключая стиль элемента управления Control.UserMouse.

В любом случае, если вам нужны сообщения мыши, вам нужно избегать стиля системы.

0 голосов
/ 12 января 2018

Я заметил, что многие события для определенных элементов управления не доступны на вкладке событий (в разделе Свойства) в VS. Вы можете просто назначить обработчик событий вручную в конструкторе родительской формы в InitializeComponents():

this.groupBox1.MouseMove += new MouseEventHandler(this.groupBox1_MouseMove);

Это вызовет следующий метод:

private void groupBox1_MouseMove(object sender, MouseEventArgs e)
{
    //doodle the stuff you want to happen after the trigger here
};
0 голосов
/ 01 января 2010

Групповое поле - это статический элемент управления, в котором находятся другие элементы управления. Он предназначен исключительно для «группировки» вещей, чтобы сделать пользовательский интерфейс интуитивно понятным, если он правильно изложен. Следовательно, есть очень мало событий, которые вы можете использовать от имени GroupBox.

Возможно, вы сможете создать новый класс, унаследованный от GroupBox, и создать его подкласс для перехвата события перемещения мыши. Существует очень полезный класс, который я использовал ранее, и действительно легко выполнить подклассы и вызвать событие для MouseMove.

Взгляните на это здесь , чтобы увидеть, как будет работать подклассы ... Хорошо, оно написано в VB.NET, но его действительно легко перевести на C #, если вы этого хотите, код, который я представляю, будет выглядеть так: Примечание. Этот код, который я включил, находится у меня в голове, поэтому в этом может быть ошибка ... но в этом суть.

Редактировать: В ответ на комментарий Джо Уайта я включил пересмотренный код, и он действительно отправляет WM_MOUSEMOVE ... посмотрите на шаги ниже, как я воспроизвел это в VS 2008 Pro.

    public class MyGroupBox : System.Windows.Forms.GroupBox
    {
        private SubClass sc;
        private const int WM_MOUSEMOVE = 0x200;
        public delegate void MyMouseMoveEventHandler(object sender, System.EventArgs e);
        public event MyMouseMoveEventHandler MyMouseMove;
        public MyGroupBox()
            : base()
        {
            sc = new SubClass(this.Handle, true);
            sc.SubClassedWndProc += new SubClass.SubClassWndProcEventHandler(sc_SubClassedWndProc);
        }

        protected override void Dispose(bool disposing)
        {
            if (sc.SubClassed)
            {
                sc.SubClassedWndProc -= new SubClass.SubClassWndProcEventHandler(sc_SubClassedWndProc);
                sc.SubClassed = false;
            }
            base.Dispose(disposing);
        }
        private void OnMyMouseMove()
        {
            if (this.MyMouseMove != null) this.MyMouseMove(this, System.EventArgs.Empty);
        }
        void sc_SubClassedWndProc(ref Message m)
        {
            if (m.Msg == WM_MOUSEMOVE) this.OnMyMouseMove();
        }

    }

    #region SubClass Classing Handler Class
    public class SubClass : System.Windows.Forms.NativeWindow
    {
        public delegate void
          SubClassWndProcEventHandler(ref System.Windows.Forms.Message m);
        public event SubClassWndProcEventHandler SubClassedWndProc;
        private bool IsSubClassed = false;

        public SubClass(IntPtr Handle, bool _SubClass)
        {
            base.AssignHandle(Handle);
            this.IsSubClassed = _SubClass;
        }

        public bool SubClassed
        {
            get { return this.IsSubClassed; }
            set { this.IsSubClassed = value; }
        }

        protected override void WndProc(ref Message m)
        {
            if (this.IsSubClassed)
            {
                OnSubClassedWndProc(ref m);
            }
            base.WndProc(ref m);
        }

        #region HiWord Message Cracker
        public int HiWord(int Number)
        {
            return ((Number >> 16) & 0xffff);
        }
        #endregion

        #region LoWord Message Cracker
        public int LoWord(int Number)
        {
            return (Number & 0xffff);
        }
        #endregion

        #region MakeLong Message Cracker
        public int MakeLong(int LoWord, int HiWord)
        {
            return (HiWord << 16) | (LoWord & 0xffff);
        }
        #endregion

        #region MakeLParam Message Cracker
        public IntPtr MakeLParam(int LoWord, int HiWord)
        {
            return (IntPtr)((HiWord << 16) | (LoWord & 0xffff));
        }
        #endregion

        private void OnSubClassedWndProc(ref Message m)
        {
            if (SubClassedWndProc != null)
            {
                this.SubClassedWndProc(ref m);
            }
        }
    }
    #endregion

  1. Создать простую пустую форму.
  2. Перетащите групповой блок из палитры инструментов и поместите его в форму, имя по умолчанию будет groupBox1
  3. В коде конструктора вашей формы измените ссылку на код, выполнив это:
    System.Windows.Forms.GroupBox groupBox1;
    до
    WindowsApplication.MyGroupBox groupBox1;
  4. В методе InitializeComponent() измените экземпляр GroupBox на этот:
    this.groupBox1 = new WindowsApplication.MyGroupBox();
  5. Сохраните и просто скомпилируйте его.
  6. Вернитесь в окно дизайнера и нажмите на групповое поле, найдите событие MyMouseMove на панели инструментов свойств и подключите его.
  7. Ваш обработчик событий должен выглядеть примерно так:
        private void groupBox1_MyMouseMove(object sender, EventArgs e)
        {
            System.Diagnostics.Debug.WriteLine("MyMouseMove!");
        }

Запустите приложение, и каждый раз, когда вы будете перемещать мышь внутри группового блока, вы увидите вывод «MyMouseMove!».

Надеюсь, это даст вам подсказку, С наилучшими пожеланиями, Том.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...