Нужно ли придумывать идентификаторы для виджетов wxErlang? - PullRequest
3 голосов
/ 19 ноября 2010

Я возился с модулем wx Эрланга и этим учебником .Раньше я не использовал wxwidgets, так что, возможно, это именно так, как это делается, но этот код кажется мне действительно ужасным:

%% create widgets
    T1001 = wxTextCtrl:new(Panel, 1001,[]),
    ST2001 = wxStaticText:new(Panel, 2001,"Output Area", []),
    B101  = wxButton:new(Panel, 101, [{label, "&Countdown"}]),
    B102  = wxButton:new(Panel, ?wxID_EXIT, [{label, "E&xit"}]),
    wxFrame:show(Frame),

Нужно ли людям назначать идентификаторы виджетов виджетам при их создании?Нормально ли называть переменную, которая указывает на виджет, после идентификатора виджета?

Ответы [ 3 ]

8 голосов
/ 19 ноября 2010

Я не знаю об Erlang, но в C ++ (и в других привязках, о которых я знаю) часто предпочтительнее использовать wxID_ANY в качестве идентификатора виджета, что означает, что вас не волнует его конкретное значение, а затем используйте Connect() для обработки событий из виджета. Явные идентификаторы могут быть удобны, если вам нужно найти виджет по его идентификатору позже (хотя вы также можете использовать имена виджетов для этого) или если вам нужен последовательный диапазон для идентификаторов (например, имеет смысл использовать идентификаторы 100, 101,. .., 109 для кнопок калькулятора, поскольку вы можете легко определить значение каждой кнопки из ее идентификатора), но нет необходимости всегда использовать их.

Что касается именования, то, конечно, нет необходимости использовать это странное соглашение (и быстрый просмотр учебника показывает, что это личное предпочтение автора - что, разумеется, я не доля).

5 голосов
/ 22 ноября 2010

Как и VZ, упомянутый выше, вы можете использовать wxID_ANY, если вам не нужно искать виджет по его идентификатору позже.

Однако я считаю, что не только ненормально называть переменные после идентификаторов, но и очень плохая идея сделать это. Назовите ваши переменные в соответствии с их значением и не используя какой-то непонятный идентификатор .

Кроме того, вам лучше определить нужные вам идентификаторы и дать им правильные (семантические) имена, чтобы они определялись только в одном месте, а позже вы сможете легко изменить идентификаторы, не влияя на вашу программу вообще, например так:

-define(ID_TEXT_CTRL, 1001).
-define(ID_OUTPUT_AREA, 2001).
-define(ID_COUNTDOWN_BUTTON, 101).
-define(ID_EXIT_BUTTON, ?wxID_EXIT).

TextCtrl = wxTextCtrl:new(Panel, ?ID_TEXT_CTRL,[]),
OutputArea = wxStaticText:new(Panel, ?ID_OUTPUT_AREA,"Output Area", []),
CountdownButton  = wxButton:new(Panel, ?ID_COUNTDOWN_BUTTON, [{label, "&Countdown"}]),
ExitButton  = wxButton:new(Panel, ?ID_EXIT_BUTTON, [{label, "E&xit"}])

Вы можете поместить определения либо в файл .erl, если он только один, либо в файл .hrl, который вам нужно будет включить во все файлы .erl, связанные с графическим интерфейсом пользователя.

1 голос
/ 31 декабря 2015

Нет.Случаи, в которых вы хотите искать что-то по идентификатору, - это примерно те же случаи, когда вам нужно искать что-то по идентификатору в C ++.Это применимо ко всем библиотекам виджетов, о которых я могу подумать - каждый раз, когда вы реагируете на сигнал с кодировкой some_standard_button_name и соответствует метке, например ?wxID_OK, вы ожидаете числовой идентификатор, представленный меткой, скрытой макросом.Большинство GUI-библиотек выполняют большую часть предварительной обработки, чтобы вымыть это, поэтому часто вы этого не замечаете (в случае библиотек sooper-dooper, таких как Qt, они все еще работают, только в фоновом режиме, и весь ваш код * 1003)* запустить прекомпилятор до того, как он станет "настоящим" C ++ ...).

Итак, как вы можете получить wx-штуку, которая была создана?Используя возвращенную ссылку.

Почти каждый вызов wx*:new() возвращает ссылку на объект [note1].Это абстрактная ссылка (внутренне кортеж, но не рассчитывайте на это) с достаточным количеством информации для привязок Эрланга и процессов системы Wx, чтобы однозначно говорить о конкретных объектах Wx, которые были созданы.Передача этих ссылок является типичным способом доступа к объектам Wx позже:

GridSz = wxFlexGridSizer:new(2, 2, 4, 4),
ok = wxFlexGridSizer:setFlexibleDirection(GridSz, ?wxHORIZONTAL),
ok = wxFlexGridSizer:addGrowableCol(GridSz, 1),

Однако менее очевидный случай - когда вам нужно что-то вроде сетки полей ввода, которую вы можете циклически перемещать или перемещать позначение ключа:

Scripts = [katakana, hiragana, kanji, latin],
Ilks    = [family, given, middle, maiden],
Rows    = [{Tag, j(J, Tag)} || Tag <- Scripts],
Cols    = [{Tag, j(J, Tag)} || Tag <- Ilks],
{GridSz, Fields} = zxw:text_input_grid(Dialog, Rows, Cols),

