如何使用 C# 中的 WinForms 实现类似主页中带有地图区域的图像(用半透明矩形覆盖区域)?

发布于 2024-12-11 05:12:21 字数 941 浏览 0 评论 0原文

我有一个面板(这里称为父面板),我在其中绘制计算图。 该图片的某些矩形区域应通过将鼠标悬停在其上方来突出显示。 这与在网页上使用 , 和 的行为相同,例如 右上侧的德国地图

吸尘时,相应的矩形应被半透明的蓝色覆盖。 (并且取决于其他颜色的 Alt、Ctrl 和/或 Shift 等键,并且可单击)。

第一个解决方案是透明面板的单个实例 - 从 Panel 类继承。 在父级的吸尘事件中,我将单个实例移动并调整大小到正确的位置,更改颜色。 这有一些问题: * 移动和调整大小 (SetBounds()) 触发了父面板的 MouseLeave 事件和单个面板的 MouseEnter 事件。必须相应地调整事件才能使其正常工作,我做到了,但由于从列表中找到正确的地图区域,速度非常慢。

第二种解决方案是为每个地图区域动态生成透明面板的实例。 每个透明面板必须在输入时设置例如 Color.FromArgb(50, Color.Blue) ,并且 离开面板时将其移除。 但似乎比之前还要慢一些。 如果鼠标快速滑过几张地图,它们都会像吸盘一样被绘制,然后慢慢再次变得透明。

有谁知道满足此要求的一个好的解决方案:

  • 在父面板中调整图片大小时,地图等必须更改以及
  • 部分透明突出显示的矩形区域。
  • 检测 Ctrl/Shift/Alt 作为区域事件和颜色变化。
  • 检测点击事件还有

其他控件可以更好地用于此目的吗?

感谢基于实践的想法。

PS:带有卫星图片的世界地图更好地显示了我想做的事情: 用吸尘器吸住时,背景或多或少仍然可见。 但在我的例子中,父图像、其大小和地图是在运行时计算的 (用户完成设置后)。

I have a panel (here called parent), where I draw a calculated picture.
Some rectangular areas of this picture shall higlight by hoovering over.
It is the same behaviour like on a web page using , and , e. g.
the german map on the right upper side.

At hoovering the according rectangle shall be covered by a half transparent blue .
(And depending on keys like Alt, Ctrl and/or Shift in other colors, and clickable).

The first solution was a single instance of a transparent Panel - inherited from the Panel class.
In the hoovering event of the parent I moved and resized the single instance to the right place, changing the color.
This had some problems:
* moving and resizing (SetBounds()) fired MouseLeave event of the parent and a MouseEnter event of the single panel. The events had to be adapted accordingly to get it working correctly, I did it, but it is was very slow, due to finding the right map area from the list.

The second solution was to generate dynamically an instance of a transparent panel for each map area.
Each transparent panel had to set the e. g. Color.FromArgb(50, Color.Blue) at entering, and
remove it at leaving the panel.
But it seems to be even slower than before.
If the mouse hurries over several maps, they are all drawn like hoovered, and slowly get transparent again.

Does anybody know a good solution for this requirements:

  • at picture resize in parent panel, map etc. has to be changed as well
  • partly transparent highlight hoovered rectangle area.
  • detection of Ctrl/Shift/Alt as events for an area and change of the color.
  • detect click events there

Are there other controls I better use for this purpose?

Thanks for on practice based ideas.

PS: The world map with satellite pictures shows better what I want to do:
At hoovering the background is still visible more or less.
But in my case the parent image, its size and the maps are calculated at runtime
(after settings are completed by the user).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

睡美人的小仙女 2024-12-18 05:12:21

解决方案

描述

