将鼠标放在两块拼图之间

时间:2014-05-13 12:20:20

标签: c# winforms mousedown

我正在winforms中构建一个益智游戏,我想识别任何一块上的mousedown,并用鼠标移动它。 问题在于,当我触摸拼图的透明部分时,我想验证那个拼图后面是否有任何一块,如果有,那么开始另一块的鼠标移动,得到它?

我也能够识别出mousedown是否在图像上方,或者它是否发生在拼图的透明部分。我的问题是获得将鼠标事件传递给后面部分的最佳方法。

非常感谢提前。

更新1

以下是拼图的课程:

class Peça : DrawingArea
{
    private Point _Offset = Point.Empty;
    public Image imagem
    {
        get;
        set;
    }


    protected override void OnDraw()
    {
        Rectangle location = new Rectangle(0, 0, imagem.Width, imagem.Height);
        this.graphics.DrawImage(imagem, location);
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        if (_Offset != Point.Empty)
        {
            Point newlocation = this.Location;
            newlocation.X += e.X - _Offset.X;
            newlocation.Y += e.Y - _Offset.Y;
            this.Location = newlocation;
        }
    }

    protected override void OnMouseUp(MouseEventArgs e)
    {
        _Offset = Point.Empty;
    }

    protected override void OnMouseDown(MouseEventArgs e)
    {
        Down(e);
        //Console.WriteLine(color.ToString());
    }

    public void Down(MouseEventArgs e)
    {
        Bitmap b = new Bitmap(imagem);
        Color? color = null;
        try
        {
            color = b.GetPixel(e.X, e.Y);
            if (color.Value.A != 0 && color != null)
            {
                if (e.Button == MouseButtons.Left)
                {
                    _Offset = new Point(e.X, e.Y);
                    this.BringToFront();
                }
            }
        }
        catch {
             }
    }
} 

以下代码是我创建的DrawingArea(Panel),以便使用透明度:

abstract public class DrawingArea : Panel
{
    protected Graphics graphics;
    abstract protected void OnDraw();

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ExStyle |= 0x00000020; //WS_EX_TRANSPARENT

            return cp;
        }
    }

    public DrawingArea()
    {

    }

    protected override void OnPaintBackground(PaintEventArgs pevent)
    {

    }

    protected override void OnPaint(PaintEventArgs e)
    {

        this.graphics = e.Graphics;


        this.graphics.TextRenderingHint =
            System.Drawing.Text.TextRenderingHint.AntiAlias;
        this.graphics.InterpolationMode =
            System.Drawing.Drawing2D.InterpolationMode.HighQualityBilinear;
        this.graphics.PixelOffsetMode =
            System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
        this.graphics.SmoothingMode =
            System.Drawing.Drawing2D.SmoothingMode.HighQuality;


        OnDraw();
    } 
}

您还可以看到我的表单代码:

 public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true);
    }

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams handleParam = base.CreateParams;
            handleParam.ExStyle |= 0x02000000;       
            return handleParam;
        }
    }
}

这些是我的作品,当我触摸第一块中的透明空间时,我想拿起第二块并将它移到mouseMouse而不是什么都不做......

看起来像这样:

enter image description here

道歉我的坏英语。

更新2

我想我已经非常接近解决方案了,但现在发生了一些奇怪的事情,当我触摸另一个背后的一块时,它就消失了...... 我究竟做错了什么?

某些代码更新

Piece Class:

class Peça : DrawingArea
{
    private Point _Offset = Point.Empty;
    public Boolean movable = false;
    public Image imagem
    {
        get;
        set;
    }

    protected override void OnDraw()
    {
        Rectangle location = new Rectangle(0, 0, imagem.Width, imagem.Height);
        this.graphics.DrawImage(imagem, location);
    }

    public void Move(MouseEventArgs e)
    {
        if (_Offset != Point.Empty)
        {
            Point newlocation = this.Location;
            newlocation.X += e.X - _Offset.X;
            newlocation.Y += e.Y - _Offset.Y;
            this.Location = newlocation;
        }
    }

    protected override void OnMouseUp(MouseEventArgs e)
    {
        _Offset = Point.Empty;
        movable = false;
    }

    protected override void OnMouseDown(MouseEventArgs e)
    {
        Down(e);
        //Console.WriteLine(color.ToString());
    }

    public Boolean Down(MouseEventArgs e, bool propaga=true)
    {
        Form parentForm = (this.Parent as Form);
        Bitmap b = new Bitmap(imagem);
        Color? color = null;
        Boolean flag = false;
        try
        {
            color = b.GetPixel(e.X, e.Y);
            if (color.Value.A != 0 && color != null)
            {
                if (e.Button == MouseButtons.Left)
                {
                    _Offset = new Point(e.X, e.Y);
                    this.BringToFront();
                    flag = true;
                    movable = true;
                }
            }
            else
            {
                if(propaga)
                (this.Parent as Form1).propagaEvento(this, e);
                flag = false;

            }
            return flag; 
        }
        catch {
            return flag; }
    }
}

