WxWidget ID问题

时间:2013-05-27 12:44:22

标签: c++ macros wxwidgets

简短:如何确保事件和/或小部件的“静态”声明ID不会在中型到大型项目中发生冲突?

......和长:

在WxWidgets中处理ID的一种方法是通过每个编译单元的枚举来声明它们,即在小部件的源文件中。但是,当在WxWidgets的事件处理中使用ID时,它们应该或必须是全局唯一的。有些不需要全局唯一,但我认为它更安全,如果它们都是,否则有可能发生运行 - “冲突”,不会触发任何警告 - 事件只是由另一个小部件处理。不幸的是,我偶然遇到过这个问题(继承了代码库) - 它们很难追踪而且很烦人,除非我遗漏了什么。无论如何,我想一劳永逸地解决这个问题: - )

我知道,WxWidgets也支持动态绑定,我们/我在某些地方使用它。但是,更改所有“静态”声明的ID的代码将是太多的努力。基本上我所拥有的是许多单独的源文件(> 60),其中存在从wxID_HIGHEST开始的枚举,其具有一些(看似)任意偏移。我认为偏移量是任意的,可能已被添加以修复上述ID冲突问题的单个案例。无论如何,将所有枚举放入单个文件/枚举中似乎有点难看,因为它将是一个非常长的列表。

所以这就是我一直在想的:我使用单个枚举为单个头文件中的不同小部件维护MIN / MAX-ID,并提供两个BEGIN和END给定ID枚举的宏。 END-macro还应检查是否未超过声明的MAX-ID。这听起来合情合理吗?解决ID冲突问题的常用方法是什么?

我想要的解决方案如下所示。我计划添加一个处理动态绑定ID的函数。我知道WxWidgets提供了与ID引用计数相关的功能,但是,我只是想到它...它的目的是尽可能地与平台无关。

#include <wx/defs.h>
#define NUM_OF_DYNAMIC_AUTO_IDS 500

namespace WxWidgetIdHelper {

  enum WxWidgetIDsEnum {
    MIN_DYNAMIC_AUTO_ID = wxID_HIGHEST + 1,
    MAX_DYNAMIC_AUTO_ID = MIN_DYNAMIC_AUTO_ID + NUM_OF_DYNAMIC_AUTO_IDS,
    STATIC_ID_OFFSET = MAX_DYNAMIC_AUTO_ID + 1,

    Widget1_MIN_ID = STATIC_ID_OFFSET + 1,
    Widget1_MAX_ID = Widget1_MIN_ID + 20,

    Widget2_MIN_ID = Widget1_MAX_ID + 1,
    Widget2_MAX_ID = Widget2_MIN_ID + 20,
    ...
  };

  template<bool> struct MaxIdCheck;
  template<> struct MaxIdCheck<false> {};
}

#define BEGIN_WXWIDGET_ID_ENUM(CLASSNAME) \
  enum CLASSNAME##_##WXWIDGET_IDs { \
    CLASSNAME##_##MIN_ID = WxWidgetIdHelper##::##CLASSNAME##_##MIN_ID,

#define END_WXWIDGET_ID_ENUM(CLASSNAME) CLASSNAME##_##MAX_ID }; \
  WxWidgetIdHelper::MaxIdCheck< \
  ( CLASSNAME##_##MAX_ID>WxWidgetIdHelper::CLASSNAME##_##MAX_ID ) > \
  INCREASE##_##CLASSNAME##_##MAX_ID_in_WxWidgetIdHelper_h;

1 个答案:

答案 0 :(得分:1)

没有普遍的答案,但我认为你应该记住以下几点:

  • ID不需要全局唯一,它们只需要在每个顶级窗口内都是唯一的。在一个典型的程序中,每个对话框都由它自己的类表示,因此它中的所有ID都只受这个类的控制,这样你就不必关心程序的所有其他功能。
  • 你可以,恕我直言,应该避免完全使用所有控件的ID。 ID唯一容易保留的地方是菜单项,因为没有与之关联的对象(您无法绑定到wxMenuItem)。但是对于所有控件,最好简单地调用control->Bind(),在这种情况下你根本不需要指定ID,因为这个控件只能为自己获取事件。虽然通过调用Bind()替换事件表宏非常简单,但您甚至不必为现有的事件表执行此操作,因为它们中没有任何ID冲突,大概是 - 所以所有您需要做的是将Bind()用于新的事件处理程序。
  • 如果您使用XRC - 再次,恕我直言,没有理由不 - 那么所有的ID都是XRC文件中指定的字符串,并且保持字符串不同当然比保持整数ID不同更简单,所以这个问题根本不会出现。值得注意的是,在XRC中定义菜单需要考虑一个ID非常方便使用的情况。

TL; DR 除菜单项外,根本不使用ID,如果必须使用它们,请在XRC中定义。