2013-05-27 7 views
1

Краткое: как убедиться, что «статически» объявленные идентификаторы для событий и/или виджетов не сталкиваются с проектом среднего и большего размера?Проблема с идентификатором WxWidget

... и долго:

Один из способов борьбы с идентификаторами в WxWidgets это объявить их с помощью перечислений на компиляции-единицы, т.е. в исходном файле-виджета. Однако, когда идентификаторы используются в обработке событий WxWidgets, они должны быть или должны быть глобально уникальными. Некоторым не обязательно быть глобально уникальными, но я думаю, что это безопаснее, если все они есть, иначе есть потенциал для выполнения - «столкновения», которые не вызывают никакого предупреждения - событие просто обрабатывается другим виджетами. К сожалению, я наткнулся на эту проблему пару раз (унаследованная база кода) - их трудно отследить и, скорее, раздражать, если я чего-то не упускаю. Во всяком случае, я хочу разобраться, раз и навсегда :-)

Я знаю, что WxWidgets также поддерживает динамическое связывание, и мы/я используем его в некоторых местах. Однако изменение кода для всех «статически» объявленных идентификаторов было бы слишком большим усилием. По сути, у меня много разных исходных файлов (> 60), где есть перечисления, начинающиеся со значения wxID_HIGHEST с некоторым (по-видимому) произвольным смещением. Я думаю, что смещение произвольное, вероятно, было добавлено, чтобы исправить отдельные случаи вышеуказанной проблемы с ID-столкновением. В любом случае, перечисление всех перечислений в один файл/перечисление кажется немного уродливым, потому что это будет невероятно длинный список.

Итак, вот что я думал: я поддерживаю MIN/MAX-ID для разных виджетов в одном заголовочном файле, используя единую перечисление, и предоставляю два макроса, которые BEGIN и END определяют идентификатор ID. END-макрос должен также проверить, что объявленный MAX-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; 

ответ

0

Там нет универсального ответа, но я думаю, что вы должны держать в виду следующее:

  • идентификаторы не должны быть глобально уникальными, они только должны быть уникальными внутри каждой вершине уровня. В типичной программе каждый диалог представлен собственным классом, поэтому все идентификаторы в нем находятся под контролем только этого класса, что позволяет не заботиться о том, что делает вся остальная часть программы.
  • Вы можете и имхо избегать использования идентификаторов полностью для всех элементов управления. Единственное место, где идентификаторы слишком удобны для их хранения, - это пункты меню, так как нет связанного с ними объекта (вы не можете привязываться к wxMenuItem). Но для всех элементов управления лучше просто позвонить control->Bind(), и в этом случае вам не нужно указывать идентификатор вообще, поскольку этот элемент управления только когда-либо будет получать события для себя. И хотя очень просто заменить макросы таблиц событий вызовами Bind(), вам даже не нужно делать это для существующих таблиц событий, поскольку у вас нет конфликтов с идентификаторами в них, по-видимому, поэтому все, что вам нужно сделать заключается в использовании Bind() для новых обработчиков событий.
  • Если вы используете XRC - и, опять же, IMHO, нет причин не делать этого - тогда все ваши идентификаторы являются строками, указанными в файлах XRC, и, тем самым, отличные строки, конечно, намного проще, чем отличать целые идентификаторы, поэтому эта проблема вообще не возникает. Примечательно, что определение ваших меню в XRC позаботится об одном случае, когда идентификаторы действительно удобны в использовании.

TL; DR Не используйте идентификаторы на все элементы меню, за исключением, определить их в XRC, если вы должны использовать их.

+0

Большое спасибо. Хотя мне нужен разумно быстрый и элегантный способ решения (унаследованного) беспорядка, с которым я имею дело. Все «живет» под одним верхним уровнем окна, таким образом, глобально уникальные идентификаторы будут более безопасными, ИМХО. То, как все это висит вместе, является своего рода не оптимальным, частично непродуманным, плохо «выращенным», не особенно ухоженным - у меня нет времени прямо сейчас для правильной очистки и повторного факторинга. IDs-To-Bind() прост: не так много, если идентификаторы используются в операторах switch в OnCommandEvent() или аналогичных методах, а также для поиска элементов управления или мне что-то не хватает (?). –

+0

Если вам нужно обрабатывать события из нескольких элементов управления в одном методе, вы можете использовать 'wxEvent :: GetEventObject()', чтобы различать их. Это в основном повторяет (обязательно уникальный) указатель управления как идентификатор. –

+0

Я нашел этот ответ, когда искал способ привязки к элементам меню без использования идентификаторов (мне тоже не нравятся). Наиболее логичным решением для меня было бы: (1) получить указатель на элемент меню внутри обработчика события из объекта 'wxCommantEvent' или (2) привязать непосредственно к' wxMenuItem'. И мне интересно, почему не представляется возможным, по крайней мере, не в wxWidgets 3.1. Или я ошибаюсь? –

Смежные вопросы