% Later on, extracting only present values as

Keys = [{S, I} || S <- Scripts, I <- Ilks],
Extract =
    fun(Key, Acc) ->
        case wxTextCtrl:getValue(proplists:get_value(Key, Fields)) of
            ""  -> Acc;
            Val -> [{Key, Val} | Acc]
        end
    end,
NewParts = lists:foldl(Extract, [], Keys),

И так далее.( zxw: text_input_grid / 3 definition и docs )

Один раз, когда вы действительно хотите ссылаться на объект по его идентификатору, а не по ссылке на объект, этотак же, как в C ++: когда вы слушаете конкретное событие щелчка:

{AddressPicker, _, _, AddressSz} =
    zxw:list_picker(Frame,
                    ?widgetADDRESS, ?addADDRESS, ?delADDRESS,
                    AddressHeader, Addresses, j(J, address)),

, а затем в цикле обработки сообщений универсального wx_object:

handle_event(Wx = #wx{id    = Id,
                      event = #wxCommand{type = command_button_clicked}},
             State) ->
    case Id of
        ?editNAME     -> {noreply, edit_name(State)};
        ?editDOB      -> {noreply, edit_dob(State)};
        ?editPORTRAIT -> {noreply, edit_portrait(State)};
        ?addCONTACT   -> {noreply, add_contact_info(State)};
        ?delCONTACT   -> {noreply, del_contact_info(State)};
        ?addADDRESS   -> {noreply, add_address_info(State)};
        ?delADDRESS   -> {noreply, del_address_info(State)};
        _ ->
            ok = unexpected(Wx),
            {noreply, State}
    end;
handle_event(Wx = #wx{id    = Id,
                      event = #wxList{type      = command_list_item_selected,
                                      itemIndex = Index}},
             State) ->
    case Id of
        ?widgetCONTACT -> {noreply, update_selection(contact, Index, State)};
        ?widgetADDRESS -> {noreply, update_selection(address, Index, State)};
        _ ->
            ok = unexpected(Wx),
            {noreply, State}
    end;

Первое предложение касаетсяв частности, с помощью нажатий на нестандартные кнопки, а второй - с событиями выбора виджета управления списком, чтобы сделать некоторые произвольные вещи в интерфейсе.Хотя развертывание записи события #wx{} не очень привлекательно для визуального отображения, использование соответствия в формировании предложения делает этот код GUI намного проще для понимания во время обслуживания, чем гигантский каскад проверок, исключений и последующих действий *Код типа 1031 *, switch или case..break и т. Д. Необходим для языков, в которых отсутствует соответствие.

В приведенном выше случае все конкретные идентификаторы помечены как макросы, точно одинаковокак это делается в Wx в C ++ и других наборах виджетов C ++. Большую часть времени ваши потребности удовлетворяются просто с помощью стандартных предопределенных типов кнопок Wx и соответствующей реакции на них;приведенный выше пример взят из кода, который вынужден нырнуть немного ниже, из-за некоторых особых требований к интерфейсу (и эквивалентный код C ++ сводится по существу к тому же, но значительно более многословному для выполнения той же задачи).

Некоторые платформы на языках чуть более высокого уровня имеют разные способы решения проблемы идентичности.Наборы виджетов для iOS и Android (и QtQuick, в этом отношении) скрывают эту деталь за чем-то вроде чуть более универсально полезной ссылки на объект, а не в зависимости от идентификаторов.То есть эти наборы виджетов по существу хранят все виджеты, созданные в хэше {ID => ObjReference}, выбирают идентификатор из каждого сигнала, извлекают ссылку на объект перед передачей управления в ваши обратные вызовы обработки и возвращают ссылку, сохраненную вхэш вместо простой передачи идентификатора напрямую.

Это замечательно, но не так, как работают старые наборы виджетов, привязанные к коду типа enums-as-label.Когда все сказанные и готовые компьютеры все еще имеют только один реальный тип: целые числа - мы придумываем всевозможные другие вещи поверх этого и наслаждаемся иллюзией типов и прочего веселья.

Мы могли бы сделать это -в Erlang также есть ссылки, но способ, которым код WxErlang обычно пишется, состоит в том, чтобы следовать традиции C ++, заключающейся в использовании идентификаторов объектов за метками макросов для событий, которые нельзя избежать уникальной идентификацией, и ссылок на объекты и стандартных меток для всего остального.

Библиотека zx_widgets, использованная выше, представляет собой набор предопределенных мета-виджетов, которые охватывают некоторые из наиболее распространенных случаев построения шаблонного поля и возвращают структуры данных, которые просты в обращении функционально.Стиль ООП Wx не совсем подходит для Erlang в некотором смысле (по этой причине самые длинные функции, которые вы когда-либо будете писать в Erlang, вероятно, будут кодом GUI), поэтому иногда для создания логики необходим дополнительный слойНосящий код вяжется с остальной частью Эрланга.Код GUI довольно универсален, но на любом языке и в любой среде.

[note1: Есть некоторые странные, неудобные случаи, когда некоторые тайны в стиле C ++ просачиваются через привязки в ваш Erlangкод, такой как процедура создания волшебной среды, используемая для использования 2D-графики DC холсты и еще много чего. ]

...