2

I tried writing code several different times, but I came to an error with each one. Basically, I'm trying to make "windows" similar to say Explorer, Paint, MediaPlayer, where you could drag then around, interact with them, minimize and close. Of course, if you clicked on a window, the one below it (they can overlap) shouldn't get affected.

I know how to do this, I have a list of the class I call Window, loop through it, and I only interact with the first window to contain the location of the mouse-click. This way, other windows overlap won't get affected.[1]

Next, I had to make it so that two buttons that are overlapping don't get activated when the user clicks in the "intersection of both buttons." I handled this by using the same method I used above.[2]

But the problem I'm facing now is that, if I hold the left click, but then I decide not to click a button, I drag the mouse away from the button, and release the left click, so that the button-click event won't be activated. But, when I remove the mouse from the boundaries of the button, and say, into another.. the new button get activated. Which it should not.[3]

My set up is like this: I have a class called Window. In Window, I have a list of the class called Interface (similar to the Control class in WinForms). And each Interface has a struct in it that contains 4 bools, if the left/right is currently down, and if they were down in the previous processing. (prevLeft, prevRight, currLeft, currRight)

So, I'm ready to discard that (I have not yet, so I still have the source code), but I need a good structure for making an object-oriented type of application. However, I am not using WinForms. I need help with the structure alone, so no actual code is necessary, description is enough. I need to avoid the 3 problems I mentioned above.

4

2 回答 2

2

创建自己的窗口管理器并非易事。我知道是因为我也在做一个;)

您可以使用现有的,虽然可能不是最好的解决方案,例如Nuclex.UI,当我第一次看到它时我个人拒绝了它,但如果您不打算制作自己的 WM,我建议使用它或混合 WinForms-XNA 方法

但是,如果您真的对实现自定义窗口管理器一无所知,那么您必须了解任何其他 WM 是如何工作的。既然我们谈论的是 XNA,它就意味着 Windows,也就是 Windows Explorer,这是一个值得学习的好东西。

你必须认识到最简单的事情是如何工作的,这真的没那么难。困难的部分是弄清楚什么时候更新什么逻辑,以及如何不把所有的 CPU 都花在 UI 更新上。让我就如何解决您在问题中提到的问题给您一些提示。

  • 为了跟踪所有窗口,我使用了 a Dictionary<string, Window>,其中Window是一个自定义类,string对于我必须按名称调用窗口的极少数情况,它是它的唯一名称。将其视为窗口 GUID 或句柄。但是您可以只使“表单”只能出现一次,并将所有引用存储在静态变量中。

  • 为了让 WM 了解您正在单击的控件,我使用矩形并检查它们是否包含Point位于光标坐标处且具有{1; 1}像素大小的 a,这可能与在 Windows 资源管理器中完成的方式大致相同。为此,您的 WM 需要知道更新活动窗口的顺序。通常,您希望从最顶部的窗口开始,然后继续到活动窗口列表的末尾。为此,您可以使用循环遍历列表foreach

  • 但这还不是全部,因为每个窗口本身都是一个Container,这意味着它包含其他控件,其中一些甚至可能是Containers 本身,例如 WinFormsPanel类。这意味着您必须遍历Windows 的每个Children控件。更新顺序也应该有意义 - 从最顶层的孩子到最底层的更新,递归地用于Container控件,以防它们也有Containers。这基本上意味着您希望GetAllControls()为您的类实现一个递归方法,WindowManager该方法将遍历 allContainers并返回 all 的列表Control

  • 绘制所有这些Controls 应该以更新它们的相反顺序完成,因此您可以在GetAllControls().Reverse()循环中迭代它们foreach

  • 在哪里绘制和更新什么取决于当前容器拥有的所有父容器以及它们与游戏窗口左上角的组合偏移量。我通过在所有子控件中存储ParentContainer引用来解决这个问题,以DrawRectangle通过递归属性获取适当的 s 和更新区域。

  • 当您单击屏幕上的某个位置并且在 a 上注册了一次单击时 ControlWindowManager请记住 ( bool clickRegistered) 并且不要在任何底层s上运行任何OnClick事件。Control

  • Windows 资源管理器会记住您单击的控件,OnRelease如果随后在同一控件的更新区域中释放光标,则会激活其事件。所以基本上 Windows 管理器只有在您释放鼠标按钮时才会执行某些操作。您可以使您的WindowManagerControls 以不同的方式处理单击事件,例如在按下鼠标按钮后立即触发事件,即OnMouseDown. 但是请记住,Microsoft 不是菜鸟,Windows 资源管理器中出现这种行为是有原因的,这是因为如果您不小心在不想要的地方按下了鼠标按钮,您仍然可以通过将光标移到按下的控件更新之外来修复它区域,而不是运行它的动作。

在这一点上,您可能会想“真的值得实现所有这些吗?” 对我来说,答案是“也许”,因为在我开始的时候,我在 C# 和 XNA 方面都是一个菜鸟,现在我知道我的游戏,原本应该使用一些窗口管理器,将从我自己的游戏中受益WM 实施远不止来自现成的第三方解决方案。此外,这是一个很好的逻辑和编程练习。

但是如果你想把自己想象成一个游戏开发者,你应该考虑尽快达到你的目标,即实际制作游戏,而不是游戏引擎。因此,在这种情况下,最好利用现有的解决方案并开始销售您的产品。

于 2013-09-28T23:32:51.790 回答
0

与其拥有 4 个布尔值的结构(类似于 xna),不如你想办法告诉鼠标“在哪里”。因此,从某种意义上说,鼠标位于Window 编号 5中,即Paint,而用户将鼠标按住在interface/control 编号 2中,即button。听起来它可以工作。

于 2013-09-28T22:37:08.037 回答