我现在找到了一个解决方案,它对用鼠标悬停的区域反应足够快。
主图片在 PictureBox 实例中绘制,更详细地说,它的属性 Image 被分配。
SizeMode 属性设置为 Zoom,可自动居中图像并调整图像大小,同时保持指定图像的纵横比。
我为每个地图区域(子区域)使用动态创建的 Picturebox 实例,如果鼠标未悬停在其上方,该实例是不可见的。
将鼠标悬停在地图区域上时,子项将出现 - 这是在父 PictureBox 的鼠标移动事件中完成的,
我在其中迭代子项,检测鼠标位置是否在子项的边界内。
找到的子项设置为可见。因此鼠标进入该子控件。
在子控件的离开事件中,我再次将其设置为不可见。
如果鼠标在所有地图区域上移动得太快,我会遇到子控件的鼠标离开事件丢失的情况。
我假设,如果鼠标指针在设置为可见之前已经离开该区域,则该事件永远不会引发。
解决方案是,如果在父控件的鼠标移动事件处理程序中确实找不到(a)子控件,则将所有(其他)子控件设置为不可见。

实施步骤

实施我的解决方案的步骤:

  • 使用设计的父 PictureBox 实例。
    • 将(动态)绘制的图片分配给 Image 属性
    • 将 SizeMode 设置为缩放
    • 作为表单字段的 Picturebox 实例列表

将新计算的图像分配给父级 Picturebox 实例:

  • 删除所有子控件、其事件处理程序、列表中的条目(如果它们已存在)。
  • 为每个地图区域动态创建一个 PictureBox 实例并将其添加到列表中。
    • 将其作为子控件添加到父 PictureBox 实例中。
    • 将其Tag属性设置为指向包含原始地图边界和矩形地图区域表示的对象的数据对象。
    • 根据父 Picturebox 实例的边界设置缩放和居中的地图区域的边界,以适应自动缩放的图像。
    • 注册鼠标点击事件
    • 注册鼠标离开事件
    • 将背景颜色设置为半透明绿色
    • 可见设置为 false

在父 Picturebox 实例中,鼠标悬停事件处理程序执行

  • 以下操作 :子 Picturebox 实例,鼠标指向的位置,
  • 如果找到,则将找到的子项设置为可见,
  • 将所有(其他)子 Picturebox 设为不可见

在父 Picturebox 中调整大小事件处理程序的实例:

  • 缩放/移动全部根据父图像的边界和父 Picturebox 实例的边界创建地图区域 Picturebox 实例。

每个地图区域 Picturebox 实例的鼠标离开事件将自身设置为不可见(前面提到的事件丢失)。
每个地图区域Picturebox实例的鼠标单击事件使得通过单击地图区域可以完成任何操作。
这里演奏的是右半音音高的正弦音。

图片

下图显示了带有地图区域的原型(尚未正确对齐,有些偏移):

第一张图片用于说明父图片和所有地图区域。
主图片(比例)和所有地图区域(动态创建的子 Picturebox 实例)都绘制在第一张图片中(通过禁用地图区域的不可见操作)。

first picture

第二张图片富有成效,鼠标悬停在色调 G4 上。
在第二个图像中,表单已调整大小 - 因此父图像会自动居中并调整大小。
地图区域只是在父 PictureBox 的调整大小事件处理程序中的 Bound 属性中进行了更改。
并且已为地图区域启用了隐形操作。

第二张图片

Solution

Description

I found now a solution, that reacts sufficiently fast to hoovering areas with the mouse.
The Main pictures is drawn in a PictureBox instance, in more detail its property Image is assigned.
The SizeMode property is set to Zoom, that automatically centers and resizes the image with keeping the aspect ratio of the assigned image.
I use a dynamically created Picturebox instance for each map area (childs), that is invisible, if the mouse does not hoover over it.
At hoovering over the map area the child shall appear - this is done in the mouse move event of the parent PictureBox,
where I iterate over the children, detecting whether the mouse position is in the bounds of a child.
The found child is set visible. Therefore the mouse enters this child control.
In the leave event of the child control I set it invisible again.
I experienced losses of mouse leave events for the child controls, if the mouse is moved too fast over all map areas.
I assume, if the mouse pointer already left the area before it has been set visible, the event is never raised.
The solution is, that all (other) child controls are set invisible, if in the mouse move event handler of the parent control does find no (a) child control.

Steps to implement

What to do, to implement my solution:

  • Use a designed parent PictureBox instance.
    • Assign the (dynamically) drawn picture to the Image property
    • Set SizeMode to Zoom
    • a list of Picturebox instances as form field

