winforms 将“在图片框上拖动”拖到其他具有透明度的图片框上

cmssoen2  于 2022-12-23  发布在  其他
关注(0)|答案(4)|浏览(135)

我想设计一个国际象棋棋盘,并拖动棋子(如pictureBox控件所示)主板(pictureBox1)的所有子级。我遇到的问题是透明度仅设置为父pictureBox1。这显示了以下效果:正方形显示.

private void CommonPiece_Mouse_Move(object sender, MouseEventArgs e)
    {
        if (Piece_Selected)
        {
            int MousePositionX = pictureBox1.PointToClient(Cursor.Position).X;
            int MousePositionY = pictureBox1.PointToClient(Cursor.Position).Y;

            (sender as PictureBox).Left = MousePositionX - 35;
            (sender as PictureBox).Top = MousePositionY - 25;
        }
    }

什么是一个好的方法去做呢?

mpbci0fu

mpbci0fu1#

这个问题有几种解决方案。下面的屏幕记录中的一种,是基于将png图像绘制为可移动的形状;它使用了我在How to drag and move shapes in C#中解释过的概念。基本上只有一个控件-绘图表面,所有其他的东西都是可移动的绘图。

  • 通过将Image传递给ImageShape,可以将任何图像用于片段
  • 您可以通过设置形状的高度来修改块的大小
  • 支持捕捉到格网
  • 您可以通过设置绘图图面的BackgroundImage轻松地自定义纹理
  • 通过设置绘图图面的GridSize属性,可以更改网格大小
  • 通过将颜色分配给WhiteColor和BlackColor,可以更改白色和格网的颜色

当然,这是一个展示如何绘制可移动对象的快速例子,包括保持透明的png图像。你知道如何改进它:)

绘制和移动形状-棋子

using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Linq;
using System.Windows.Forms;

public interface IShape
{
    bool HitTest(Point p);
    void Draw(Graphics g);
    void Move(int dx, int dy);
    Point Location { get; set; }
}

public class ImageShape : IShape
{
    public int Height { get; set; } = 100;
    public Point Location { get; set; }
    private Image _image;
    public ImageShape(Image image)
    {
        _image = image;
    }
    public void Draw(Graphics g)
    {
        var r = new Rectangle(Location, new Size(Height, Height));
        r.Inflate(-5, -5);
        g.DrawImage(_image, r);
    }
    public bool HitTest(Point p)
    {
        return new Rectangle(Location, new Size(Height, Height)).Contains(p);
    }
    public void Move(int dx, int dy)
    {
        Location = new Point(Location.X + dx, Location.Y + dy);
    }
}
public class DrawingSurface : Control
{
    public List<IShape> Shapes { get; private set; }
    public int GridSize { get; set; } = 100;
    public Color WhiteColor = Color.FromArgb(200, Color.White);
    public Color BlackColor = Color.FromArgb(120, Color.Black);
    IShape selectedShape;
    bool moving;
    Point previousPoint = Point.Empty;
    public DrawingSurface()
    {
        DoubleBuffered = true;
        ResizeRedraw = true;
        Shapes = new List<IShape>();
    }
    protected override void OnMouseDown(MouseEventArgs e)
    {
        for (var i = Shapes.Count - 1; i >= 0; i--)
            if (Shapes[i].HitTest(e.Location))
            {
                selectedShape = Shapes[i];
                break;
            }
        if (selectedShape != null)
        {
            moving = true;
            previousPoint = e.Location;
            Invalidate();
        }
        base.OnMouseDown(e);
    }
    protected override void OnMouseMove(MouseEventArgs e)
    {
        if (moving)
        {
            var dx = e.X - previousPoint.X;
            var dy = e.Y - previousPoint.Y;
            selectedShape.Move(dx, dy);
            previousPoint = e.Location;
            this.Invalidate();
        }
        base.OnMouseMove(e);
    }
    protected override void OnMouseUp(MouseEventArgs e)
    {
        if (moving)
        {
            int i = (e.X / GridSize) * GridSize;
            int j = (e.Y / GridSize) * GridSize;
            selectedShape.Location = new Point(i, j);
            selectedShape = null;
            moving = false;
            this.Invalidate();
        }
        base.OnMouseUp(e);
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        var g = e.Graphics;
        g.InterpolationMode = InterpolationMode.High;
        g.SmoothingMode = SmoothingMode.HighQuality;
        g.TextRenderingHint = TextRenderingHint.AntiAliasGridFit;
        g.CompositingQuality = CompositingQuality.HighQuality;
        foreach (var shape in Shapes.Except(new[] { selectedShape }))
            shape.Draw(g);
        if (selectedShape != null)
            selectedShape.Draw(g);
    }
    protected override void OnPaintBackground(PaintEventArgs e)
    {
        base.OnPaintBackground(e);
        var g = e.Graphics;
        using (var w = new SolidBrush(WhiteColor))
        using (var b = new SolidBrush(BlackColor))
            for (int i = 0; i < 8; i++)
                for (int j = 0; j < 8; j++)
                    g.FillRectangle((i + j) % 2 == 0 ? b : w, 
                        i * GridSize, j * GridSize, GridSize, GridSize);
    }
}

