如何制作窗口管理器?

时间:2013-09-28 22:33:12

标签: c# user-interface xna window-managers

我尝试了几次编写代码,但每次都出错了。 基本上,我试图让“windows”类似于Explorer,Paint,MediaPlayer,你可以在那里拖动它们,与它们交互,最小化和关闭。当然,如果你点击一个窗口,它下面的那个(它们可以重叠)不应该受到影响。

我知道如何做到这一点,我有一个我调用Window的类的列表,循环遍历它,我只与第一个窗口交互以包含鼠标单击的位置。这样,其他窗口重叠不会受到影响。 [1]

接下来,我必须做到这一点,当用户点击“两个按钮的交叉点”时,两个重叠的按钮不会被激活。我使用上面使用的相同方法处理了这个问题。 [2]

但我现在面临的问题是,如果我按住左键,但我决定不点击按钮,我将鼠标拖离按钮,然后释放左键,以便按钮-click事件不会被激活。但是,当我从按钮的边界移除鼠标,并说,进入另一个...时,新按钮被激活。它不应该。 [3]

我的设置是这样的: 我有一个名为Window的类。 在Window中,我有一个名为Interface的类的列表(类似于WinForms中的Control类)。 并且每个接口都有一个结构,其中包含4个bool,如果左/右当前是down,如果它们在之前的处理中是down。 (prevLeft,prevRight,currLeft,currRight)

所以,我已经准备好丢弃(我还没有,所以我仍然有源代码),但是我需要一个很好的结构来构建面向对象的应用程序。但是,我没有使用WinForms。我需要单独的结构帮助,所以不需要实际的代码,描述就足够了。我需要避免上面提到的3个问题。

2 个答案:

答案 0 :(得分:2)

创建自己的Window Manager并非易事。我知道,因为我也在制作它;)

您可以使用现有的,但可能不是最好的解决方案,例如Nuclex.UI,我个人在第一次看到它时就拒绝了,但是如果你没有死定制造自己的WM,我建议使用它或hybrid WinForms-XNA approach

但是,如果你真的死定了实现自定义窗口管理器,你必须了解任何其他WM的工作原理。由于我们谈论的是XNA,它意味着Windows,这意味着Windows资源管理器,这是一个值得学习的好东西。

你必须认识到最简单的事情是如何运作的,而且它真的不那么难。困难的部分是弄清楚什么时候更新逻辑,以及如何不仅仅在UI更新上花费所有CPU。让我给你一些关于如何解决你在问题中提到的问题的提示。

  • 要跟踪所有窗口,我使用的是Dictionary<string, Window>,其中Window是自定义类,string是其唯一的名称,适用于罕见的情况我必须按名称调用windows。可以将其视为窗口GUID或句柄。但你可以这样做,以便“表单”只出现一次,并将所有引用存储在静态变量中。

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

  • 但并非全部,因为每个窗口本身都是Container,这意味着它包含其他控件,其中一些甚至可能是Container本身,如WinForms {{1} }类。这意味着您必须遍历每个Panel s'Window控件。更新顺序也应该有意义 - 如果Children控件中有Container个句子,则从最顶层子项更新到最底层,递归执行Container控件。这基本上意味着您需要为GetAllControls()类实现一个递归WindowManager方法,该方法将迭代所有Containers并返回所有Control的列表。

  • 绘制所有这些Control应该按照更新它们的相反顺序完成,这样你就可以GetAllControls().Reverse()并在foreach循环中迭代它。

  • 绘制位置和更新内容取决于当前容器具有的所有父容器以及它们与游戏窗口左上角的组合偏移量。我通过在所有子控件中存储ParentContainer引用来解决此问题,以获取相应的DrawRectangle并通过递归属性更新区域。

  • 当您点击屏幕上的某个位置并在Control上注册了点击时,请WindowManager记住(bool clickRegistered)并且不运行任何OnClick任何基础Control s上的事件。

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

此时你可能会想“这真的值得实现这一切吗?”对我来说答案是“也许”,因为在我开始的时候,我在C#和XNA中都是一个完全的菜鸟,现在我知道我的游戏原本应该使用一些Window Manager,它将从我自己的游戏中受益WM的实施远远超过现成的第三方解决方案。此外,这是一个很好的逻辑和编程练习。

但如果您想将自己视为游戏开发者,那么您应该考虑尽快实现目标,即实际制作游戏,而不是游戏引擎。因此,在这种情况下,更好地利用现有解决方案并开始销售您的产品。

答案 1 :(得分:0)

不是让结构有4个布尔值(类似于xna),而是如何让你知道鼠标“在哪里”。所以从某种意义上说,鼠标位于 Window 数字5 Paint ,并且用户将鼠标放在界面上/ control number 2 ,这是一个按钮。 听起来它可以起作用。