At assignment of a newly calculated image to the parent Picturebox instance:

  • remove all child controls, its event handler, its entry from the list, if they already exist.
  • create dynamically a PictureBox instance for each map area and add it to a list.
    • add it to the parent PictureBox instance as a child control.
    • set its Tag property points to a data object containing the origin map bounds and the object represented by the rectangular map area.
    • set the bounds to the map area scaled and centered according to the bounds of the parent Picturebox instance, that it suits the automatically zoomed image.
    • register a mouse click event
    • register a mouse leave event
    • set background color to e. g. semi transparent green
    • set Visible to false

In the parent Picturebox instance the mouse over event handler does:

  • finding the child Picturebox instance, where the mouse points at
  • if found it sets the found child visible
  • set all (other) child Picturebox invisible

In the parent Picturebox instance the resize event handler does:

  • scale/move all the map area Picturebox instances according to the bounds of the parent image and the bounds of the parent Picturebox instance.

The mouse leave event of each map area Picturebox instance set itself invisible (losses of events previously mentionned).
The mouse click event of each map area Picturebox instance makes whatever shall be done by clicking the map area.
Here playing a sine tone of the right chromatic pitch.

Pictures

The pictures below show the prototype with the map areas (not yet correctly aligned, some offset):

The first picture is for illustration of parent picture and all map areas.
The main picture (scale) and all map areas (dynamically created child Picturebox instances) are drawn in the first picture (by disabling the invisible action for map areas).

first picture

The second image is productive, where the mouse hoovers over tone G4.
In the second image the form has been resized - therefore the parent image is automatically been centered and resized.
The map areas were simply changed in their Bound property in the resize event handler of the parent PictureBox.
And the invisible action has been enabled for the map areas.

second picture

我为君王 2024-12-18 05:12:21

我检查了 ImageMap
它是一个用户控件,包含在编译前绘制的静态图像。
在运行时添加可点击区域 - 矩形、多边形、椭圆形都是可能的。
它使用 PictureBox,它是作为 ImageMap 的子级创建的(从 UserControl 继承)。
它将 Click、Move 和 Leave 事件注册到其事件处理程序。
在这些事件处理程序中,它根据 GraphicsPath 实例中的路径列表检查当前位置并返回索引 (int)。
ImageMap 跟踪最后选择的索引(-1 = 未选择对象),相应地设置光标(手动或默认),设置或删除工具提示。
但它没有吸尘事件,它不会改变吸尘时的区域,就像我也需要它一样。

因此我需要 ImageMap 它来正确检测区域,
但我的图片是在运行时绘制的!
我仍然必须打开和关闭矩形及其半透明层。
我想到使用 Visible 属性来打开和关闭区域的控件。
为了更容易绘制,我将背景设置为父图像的部分,
用半透明颜色覆盖 - 这是一种解决方法,这是可能的,
因为地图相对固定于父图片。
如果我有时间,我会测试这个解决方案的想法 - 这是一个私人项目,因此我不能全职工作:-)。

I checked the ImageMap:
It is a user control, that contains a static image, that was drawn before compile time.
At runtime the clickable areas are added – rectangle, polygon, ellipse are possible.
It uses a PictureBox, that is created as child of the ImageMap (that is inherited from UserControl).
It registers a Click, a Move and a Leave event to its event handlers.
In these event handlers it checks the current position against the list of paths in a GraphicsPath instance and returns an index (int).
The ImageMap keeps track of the last selected index (-1 = no object selected), sets the cursor accordingly (hand or default), sets or removes the tooltip.
But it has no hoover event, it does not change the area at hoovering, like I need it too.

Therefore I can need ImageMap it for proper detection of area,
but my picture is drawn at runtime!
And still I have to switch on and off the rectangles with its semi transparent layer.
I got the idea to use the property Visible to switch on and off the controls for the areas.
That it is easier to draw, I will set the background to the part of the parent image,
covered with the semi transparent color - this is a workaround, that is possible,
because the maps are relatively fixed to the parent picture.
If I have time, I will test this solution idea - it is a private project, therefore I can not work fulltime :-).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文