如何使用 WxWidgets 关闭 Erlang 程序?

How to close a programm in Erlang with WxWidgets?

我在关闭 Erlang 程序时遇到问题。我使用 wxWidgets.

-module(g).
-compile(export_all).
-define(height, 500).
-define(width, 500).  
-include_lib("wx/include/wx.hrl").
-define(EXIT,?wxID_EXIT).

init() ->
    start().

start() ->
    Wx = wx:new(),
    Frame = wxFrame:new(Wx, -1, "Line", [{size, {?height, ?width}}]),   
    setup(Frame),
    wxFrame:show(Frame),
    loop(Frame).

setup(Frame) ->
    menuBar(Frame),
    wxFrame:connect(Frame, close_window).

menuBar(Frame) ->
    MenuBar = wxMenuBar:new(),
    File = wxMenu:new(),
    wxMenuBar:append(MenuBar,File,"&Fichier"),
    wxFrame:setMenuBar(Frame,MenuBar),  
    Quit = wxMenuItem:new ([{id,400},{text, "&Quit"}]),
    wxMenu:append (File, Quit).

loop(Frame) ->
    receive
        #wx{event=#wxCommand{type=close_window}} ->
            io:format("quit icon"),
            wxWindow:close(Frame,[]);       

        #wx{id=?EXIT, event=#wxCommand{type=command_menu_selected}} ->
            io:format("quit file menu"),
            wxWindow:close(Frame,[])
    end.

但是程序没有关闭;退出图标或菜单中的退出都没有任何作用。

你快完成了,但是有一些错误。

首先,您提到的退出选择不会生成任何事件,您需要再次使用 connect,如下所示:

Quit = wxMenuItem:new ([{id,400},{text, "&Quit"}]),
wxFrame:connect(Frame, command_menu_selected),

现在每个退出方法都有一个事件,但它们都不起作用。

您的退出图标事件不匹配,因为您在模式匹配中输入了错误的事件类型,并且菜单退出选择事件不匹配,因为您正在查找 ID 为 ?EXIT ,它被定义为 ?wxID_EDIT,它被定义为......很明显不是 400,你在创建退出菜单项时使用的 ID。所以你的 receive 子句需要改成这样:

receive
    #wx{event=#wxClose{type=close_window}} ->
        io:format("quit icon"),
        wxFrame:destroy(Frame);
    #wx{id=400, event=#wxCommand{type=command_menu_selected}} ->
        io:format("quit file menu"),
        wxFrame:destroy(Frame)
    end.

除了 Michael 关于使用 connect/3 来监听菜单命令的回答之外,几乎任何框架都需要一些标准事件连接才能按照您期望的方式运行,除了您需要的任何特定内容之外进行中。请注意,这是连接到 close_window 事件并使用选项 {skip, true}。这样一来,信号在到达 Wx 的一部分之前不会停止传播,该部分将按照您期望的方式处理它(单击一次关闭),而不是在某些平台上需要两次单击才能关闭框架。

基本骨架通常是这样的:

init(Args) ->
    Wx = wx:new(),
    Frame = wxFrame:new(Wx, ?wxID_ANY, ""),

    % Generate whatever state the process represents
    State = some_state_initializer(Args),

    % Go through the steps to create your widget layout, etc.
    WidgetReferences = make_ui(Frame),

    % The standardish connects nearly any frame will need.
    ok = wxFrame:connect(Frame, close_window, [{skip, true}]),
    ok = wxFrame:connect(Frame, command_button_clicked),
    ok = wxFrame:connect(Frame, command_menu_selected),
    % Add more connects here depending on what you need.

    % Adjust the frame size and location, if necessary
    Pos = initial_position(Args),
    Size = initial_size(Args),
    ok = wxFrame:move(Frame, Pos),
    ok = wxFrame:setSize(Frame, Size),

    wxFrame:show(Frame),

    % Optional step to add this frame to a UI state manager if you're
    % writing a multi-window application.
    ok = gui_manager:add_live(self()),

    % Required return for wx_object behavior
    {Frame, State}.

有点偏离原文,但强烈相关...

许多 wxWidgets 应用程序有一些与此非常非常 类似的东西,根据需要定制不是通过重新写所有这些,而是​​通过定义您自己的回调模块并将其作为参数传递:

init({Mod, Args}) ->
    % ...
    PartialState = blank_state([{mod, Mod}, {frame, Frame}, {wx, Wx}]),
    State = Mod:finalize(PartialState, Args),

其中 blank_state/1 接受一个 proplist 和 returns 稍后实际的数据结构(通常是这个级别的记录,看起来像 #s{mod, frame, wx, widgets, data}),并且 Mod:finalize/2 获取不完整的状态和初始参数和 returns 一个完整的 GUI 框架加上它应该管理的任何程序状态——特别是 widgets 数据结构,它包含对任何 GUI 元素的引用以后需要监听、匹配或操作。

稍后您将拥有一些非常基本的通用处理程序,所有帧可能都需要处理,并将任何其他消息传递给特定的 Mod:

handle_call(Message, From, State = #s{mod = Mod}) ->
    Mod:handle_call(Message, From, State).

handle_cast(blit, State) ->
    {ok, NewState} = do_blit(State),
    {noreply, NewState};
handle_cast(show, State) ->
    ok = do_show(State),
    {noreply, State};
handle_cast(Message, State = #s{mod = Mod}) ->
    Mod:handle_cast(Message, State).

在这种情况下,do_blit/1 最终在重建和刷新 GUI 的回调模块中调用 Mod:blit/1,通过调用在 wx:batch/1 内执行此操作的函数从零开始重建它让它对用户来说是即时的:

blit(State) ->
    wx:batch(fun() -> freshen_ui(State) end).

如果您要在 GUI 中同时更改很多元素,从用户的角度来看,blitting 比逐步改组或 hiding/showing 元素要顺畅和快捷得多 -- 而且是 很多 更确定跨平台和各种计算机速度和用户态负载感觉相同(否则一些 Wx 后端会产生大量闪烁或中间显示怪异)。

do_show/1 函数通常类似于

do_show(#s{frame = Frame}) ->
    ok = wxFrame:raise(Frame),
    wxFrame:requestUserAttention(Frame).

(我一直想写一个基本的 "here is one way to structure a multi-window wxErlang application" tutorial/example 但一直没时间写,所以这里遗漏了很多细节,但你会偶然发现它们在写了几个程序之后你自己的。)