我正在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而不是什么都不做......
看起来像这样:
道歉我的坏英语。
更新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;
}
}
}
}
再次提前致谢:)
答案 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()
。PlusArea
或MinusArea
(不知道如何更好地调用它们,这是片状连接器的额外或缺失区域),这是简化,你可以改进它。答案 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;
}
}
道歉重复和困惑的代码,但正如我所说,我已经在几秒钟前完成了,并且还没有清理代码;)