wxWidgets 그래프 구현 예제

wxWidgets 그래프 구현 예제

출처: http://www.daniweb.com/code/snippet217195.html

/* Create a new <strong class="highlight">graph</strong> with dimensions 750x500 */
m_plot = new neGraph( this,wxSize(750,500)); 
/* Set offset from wxCoord(0,0), so basically the position of the <strong class="highlight">graph</strong> */
m_plot->SetOffSet(wxSize(0,0));
/* Set x-scale to '2' which is 1 hour*/
m_plot->SetScale(2);
/* Scroll up */
m_plot->Scroll(0,0);
/* Draw a grid */
m_plot->DrawGrid(true);
#include <vector>
#include "wx/wx.h"
#include "main.h" // for myFrame*

#define BUTTON_START        7000
#define COMBO_BOX_TIMESPAN  7001

#define C_HOUR       "1 hour"
#define C_DAY        "1 day"
#define C_WEEKS      "2 weeks"
#define STD_OFFSET   50

struct neCoord
{
    long minutes;
    double y;
};

class neLine
{
public:
    std::vector<neCoord> coords;
    neLine() {line_name = "<empty>";}
    neLine(std::vector<neCoord>,wxString name = "<empty>");
    ~neLine(){};
    void ClearItems(void);
    wxString line_name;
    void Add(neCoord in_coord){coords.push_back(in_coord);}
};

// define a scrollable canvas for drawing onto
class neGraph: public wxScrolledWindow
{
public:
    neGraph( MyFrame*);
    neGraph( MyFrame*, wxSize );
    ~neGraph();
    void SetOffSet(wxSize);
    void SetScale(int);
    int  GetScale(void) { return scale; }
    void SetStartDate(const wxChar*);
    void AddData(neLine in_data) {grid_data.push_back(in_data);}
    void ClearGraph(void);
    void SetGridSize(wxSize);
    void DrawGrid(bool in ) { grid = in; }
private:
    void InitGraph(wxInitDialogEvent &event);
    void OnPaint(wxPaintEvent &event);
    void OnStartClicked(wxCommandEvent &event);
    void OnTimeSelection(wxCommandEvent &event);
    void DrawAxes(wxDC& dc);
    void DrawControls(void);
    void FillAxes(wxDC& dc);
    void DrawData(wxDC& dc);
    wxDateTime start;
    int scale;
    bool grid;
    MyFrame *m_owner;
    wxSize g_size;
    wxSize req_g_size;
    wxSize offset;
    std::vector< neLine > grid_data;
    wxTextCtrl *t_inputd;
    wxTextCtrl *t_inputt;
    wxButton *b_go;
    wxComboBox *c_timespan;
    DECLARE_EVENT_TABLE();
};

void neBox(const wxString);
std::string IntToString(int Input, int add_a_zero = 0);

#endif
#include <sstream>
#include <string>
#include "graph.h"
#include "wx/wx.h"

using std::vector;

neLine::neLine(std::vector<neCoord> in_vec,wxString name)
{
    coords = in_vec;
    line_name = name;
}

void neLine::ClearItems(void)
{
    for (unsigned int i = 0; i < coords.size(); i++)
        coords.pop_back();
}

BEGIN_EVENT_TABLE(neGraph, wxScrolledWindow)
    EVT_PAINT       (neGraph::OnPaint)
    EVT_INIT_DIALOG (neGraph::InitGraph)
    EVT_BUTTON      (BUTTON_START, neGraph::OnStartClicked)
    EVT_COMBOBOX    (COMBO_BOX_TIMESPAN, neGraph::OnTimeSelection)
END_EVENT_TABLE()

neGraph::neGraph(MyFrame *parent)
: wxScrolledWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
                   wxHSCROLL | wxVSCROLL | wxNO_FULL_REPAINT_ON_RESIZE)
{
    start = wxDateTime::Now();
    scale = 0;
    grid = false;
    g_size.x = 170;
    g_size.y = 220;
    req_g_size = wxSize(170,220);
    m_owner = parent;
    offset = wxSize(STD_OFFSET,STD_OFFSET);
    DrawControls();
}

neGraph::neGraph( MyFrame *parent, wxSize gridsize)
: wxScrolledWindow(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize,
                   wxHSCROLL | wxVSCROLL | wxNO_FULL_REPAINT_ON_RESIZE)
{
    start = wxDateTime::Now();
    scale = 0;
    grid = false;
    m_owner = parent;
    offset = wxSize(STD_OFFSET,STD_OFFSET);
    req_g_size = gridsize;
    SetGridSize(gridsize);
    DrawControls();
}

neGraph::~neGraph()
{
    delete t_inputd;
    delete t_inputt;
    delete b_go;
    delete c_timespan;
}