Form1中:

public partial class Form1 : Form
{
    private List<Peça> peças;
    private Point _Offset = Point.Empty;
    public Form1()
    {
        InitializeComponent();

        peças = new List<Peça>();
        SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true);
        criaListaPecas();
        associaEventosPecas();      
    }

    private void associaEventosPecas()
    {
        foreach (Peça p in peças)
        {
            p.MouseMove += Form1_MouseMove;
        }
    }

    private void criaListaPecas()
    {
        peças.Clear();
        foreach (Control p in this.Controls)
        {
            if (p.GetType() == typeof(Peça))
                peças.Add((Peça)p);
        }
        Console.WriteLine(peças[0].Name);
        Console.WriteLine(peças[1].Name);
        Console.WriteLine(peças[2].Name);
    }

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams handleParam = base.CreateParams;
            handleParam.ExStyle |= 0x02000000;       
            return handleParam;
        }
    }

    private void Form1_MouseMove(object sender, MouseEventArgs e)
    {
        label1.Text = e.Location.ToString();
        gereMovimento(e);
    }

    private void gereMovimento(MouseEventArgs e)
    {
        foreach (Peça p in peças)
        {
            if (p.movable)
            {
                p.Move(e);
            }
        }
    }

    internal void propagaEvento(Peça peça, MouseEventArgs e)
    {
        foreach (Peça p in peças)
        {
            if (p != peça)
            {
                if (p.Down(e, false))
                    break;
            }
        }
    }
}

再次提前致谢:)

3 个答案:

答案 0 :(得分:0)

一般情况下,保留所有拼图控件的列表,自上而下排序。当您在一个部件上获得鼠标按下事件时,检查该点的透明度,如果它不透明处理该部件上的事件。如果它是透明的,则将事件转发到列表中的下一个部分(直接调用事件处理程序可能是最简单的方法)。继续这样做,直到你找到一个不透明的点,或者用完一块。

UPDATE 这是一个项目的链接,显示了如何在纯GDI中执行此操作的示例。 https://drive.google.com/file/d/0B42fIyGTLNv3WlJwNGVRN2txTGs/edit?usp=sharing

答案 1 :(得分:0)

作品可以表示为:

public class Piece
{
    public Point Location {get; set;}
    public int Z {get; set;}
    public int ID {get; set;} // to be bound to control or a control itself?
    public Image Image {get; set;} // texture?
    public DockStyle PlusArea {get; set;}
    public DockStyle MinusArea {get; set;}  // can be None
    ...

    public bool HitTest(Point point)
    {
        // assuming all of same size
        if((new Rectangle(Location, new Size(...)).Contains(point))
        {
            switch(MinusArea)
            {
                case Top:
                    if((new Rectangle(...)).Contains(point))
                        return false;
                ...
            }
        }
        switch(MinusArea)
        {
            case Top:
                if((new Rectangle(...)).Contains(point))
                    return true;
            ...
        }
        return false;
    }

然后拼图是

public class Puzzle
{
    public List<Piece> Pieces {get; set;}

    public void Draw(Graphics graphics)
    {
        // draw all pictures with respect to z order
    }

    public Piece HitTest(Point point)
    {
        ... // hittest all pieces, return highest z-order or null
    }
}

这不是一个完整的解决方案,但应该给你一个想法。

基本上:

  • 在鼠标事件中,您致电Figure.HitTest()以获得开始移动的数字(这就是您所需要的)。
  • 您可以通过调用Figure.Draw()将所有内容绘制为所有者绘制的控件。
  • 显然,拖放操作正在调用Invalidate()
  • 你可能有一个特殊的标志来表示被拖动的图形并以不同的方式绘制它(有阴影,有点偏移以模拟它被拉过其他部分等)。
  • 每个图形都表示为矩形和PlusAreaMinusArea(不知道如何更好地调用它们,这是片状连接器的额外或缺失区域),这是简化,你可以改进它。

答案 2 :(得分:0)

已解决:)

我已经弄清楚了...... 这是任何人需要的代码 (我现在已经做好了,所以代码还不干净):

Piece Class:

class Peça : DrawingArea
{
    private Point _Offset = Point.Empty;
    public Boolean movable = false;

    public Image imagem
    {
        get;
        set;
    }

    protected override void OnDraw()
    {
        Rectangle location = new Rectangle(0, 0, imagem.Width, imagem.Height);
        this.graphics.DrawImage(imagem, location);
    }

