Как получить сообщения Windows в соответствии с ребенком? - PullRequest
0 голосов
/ 30 сентября 2019

Я создаю форму внутри другой формы. В дочерней форме я создал кнопку панели задач. Я переопределяю WndProc в кнопке. Я имею в виду https://www.codeproject.com/Articles/10171/Adding-a-Minimize-to-tray-button-to-a-Form-s-caption бар. Но всякий раз, когда я получаю сообщения (координаты мыши), они указываются относительно родительской формы. Это создает проблемы в расчетах. Я хочу, чтобы те, которые относятся к детской форме. Как этого добиться?

Это код для формы1

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        Form2 form2 = new Form2();
        form2.TopLevel = false;
        form2.AutoScroll = true;
        form2.Anchor = AnchorStyles.Top;
        form2.Dock = DockStyle.Fill;

        this.splitContainer1.Panel2.Controls.Add(form2);
        form2.Show();
    }
}

это форма 2.

public partial class Form2 : Form
{
    TyronM.MinTrayBtn Pin_Button;
    public Form2()
    {
        InitializeComponent();
        Pin_Button = new TyronM.MinTrayBtn(this);
        Pin_Button.MinTrayBtnClicked += new TyronM.MinTrayBtnClickedEventHandler(this.Pin_Button_Clicked);

    }
    public void Pin_Button_Clicked(object sender, EventArgs e)
    {
        MessageBox.Show("Pin button got Clicked");
    }

    protected override void WndProc(ref Message message)
    {
        const int WM_SYSCOMMAND = 0x0112;
        const int SC_MOVE = 0xF010;

        switch (message.Msg)
        {
            case WM_SYSCOMMAND:
                int command = message.WParam.ToInt32() & 0xfff0;
                if (command == SC_MOVE)
                    return;
                break;
        }

        base.WndProc(ref message);
    }
}

И это для кнопки.

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Diagnostics;
using System.Resources;
using System.Runtime.InteropServices;

namespace TyronM {
public delegate void MinTrayBtnClickedEventHandler(object sender, EventArgs e);

/// <summary>
/// Summary description for Class.
/// </summary>
public class MinTrayBtn : NativeWindow {
    bool pinned = false;

    bool pressed = false;
    Size wnd_size = new Size();
    public bool captured;
    Form parent;
    public event MinTrayBtnClickedEventHandler MinTrayBtnClicked;

    #region Constants
    const int WM_SIZE = 5;
    const int WM_SYNCPAINT = 136;
    const int WM_MOVE = 3;
    const int WM_ACTIVATE = 6;
    const int WM_LBUTTONDOWN =513;
    const int WM_LBUTTONUP =514;
    const int WM_LBUTTONDBLCLK =515;
    const int WM_MOUSEMOVE = 512;

    const int WM_PAINT = 15;

    const int WM_GETTEXT = 13;

    const int WM_NCCREATE =129;
    const int WM_NCLBUTTONDOWN = 161;
    const int WM_NCLBUTTONUP = 162;
    const int WM_NCMOUSEMOVE = 160;
    const int WM_NCACTIVATE =134;
    const int WM_NCPAINT = 133;
    const int WM_NCHITTEST = 132;
    const int WM_NCLBUTTONDBLCLK = 163;

    const int VK_LBUTTON = 1;

    const int SM_CXSIZE = 30;
    const int SM_CYSIZE = 31;               
    #endregion

    #region Extra Constants
    const int WM_MBUTTONUP = 0x0208;                    
    #endregion
    #region WinAPI Imports
    [DllImport("user32")]
    public static extern int GetWindowDC(int hwnd);

    [DllImport("user32")]
    public static extern short GetAsyncKeyState(int vKey);

    [DllImport("user32")]
    public static extern int SetCapture(int hwnd);

    [DllImport("user32")]
    public static extern bool ReleaseCapture();

    [DllImport("user32")]
    public static extern int GetSysColor(int nIndex);

    [DllImport("user32")]
    public static extern int GetSystemMetrics(int nIndex);
    #endregion

    #region Constructor and Handle-Handler ^^
    public MinTrayBtn(Form parent) {
        parent.HandleCreated += new EventHandler(this.OnHandleCreated);
        parent.HandleDestroyed+= new EventHandler(this.OnHandleDestroyed);
        parent.TextChanged+= new EventHandler(this.OnTextChanged);
        this.parent = parent;
    }

