我应该如何在Windows上创建自定义图形控制台/终端?

时间:2012-02-22 15:56:53

标签: c# .net windows graphics console

Windows控制台界面(想想cmd窗口)对用户来说是一个非常简单的GUI。然而,处理渲染,用户输入和滚动的效率水平非常高。用于创建此接口的方法无疑与传统桌面GUI完全不同。

我有兴趣为Windows创建自己的自定义控制台/终端,最好使用基于C#和.NET的技术(例如托管GDI +或WPF)。作为一个起点,我非常希望重新创建标准的简单Windows shell。然后我可以扩展内容并从那里添加功能。

我正在寻找有关如何创建此类控制台UI的一般指导,但一些具体要点包括:

  • 我应该使用哪种渲染模型?渲染循环?部分更新(如WPF)? WinForms模型(不确定这是如何工作的)?

  • 渲染模型中使用了哪种缓存?

  • 如何加载字体以及如何呈现字体?它们是标准的TrueType字体,位图字体还是其他什么?

  • 滚动如何有效地执行?

  • 您认为其他任何可能相关的内容!

内置的Windows控制台UI(甚至是高级Linux终端用户界面)如何做这些事情 - 以及我如何模仿它们 - 的任何解释都是理想的事实。

编辑:要明确,我真的想从头开始完成这项工作。基于像GDI +或WPF这样的图形框架,但不多了。

7 个答案:

答案 0 :(得分:19)

我曾经从头开始实现一个文本输出窗口 - 我想要一个像Visual Studio中的Output窗口一样工作的窗口。事实证明它比我想象的要复杂得多,而且没有任何输入功能。

不幸的是,代码是用C ++编写的,属于前雇主,因此我无法与您分享。但我可以让你知道会发生什么。

您需要一种方法来存储可以快速索引的输出行。如果您要对显示的行数进行限制,则还需要从顶部轻松擦除行。在C ++中,deque<string>是完美的,我不知道C#中的等价物是什么(如果有的话)。

您需要处理以下Windows消息的处理程序,无需特别顺序。

  • WM_LBUTTONDOWN - 开始选择。在按钮关闭时使用SetCapture跟踪鼠标。
  • WM_LBUTTONUP - 结束选择。
  • WM_RBUTTONUP - 翻译成WM_CONTEXTMENU。
  • WM_CONTEXTMENU - 显示带有复制/剪切/粘贴的菜单以及您想要的任何其他内容。
  • WM_KEYDOWN - 响应4个光标键,Home / End,PageUp / PageDown。 CTRL-A / CTRL-C / CTRL-X / CTRL-V / CTRL-d。
  • WM_PAINT - 绘制窗口内容。
  • WM_SIZE - 在窗口大小更改时更新滚动条。
  • WM_VSCROLL - 在垂直滚动期间更新窗口的可见部分。
  • WM_HSCROLL - 在水平滚动期间更新窗口的可见部分。
  • WM_CREATE - 用于在创建窗口时进行初始化。
  • WM_SETFOCUS - 创建系统插入符以显示窗口中的当前位置。
  • WM_KILLFOCUS - 杀死插入符,因为只有当前关注的窗口才会显示插入符号。
  • WM_MOUSEMOVE - 在鼠标左键按下时跟踪选择的更改。
  • WM_CAPTURECHANGED - 结束选择。
  • WM_TIMER - 在选择过程中光标离开窗口时自动滚动。
  • WM_GETDLGCODE - 添加DLGC_WANTARROWS以便箭头键完成。
  • WM_MOUSEWHEEL - 响应鼠标滚轮滚动。

当行添加到文本缓冲区时,请调整滚动条的范围。垂直滚动条范围将是总行数,水平滚动条范围将是最宽行的宽度。

最好有一个等宽字体 - 它使计算更容易。特定的字体技术并不重要。您只需要能够跟踪角色的位置。

滚动如何有效地执行?在滚动时跟踪窗口的顶部和底部线条,当出现绘制消息时,您只绘制当前可见的线条。其他人仍然在缓冲区,但他们没有被触及。可以在滚动窗口时将窗口内容加入blit,只绘制从顶部或底部进入的部分,但是使用今天的处理器会浪费精力 - 窗口会快速重新绘制,以至于您不会注意到

编辑:巧合的是,我遇到了这个微软滚动条指南,它应该是这项任务必不可少的阅读材料。 http://msdn.microsoft.com/en-us/library/windows/desktop/bb787527.aspx

答案 1 :(得分:8)

如果你想创建一个漂亮的基于.NET的命令提示符替换,那么我建议查看http://poshconsole.codeplex.com/它使用WPF作为图形元素,它实现了PowerShell脚本宿主。 PowerShell是Microsoft对古老的命令提示符的替代品。 PowerShell默认安装在Windows 7中,但您可以下载它用于XP和Vista。尽管直接使用.NET对象编写脚本,但PowerShell具有高度可扩展性。它也可以嵌入其他程序中。

WPF + PowerShell将是您想要做的一个很好的起点。如果您愿意,可以将PowerShell替换为您自己的命令/脚本引擎。如果你真的雄心勃勃,你可以在DLR上实现自己的脚本语言,以充当你的命令解释器。

祝你好运。

答案 2 :(得分:4)

查看Console开源项目。它做了很多,而且做得很好。它为基于角色的任何内容提供统一的控制台。我在他们自己的选项卡中运行cmd,bash和python。

它是在C ++中,但它不会提供自己编写它的乐趣。

答案 3 :(得分:3)

我在RichTextBox输出方面取得了巨大成功。实际上,它可以满足您的所有需求:颜色自定义,有效渲染和滚动,剪贴板操作等。输入是通过拦截窗口的KeyPress事件来组织的。

答案 4 :(得分:3)

如果速度是最重要的,那么XNA是一种非常快速的方式(最小编码)来高速绘制文本。它可以在100的FPS下处理数千个精灵。使用SpriteBatch :: DrawString()和SpriteFont,您可以获得一个高速“控制台”,只需很少的编码工作。可以修改标准“游戏”类以按需重新绘制屏幕的子区域。注意事项包括不完美的字距调整,使文本外观模糊(您可以通过关闭消除锯齿并小心投影和精灵放置来解决此问题)。如果这是一个问题,那么也许Direct2D提供了更好的解决方案(或任何已经提到的解决方案)。

答案 5 :(得分:2)

作为第一个简单的方法,我会在多行模式下使用TextBox。观察TextChangedKeyPressedKeyUp事件并采取相应措施。稍后,您可以通过从简单的Panel控件派生一个来创建自己的控件。通过覆盖OnPaint方法(WinForms)进行渲染。无需循环,只需拨打InvalidateRefresh

即可

使用字符串数组或List<string>LinkedList<string>作为行缓冲区,或者只使用文本框中存储的文本。

如果使用WinForms创建自己的控件,System.Windows.Forms.TextRenderer是渲染文本的不错选择。它将在OnPaint中使用。

如果您创建自己的控件,滚动是一件棘手的事情。 System.Windows.Controls.Panel已经包含滚动支持,但是当文本发生变化时,您仍然必须告诉控件如何放置和调整滚动条按钮的大小。另一方面,当用户移动滚动条并相应地更新显示时,您可以移动文本。对于这种简单的控制,性能不应该是一个问题。

答案 6 :(得分:1)

github上的

FastColoredTextBox项目有一个控制台示例。它是:

  • 高效快速
  • 在WPF和WinForm中可用
  • 在C#中易于阅读

我认为阅读代码会对你有所帮助。