【问题标题】:Is there a painless way to build a Windows UI in C?有没有用 C 语言构建 Windows UI 的轻松方法?
【发布时间】:2010-10-30 01:55:36
【问题描述】:

编辑

好吧,我猜C本质上是痛苦的--只是,这部分,特别痛苦。
此外,我只使用 C 编写并没有真正的原因,除了,这是我现在想要编写并精通的语言。我知道从 C 迁移到 C++ 很糟糕,但无论如何。

对于我在程序中创建多个窗口的问题,有人知道解决方案吗?


嗯,我 将一个 C DLL 与一个 VB6 前端接口,但是 -- 尝试来回传递字符串变得很难看,而且似乎每次我添加一个新函数时, 其他一切都会坏掉。所以,我想,我为什么要让自己经历所有这些痛苦,只是为了与一种甚至不再受支持的语言交互?为什么不更好地利用这些痛苦并学习用 C 构建前端?

好吧,我开始了,但我不得不问:有没有简单的方法可以做到这一点? WndProc 的巨大 switch 语句伤害了我的眼睛,与我学到的关于干净代码的一切背道而驰(很像 12 参数 CreateWindowEx() 或 14 参数 CreateFont())。

我意识到我可以在一定程度上重构这一切——如果我使用 C++,我可以将窗口及其组件放入类中,并以一种更自然的方式访问它们……

无论如何,我设法构建了一个名为“主窗口!”的大表单,带有“弹出消息!”按钮,效果很好——而且一点也不复杂。然后是“更改该文本!”更改编辑控件中的文本的按钮。为此,WndProc 必须在从按钮接收WM_COMMAND 消息时了解编辑控件。我不能将编辑控件的 hWnd 传递给它,因为我不是调用它的人,而且您不能只向 WndProc 添加参数。所以我必须将编辑控件放入全球范围。

我想将按钮的字体更改为 13pt Tahoma —— 很简单,对吧?当然——但我无法比WM_PARENTNOTIFY 消息更进一步……在仔细阅读MSDN 之后,我发现有些信息在wParam 的高位字中,而有些在低位字中。所以,我不得不写这个:if(wParam==(WM_CREATE | (POPUP_COMMAND<<16))){

使控件全局化?巨大的switch语句? 12和14参数函数调用?简单通知的位移?我什至不知道如何让更多的一个窗口(窗口窗口,而不是控制窗口)出现——这很痛苦......

请告诉我有更好的方法!

顺便说一句,我如何制作多个窗口?如果我只注册两个类,或者在同一个类上两次 CreateWindowEx(对于两个句柄),则只会出现第一个。我尝试了一点 dwStyle 参数,但无济于事。有人吗?

【问题讨论】:

  • 无痛? C?你是在开玩笑吧? ;)
  • 我猜你用 C 写这个是有原因的,虽然你没有提到它是什么
  • 还有其他方法,例如使用DIALOGEX resource。 .rc 文件提供了一种简洁的方式来编写与 C 一起使用的 GUI 脚本。虽然编写 C 可能会让人觉得冗长而痛苦,但它有一个显着的优势:C 代码实际上是可读的。几乎没有不可见的代码,与 C++ 完全相反。这也使得 C 代码更容易调试。您必须做出决定:您是否想要一种编写速度快的语言,选择 C++。如果您想要一种易于阅读的语言,请坚持使用 C。

标签: c user-interface winapi


【解决方案1】:

Win32 + C 是一种非常底层的方法,它有它的优点和缺点。也就是说,有一些方法可以让事情变得更容易。

首先,关于位移,有several macros to work with WPARAMs and LPARAMs。实际上,您可能不应该编写位移,因为size of WPARAM and LPARAM has changed over the years,您可能会在未来创建一个错误。

其次,关于 WindowProc 函数中的巨大 switch 语句,虽然它会在那里,但有一种方法可以使它更易于管理。 #include <windowsx.h> 获得一大堆有用的宏,最值得注意的是 HANDLE_MSG。而不是需要写

LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)    {
    switch(Message) {
    case WM_COMMAND:
        ...
    }
}

您可以改为:

void MyOnCommand(HWND hwnd, int controlID, HWND hwndCtl, UINT codeNotify);
LRESULT CALLBACK MyWindowProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)    {
    switch(Message) {
    HANDLE_MSG(hwnd, WM_COMMAND, MyOnCommand);
    }
}

并且宏会自动将该消息类型的所有不同参数转换并分离为适当命名的和类型化的变量。浏览windowsx.h 以查看已处理的消息及其所需的函数原型。并非所有不同的消息都得到处理,但有不少。

至于同时拥有多个窗口,不应该有任何东西阻止您多次调用 CreateWindow 或其亲属。虽然您只有一个HINSTANCE(在您的WinMain 中提供给您),但您可以拥有任意数量的HWND

您可能会发现Raymond Chen's scratch program 很有用,因为它应该为您提供一个不错的骨架。您也可以考虑让您的应用程序使用dialog box 而不仅仅是一个窗口;您可以免费获得一堆东西,并且可以使用资源编辑器来设计窗口及其所有控件。 Visual C++ Standard and above 包括一个资源编辑器,还有几个免费的:XN Resource Editor 似乎是一个流行的开源编辑器,我相信你可以在谷歌上找到更多。所有这些都会生成一个资源脚本,并且您的工具链中应该有一个资源编译器:rc.exe 用于 Visual Studio(包括 Express 版本,或作为 SDK 的一部分提供),或windres 作为 GNU BinUtils 的一部分在 cygwin 或 mingw 中。

【讨论】:

  • 啊,是的,windowsx 标头——为什么没有更突出地记录呢? :) 这也是您获得许多方便的宏来检查和设置组件功能(例如复选框状态)的地方,对吧?
  • 谢谢,很好的答案。至于对话框,这听起来更轻松一些......虽然我没有使用 Visual C++ 编译(我正在等待它下载——虽然我只是搭载慢速无线互联网,所以需要几天时间( MSDN 在那里)),那么还有其他方法吗?
  • @christoffer:我不知道,真的应该是……我什至找不到合适的链接。 @Carson Myers:对话框放在资源脚本中,您的编译器应该能够处理它并且有任意数量的编辑器,而不仅仅是 Visual C++。而且,想想看,Express Edition 不包括资源编辑器......我会更新我的答案。
【解决方案2】:

使用GTK+,您可以使用Glade 来构建用户界面。

【讨论】:

  • 这与 Windows 兼容吗?如果没有,我还是看看,因为我需要学习 Linux 编程一次或一次(注意:“需要”在这里的意思是,最终觉得它)。
  • @Carson:GTK+ 在 Windows 上工作。 Glade 还有一个 Windows 端口:sourceforge.net/projects/gladewin32。不过与 Win32 相比,GTK+ 会增加一个外部依赖。
【解决方案3】:

如果你想用 C 语言来做,你肯定想要 Charles Petzold 的 Programming Windows。

【讨论】:

  • 呵呵,那本书的两个推荐,我现在一定要读了
【解决方案4】:

我将提出我传统的开箱即用建议:将 Lua 添加到您的应用程序中,并结合 Lua 和合适的工具包模块构建 GUI。一个不错的选择是IUP,另一个是wxWidgets。两者都有质量不错的 Lua 绑定。更好的是,Lua 本身以及 wxLua 和 IUP 可以与来自Lua for Windows 项目的许多其他有用的 Lua 模块一起安装在一个单独的安装中。

Lua 很容易与 C 代码集成,因为它从一开始就是为此目的而设计的。

使用 Lua 作为将应用程序结合在一起的粘合剂也很容易,核心功能用 C 语言实现或作为原生 API 调用的接口。

SWIG 也支持 Lua,以防你有大量的库需要适应。

当然,您可以直接从 C 中使用 wxWidgets 或 IUP,因为它们都有 C 可调用的 API,但是事件驱动的 GUI 通常充满了在一种脚本语言。

