如何使用 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 但一直没时间写,所以这里遗漏了很多细节,但你会偶然发现它们在写了几个程序之后你自己的。)
我在关闭 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 但一直没时间写,所以这里遗漏了很多细节,但你会偶然发现它们在写了几个程序之后你自己的。)