鼠标放在两块拼图之间

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

我也能够识别出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 += eX - _Offset.X; newlocation.Y += eY - _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(eX, eY); if (color.Value.A != 0 && color != null) { if (e.Button == MouseButtons.Left) { _Offset = new Point(eX, eY); 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而不是什么都不做……

它看起来像这样:

在此处输入图像描述

道歉我的坏英语。

更新2

我觉得我已经非常接近解决方案了,但是现在发生了一些奇怪的事情,当我触摸另一个后面的一块时,它消失了……我做错了什么?

一些代码更新

件类:

 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 += eX - _Offset.X; newlocation.Y += eY - _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(eX, eY); if (color.Value.A != 0 && color != null) { if (e.Button == MouseButtons.Left) { _Offset = new Point(eX, eY); 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ças; private Point _Offset = Point.Empty; public Form1() { InitializeComponent(); peças = new List(); 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; } } } } 

再次提前感谢:)

件可以表示为:

 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 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 (不知道如何更好地调用它们,这是片状连接器的额外或缺失区域),这是简化,您可以改进它。

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

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

已解决 🙂

我已经弄明白了…这里的代码是任何人的需求(我现在已经做到了,所以代码还不干净):

件类:

 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(eX, eY); 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ç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ç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(eX + (sender as Peça).Location.X, eY + (sender as Peça).Location.Y)); Point newlocation = atual.Location; newlocation.X += pX - _Offset.X; newlocation.Y += pY - _Offset.Y; atual.Location = newlocation; } else { Point newlocation = atual.Location; newlocation.X += eX - _Offset.X; newlocation.Y += eY - _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(eX, eY); canMove = true; other = false; } else { Console.WriteLine(peças[1].PointToClient(new Point(eX + atual.Location.X, eY + atual.Location.Y))); Console.WriteLine(atual.Location); Point p = new Point(); if (peças[1].ClientRectangle.Contains(peças[1].PointToClient(new Point(eX + atual.Location.X, eY + atual.Location.Y))) && peças[1].Down(peças[1].PointToClient(new Point(eX + atual.Location.X, eY + atual.Location.Y)))) { p = peças[1].PointToClient(new Point(eX + atual.Location.X, eY + 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(eX + atual.Location.X, eY + atual.Location.Y))) && peças[2].Down(peças[2].PointToClient(new Point(eX + atual.Location.X, eY + atual.Location.Y)))) { p = peças[2].PointToClient(new Point(eX + atual.Location.X, eY + 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(eX + atual.Location.X, eY + atual.Location.Y))) && peças[3].Down(peças[3].PointToClient(new Point(eX + atual.Location.X, eY + atual.Location.Y)))) { p = peças[3].PointToClient(new Point(eX + atual.Location.X, eY + 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; } } 

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