定义Picturebox图像中的可点击区域 - 工具提示c#

时间:2017-12-21 12:06:31

标签: c# picturebox

我在C#中的Winform项目中有一个带有加载图像的图片框。我定义了一个包含几个椭圆(X点,Y点,宽度,高度,ZoneID,ZoneDescription)的Struct,我在初始化表单时将其加载到Picturebox中。

我想尝试做两件事。 1)允许用户用鼠标移动到图片框中的图片上,一旦鼠标进入结构中标识的区域,它就会显示一个工具提示,显示结构中的ZoneDescription。

2)然后,当用户点击任意一个区域时,它应该生成一个响应,我可以捕获ZoneID(我已在结构中定义)。然后我将其添加到数据集中。这部分我可以做。

我只是不知道怎么去Pt1。 我在某处读到了我应该为所有区域定义一个MouseEnter事件处理程序和一个MouseLeave EventHandler,但我不知道该怎么做。 我已经在表单上有一个工具提示。

以下是包含区域的结构定义:

 public struct TreatmentZone
    {

        public int nZoneID;
        public string sZoneCode;
        public string sZoneDesc;
        public Color sbPaintbrush;
        public int nZonewidth;
        public int nZoneheight;
        public int nZoneX;
        public int nZoneY;

        public TreatmentZone(int _ZoneID, string _sZoneCode,string _ZoneDesc, Color _sbBrush, int _ZoneX, int _ZoneY, int _Zonewidth, int _Zoneheight)
        {
            this.nZoneID = _ZoneID;
            this.sZoneCode = _sZoneCode;
            this.sZoneDesc = _ZoneDesc;
            this.sbPaintbrush = _sbBrush;
            this.nZoneX = _ZoneX;
            this.nZoneY = _ZoneY;
            this.nZonewidth = _Zonewidth;
            this.nZoneheight = _Zoneheight;

        }
    };
    TreatmentZone[] tZone = {
                                new TreatmentZone(1,"R1","Brain", Color.AliceBlue,155,35,30,20),
                                new TreatmentZone(5,"R2", "Hypothalamus", Color.AliceBlue,184,55,12,12)                                   
                                };
    private void pic_TreatmentZones1_RightSole_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.FillEllipse(new System.Drawing.SolidBrush(tZone[0].sbPaintbrush), tZone[0].nZoneX, tZone[0].nZoneY, tZone[0].nZonewidth, tZone[0].nZoneheight);
        e.Graphics.FillEllipse(new System.Drawing.SolidBrush(tZone[1].sbPaintbrush), tZone[1].nZoneX, tZone[1].nZoneY, tZone[1].nZonewidth, tZone[1].nZoneheight);
    }

我如何在Pt1中执行所需的步骤?有没有人有我可以使用的代码示例?

2 个答案:

答案 0 :(得分:0)

所以基本上你需要订阅MouseMove(用于胡佛)和PictureBox的Click Event。然后,您需要指定当前光标是否在治疗区域上并处理它。

我已经采用了您的代码并构建了一个小型演示。 请注意,我已更改了一些TREZone变量的名称以匹配C#命名约定。并且还将它们更改为属性。

注意:您需要在表单中添加工具提示。

public struct TreatmentZone
{
#region members

private readonly GraphicsPath path;

#endregion

//changed to properties

public int Id { get; private set; }
public string Code { get; private set; }
public string Description { get; private set; }
public Color Color { get; set; } 
public int Width { get; private set; }
public int Height { get; private set; }
public int X { get; private set; }
public int Y { get; private set; }

public TreatmentZone(int zoneId, string zoneCode, string description, Color color, int x, int y, int width, int height)
{
  this.Id = zoneId;
  this.Code = zoneCode;
  this.Description = description;
  this.Color = color;
  this.X = x;
  this.Y = y;
  this.Width = width;
  this.Height = height;
  this.path = new GraphicsPath();

  //needed for hittest
  this.path.AddEllipse(this.X, this.Y, this.Width, this.Height);
}

//https://stackoverflow.com/questions/13285007/how-to-determine-if-a-point-is-within-an-ellipse
//This will check if the point (from mouse) is over ellips or not
public bool HitTest(Point point)
{
  var x = point.X - this.X;
  var y = point.Y - this.Y;
  return this.path.IsVisible(x, y);
}

}

这是你的表格: 请注意我的PictureBox刚刚命名为pictureBox1

公共部分类Form1:表单   {

private readonly List<TreatmentZone> treatmentZones = new List<TreatmentZone>();

public Form1()
{
  this.InitializeComponent();
  this.treatmentZones.Add(new TreatmentZone(1, "a", "b", Color.Blue, 10, 10, 200, 400));
}

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
  foreach (var treatmentZone in this.treatmentZones)
  {
    using(var brush = new SolidBrush(treatmentZone.Color))
      e.Graphics.FillEllipse(brush, treatmentZone.X, treatmentZone.Y, treatmentZone.Width, treatmentZone.Height);
  }
}

