wxListCtrl 例子 二
wxListCtrl 事例代码:
关于list 中添加一个 Report 头,可以给头,类似toobar,可以给其中添加控件;但是添加控件的方式有两种:
一: 我认为有控件可以放在左中右,用一个参数或 integer 或 tuple 告诉toobar 左面几个,中间几个,剩下的都是右边的
这只需要一个 Sizer 就可以了,
这样:
case Align of
undefined ->
%%All controls AlignLeft
right ->
%% All contrils AlignRight
center ->
%% All controls AlignCenter
Integer ->
%% put the first Integer s of controls AlignLeft , the remaining right
{Integer, right} ->
%% put the fitst Integers of controls AlignCenter, the remaining right
{Left, Center} ->
%% put the first Integers of controls AlignLeft, then the Centers of controls AlignCenter, the remaining right
实际上,当前需要用两个Sizer, 需要说明这个是左边第一个,这个是右边第一个,我不明白的是为什么不直接按照顺序来?这样人
写着也感觉不顺啊
本例子中有两个wxListCtrl,一个是基本方式添加行和列,一种是用maps 实现按照预先设置的行列位置映射添加数据所在的行和列,
实现了消息注册,在module 只有一个消息处理 handle_event, 大致实现动态消息处理
-module(list).
-include_lib("wx/include/wx.hrl").
-behaviour(wx_object).
-export([new/1,
tbar/2,
columns/2,
load_data/2]).
-export([update/1,
reg_handlers/2,
stop/0,]).
-export([init/1,
terminate/2,
code_change/3,
handle_info/2,
handle_call/3,
handle_cast/2,
handle_event/2]).
-define(FIRST_COL, 0).
-define(SECOND_COL, 1).
-define(THIRD_COL, 2).
-record(state,
{
panel,
config,
report,
tbar_items,
selected_rows = [],
list_relative_complex,
event_function_map,
header_pos,
columns
}).
-record(col_def, { text ,
data_index,
align = ?wxLIST_FORMAT_LEFT,
sortable = false,
width = ?wxLIST_AUTOSIZE,
colour = ?wxBLACK
}).
%%%===================================================================
%%% API
%%%===================================================================
%%--------------------------------------------------------------------
%% @doc
%% @spec
%% @end
%%--------------------------------------------------------------------
new(Config) ->
wx:new(),
start(Config).
%%--------------------------------------------------------------------
%% @doc
%% @spec
%% @end
%%--------------------------------------------------------------------
start(Config) ->
wx_object:start_link(?MODULE, Config, []).
tbar(This, Items) ->
wx_object:call(This, {tbar, Items}).
update(This) ->
wx_object:call(This, update).
reg_handlers(This, EventAndHandler) ->
wx_object:call(This, {reg_handlers, EventAndHandler}).
columns(This, Columns) ->
wx_object:call(This, {columns, Columns}).
load_data(This, Data) ->
wx_object:call(This, {load_data, Data}).
stop() ->
wx_object:call(?MODULE, shutdown).
%%--------------------------------------------------------------------
%% @doc
%% @spec
%% @end
%%--------------------------------------------------------------------
init(Config) ->
wx:batch(fun() -> do_init(Config) end).
handle_event(#wx{id = Id, event = Event}, #state{report = ListView} = State) ->
#state{event_function_map = EventFunctionMap, selected_rows = SelectedRows} = State,
FunctionResult =
case Event of
#wxCommand{type = Type} ->
Function = maps:get({Id, Type}, EventFunctionMap, not_matched),
case Function of
not_matched ->
[];
Fun ->
Fun(SelectedRows),
[]
end;
#wxList{itemIndex = Item, type = Type} ->
Function = maps:get({?wxID_ANY, Type}, EventFunctionMap, not_matched),
case Function of
not_matched ->
[];
Fun ->
Fun(ListView, Item)
end;
_ ->
[]
end,
ReSelect =
case FunctionResult of
[] ->
[];
FunctionResult when is_list(FunctionResult)->
[FunctionResult | SelectedRows];
_ ->
SelectedRows
end,
{noreply, State#state{selected_rows = ReSelect}}.
handle_call({columns, Columns}, _From, #state{list_relative_complex = ComplexList} = State) ->
HeaderPos = set_headers(ComplexList, Columns),
{reply, ok, State#state{columns = Columns, header_pos = HeaderPos}};
handle_call({load_data, Data}, _From, State) ->
#state{header_pos = HeaderPos, list_relative_complex = ComplexList} = State,
HeaderPosMap = insert_rows_to_report(ComplexList, HeaderPos, Data),
{reply, ok, State#state{header_pos = HeaderPosMap}};
handle_call({reg_handlers, EventAndHandler}, _From, State) ->
EventFunctionMap =
lists:foldl(fun({Event, Fun}, RegMap) ->
maps:put(Event, Fun, RegMap)
end, #{}, EventAndHandler),
{reply, ok, State#state{event_function_map = EventFunctionMap}};
handle_call({tbar, TbarItems}, _From, State) ->
[First | _Remaining] = TbarItems,
wxButton:connect(First, command_button_clicked),
{reply, ok, State#state{tbar_items = TbarItems}};
handle_call(update, _From, #state{panel = Panel} = State) ->
#state{tbar_items = TbarItems, report = ListView,
list_relative_complex = ComplexList} = State,
Tbar =
case TbarItems of
TbarItems when is_list(TbarItems), length(TbarItems) =:= 0 ->
wxFlexGridSizer:new(0, 0, 0, 0);
TbarItems when is_list(TbarItems) ->
create_tbar(Panel, TbarItems);
_ ->
wxFlexGridSizer:new(0, 0, 0, 0)
end,
MainSizer = wxBoxSizer:new(?wxVERTICAL),
wxSizer:add(MainSizer, Tbar, [{flag, ?wxEXPAND}]),
ReportSizer = wxBoxSizer:new(?wxHORIZONTAL),
wxSizer:add(ReportSizer, ListView, [{flag, ?wxEXPAND}, {proportion, 1}]),
wxSizer:add(ReportSizer, ComplexList, [{flag, ?wxEXPAND}, {proportion, 1}]),
wxSizer:add(MainSizer, ReportSizer, [{flag, ?wxEXPAND}, {proportion, 1}]),
wxPanel:setSizer(Panel, MainSizer),
wxSizer:fit(MainSizer, Panel),
{reply, ok, State};
handle_call(shutdown, _From, State=#state{panel=Panel}) ->
wxPanel:destroy(Panel),
{stop, normal, ok, State};
handle_call(Msg, _From, State) ->
io:format("Got Call ~p\n",[Msg]),
{reply,ok,State}.
handle_cast(Msg, State) ->
io:format("Got cast ~p~n",[Msg]),
{noreply,State}.
handle_info(Msg, State) ->
io:format("Got Info ~p~n",[Msg]),
{noreply,State}.
code_change(_, _, State) ->
{stop, ignore, State}.
terminate(_Reason, _State) ->
ok.
%%--------------------------------------------------------------------
%% @doc
%% @spec
%% @end
%%--------------------------------------------------------------------
do_init(Config) ->
Parent = proplists:get_value(parent, Config),
Panel = wxPanel:new(Parent, []),
%% Setup sizers
ListCtrl = create_list_ctrl(Panel, [{style, ?wxLC_REPORT }]),
ComplexList = wxListCtrl:new(Panel, [{style, ?wxLC_REPORT }]),
wxListCtrl:connect(ListCtrl, command_list_item_selected, []),
{Panel, #state{panel = Panel, config = Config, report = ListCtrl,
list_relative_complex = ComplexList}}.
%% 简单方式插入数据
create_list_ctrl(Win, Options) ->
ListCtrl = wxListCtrl:new(Win, Options),
wxListCtrl:insertColumn(ListCtrl, ?FIRST_COL, "First Col", []),
wxListCtrl:insertColumn(ListCtrl, ?SECOND_COL, "Second Col", []),
wxListCtrl:insertColumn(ListCtrl, ?THIRD_COL, "Third Col", []),
Fun =
fun(Int) ->
Name = integer_to_list(Int),
wxListCtrl:insertItem(ListCtrl, Int, ""),
wxListCtrl:setItem(ListCtrl, Int, ?FIRST_COL, "First "++Name),
wxListCtrl:setItem(ListCtrl, Int, ?SECOND_COL, "Second "++Name),
wxListCtrl:setItem(ListCtrl, Int, ?THIRD_COL, "Third "++Name)
end,
wx:foreach(Fun, lists:seq(0,20)),
ListCtrl.
%% 创建Report 头
create_tbar(Panel, Items) ->
ItemNumber = length(lists:flatten(Items)),
LeftSizer = wxFlexGridSizer:new(1, ItemNumber, 0, 0),
RightSizer = wxFlexGridSizer:new(1, ItemNumber, 0, 0),
[insert_control_to_bar(Item, Panel, LeftSizer, RightSizer) || Item <- Items],
MainSizer = wxBoxSizer:new(?wxHORIZONTAL),
wxSizer:add(MainSizer, LeftSizer),
wxSizer:add(MainSizer, 60 ,20, [{proportion, 1}, {flag, ?wxEXPAND}]),
wxSizer:add(MainSizer, RightSizer),
MainSizer.
%% 给Report 头tbar插入控件
insert_control_to_bar(Item, NewParent, LeftSizer, RightSizer) ->
case Item of
{Control, left} ->
wxWindow:reparent(Control, NewParent),
wxSizer:add(LeftSizer, Control, [{proportion, 0}, {flag, ?wxALIGN_CENTER}]);
{Control, right} ->
wxWindow:reparent(Control, NewParent),
wxSizer:add(RightSizer, Control, [{proportion, 0}, {flag, ?wxALIGN_CENTER}]);
Item ->
wxWindow:reparent(Item, NewParent),
wxSizer:add(LeftSizer, Item, [{proportion, 0}, {flag, ?wxALIGN_CENTER}])
end.
%% 设置Report 头
set_headers(Report, Columns) ->
[_LastIndex , HeaderPosMap] =
lists:foldl(
fun(Column, [Index, HeaderPos]) ->
#col_def{text = Text, data_index = DataIndex, sortable = Sortable,
align = Align, width = Width, colour = Color} = Column,
% validate DataIndex, it should exist!
HeaderCol = create_one_column_header(Align, Width, Text),
wxListCtrl:insertColumn(Report, Index, HeaderCol),
[Index + 1, maps:put(DataIndex, Index, HeaderPos)]
end, [0, #{}], Columns),
HeaderPosMap.
%%
create_one_column_header(Align, Width, Text) ->
HeaderCol = wxListItem:new(),
wxListItem:setAlign(HeaderCol, Align),
wxListItem:setWidth(HeaderCol, Width),
wxListItem:setText(HeaderCol, Text),
%wxListItem:setTextColour(Item, Color),
HeaderCol.
insert_rows_to_report(ListView, undefined, Data) ->
[FirstRow | _RemainingRows] = Data,
case FirstRow of
{struct, RowData} when is_list(RowData)->
create_header_and_insert_rows(ListView, RowData, Data);
{obj, RowData} when is_list(RowData)->
create_header_and_insert_rows(ListView, RowData, Data);
Row when is_list(Row) ->
create_header_and_insert_rows(ListView, Row, Data);
_Row ->
ok
end;
insert_rows_to_report(ListView, HeaderPos, Data) ->
% LastRowNo = 0, % TODO: should append to
LastRowNo = wxListCtrl:getItemCount(ListView),
lists:foldl(
fun(Row, [RIndex]) ->
% fill up cells
case Row of
{struct, RowData} when is_list(RowData)->
insert_a_row_to_report(ListView, HeaderPos, RIndex, RowData),
[RIndex + 1];
{obj, RowData} when is_list(RowData)->
insert_a_row_to_report(ListView, HeaderPos, RIndex, RowData),
[RIndex + 1];
Row when is_list(Row) ->
insert_a_row_to_report(ListView, HeaderPos, RIndex, Row),
[RIndex + 1];
_Row ->
[RIndex]
end
end, [LastRowNo], Data),
HeaderPos.
create_header_and_insert_rows(ListView, FirstRowDataObject, Data) ->
{ListViewWidth, _ListViewHeight} = wxListCtrl:getSize(ListView),
ColumnWidth = ListViewWidth div length(FirstRowDataObject),
[_LastIndex , HeaderPosMap] =
lists:foldl(
fun({DataIndex, _DataObject}, [Index, HeaderPos]) ->
HeaderCol = create_column_header(?wxLIST_FORMAT_LEFT, ColumnWidth,
any_to_list(DataIndex)),
wxListCtrl:insertColumn(ListView, Index, HeaderCol),
[Index + 1, maps:put(any_to_atom(DataIndex), Index, HeaderPos)]
end, [0, #{}], FirstRowDataObject),
insert_rows_to_report(ListView, HeaderPosMap, Data).
insert_a_row_to_report(ListView, HeaderPos, RIndex, RowDataObject) ->
wxListCtrl:insertItem(ListView, RIndex, ""),
lists:foldl(
fun({DataIndex, Val} = _Cell, _Bool) ->
case maps:get(any_to_atom(DataIndex), HeaderPos, -1) of
-1 ->
false;
CIndex ->
Cell = wxListItem:new(),
wxListItem:setId(Cell, RIndex),
wxListItem:setColumn(Cell, CIndex),
wxListItem:setText(Cell, any_to_list(Val)),
wxListCtrl:setItem(ListView, Cell)
end
end, true, RowDataObject).
%%--------------------------------------------------------------------
%% @doc
%% 类型转化
%% @spec
%% @end
%%--------------------------------------------------------------------
any_to_list(undefined) ->
"";
any_to_list(List) when is_list(List) ->
List;
any_to_list(Bin) when is_binary(Bin) ->
case unicode:characters_to_binary(Bin, utf8, utf8) of
Bin -> unicode:characters_to_list(Bin);
_ -> binary_to_list(Bin)
end;
any_to_list(Atom) when is_atom(Atom) ->
atom_to_list(Atom);
any_to_list(Number) when is_integer(Number) ->
integer_to_list(Number);
any_to_list(Number) when is_float(Number) ->
float_to_list(Number, [{decimals, 2}]);
any_to_list(_) ->
throw(badarg).
any_to_atom(Atom) when is_atom(Atom) ->
Atom;
any_to_atom(List) when is_list(List) ->
list_to_atom(List);
any_to_atom(Bin) when is_binary(Bin) ->
list_to_atom(any_to_list(Bin));
any_to_atom(_) ->
throw(badarg).
wxListCtrl 测试代码
-module(testlist).
-behaviour(wx_object).
-export([new/0, start/1, destroy/0]).
-export([init/1,
terminate/2,
code_change/3,
handle_info/2,
handle_call/3,
handle_cast/2,
handle_event/2]).
-export([button_one_clicked/1,
report_items_selected/2]).
-include_lib("wx/include/wx.hrl").
-define(APPEND, 1).
-define(CLEAR, 2).
-define(INSERTIONPOSITION, 3).
-define(BREAKLINE, 4).
-define(TESTSTRING, 5).
-record(state,
{
frame,
parent,
config
}).
-record(col_def, { text ,
data_index,
align = ?wxLIST_FORMAT_LEFT,
sortable = false,
width = ?wxLIST_AUTOSIZE,
colour = ?wxBLACK
}).
%%%===================================================================
%%% API
%%%===================================================================
%%--------------------------------------------------------------------
%% @doc
%% @spec
%% @end
%% wxclient_position_select:new(Config)
%%--------------------------------------------------------------------
new() ->
_WX = wx:new(),
Size = {size, {800, 600}},
Pos = {pos, {200, 300}},
Style = {style, ?wxDEFAULT_FRAME_STYLE},
NOptions = [Pos, Size, Style],
Frame = makeFrame("wxTextCtrl Text", NOptions),
new([{parent, Frame}]).
new(Config) ->
start(Config).
start(Config) ->
wx_object:start_link({local, ?MODULE}, ?MODULE, Config, []).
%%--------------------------------------------------------------------
%% @doc
%% @spec
%% @end
%% wxclient_position_select:destroy()
%%--------------------------------------------------------------------
destroy() ->
wx_object:call(?MODULE, shutdown).
show() ->
wx_object:call(?MODULE, show).
init(Config) ->
wx:batch(fun() -> do_init(Config) end).
handle_info(Info, State) ->
io:format("Got Info ~p\n",[Info]),
{noreply, State}.
handle_call(CallMsg, _From, State) ->
io:format("Got Call ~p\n",[CallMsg]),
{reply, ok, State}.
handle_cast(CastMsg, State) ->
io:format("Got cast ~p~n",[CastMsg]),
{noreply,State}.
code_change(_, _, State) ->
{stop, ignore, State}.
terminate(_Reason, _State) ->
ok.
handle_event(#wx{}, State) ->
{noreply, State}.
%%%===================================================================
%%% API
%%%===================================================================
do_init(Config) ->
%% define parent Panel
Parent = proplists:get_value(parent, Config),
Panel = wxPanel:new(Parent, []),
Report = list:new([{parent, Panel}]),
ButtonOne = wxButton:new(Panel, 15, [{label, "Button1"}, {size, {80, 25}}]),
ButtonTwo = wxButton:new(Panel, 16, [{label, "Button2"}, {size, {80, 25}}]),
ButtonThree = wxButton:new(Panel, 17, [{label, "Button3"}, {size, {80, 25}}]),
ButtonFour = wxButton:new(Panel, 18, [{label, "Button4"}, {size, {80, 25}}]),
ButtonFive = wxButton:new(Panel, 19, [{label, "Button5"}, {size, {80, 25}}]),
TbarItems = [ButtonOne, {ButtonTwo, left}, {ButtonThree, right},
{ButtonFour, left}, {ButtonFive, right}],
list:tbar(Report, TbarItems),
list:update(Report),
EventButtonClicked = {15, command_button_clicked},
EventReportSelected = {?wxID_ANY, command_list_item_selected},
list:reg_handlers(Report,
[{EventButtonClicked, fun ?MODULE:button_one_clicked/1},
{EventReportSelected, fun ?MODULE:report_items_selected/2}]),
Data =[
[{<<"student_id">>,100010},{<<"department">>,<<"math">>},{<<"name">>,<<"nancy">>},
{<<"ppp">>, <<"ddd">>}],
[{<<"student_id">>,100005},{<<"department">>,<<"computer">>},{<<"name">>,<<"shank">>},
{<<"ppp">>, <<"bbb">>}],
[{<<"student_id">>,100009},{<<"department">>,<<"georraphy">>},{<<"name">>,<<"kobe">>},
{<<"ppp">>, <<"1235">>}]],
Columns =
[#col_def{text = "第1列", data_index = student_id, width = 100, sortable = false,
align = ?wxLIST_FORMAT_RIGHT },
#col_def{text = "第2列", data_index = department, width = 100, sortable = false,
align = ?wxLIST_FORMAT_RIGHT },
#col_def{text = "第3列", data_index = name, width = 100,sortable = false,
align = ?wxLIST_FORMAT_RIGHT }],
list:columns(Report, Columns),
list:load_data(Report, Data),
list:load_data(Report, Data),
MainSizer = wxBoxSizer:new(?wxVERTICAL),
wxSizer:add(MainSizer, Report, [{flag, ?wxEXPAND}, {proportion, 1}]),
wxPanel:setSizer(Panel, MainSizer),
wxFrame:show(Parent),
{Panel, #state{frame = Parent, parent = Panel}}.
makeFrame(Title, Options) ->
Frame = wxFrame:new(wx:null(), ?wxID_ANY, Title, Options),
MenuSet = wxMenu:new(),
MenuHelp = wxMenu:new(),
wxMenu:append(MenuHelp, 1, "关于..."),
MenuBar = wxMenuBar:new(),
wxMenuBar:append(MenuBar, MenuSet, "设置"),
wxMenuBar:append(MenuBar, MenuHelp, "帮助"),
wxFrame:setMenuBar(Frame, MenuBar),
wxFrame:createStatusBar(Frame),
wxFrame:setStatusText(Frame,"Erlang wxListCtrl"),
wxFrame:connect(Frame, command_menu_selected),
Frame.
report_items_selected(Report, Item) ->
ColumnNumber = wxListCtrl:getColumnCount(Report),
Cell = wxListItem:new(),
wxListItem:setId(Cell, Item),
lists:foldl(fun(Column, Result) ->
wxListItem:setColumn(Cell, ColumnNumber - 1 - Column),
wxListCtrl:getItem(Report, Cell),
ColumnText = wxListItem:getText(Cell) ,
[ColumnText | Result]
end, [], lists:seq(0, ColumnNumber - 1)).
button_one_clicked(Result) ->
io:format("Selected Items is ~p~n", [Result]).

浙公网安备 33010602011771号