    public Boolean Down(Point e, bool propaga = true)
    {
        Bitmap b = new Bitmap(imagem);
        Color? color = null;
        Boolean flag = false;
        try
        {
            color = b.GetPixel(e.X, e.Y);
            if (color.Value.A != 0 && color != null)
            {
               flag = true;
            }
            else
            {
                flag = false;
            }
            return flag;
        }
        catch
        {
            return flag;
        }
    }
}

<强> Form1中:

public partial class Form1 : Form
{
    private List<Peça> peças;
    private Point _Offset = Point.Empty;
    private Peça peça1, peça2, peça3, peça4;
    private bool canMove;
    private Peça atual;
    private bool other=false;
    public Form1()
    {
        FormBorderStyle = FormBorderStyle.None;
        WindowState = FormWindowState.Maximized;
        InitializeComponent();

        atual = new Peça();

        peça1 = new Peça();
        peça2 = new Peça();
        peça3 = new Peça();
        peça4 = new Peça();
        peça1.imagem = Properties.Resources._4p1_1;
        peça2.imagem = Properties.Resources._4p1_2;
        peça3.imagem = Properties.Resources._4p1_3;
        peça4.imagem = Properties.Resources._4p1_4;

        peças = new List<Peça>();

        peça1.Name = "peça1";
        peça2.Name = "peça2";
        peça3.Name = "peça3";
        peça4.Name = "peça4";

        this.Controls.Add(peça1);
        this.Controls.Add(peça2);
        this.Controls.Add(peça3);
        this.Controls.Add(peça4);

        criaListaPecas();

        foreach (Peça p in peças)
        {
            p.Size = new Size(p.imagem.Width, p.imagem.Height);
        }

        SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint, true);

        associaEventosPecas();
        canMove = false;
    }

    private void associaEventosPecas()
    {
        foreach (Peça p in peças)
        {
            p.MouseMove += Form1_MouseMove;
            p.MouseDown += Form1_MouseDown;
            p.MouseUp += Form1_MouseUp;
        }
    }

    private void criaListaPecas()
    {
        peças.Clear();
        foreach (Control p in this.Controls)
        {
            if (p.GetType() == typeof(Peça))
                peças.Add((Peça)p);
        }
        Console.WriteLine(peças[0].Name);
        Console.WriteLine(peças[1].Name);
        Console.WriteLine(peças[2].Name);
        Console.WriteLine(peças[3].Name);
    }

    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams handleParam = base.CreateParams;
            handleParam.ExStyle |= 0x02000000;
            return handleParam;
        }
    }

    private void Form1_MouseMove(object sender, MouseEventArgs e)
    {
        if (sender.GetType().Equals(typeof(Peça)))
        {
            label1.Text = new Point(e.Location.X + (sender as Peça).Location.X, e.Location.Y + (sender as Peça).Location.Y).ToString();
        }
        else
        label1.Text = e.Location.ToString();
        gereMovimento(sender, e);
    }

    private void gereMovimento(object sender, MouseEventArgs e)
    {
        if (canMove)
        {
            if (other)
            {
                Point p = atual.PointToClient(new Point(e.X + (sender as Peça).Location.X, e.Y + (sender as Peça).Location.Y));

                Point newlocation = atual.Location;
                newlocation.X += p.X - _Offset.X;
                newlocation.Y += p.Y - _Offset.Y;
                atual.Location = newlocation;
            }
            else
            {
                Point newlocation = atual.Location;
                newlocation.X += e.X - _Offset.X;
                newlocation.Y += e.Y - _Offset.Y;
                atual.Location = newlocation;
            }
        }
    }

    private void Form1_MouseDown(object sender, MouseEventArgs e)
    {
        if (sender.GetType().Equals(typeof(Peça)) && e.Button == MouseButtons.Left)
        {
            atual = sender as Peça;
            atual.BringToFront();
            criaListaPecas();
            if (atual.Down(e.Location))
            {
                _Offset = new Point(e.X, e.Y);
                canMove = true;
                other = false;
            }
            else
            {
                Console.WriteLine(peças[1].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y)));
                Console.WriteLine(atual.Location);
                Point p = new Point(); 
                if (peças[1].ClientRectangle.Contains(peças[1].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y)))
                    && peças[1].Down(peças[1].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y))))
                {
                    p = peças[1].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y));
                    atual = peças[1];
                    atual.BringToFront();
                    criaListaPecas();
                    _Offset = p;
                    canMove = true;
                    other = true;
                }
                else if (peças[2].ClientRectangle.Contains(peças[2].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y)))
                    && peças[2].Down(peças[2].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y))))
                {
                    p = peças[2].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y));
                    atual = peças[2];
                    atual.BringToFront();
                    criaListaPecas();
                    _Offset = p;
                    canMove = true;
                    other = true;
                }
                else if (peças[3].ClientRectangle.Contains(peças[3].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y)))
                    && peças[3].Down(peças[3].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y))))
                {
                    p = peças[3].PointToClient(new Point(e.X + atual.Location.X, e.Y + atual.Location.Y));
                    atual = peças[3];
                    atual.BringToFront();
                    criaListaPecas();
                    _Offset = p;
                    canMove = true;
                    other = true;
                }
            }
        }
    }

    private void Form1_MouseUp(object sender, MouseEventArgs e)
    {
        canMove = false;
    }
}

道歉重复和困惑的代码,但正如我所说,我已经在几秒钟前完成了,并且还没有清理代码;)