wxErlang 在screen绘图 以及在 window(wxTextCtrl)中用双缓冲绘图示例

-module(text_ctrl_draw).

-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]).

-include_lib("wx/include/wx.hrl").
-define(APPEND, 1).
-define(DRAW, 2).
-define(CLEAR, 3).
-record(state,
  {
      frame,
      parent,
      text_ctrl
   }).
%%%===================================================================
%%% API
%%%===================================================================
%%--------------------------------------------------------------------
%% @doc
%% @spec
%% @end
%%--------------------------------------------------------------------
new() ->
    _WX = wx:new(),
    Size = {size, {400, 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, destroy).

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(destroy, _From, #state{parent = Panel} = State) ->
    wxPanel:destroy(Panel),
    {stop, normal, ok, State};

handle_call(show, _From, #state{frame = Frame} = State) ->
    wxWindow:center(Frame),
    wxFrame:show(Frame),
    {reply, ok,  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{id = ?APPEND}, #state{parent = Tab,text_ctrl = TextCrl} = State) ->
    wxTextCtrl:hide(TextCrl),
   {TabSizeX, TabSizeY} = wxWindow:getVirtualSize(Tab),
    {OriSX , OriSY} = wxWindow:getScreenPosition(Tab),
    GridHeight = trunc((TabSizeY - 40) / 3),
    BottomPriceLine = OriSY + GridHeight * 2 + 20,%%2500
    EachPriceOccupy = GridHeight * 2 / (37000 - 34000),
    io:format("OriSY = ~p, EachPriceOccupy = ~p~n", [OriSY, EachPriceOccupy]),
    io:format("BottomPriceLine = ~p~n", [BottomPriceLine]),
    CDC = wxScreenDC:new(),
    % CDC = wxClientDC:new(Tab),
    % CDC = wxWindowDC:new(Tab),
    wxDC:setPen(CDC, wxPen:new(?wxLIGHT_GREY, [{width, 1}])),
    wxDC:drawLine(CDC, {OriSX + 0, OriSY + 20}, {OriSX + TabSizeX, OriSY + 20}),
    wxDC:drawLine(CDC, {OriSX + 0, OriSY + GridHeight * 2 + 20}, 
                        {OriSX + TabSizeX, OriSY + GridHeight * 2 + 20}),
    wxDC:drawLine(CDC, {OriSX + 0, OriSY + TabSizeY - 20}, 
                        {OriSX + TabSizeX, OriSY + TabSizeY -  20}),
    wxDC:drawLine(CDC, {OriSX + 50, OriSY + TabSizeY - 20 }, {OriSX + 50, OriSY + 20}),
    wxDC:drawLine(CDC, {OriSX + 750, OriSY + TabSizeY - 20}, {OriSX + 750, OriSY + 20}),
    wxDC:drawLine(CDC, {OriSX + 800, OriSY + TabSizeY }, {OriSX + 800, OriSY }),
    wxDC:setTextForeground(CDC, ?wxGREEN),
    wxDC:setTextBackground(CDC, ?wxBLUE),
    wxDC:drawText(CDC, "if1501time", {OriSX, OriSY}),
    wxDC:drawText(CDC, "分时走势", {OriSX + 50, OriSY + 40}),
    % wxDC:setTextForeground(CDC, ?wxYELLOW),
    wxDC:setTextForeground(CDC, ?wxBLUE),
    BottomVolumnLine =  OriSY + TabSizeY - 20,
    wxDC:drawText(CDC, "if1501", {OriSX + 50, BottomPriceLine}),
    wxScreenDC:destroy(CDC),
    % wxClientDC:destroy(CDC).%% showed a little down!!!
    % wxWindowDC:destroy(CDC),
    {noreply, State};

% 用双缓冲在窗口中绘图过程
handle_event(#wx{id = ?DRAW}, #state{text_ctrl = TextCrl, frame = Parent} = State) ->
    CDC = wxClientDC:new(TextCrl),
    BDC = wxBufferedDC:new(CDC),
    wxBufferedDC:init(BDC, BDC),
    wxDC:setBackground(BDC, ?wxBLACK_BRUSH),
    wxDC:clear(BDC),
    %%%%------------
    % 绘图过程,只是示例,自己可以做更复杂些
    wxDC:setTextForeground(BDC, ?wxBLUE),
    wxDC:drawText(BDC, "TTTTTTT", {25, 25}),
    %%%%------------
    % 把绘制好的图复制过去,可以根据需求复制图片的面积以及接受绘图结果的面积
    % eg (1)
    wxDC:blit(CDC, {10 + 5, 10 + 5}, {50, 50}, BDC, {0, 0}),
    % eg(2)
    % {TabSizeX, TabSizeY} = wxWindow:getVirtualSize(TextCrl),
    % wxDC:blit(CDC, {0, 0}, {TabSizeX, TabSizeY}, BDC, {0, 0}),
    wxBufferedDC:destroy(BDC),
    wxClientDC:destroy(CDC),   
    {noreply, State};

handle_event(#wx{},  State) ->
    {noreply, State}.

%%-------------------------
%%%===================================================================
%%% API
%%%===================================================================
do_init(Config) ->
    %% define parent Panel
    Parent = proplists:get_value(parent, Config),
    Panel = wxPanel:new(Parent, []),  
    % define controls ?
    AccountInput   = wxTextCtrl:new(Panel, 11, [{value, ""}, {size, {380, 400}}, 
                                    {style, ?wxTE_LEFT  bor ?wxTE_MULTILINE bor ?wxTE_CAPITALIZE }]),
    Append = wxButton:new(Panel, ?APPEND, [{label, "屏幕绘图"}]),
    Draw = wxButton:new(Panel, ?DRAW, [{label, "双缓冲绘图"}]),
    %% organization
    %% Canvas = wxPanel:new(Panel, [{style, ?wxFULL_REPAINT_ON_RESIZE}]),
    MainSizer = wxBoxSizer:new(?wxVERTICAL),
    wxSizer:add(MainSizer, AccountInput),
    wxSizer:add(MainSizer, Append),
    wxSizer:add(MainSizer, Draw),
    wxPanel:setSizer(Panel, MainSizer),
    wxWindow:center(Parent),
    wxTextCtrl:setFocus(AccountInput),
    wxTextCtrl:setInsertionPoint(AccountInput, 1),
    wxFrame:show(Parent),
    % wxFrame:setBackgroundColour(Parent, ?wxBLUE),
    wxButton:connect(Append, command_button_clicked),
    wxButton:connect(Draw,   command_button_clicked),
    wxTextCtrl:connect(AccountInput, command_text_updated),
    {Panel, #state{frame = Parent, parent = Panel, 
                   text_ctrl = AccountInput}}.

makeFrame(Title, Options) ->
    Frame = wxFrame:new(wx:null(), ?wxID_ANY, Title, Options),
    MenuSet  = wxMenu:new(),
    MenuBar = wxMenuBar:new(),
    wxMenuBar:append(MenuBar, MenuSet, "Setting"),
    wxFrame:setMenuBar(Frame, MenuBar),
    wxFrame:createStatusBar(Frame),
    wxFrame:setStatusText(Frame,"deal wxTextCtrl wxDC"),
    Frame.