1

I would like to design a chess board and drag over pieces (shown in pictureBox Controls) all child of the main board (pictureBox1). Problem I encounter is the transparency is only set to the Parent pictureBox1. Which shows this effect: The square is showing. enter image description here

 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;
        }
    }

What would be a good way to go about it?

DarkWarrior
  • 114
  • 1
  • 11
  • You can draw the pieces by calling `Graphics.DrawImage` rather than using a `PictureBox`. – jtxkopt Dec 17 '22 at 12:03
  • This is asked quite often, but: This will not work well as you will want to have the transparency work with board and other pieces. Drawing them yourself will actually be easier. Just make sure to draw the moving piece last! – TaW Dec 17 '22 at 15:00
  • But the user can move any pieces, Should I redraw the piece every time he select one? – DarkWarrior Dec 17 '22 at 17:02
  • I drew the images using Graphics.DrawImage like this: Graphics g = this.CreateGraphics(); Image New_Piece = Image.FromFile("images\\WB.png"); g.DrawImage(New_Piece, 50, 50); but this image object doesn't have any event, such as Click , MouseMove, MouseUp etc ... Possible to Drag it without having any event linked to it? – DarkWarrior Dec 17 '22 at 17:26
  • True, things drawn with `DrawImage` won't have events. You'd have to do hit testing and track mouse state, etc. Another option is to create a `Region` from a `GraphicsPath` in the shape of the chess piece, which would make the PictureBox non-rectangular, allowing the things around the chess piece to be seen as you drag it around. – Idle_Mind Dec 19 '22 at 22:41
  • You can use either of these ideas: [How to make two transparent layer with c#](https://stackoverflow.com/a/36102074/3110834) or [How to drag and move shapes in C#](https://stackoverflow.com/a/38749134/3110834), or similar posts. – Reza Aghaei Dec 21 '22 at 19:46
  • FWIW, this project claims to implement "The sexiest Drag&Drop for WinForms on this planet." https://github.com/awaescher/FluentDragDrop (I guess it supports transparency but I've not checked) – Simon Mourier Dec 22 '22 at 08:52
  • Can you post a link to download images for the board and one chess piece? – Idle_Mind Dec 22 '22 at 14:55
  • here I uploaded the pieces and board png format : www.bunny-poker.com/files/pieces.zip – DarkWarrior Dec 22 '22 at 21:09

4 Answers4

1

Here's an example that makes the PictureBox Non-Rectangular. The PB will literally not exist where the transparent areas were:

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;
        }

    }

}

Example run:

enter image description here

Idle_Mind
  • 38,363
  • 3
  • 29
  • 40
1

There are several solutions for this problem. The one in the following screen recording, is based on drawing png images as movable shapes; it uses the idea that I've explained in How to drag and move shapes in C#. Basically there's only one control -the drawing surface, and all the other stuff are movable drawings.

  • You can use any image for the pieces by passing an Image to the ImageShape
  • You can modify the size of the Pieces by setting Height of the shape
  • It supports snapping to the grid
  • You can customize the texture, easily by setting the BackgroundImage of the drawing surface
  • You can change the grid size, by setting GridSize property of the drawing surface
  • You can change the Color of White and Grid grids, by assigning the color to WhiteColor and BlackColor

It's of course a quick example showing how to draw movable objects, including png images keeping their transparency. You know how to improve it :)

enter image description here

Drawing and moving shapes - Chess pieces

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);
    }
}

To add pieces:

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) });
}
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • The image that I used as background is downloaded from [here](https://img.freepik.com/free-photo/wooden-wood-backgrounds-textured-pattern-wallpaper-concept_53876-14103.jpg?w=800); as you can see it's just texture, not the grid, I've drawn the grid on top of it in the code. The pieces images are downloaded from [here](https://commons.wikimedia.org/wiki/Category:SVG_chess_pieces); just click on any image, and when the large image opened, right click and save. – Reza Aghaei Dec 22 '22 at 23:11
0

I did something similar, but I did not use Drag & Drop events

On MouseDown I assumed a drag operation started, I've opened a translucent unfocused window on top of the drop area, and started drawing dragged image on that form. Since the form is translucent it can show images with transparency on top of everything. I did not use images, but instead draw rectangles where users could drop. If my memory serves me correct, MouseMove events are forwarded to the dragged component, the original chess piece in your case, or the opened but unfocused form, so I can easily track the location. On MouseUp event I wrapped everything.

Since you can draw the image on the new form you can tilt image chess piece image to the left or right for a nice touch.

I developed a very strict forms designer application using this technique.

Erdogan Kurtur
  • 3,630
  • 21
  • 39
0

You can use the panel instead of using the pictureBox and display the image in the background of the controls. Remember that your images must be "png" and the surrounding of the image must be completely transparent. Also, the background color of the controls of the panels Set by events so that it becomes transparent during drag and returns to the cell color after drag and drop. Good luck.

aria
  • 1