private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
  foreach (var treatmentZone in this.treatmentZones)
  {
    if(treatmentZone.HitTest(e.Location))
      this.toolTip1.Show(treatmentZone.Description, this.pictureBox1, e.Location);
  }
}

private void pictureBox1_Click(object sender, EventArgs e)
{
  var location = this.pictureBox1.PointToClient(Cursor.Position);
  foreach (var treatmentZone in this.treatmentZones)
  {
    if (treatmentZone.HitTest(location))
      MessageBox.Show("Handle the click of " + treatmentZone.Code + ".");
  }

}

}

答案 1 :(得分:0)

所以在我探索的最后,我按照这种方法做到了: (请记住,这是一个带Winforms的桌面应用程序)

1)创建一个图片框并加载图片 - 在这种情况下是一个png文件。 2)使用List对象在图片框内的此图像上创建多个可单击区域。在我的情况下,我想要椭圆形可点击区域。 3)列表对象的字段被加载到SQL表中(或者您可以手动将列表对象加载为类 - 它由您决定)

以下是我使用的代码:

包含可点击区域的类:

public class clsClickableZones
    {
        public int nZoneID { get; set; }
        public string sZoneCode { get; set; }
        public string sZoneDesc { get; set; }
        public System.Drawing.Color sbPaintbrush { get; set; }
        public int nZonewidth { get; set; }
        public int nZoneheight { get; set; }
        public int nZoneX { get; set; }
        public int nZoneY { get; set; }

    }
然后执行这个类。 在&#34; InitialiseComponent&#34;之后的公共表单事件上我打电话给我创建一个新的调用LoadClickableZones()。

在这个Form类中,我定义了包含值的Listobject:

List<clsClickableZones> tZones = new List<clsClickableZones>();

然后我用这个方法加载区域:

手动:

public void LoadClickableZone()
        {
            //this can now be loaded into table and pulled from dataset into class if so desired
            //Use Test Colour for visibility sbPaintbrush=Color.Bisque and Transparent for functionality
            System.Drawing.Color sbPCol = Color.Cornsilk;
            //System.Drawing.Color sbPCol = Color.Transparent;

            try
            {

            tZones.Add(new clsClickableZones() { nZoneID = 1, sZoneCode = "R1", sZoneDesc = "Zone 1", sbPaintbrush = sbPCol, nZoneX = 160, nZoneY = 30, nZonewidth = 25, nZoneheight = 20 });
            tZones.Add(new clsClickableZones() { nZoneID = 2, sZoneCode = "R2", sZoneDesc = "Zone 2", sbPaintbrush = sbPCol, nZoneX = 184, nZoneY = 55, nZonewidth = 12, nZoneheight = 12 });
            tZones.Add(new clsClickableZones() { nZoneID = 3, sZoneCode = "R3a", sZoneDesc = "Zone 3", sbPaintbrush = sbPCol, nZoneX = 160, nZoneY = 58, nZonewidth = 12, nZoneheight = 12 });
            tZones.Add(new clsClickableZones() { nZoneID = 63, sZoneCode = "R3b", sZoneDesc = "Zone 4", sbPaintbrush = sbPCol, nZoneX = 177, nZoneY = 68, nZonewidth = 12, nZoneheight = 12 });
            tZones.Add(new clsClickableZones() { nZoneID = 4, sZoneCode = "R4", sZoneDesc = "Zone 5", sbPaintbrush = sbPCol, nZoneX = 160, nZoneY = 90, nZonewidth = 25, nZoneheight = 15 });
            tZones.Add(new clsClickableZones() { nZoneID = 5, sZoneCode = "R5", sZoneDesc = "Zone 6", sbPaintbrush = sbPCol, nZoneX = 160, nZoneY = 115, nZonewidth = 15, nZoneheight = 10 });
            tZones.Add(new clsClickableZones() { nZoneID = 6, sZoneCode = "R6", sZoneDesc = "Zone 7", sbPaintbrush = sbPCol, nZoneX = 147, nZoneY = 80, nZonewidth = 10, nZoneheight = 10 });
            tZones.Add(new clsClickableZones() { nZoneID = 7, sZoneCode = "R7", sZoneDesc = "Zone 8", sbPaintbrush = sbPCol, nZoneX = 186, nZoneY = 135, nZonewidth = 12, nZoneheight = 20 });
            tZones.Add(new clsClickableZones() { nZoneID = 8, sZoneCode = "R8", sZoneDesc = "Zone 9", sbPaintbrush = sbPCol, nZoneX = 170, nZoneY = 145, nZonewidth = 20, nZoneheight = 30 });
            tZones.Add(new clsClickableZones() { nZoneID = 9, sZoneCode = "R9", sZoneDesc = "Zone 10", sbPaintbrush = sbPCol, nZoneX = 151, nZoneY = 180, nZonewidth = 33, nZoneheight = 20 });

catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error loading Zones", MessageBoxButtons.OK);
            }
}