要添加片段:

private void Form1_Load(object sender, EventArgs e)

{
    this.drawingSurface1.Shapes.Add(new ImageShape(
        Properties.Resources.KingWhite) { Location = new Point(0, 0) });
    this.drawingSurface1.Shapes.Add(
        new ImageShape(Properties.Resources.kingBlack) { Location = new Point(0, 100) });
}
nkcskrwz

nkcskrwz2#

下面是一个使PictureBox非矩形化的例子。PB实际上将不存在于透明区域所在的位置:

using System.Runtime.InteropServices;
namespace CS_Scratch_WindowsFormsApp2
{

    public partial class Form1 : Form
    {

        public const int HT_CAPTION = 0x2;
        public const int WM_NCLBUTTONDOWN = 0xA1;

        [System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
        public static extern bool ReleaseCapture();
        [System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);
        
        public Form1()
        {
            InitializeComponent();
            pbChessPiece.MouseMove += PbChessPiece_MouseMove;
        }

        private void PbChessPiece_MouseMove(object sender, MouseEventArgs e)
        {
            PictureBox pb = (PictureBox)sender;
            if (!DesignMode && e.Button == MouseButtons.Left)
            {
                ReleaseCapture();
                SendMessage(pb.Handle, WM_NCLBUTTONDOWN, HT_CAPTION, 0);
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Bitmap bmp = (Bitmap)pbChessPiece.Image;
            Region rgn = new Region();
            rgn.Union(new Rectangle(0, 0, bmp.Width, bmp.Height));
            for(int x=0; x<bmp.Width; x++)
            {
                for(int y=0; y<bmp.Height; y++)
                {
                    if (bmp.GetPixel(x, y).A == 0)
                    {
                        rgn.Exclude(new Rectangle(x, y, 1, 1));
                    }
                }
            }
            pbChessPiece.Region = rgn;
        }

    }

}

运行示例:

jtjikinw

jtjikinw3#

我做了类似的操作,但没有使用拖放事件
在MouseDown上,我假设拖动操作已经开始,我已经在拖放区域的顶部打开了一个半透明的无焦点窗口,并开始在该窗体上绘制拖动的图像。由于窗体是半透明的,它可以在所有内容的顶部显示透明的图像。我没有使用图像,而是在用户可以拖放的地方绘制了矩形。如果我没有记错的话,MouseMove事件将转发到拖动组件。在你的例子中,原始的棋子,或者打开但是没有聚焦的窗体,这样我就可以很容易地跟踪位置。
由于您可以在新的窗体上绘制图像,因此您可以向左或向右倾斜图像棋子图像,以获得良好的触感。
我使用这种技术开发了一个非常严格的窗体设计器应用程序。

sr4lhrrt

sr4lhrrt4#

您可以使用面板而不是pictureBox,并在控件的背景中显示图像。请记住,您的图像必须是“png”,并且图像的周围必须完全透明。此外,面板控件的背景颜色由事件设置,以便在拖动过程中变为透明,并在拖放后恢复为单元格颜色。祝您好运。

相关问题