void neGraph::SetGridSize(wxSize gridsize) 
{
    req_g_size = gridsize;
    /* First find a number of pixels that can be cut in equal parts */
    while (gridsize.y % 10) gridsize.y--;
    if (scale == 0) /* 2 weeks */
        while (gridsize.x % 14) gridsize.x--; 
    else  /* one day or 1 hour*/
        while (gridsize.x % 12) gridsize.x--; 

    g_size.x = gridsize.x;
    g_size.y = gridsize.y;
}

void neGraph::ClearGraph()
{
    for (unsigned int i = 0; i < grid_data.size(); i++)
        grid_data.clear();
}
void neGraph::SetStartDate(const wxChar* indate)
{
    start.ParseDate(indate);
}
void neGraph::SetOffSet(wxSize off)
{
    offset.x = off.x + STD_OFFSET;
    offset.y = off.y + STD_OFFSET;
}

/* - Set X-axes scale. 0=2 weeks, 1=1 day, 2=1 hour*/
void neGraph::SetScale(int sc)
{
    scale = sc;
    SetGridSize(req_g_size);
} 

void neGraph::DrawAxes(wxDC& dc)
{
    if (grid)
    {
        wxPen pen(wxColour(180,180,180), 1); 
        dc.SetPen(pen);
        for (int i = 0; i < g_size.x; i += 10)
            dc.DrawLine(offset.x+i, offset.y, offset.x+i, offset.y+g_size.y);
        for (int j = 0; j < g_size.y; j += 10)
            dc.DrawLine(offset.x, offset.y+j, offset.x+g_size.x, offset.y+j);
    }
    wxPen pen2(*wxBLACK, 2); 
    dc.SetPen(pen2);
    dc.DrawLine(offset.x, offset.y, offset.x, offset.y+g_size.y+5);
    dc.DrawLine(offset.x-5, offset.y+g_size.y, offset.x+g_size.x, offset.y+g_size.y);
    dc.DrawLine(offset.x-5, offset.y, offset.x+5, offset.y);
    dc.DrawLine(offset.x+g_size.x, offset.y+g_size.y-5, offset.x+g_size.x, offset.y+g_size.y+5);
    dc.SetPen(wxNullPen);
}

void neGraph::FillAxes(wxDC& dc)
{
    double step=0;
    wxDateTime datetime = start;
    // X-axes can have only 3 scales (2 weeks, 1 day or 1 hour)
    switch (scale)
    {
    case 0: // 2 weeks
        step = g_size.x / 14;
        for (int i = 0; i <= 14; i++)
        {
            std::string temp = IntToString(datetime.GetDay(),1) + "-" + IntToString(datetime.GetMonth()+1,1);
            dc.DrawLine(offset.x+(i*step), offset.y+g_size.y, offset.x+(i*step), offset.y+g_size.y+5); 
            if ((g_size.x > 500) || (g_size.x > 250 && g_size.x <=500 && !(i%2)) ||(g_size.x <= 250 && !(i%4)))
                dc.DrawText(temp , offset.x+(step*i)-20, offset.y+g_size.y+10);
            datetime.Add(wxTimeSpan::Day());
        }
        break;
    case 1: // 1 day
        step = g_size.x / 12;
        for (int i = 0; i <= 12; i++)
        {
            std::string temp = IntToString(datetime.GetHour(),1) + ":" + IntToString(datetime.GetMinute(),1);
            dc.DrawLine(offset.x+(i*step), offset.y+g_size.y, offset.x+(i*step), offset.y+g_size.y+5); 
            if ((g_size.x > 500) || (g_size.x > 250 && g_size.x <=500 && !(i%2)) ||(g_size.x <= 250 && !(i%4)))
                dc.DrawText(temp, offset.x+(step*i)-20, offset.y+g_size.y+10);
            datetime.Add(wxTimeSpan::Hours(2));
        }
        break;
    case 2: // 1 hour
        step = g_size.x / 12;
        for (int i = 0; i <= 12; i++)
        {
            std::string temp = IntToString(datetime.GetHour(),1) + ":" + IntToString(datetime.GetMinute(),1);
            dc.DrawLine(offset.x+(i*step), offset.y+g_size.y, offset.x+(i*step), offset.y+g_size.y+5); 
            if ((g_size.x > 500) || (g_size.x > 250 && g_size.x <=500 && !(i%2)) ||(g_size.x <= 250 && !(i%4)))
                dc.DrawText(temp, offset.x+(step*i)-20, offset.y+g_size.y+10);
            datetime.Add(wxTimeSpan::Minutes(5));
        }
        break;
    }

    step = g_size.y / 10;
    for (int i = 0; i <= 10; i ++)
    {
        dc.DrawLine(offset.x-5, offset.y+g_size.y-(i*step),offset.x,offset.y+g_size.y-(i*step));
        dc.DrawText(IntToString(i*10), offset.x-50, offset.y+g_size.y-(i*step)-10);
    }   
}