您也可以从SQL中的表中加载所有区域,如下所示:

public void LoadTreatmentZone_RSole()
        {
            //this can now be loaded into table and pulled from dataset into class if so desired
            //Use Test Colour for visibility sbPaintbrush=Color.Bisque and Transparent for functionality
            System.Drawing.Color sbPCol = Color.Cornsilk;
            //System.Drawing.Color sbPCol = Color.Transparent;

            try
            {
                string sSQL = "SELECT pkID, TreatmentAreaCode, TreatmentAreaDesc, ZoneX, ZoneY, ZoneH, ZoneW FROM myDB.lkMyZones ; ";
                Datafeed cData = new Datafeed();
                DataSet dsData = new DataSet();
                cData.GetDataset(sSQL, ref dsData);
                cData = null;

                if (dsData.Tables[0].Rows.Count > 0)
                {
                    foreach (DataRow row in dsData.Tables[0].Rows)
                    {
                        tZones.Add(new clsClickablesZones()
                        {
                            nZoneID = Convert.ToInt32(row["pkID"].ToString()),
                            sZoneCode = row["TreatmentAreaCode"].ToString(),
                            sZoneDesc = row["TreatmentAreaDesc"].ToString(),
                            sbPaintbrush = sbPCol,
                            nZoneX = Convert.ToInt32(row["ZoneX"].ToString()),
                            nZoneY = Convert.ToInt32(row["ZoneY"].ToString()),
                            nZonewidth = Convert.ToInt32(row["ZoneW"].ToString()),
                            nZoneheight = Convert.ToInt32(row["ZoneH"].ToString())
                        });
                    }
                }

                dsData = null;

            }

            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Error loading Treatment Zones - R Sole", MessageBoxButtons.OK);
            }
}

现在可以使用Click事件单击每个区域,或者您可以使用MouseMove事件将鼠标悬停在其上,如下所示:

移动/点击事件的功能:

private int ZoneClickedRS(int mouseX, int mouseY,int ZoneArea)
        {


                    int ix;
                        for (ix = 0; ix < tZones.Count; ix++)
                        {
                            if ((mouseX >= tZones[ix].nZoneX) && (mouseX <= (tZones[ix].nZoneX + tZones[ix].nZonewidth)) &&
                        (mouseY >= tZones[ix].nZoneY) && (mouseY <= (tZones[ix].nZoneY + tZones[ix].nZoneheight)))
                                return ix;                          
                        }                       
                        break;   

            return NOT_IN_ZONE;

        }

调用来自MouseMove或MouseClick,如下所示:

private void pic_Zones_MouseClick(object sender, MouseEventArgs e)
        {
            int SelectedZoneID = ZoneClickedRS(e.X, e.Y,1);
            if (SelectedZoneID == NOT_IN_ZONE)
                return;
            string sZone = tZones[SelectedZoneID].sZoneDesc;
            miSelectedZoneID = tZones[SelectedZoneID].nZoneID; //Defined elsewhere

           // For Testing: 
           //MessageBox.Show("The selected Zone:" + sZone, "Selected Zone", MessageBoxButtons.OK);
        }

或者对于MouseMove(将数据传递给ToolTip控件,如下所示)

private void pic_Zones_MouseMove(object sender, MouseEventArgs e)
        {
            int SelectedZoneID = ZoneClickedRS(e.X, e.Y,1);
            string sZone = "";

            if (SelectedZoneID == NOT_IN_ZONE)

                tipZoneArea.RemoveAll();
            else
                sZone = tZones[SelectedZoneID].sZoneDesc;
            tipZoneArea.SetToolTip(pic_Zones, "Clicked" + sZone);

        }

最后,为了让您的图片框上显示区域,您可以进行以下呼叫:

private void pic_Zones__Paint(object sender, PaintEventArgs e)
        {

            int ii;
            for (ii = 0; ii < tZones.Count; ii++)
            {
                e.Graphics.FillEllipse(new System.Drawing.SolidBrush(tZones[ii].sbPaintbrush), tZones[ii].nZoneX, tZones[ii].nZoneY, tZones[ii].nZonewidth, tZones[ii].nZoneheight);
            }               

        }