Вопрос

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

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

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

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

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

Это было полезно?

Решение

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

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

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

Другие советы

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

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

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

Групповой блок - это статический элемент управления, внутри которого находятся другие элементы управления.Он предназначен исключительно для того, чтобы "сгруппировать" вещи вместе, чтобы сделать пользовательский интерфейс интуитивно понятным, если он правильно оформлен.Следовательно, существует очень мало событий, которые вы можете использовать от имени 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!".

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

Я заметил, что многие события для определенных элементов управления недоступны через вкладку «События» (в разделе «Свойства») в 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
};
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top