domingo, 4 de mayo de 2008

WxOGL vs WxDC vs WxArt2D

This Week I was working in the graphical part of the Query Builder and search for all possible options to implement it using wxWidgets, as part of my research I found only three probably options (there are more options but only take in count this by now) where I run and write some test application for evaluation purposes:


1. WxArt2D:
is a graphical library for 2D, the drawing document can be made hierarchical by adding child primitives to a parent primitive, everything that is drawn from within a document, is done by calling drawing methods via a a2dCanvasView through it's device context a2dDrawer2D. A document can have several views open at the same time. And each view can display whatever part of the document. Source: http://wiki.wxwidgets.org/WxArt2d

Pros:
  • It's a multi-document framework.
  • Can draw complex objects in a easy way.
  • Can exists several views of objects in hierarchy.
  • Can save image to svg format.
  • Allow to handled events in graphical objects.
  • It's Highly optimized.
  • Good community support.
Cons:
  • The only way to use it, is downloading directly from CVS.
  • Configuration, Compilation and use can be difficult for begginners because cmake haven't a useful way of explain errors and their solutions (even the simplest).
  • Adds a new level of complexity in a project when the learning curve of understanding of source code grows because use it.
  • If a error related to the library is raised when you use an application (that happens to me with the examples) only have two options: fix by myself (I don't want to do it ) or ask for help (can take long time).
  • I try a demo of electronic parts diagram and I catch a lot of problems and exceptions only testing, without really using it, this don't give me a good advice about stability.
2. WxOGL: it's a good graphical library written when dinosaurs ruled the world :), but in my own words is a very good objects graphical library written in C++ that allow to create some simple and complex objects given to it the possibility of add events & properties.

Pros:
  • Very easy to use.
  • Configuration and use is very simple.
  • Used by pgAdmin right now, not new dependencies needed.
  • Good Stability.
Cons:
  • Poor documented.
  • Doesn't have support of a community.
  • Development status dead.
  • Don't give all control I want from my graphical objects.
  • Library is not good for and architectural pattern like Model View Controller (MVC).
  • Adds an extra overhead for simple graphics needed, forcing to create complex objects that some times are not needed.
  • Use wxDC as their drawing method, not really a cons but an interesting afirmation.
3. WxDC: device context graphic library, allows you to draw stuff manually.

Pros:
  • Have a lot of flavors: wxPaintDC for paint events, wxClientDC can be used outside paint events, wxBufferedDC for flickerless Drawing, Can paint into postscript files with wxPostScriptDC .
  • Give all control to implement the design pattern that I want to use (MVC).
  • It's very stable because their operations are very simple.
  • Allow full control over the way stuff will be painted.
  • Very simple to learn and use.
  • It's integrated with the wxWidgets library not need aditional steps or configurations.
  • Because their simplicity and integration with wx library, it's most probably don't have any issues when compiling source code in different plataforms
  • Very well documented WxWidgets Book Chapter Sample
Cons:
  • It's not as powerful as WxArt2D or WxOGL.
  • All drawing stuff are now responsability of programmer.
  • A bad implementation of drawing maybe can finish with a buggy application.
  • A functional application can take a little more time (not too much) to be completed that using WxOGL or WxArt2D.

My Choice until now it's: WxDC because their simplicity and the full control that give to programmer of doing almost all things needed for a graphical query builder only using graphics primitives (in a pattern like MVC).

I create a very little (and not optimized or good programmed, just functional) hello graphic world proof of concept for a diagram of tables, you can drag and drop tables (just simple squares with text) around application only:

#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#endif

#include "wx/wx.h"

class MyApp: public wxApp
{
virtual bool OnInit();
};


IMPLEMENT_APP(MyApp)



class MyFrame: public wxFrame
{
public:

MyFrame(const wxString& title,
const wxPoint& pos, const wxSize& size);

void OnQuit(wxCommandEvent& event);
void OnAbout(wxCommandEvent& event);
void MyFrame::OnPaint(wxPaintEvent& event);
void MyFrame::OnMotion(wxMouseEvent& event);
wxRect rectToDraw;
wxRect rectToDraw2;
int xx, xx2;
int yy, yy2;
int pressed;
DECLARE_EVENT_TABLE()
};


bool MyApp::OnInit()
{
MyFrame *frame = new MyFrame( wxT("Hello World"),
wxPoint(50,50), wxSize(800,600) );
frame->Show(TRUE);
SetTopWindow(frame);
frame->xx=10;
frame->yy=10;
frame->xx2=35;
frame->yy2=35;
frame->pressed=0;
return TRUE;
}


enum
{
ID_Quit = 1,
ID_About = 0,

};

BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(ID_Quit, MyFrame::OnQuit)
EVT_MENU(ID_About, MyFrame::OnAbout)
EVT_PAINT(MyFrame::OnPaint)
EVT_MOTION(MyFrame::OnMotion)
EVT_LEFT_DOWN(MyFrame::OnMotion)
EVT_LEFT_UP(MyFrame::OnMotion)
END_EVENT_TABLE()



void MyFrame::OnPaint(wxPaintEvent& event)
{
wxPaintDC dc(this);
dc.SetPen(*wxBLACK_PEN);

wxRect tmp(wxPoint(xx, yy), wxSize(70,70));
rectToDraw = tmp;

wxRect tmp2(wxPoint(xx2, yy2), wxSize(70,70));
rectToDraw2 = tmp2;
//Do not draw if not exposed
if (IsExposed(rectToDraw)){
//draw object 1
dc.SetBrush(*wxBLUE_BRUSH);
dc.DrawRectangle(rectToDraw);
dc.DrawText(wxT("Table 1"),xx,yy);
dc.DrawText(wxT("Col1"),xx,yy+12); //use font metrics here
//draw object 2
dc.SetBrush(*wxWHITE_BRUSH);
dc.DrawRectangle(rectToDraw2);
dc.DrawText(wxT("Table 2"),xx2,yy2);
dc.DrawText(wxT("Col1"),xx2,yy2+12);
}
}


MyFrame::MyFrame(const wxString& title,
const wxPoint& pos, const wxSize& size)
: wxFrame((wxFrame *)NULL, -1, title, pos, size)
{
wxMenu *menuFile = new wxMenu;
menuFile->Append( ID_About, wxT("&About..." ));
menuFile->AppendSeparator();
menuFile->Append( ID_Quit, wxT("E&xit" ));

wxMenuBar *menuBar = new wxMenuBar;
menuBar->Append( menuFile, wxT("&File") );

SetMenuBar( menuBar );

CreateStatusBar();
SetStatusText( wxT("Proof of Concept drawing moving objects, just click one and drag & drop [flicker can be eliminated with buffering]") );
}


void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
{
Close(TRUE);
}

void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
{

wxMessageBox(wxT("This is a Hello Direct Contex Application in wxWidgets"),
wxT("About Hello DC"), wxOK | wxICON_INFORMATION, this);
}


//Change position of objects when mouse is dragged & refresh painting
void MyFrame::OnMotion(wxMouseEvent& event)
{
if(event.ButtonDown()&&pressed==0){
pressed=1;
}
if(event.ButtonUp()){
pressed=0;
}

if (event.Dragging())
{
wxClientDC dc(this);
wxPen pen(*wxRED, 1); // red pen of width 1
dc.SetPen(pen);
dc.DrawPoint(event.GetPosition());
dc.SetPen(wxNullPen);
int posx=event.GetPosition().x;
int posy=event.GetPosition().y;
if(pressed==1 &&( posx-xx>0 && xx+50>posx ) && (posy-yy>0 && yy+50>posy)){
pressed=2;
}else if(pressed==1 &&( posx-xx2>0 && xx2+50>posx ) && (posy-yy2>0 && yy2+50>posy)){
pressed=3;
}

if(pressed==2){
xx=posx-25;
yy=posy-25;
}else if (pressed==3){
xx2=posx-25;
yy2=posy-25;
}

this->Refresh();
}
}

1 comentario:

Michel Laglasse dijo...

Excellent article ! Exactly what I was looking for.
And excellent little sample !
Thanks for sharing !