void neGraph::DrawData(wxDC& dc)
{
    wxColour colour_arr[10] = {*wxBLUE,*wxRED,*wxCYAN,*wxGREEN,*wxWHITE,*wxLIGHT_GREY,*wxBLUE,*wxRED,*wxCYAN,*wxGREEN};
    // calc how many minutes 
    double minute_step=0.0;
    switch(scale)
    {
    case 0:
        minute_step = (double)g_size.x / (14.0*24.0*60.0);
        break;
    case 1:
        minute_step = (double)g_size.x / (24.0*60.0);
        break;
    case 2:
        minute_step = (double)g_size.x / 60.0;
        break;
    }
    // max of 10 line per graph 
    for (unsigned int line = 0; line < grid_data.size() && line < 10; line++)
    {
        wxPen pen(colour_arr[line], 1); 
        dc.SetBrush(colour_arr[line]);
        dc.SetPen(pen);
        dc.DrawRoundedRectangle(offset.x+g_size.x, offset.y+(25*line), 30, 20,5.0);
        dc.FloodFill(offset.x+g_size.x+10, offset.y+(25*line)+10, *wxWHITE, wxFLOOD_SURFACE);
        dc.DrawText(grid_data[line].line_name,offset.x+g_size.x+40, offset.y+(25*line)); 

        for (unsigned int point = 0; point < grid_data[line].coords.size() -1; point++)
        {
            dc.DrawLine(
                offset.x+(grid_data[line].coords[point].minutes*minute_step),
                offset.y+g_size.y-((g_size.y/100)*grid_data[line].coords[point].y),
                offset.x+(grid_data[line].coords[point + 1].minutes*minute_step),
                offset.y+g_size.y-((g_size.y/100)*grid_data[line].coords[point + 1].y)
                );
        }
    }   
}

void neGraph::DrawControls()
{
    t_inputd = new wxTextCtrl(this, -1, "dd-mm-yyyy", wxPoint(20,0));
    t_inputt = new wxTextCtrl(this, -1, "hh:mm:ss", wxPoint(t_inputd->GetPosition().x+t_inputd->GetSize().x + 10,0));
    c_timespan = new wxComboBox(this, COMBO_BOX_TIMESPAN,C_HOUR, wxPoint(t_inputt->GetPosition().x+t_inputt->GetSize().x + 10, 0));
    c_timespan->AppendString(C_HOUR);
    c_timespan->AppendString(C_DAY);
    c_timespan->AppendString(C_WEEKS);
    b_go = new wxButton(this, BUTTON_START , "Start",wxPoint(c_timespan->GetPosition().x+c_timespan->GetSize().x + 10, 0));     
}


void neGraph::OnPaint(wxPaintEvent &WXUNUSED(event) )
{      
    wxPaintDC dc(this);
    PrepareDC(dc);
    dc.Clear();
    DrawAxes(dc);
    FillAxes(dc);
    DrawData(dc);
}

void neGraph::InitGraph(wxInitDialogEvent &WXUNUSED(event))
{
}

void neGraph::OnStartClicked(wxCommandEvent &WXUNUSED(event))
{
    wxDateTime in_time;
    wxString dt = t_inputd->GetValue() + " " + t_inputt->GetValue();
    if (!in_time.ParseDateTime(dt))
    {
        neBox("Error in input!");
        t_inputt->SetValue("hh:mm:ss");
        t_inputd->SetValue("dd-mm-yyyy");
        return;
    }
    start = in_time;
    ClearGraph();
    /*****************************/
    /* TODO: Reload data here !! */
    /*****************************/
    this->Refresh();
}

void neGraph::OnTimeSelection(wxCommandEvent &WXUNUSED(event))
{
    if (c_timespan->GetValue() == C_DAY)
        SetScale(1);
    else if (c_timespan->GetValue() == C_WEEKS)
        SetScale(0);
    else SetScale(2);
    ClearGraph();
    /*****************************/
    /* TODO: Reload data here !! */
    /*****************************/
    this->Refresh();
}

/* some common functions */
void neBox(const wxString input)
{
    wxMessageDialog* temp =  new wxMessageDialog(NULL,input);
    temp->ShowModal();
    delete temp;
    return; 
}

std::string IntToString(int Input, int add_a_zero)
{
    std::stringstream temp;
    std::string str;
	temp << Input;
	temp >> str;
    if (add_a_zero && Input < 10) str = "0" + str;
	return str;
}

Leave a Reply

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>


이 사이트는 스팸을 줄이는 아키스밋을 사용합니다. 댓글이 어떻게 처리되는지 알아보십시오.