    // Listen for the control's window creation and then hook into it.
    internal void OnHandleCreated(object sender, EventArgs e){
        // Window is now created, assign handle to NativeWindow.
        AssignHandle(((Form)sender).Handle);
    }
    internal void OnHandleDestroyed(object sender, EventArgs e) {
        // Window was destroyed, release hook.
        ReleaseHandle();
    }

    // Changing the Text invalidates the Window, so we got to Draw the Button again
    private void OnTextChanged(object sender, EventArgs e) {
        DrawButton();
    }
    #endregion

    #region WndProc
    [System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name="FullTrust")]
    protected override void WndProc(ref Message m){
        //label3.Text = "Button pressed: " + pressed;
        //label4.Text = "Mouse captured: " + captured;

        // Change the Pressed-State of the Button when the User pressed the
        // left mouse button and moves the cursor over the button
        if (m.Msg == WM_LBUTTONDBLCLK ||m.Msg == WM_LBUTTONDOWN || m.Msg == WM_LBUTTONUP 
            ||m.Msg == WM_MBUTTONUP
            )

            MessageBox.Show("click happened");
        if(m.Msg==WM_MOUSEMOVE) {
            Point pnt2 = new Point((int)m.LParam);
            Size rel_pos2 = new Size(parent.PointToClient(new Point(parent.Location.X, parent.Location.Y)));
            // Not needed because SetCapture seems to convert the cordinates anyway
            //pnt2 = PointToClient(pnt2);
            pnt2-=rel_pos2;
            //label2.Text = "Cursor @"+pnt2.X+"/"+pnt2.Y;

            if(pressed) {
                Point pnt = new Point((int)m.LParam);
                Size rel_pos = new Size(parent.PointToClient(new Point(parent.Location.X, parent.Location.Y)));
                //pnt = PointToClient(pnt);
                pnt-=rel_pos;

                if(!MouseinBtn(pnt)) {
                    pressed = false;
                    DrawButton();
                }

            } else {
                if((GetAsyncKeyState(VK_LBUTTON)&(-32768))!=0) {
                    Point pnt = new Point((int)m.LParam);
                    Size rel_pos = new Size(parent.PointToClient(new Point(parent.Location.X, parent.Location.Y)));
                    //pnt = PointToClient(pnt);
                    pnt-=rel_pos;

                    if(MouseinBtn(pnt)) {
                        pressed = true;
                        DrawButton();
                    }
                }
            }  
        }

        // Ignore Double-Clicks on the Traybutton
        if(m.Msg==WM_NCLBUTTONDBLCLK) {
                Point pnt = new Point((int)m.LParam);
                Size rel_pos = new Size(parent.PointToClient(new Point(parent.Location.X, parent.Location.Y)));
                pnt = parent.PointToClient(pnt);
                pnt-=rel_pos;
                if(MouseinBtn(pnt)) {
                    return;
                }
        }

        #region NOT WORKING
        // Button released and eventually clicked 
        if(m.Msg==WM_LBUTTONUP)
        {
            ReleaseCapture();
            captured = false;

            if(pressed) {
                pressed = false;
                DrawButton();

                Point pnt = new Point((int)m.LParam);
                Size rel_pos = new Size(parent.PointToClient(new Point(parent.Location.X, parent.Location.Y)));
                pnt-=rel_pos;
                if(MouseinBtn(pnt)) {
                    //TrayButton_clicked();
                    EventArgs e = new EventArgs();
                    if (MinTrayBtnClicked != null)
                        MinTrayBtnClicked(this, e);
                    return;
                }
            }
        }
        #endregion
        // Clicking the Button - Capture the Mouse and await until the Uses relases the Button again
        if(m.Msg==WM_NCLBUTTONDOWN) {
            //MessageBox.Show("clicked");
            Point pnt = new Point((int)m.LParam);
            Size rel_pos = new Size(parent.PointToClient(new Point(parent.Location.X, parent.Location.Y)));
            pnt = parent.PointToClient(pnt);
            pnt-=rel_pos;

            if(MouseinBtn(pnt)) {
                MessageBox.Show("clicked");
                pressed = true;
                DrawButton();
                SetCapture((int)parent.Handle);
                captured = true;
                return;
            }
        }

        // Drawing the Button and getting the Real Size of the Window
        if(m.Msg == WM_ACTIVATE || m.Msg==WM_SIZE || m.Msg==WM_SYNCPAINT || m.Msg==WM_NCACTIVATE || m.Msg==WM_NCCREATE || m.Msg==WM_NCPAINT || m.Msg==WM_NCACTIVATE || m.Msg==WM_NCHITTEST || m.Msg==WM_PAINT) {
            if(m.Msg==WM_SIZE) wnd_size = new Size(new Point((int)m.LParam));
            DrawButton();
        }
        base.WndProc(ref m);
    }
    #endregion

