winforms 将图像放置在UserControl的顶部

nafvub8i  于 2023-10-23  发布在  其他
关注(0)|答案(2)|浏览(105)

我有一个非常简单的winforms项目。它有一个主窗体和一个用户控件。
UserControl由一个面板和一个按钮组成。
我想在UserControl的顶部放置一个图像。任何图像都可以。
问题是图像显示在用户控件的下面,而不是用户控件的顶部(属于用户控件的按钮的顶部)。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace DragImageOnUserControl
{
    public partial class Form1 : Form
    {
        private string _directoryContainingThePieces;
        private string _imageFileName;
        private Image _image;

        public Form1()
        {
            InitializeComponent();

            this.ClientSize = new Size(1000, 800);
            this.BackColor = Color.Bisque;

            _directoryContainingThePieces = @"g:\Programming\Chess\ChessboardWithPieces\Chess Pieces\";
            _imageFileName = "White King.PNG";
            _image = Image.FromFile(_directoryContainingThePieces + _imageFileName);

            UserControl_PanelAndButton panelAndButton = new UserControl_PanelAndButton();
            panelAndButton.Location = new Point(50, 50);
            panelAndButton.ImageToDisplay = _image; // Set the image after initializing _image.
            this.Controls.Add(panelAndButton);
        }
    }
}

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace DragImageOnUserControl
{
    public partial class UserControl_PanelAndButton : UserControl
    {
        public UserControl_PanelAndButton()
        {
            InitializeComponent();

            _panel1 = new Panel();
            _panel1.Location = new Point(20, 20);
            _panel1.Size = new Size(500, 500);
            _panel1.BackColor = Color.Cyan;
            _panel1.Parent = this; // Set the panel's parent to the user control
            _panel1.SendToBack(); // Send the panel to back.

            _button1 = new Button();
            _button1.Location = new Point(200, 200);
            _button1.Size = new Size(75, 75);
            _button1.BackColor = Color.Orchid;
            _panel1.Controls.Add(_button1); // Add the button to the panel
            _button1.SendToBack(); // Send the button to back.
        }

        private Panel _panel1;
        private Button _button1;

        private Image _imageToDisplay;
        public Image ImageToDisplay
        {
            get { return _imageToDisplay; }
            set 
            { 
                _imageToDisplay = value;
                Refresh(); // Force a redraw when the image changes.
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            // Draw the image.
            if (_imageToDisplay != null)
            {
                int x = Math.Max(0, (Width - _imageToDisplay.Width) / 2); // Center the image horizontally.
                int y = Math.Max(0, (Height - _imageToDisplay.Height) / 2); // Center the image vertically.

                e.Graphics.DrawImage(_imageToDisplay, new Point(x, y));
            }
        }
    }
}

这是整个代码。
我还有一个非常类似的项目。它有一个主窗体,而不是UserControl,它有一个面板。
我使用相同的图像,图像显示在面板的顶部。我甚至可以在面板的边界内拖动它。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace DragImageOnForm
{
    public partial class Form1 : Form
    {
        private Panel _panel1;
        private string _directoryContainingThePieces;
        private string _imageFileName;
        private Image _image;
        private Point _imageLocation;
        private Point _dragOffset;
        private bool _isDragging;
        private Rectangle _previousImageRect;

        public Form1()
        {
            InitializeComponent();

            this.ClientSize = new Size(1000, 800);
            this.BackColor = Color.Bisque;

            _panel1 = new Panel();
            _panel1.Location = new Point(200, 200);
            _panel1.Size = new Size(500, 500);
            _panel1.BackColor = Color.Violet;

            _panel1.MouseDown += Panel1_MouseDown;
            _panel1.MouseMove += Panel1_MouseMove;
            _panel1.MouseUp += Panel1_MouseUp;
            _panel1.Paint += Panel1_Paint; // Attach the paint event handler.

            this.Controls.Add(_panel1);

            _directoryContainingThePieces = @"g:\Programming\Chess\ChessboardWithPieces\Chess Pieces\";
            _imageFileName = "White King.PNG";
            _image = Image.FromFile(_directoryContainingThePieces + _imageFileName);
            _imageLocation = new Point(100, 100); // Initial position.
            _isDragging = false;

            // Initialize previousImageRect with initial image location and size.
            _previousImageRect = new Rectangle(_imageLocation, _image. Size);
        }

        private void Panel1_Paint(object sender, PaintEventArgs e)
        {
            // Draw the image at the current location on the panel.
            e.Graphics.DrawImage(_image, _imageLocation);
        }

        private void Panel1_MouseDown(object sender, MouseEventArgs e)
        {
            // Check if the mouse click is within the image's bounds.
            Rectangle imageRect = new Rectangle(_imageLocation, _image. Size);
            if (imageRect.Contains(e.Location))
            {
                _isDragging = true;
                _dragOffset = new Point(e.X - _imageLocation.X, e.Y - _imageLocation.Y);
            }
        }

        private void Panel1_MouseMove(object sender, MouseEventArgs e)
        {
            if (_isDragging)
            {
                // Update the image's location based on the mouse position.
                _imageLocation = new Point(e.X - _dragOffset.X, e.Y - _dragOffset.Y);

                // Calculate the union of the previous and current image rectangles
                // and invalidate only that region to minimize redraw.
                Rectangle newImageRect = new Rectangle(_imageLocation, _image.Size);
                Rectangle updateRect = Rectangle.Union(_previousImageRect, newImageRect);

                // Invalidate to update rectangle.
                _panel1.Invalidate(updateRect);

                // Update previous image rectangle.
                _previousImageRect = newImageRect;
            }
        }

        private void Panel1_MouseUp(object sender, MouseEventArgs e)
        {
            _isDragging = false;
        }
    }
}

这个项目运作良好。唯一的区别是,在这里它是一个面板的图像是在顶部。
在具有UserControl的项目中,图像应显示在UserControl的顶部而不是其下方。
任何帮助将不胜感激。
我更改了图像示例的位置,使其超出UserControl的边界。
图像确实存在,但它在UserControl之下。只有超出UserControl边界的图像部分可见。
我需要的图像是在用户控件的顶部(在属于UserControl按钮的顶部),而不是在它下面。

epggiuax

epggiuax1#

根据谜团的答案,我想出了这个程序。
它包含一个由4个边框面板、一个背景PictureBox和一个按钮组成的用户控件。
图像被放置在属于用户控件的按钮的顶部,并且图像还保留其透明背景。由于图像的大小小于按钮的大小,因此按钮在图像的外轮廓(而不是矩形)周围可见。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace DragAndDropIamgeOnUserContol
{
    public partial class UserControl_BorderPanelsBackgroundPictureBoxAndButton : UserControl
    {
        private Panel _panel_Top;
        private Panel _panel_Bottom;
        private Panel _panel_Left;
        private Panel _panel_Right;
        private PictureBox _background;
        private Button _button1;

        public UserControl_BorderPanelsBackgroundPictureBoxAndButton()
        {
            InitializeComponent();

            this. Size = new Size(600, 600);

            _panel_Top = new Panel();
            _panel_Top.Location = new Point(20, 20);
            _panel_Top.Size = new Size(310, 30);
            _panel_Top.BackColor = Color.Blue;
            this.Controls.Add(_panel_Top);

            _panel_Bottom = new Panel();
            _panel_Bottom.Location = new Point(20, 300);
            _panel_Bottom.Size = new Size(310, 30);
            _panel_Bottom.BackColor = Color.Blue;
            this.Controls.Add(_panel_Bottom);

            _panel_Left = new Panel();
            _panel_Left.Location = new Point(20, 20);
            _panel_Left.Size = new Size(30, 310);
            _panel_Left.BackColor = Color.Blue;
            this.Controls.Add(_panel_Left);

            _panel_Right = new Panel();
            _panel_Right.Location = new Point(300, 20);
            _panel_Right.Size = new Size(30, 310);
            _panel_Right.BackColor = Color.Blue;
            this.Controls.Add(_panel_Right);

            _background = new PictureBox();
            _background. Location = new Point(50, 50);
            _background. Size = new Size(250, 251);
            _background.BackColor = Color.Orange;
            this.Controls.Add(_background);

            _button1 = new Button();
            _button1.Size = new Size(100, 100);
            _button1.Location = new Point((_background.ClientSize.Width - _button1.Width) / 2, (_background.ClientSize.Height - _button1.Height) / 2);
            _button1.BackColor = Color.Aquamarine;
            _background.Controls.Add(_button1);
            _button1.SendToBack();
        }
    }
}

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace DragAndDropIamgeOnUserContol
{
    public partial class Form1 : Form
    {
        private UserControl_BorderPanelsBackgroundPictureBoxAndButton borderPanelsBackgroundPictureBoxAndButton;
        private PictureBox _chessPiece;
        private Point _offset;

        public Form1()
        {
            InitializeComponent();

            this.DoubleBuffered = true;
            this.Size = new Size(1000, 800);
            this.BackColor = Color.Bisque;

            borderPanelsBackgroundPictureBoxAndButton = new UserControl_BorderPanelsBackgroundPictureBoxAndButton();
            borderPanelsBackgroundPictureBoxAndButton.Location = new Point(0, 0);
            this.Controls.Add(borderPanelsBackgroundPictureBoxAndButton);

            _chessPiece = new PictureBox();
            _chessPiece.Size = new Size(100, 100);
            _chessPiece.Image = Image.FromFile(@"g:\Programming\Chess\ChessboardWithPieces\Chess Pieces\White King.PNG");
            _chessPiece.BackColor = Color.Transparent;
            _chessPiece.SizeMode = PictureBoxSizeMode.AutoSize;
            _chessPiece.Location = new Point(280, 250);
            _chessPiece.Parent = borderPanelsBackgroundPictureBoxAndButton;
            borderPanelsBackgroundPictureBoxAndButton.Controls.Add(_chessPiece);
            _chessPiece.BringToFront();

            ExcludeTransparentImagePortions();

            _chessPiece.MouseDown += ChessPiece_MouseDown;
            _chessPiece.MouseMove += ChessPiece_MouseMove;
            _chessPiece.MouseUp += ChessPiece_MouseUp;
        }

        /// <summary>
        /// The purpose of the ExcludeTransparentImagePortions method is to create a region that defines which parts of the PictureBox _piece 
        /// are considered "active" or "clickable" and which parts are not. 
        /// This is achieved by excluding regions that correspond to transparent or partially transparent pixels in the image.
        ///     1. Initialization: 
        ///        The method starts by getting the image of the PictureBox _piece as a Bitmap object (pieceBitmap) and initializing a Region object (pieceRegion) 
        ///        that will hold the information about the active and inactive areas of the PictureBox.
        ///     2. Union of Initial Region:
        ///        Initially, the entire area of the PictureBox _piece is added to the pieceRegion using the Union method.
        ///        This effectively sets up the initial state of the region where all pixels in the PictureBox are considered active.
        ///     3. Calculating Exclusion Region: 
        ///        The method then goes through each pixel in the image using nested loops.
        ///        For each pixel, it checks if the alpha channel value of that pixel (indicated by .GetPixel(x, y).A) is equal to 0.
        ///        An alpha value of 255 indicates a fully opaque pixel, while any value less than 255 indicates a transparent or partially transparent pixel.
        ///        An alpha value of 0 indicates a fully transparent pixel.
        ///     4. Excluding Transparent Pixels:
        ///        If the alpha value of the pixel is equal to 0, it means the pixel is fully transparent.
        ///        In this case, the method excludes a small rectangle (typically 1x1 pixel around the pixel whose alpha value is equal to 0) from the pieceRegion.
        ///        This effectively marks the area of 1x1 pixel around the pixel whose alpha value is equal to 0 as inactive or non-clickable.
        ///     5. Applying the Updated Region:
        ///        After processing all pixels, the pieceRegion contains the updated information about which parts of the _piece PictureBox should be considered active 
        ///        and which parts should be inactive.
        ///        The method sets this updated region to the _piece.Region property, which determines the clickable area of the PictureBox.
        ///        
        /// The purpose of this method is to create a precise region that corresponds to the visible area of the image, excluding transparent portions.
        /// </summary>
        private void ExcludeTransparentImagePortions()
        {
            Bitmap chessPieceBitmap = (Bitmap)_chessPiece.Image;
            Region chessPieceRegion = new Region();
            chessPieceRegion.Union(new Rectangle(0, 0, chessPieceBitmap.Width, chessPieceBitmap.Height));

            // Calculate the exclusion region based on transparent pixels.
            for (int x = 0; x < chessPieceBitmap.Width; x++)
            {
                for (int y = 0; y < chessPieceBitmap.Height; y++)
                {
                    if (chessPieceBitmap.GetPixel(x, y).A == 0) // The pixel is fully transparent.
                    {
                        chessPieceRegion.Exclude(new Rectangle(x, y, 1, 1));
                    }
                }
            }
            _chessPiece.Region = chessPieceRegion;
        }

        private void ChessPiece_MouseDown(object sender, MouseEventArgs e)
        {
            _chessPiece = (PictureBox)sender;
            _offset = new Point(e.X, e.Y);
        }

        private void ChessPiece_MouseMove(object sender, MouseEventArgs e)
        {
            PictureBox chessPiece = (PictureBox)sender;
            if (e.Button == MouseButtons.Left)
            {
                chessPiece.Left = e.X + chessPiece.Left - _offset.X;
                chessPiece.Top = e.Y + chessPiece.Top - _offset.Y;
            }
        }

        private void ChessPiece_MouseUp(object sender, MouseEventArgs e)
        {
            PictureBox piece = (PictureBox)sender;
        }
    }
}
plupiseo

plupiseo2#

这是一个Windows窗体应用程序,可以做你想要的。它使用Microsoft Reactive Framework(NuGet System.Reactive.Windows.Forms来获取组件)。

public class DragDropDemo : System.Windows.Forms.Form
{
    private System.Windows.Forms.PictureBox _background = new System.Windows.Forms.PictureBox()
    {
        Size = new System.Drawing.Size(290, 290),
        ImageLocation = @"D:\Projects\Drag-Drop Demo\Painting.jpg",
    };
    
    private System.Windows.Forms.PictureBox[] _pieces = new []
    {
        new System.Windows.Forms.PictureBox() { Size = new System.Drawing.Size(60, 60), ImageLocation = @"D:\Projects\Drag-Drop Demo\Chess_bdt60.png", BackColor = System.Drawing.Color.Transparent, },
        new System.Windows.Forms.PictureBox() { Size = new System.Drawing.Size(60, 60), ImageLocation = @"D:\Projects\Drag-Drop Demo\Chess_blt60.png", BackColor = System.Drawing.Color.Transparent, },
        new System.Windows.Forms.PictureBox() { Size = new System.Drawing.Size(60, 60), ImageLocation = @"D:\Projects\Drag-Drop Demo\Chess_kdt60.png", BackColor = System.Drawing.Color.Transparent, },
        new System.Windows.Forms.PictureBox() { Size = new System.Drawing.Size(60, 60), ImageLocation = @"D:\Projects\Drag-Drop Demo\Chess_klt60.png", BackColor = System.Drawing.Color.Transparent, },
    };
    
    public DragDropDemo()
    {
        this.DoubleBuffered = true;
        this.Size = new System.Drawing.Size(305, 305);
        this.Controls.Add(_background);

        for (int i = 0; i < _pieces.Length; i++)
        {
            _pieces[i].Parent = _background;
            _pieces[i].Location = new System.Drawing.Point(10 + i * 70, 10);
            _background.Controls.Add(_pieces[i]);
            this.EnableDragAndDrop(_pieces[i]);
        }
    }
    
    private void EnableDragAndDrop(System.Windows.Forms.PictureBox pb)
    {
        var downs =
    Observable
        .FromEventPattern<System.Windows.Forms.MouseEventHandler, System.Windows.Forms.MouseEventArgs>(
            h => pb.MouseDown += h,
            h => pb.MouseDown -= h)
        .Select(x => x.EventArgs);

        var moves =
            Observable
                .FromEventPattern<System.Windows.Forms.MouseEventHandler, System.Windows.Forms.MouseEventArgs>(
                    h => pb.MouseMove += h,
                    h => pb.MouseMove -= h)
                .Select(x => x.EventArgs);

        var ups =
            Observable
                .FromEventPattern<System.Windows.Forms.MouseEventHandler, System.Windows.Forms.MouseEventArgs>(
                    h => pb.MouseUp += h,
                    h => pb.MouseUp -= h)
                .Select(x => x.EventArgs);

        var deltas = from down in downs
                     from move in moves.TakeUntil(ups)
                     select new System.Drawing.Point()
                     {
                         X = move.X - down.X,
                         Y = move.Y - down.Y
                     };

        var subscription =
                deltas
                    .Subscribe(d =>
                        pb.SetBounds(
                            pb.Location.X + d.X,
                            pb.Location.Y + d.Y,
                            0,
                            0,
                            System.Windows.Forms.BoundsSpecified.Location));
    }
}

当我运行时,我会显示这个:

然后我可以拖放:

相关问题