另一个需要考虑的工具包是Tk,它最常与Tcl 脚​​本语言结合使用。 Tcl 在开发时也考虑到了嵌入到更大的应用程序中,尽管它已经从它的主要用例演变而来。 Tk 已绑定到多种其他语言,包括 Perl。

【讨论】:

    【解决方案5】:

    理想情况下,GUI 由比 C 更抽象的语言处理,否则会有很多冗余的样板代码,从这个意义上说,我建议您考虑将脚本语言解释器嵌入到您的 C 应用程序中,以便 GUI 主要由脚本,而您的应用程序的核心是用 C 编码的。

    这还具有使您的应用程序更可配置和更灵活的优势,而无需重新编译。

    您将需要研究用 ANSI C 编写并提供与 QT、GTK、wxWindows 等 GUI 库的绑定的轻量级脚本引擎。

    您可能想查看Luanasal,它们都相当轻量级并且确实为 GUI 库提供绑定。

    对于一些示例用途,您可能需要查看以下两个应用程序的屏幕截图,这些应用程序具有主要基于鼻腔及其 GTK 绑定的 GUI:

    【讨论】:

      【解决方案6】:

      只是为了让您了解在 Win UI 应用程序方面 C 与其他语言的比较:前段时间,一个具有几个窗口和几个类的简单 MDI 应用程序用于可视化医疗数据我 17k 行 C 代码。几年后,我在 Delphi 中重写了这个,只用了 5k LOCs

      【讨论】:

        【解决方案7】:

        我从来没有真正看到用纯 C 编写 Win32 的东西有什么问题,我实际上认为它比我尝试过的替代方案(MFC、WTL、QT 和其他一些)要干净得多。一些简单的指针:

        • 关于高位和低位字参数,有很好的宏可以为您处理——不过我现在不知道这些名称。

        • 您可以通过分配“应用程序”结构并使用 SetWindowLong() 存储其地址以一种相当不错的面向对象方式工作,从而解决了拥有全局句柄的问题。

        • 您可以从 WM_MESSAGE -> 函数指针创建一个相当简单的映射,以减轻窗口进程中长开关的可重复性,或者将其重构为更简单的函数以获得更好的概览。

        所以,总而言之,写出漂亮而干净的东西是可能的,但很难。其他所有方法也是如此,唯一不同的是“可能”和“困难”的值:)

        【讨论】:

        • 另外,一种非常简洁的Resource-Definition 文件格式,在可读性方面胜过任何新奇的、基于 XML 的化身。
        【解决方案8】:

        有更好的方法。使用 Qt。它适用于 C++,但 C++ 更适合 GUI,因为它的面向对象模型非常适合该领域。 Qt 本身是一个很棒的库,具有惊人的深度和广度,得到很好的支持和设计,获得 LGPL 许可并且使用起来很有趣。它带有一个完整的 GUI 设计器,可以帮助您以图形方式非常快速地构建对话框。

        如果你坚持使用 C 和原生 Win32,还有一种方法。购买 Petzold 的 Programming Windows 书 - 非常好。在阅读了前几章之后,您将能够相对容易地用 C 构建有趣的 GUI。与使用 Qt 相比,需要更多的代码和工作量,但积极的一面是,您将获得小巧而快速的可执行文件,而无需外部依赖。

        【讨论】:

        • 感谢您的建议——我可能会看看那本书,当我转向 C++ 时,我会记住 Qt。
        【解决方案9】:

        作为 C Windows 编程的前任讲师,我可以肯定地说,使用 C 构建 GUI 没有简单的方法 - 该语言不太适合这项任务。几乎其他任何东西都是更好的选择——我自己最喜欢的 GUI 开发是 Delphi。

        【讨论】:

        • 可能不在 Windows 中。在 unix 世界中,这并不难(尤其是在使用 UIM/X 时)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-03-20
        相关资源
        最近更新 更多