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 ",[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 ",[Info]), {noreply, State}. handle_call(CallMsg, _From, State) -> io:format("Got Call ~p ",[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]).