    #region Button-Specific Functions
    public bool MouseinBtn(Point click) {
        int btn_width = GetSystemMetrics(SM_CXSIZE);
        int btn_height = GetSystemMetrics(SM_CYSIZE);
        Size btn_size = new Size(btn_width, btn_height);

        Point pos = new Point(wnd_size.Width - 3 * btn_width - 12 - (btn_width - 18)+7, 6+4);

        return click.X>=pos.X && click.X<=pos.X+btn_size.Width &&
               click.Y>=pos.Y && click.Y<=pos.Y+btn_size.Height;
    }

    public void DrawButton() {
        Graphics g = Graphics.FromHdc((IntPtr)GetWindowDC((int)parent.Handle)); //m.HWnd));
        DrawButton(g, pressed);
    }

    public void DrawButton(Graphics g, bool pressed) {
        int btn_width = GetSystemMetrics(SM_CXSIZE);
        int btn_height = GetSystemMetrics(SM_CYSIZE);

        //Point pos = new Point(wnd_size.Width-3*btn_width-12-(btn_width-18),6);
        Point pos = new Point(wnd_size.Width - 3 * btn_width - 12 - (btn_width - 18)+7, 6+4);

        // real button size
        btn_width-=2;
        btn_height-=4;

        Color light = SystemColors.ControlLightLight;
        Color icon = SystemColors.ControlText;
        Color background = SystemColors.Control;
        Color shadow1 = SystemColors.ControlDark;
        Color shadow2 = SystemColors.ControlDarkDark;

        Color tmp1, tmp2;

        if(pressed) {
            tmp1 = shadow2;
            tmp2 = light;
        } else {
            tmp1 = light;
            tmp2 = shadow2;
        }

        g.DrawLine(new Pen(tmp1),pos, new Point(pos.X+btn_width-1,pos.Y));
        g.DrawLine(new Pen(tmp1),pos, new Point(pos.X,pos.Y+btn_height-1));

        if(pressed) {
            g.DrawLine(new Pen(shadow1),pos.X+1, pos.Y+1, pos.X+btn_width-2, pos.Y+1);
            g.DrawLine(new Pen(shadow1),pos.X+1, pos.Y+1, pos.X+1, pos.Y+btn_height-2);
        } else {
            g.DrawLine(new Pen(shadow1),pos.X+btn_width-2, pos.Y+1, pos.X+btn_width-2, pos.Y+btn_height-2);
            g.DrawLine(new Pen(shadow1),pos.X+1, pos.Y+btn_height-2, pos.X+btn_width-2, pos.Y+btn_height-2);
        }

        g.DrawLine(new Pen(tmp2),pos.X+btn_width-1, pos.Y+0, pos.X+btn_width-1, pos.Y+btn_height-1);
        g.DrawLine(new Pen(tmp2),pos.X+0, pos.Y+btn_height-1, pos.X+btn_width-1, pos.Y+btn_height-1);

        g.FillRectangle(new SolidBrush(background),pos.X+1+Convert.ToInt32(pressed), pos.Y+1+Convert.ToInt32(pressed), btn_width-3,btn_height-3);


        #region Added Code
        g.FillRectangle(new SolidBrush(icon),pos.X+(float)0.5625*btn_width+Convert.ToInt32(pressed),pos.Y+(float)0.6428*btn_height+Convert.ToInt32(pressed),btn_width*(float)0.1875,btn_height*(float)0.143);
        g.DrawImage(Image.FromFile("red_Pushpin.jfif"),new Rectangle( pos,new Size(btn_width,btn_height)));
        #endregion
    }
    #endregion

}
}

Этокод для основного

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
}

Это скриншот winform. enter image description here

РЕДАКТИРОВАТЬ: При расследовании я обнаружил, что WM_LBUTTONUP (левая кнопка мыши вверх) не срабатывает. Или это не происходит внутри WndProc.

EDIT1: Кажется, была проблема в скобках. Я изменил условия if в случай переключения. Это несколько прояснило проблему «мыши левой кнопкой вверх». Теперь это правильно срабатывает. Оставшаяся проблема - точки мыши на основе родительской формы.

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