wxGraphicsContex Text Drawing

Are you writing your own components and need help with how to set them up or have questions about the components you are deriving from ? Ask them here.
sam_des
In need of some credit
In need of some credit
Posts: 4
Joined: Wed Aug 30, 2017 4:55 am

wxGraphicsContex Text Drawing

Postby sam_des » Wed Aug 30, 2017 5:14 am

Hello,

I am writing a custom control & using & wxBufferedPaintDC & wxGraphicsContext for it. I am able to draw rectangles, lines, circle etc. & its works as expected. But unable to draw the text. Nothing appears at all.
I am using wxWidgets 3.0.3 & Code::Blocks/mingw

Code: Select all

void PlotWidget::DrawBackground( wxBufferedDC* dc )
{
    wxGraphicsContext* gc = wxGraphicsContext::Create( *dc );

    wxRect rc = GetClientRect();
   
    gc->SetBrush( wxBrush(m_WidgetBkColor) );
    gc->SetPen( wxPen(m_WidgetBkColor, 1, wxSOLID) );
    gc->DrawRectangle( rc.x, rc.y, rc.width, rc.height );
    // This works as expected

    gc->SetFont( m_PlotLabelFont, m_PlotLabelColor );
    // these are wxFont & wxColour class members, initialized elsewhere
    // Creating a font & colour explicitly here also doesn't work either

    gc->DrawText( _("SOME TEXT"), rc.width/2, rc.height/2 );

    delete gc;
}


I also tried the same code with wxPython 4.0.0b1 which works just fine.
If I disable wxGraphicsContext with C++, everything again works fine, including drawing text.

Any help would be highly appreciated.
TIA,
sam_des

User avatar
doublemax
Moderator
Moderator
Posts: 11290
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxGraphicsContex Text Drawing

Postby doublemax » Wed Aug 30, 2017 10:13 am

There isn't much you can do wrong when drawing text. I suspect the text has the same color as the background. Try drawing at a different postion and / or a different color for a test.

And check that the font is valid with wxFont::IsOk()

BTW: I'm not 100% if this is the right thing to do:

Code: Select all

wxRect rc = GetClientRect();
What values do you get for rc.x and rc.y? They should be zero. If they're not, use this instead:

Code: Select all

wxRect rc( GetClientSize() );
Use the source, Luke!

sam_des
In need of some credit
In need of some credit
Posts: 4
Joined: Wed Aug 30, 2017 4:55 am

Re: wxGraphicsContex Text Drawing

Postby sam_des » Wed Aug 30, 2017 3:12 pm

Hello,

Tried following things,
1) wxFont is valid
2) Created separate font in DrawBackground() itself, explicitly specifying different colour.
3) wxRect rc( GetClientSize() ) instead of wxRect rc = GetClientRect(). Although I do get correct x,y,h,w with original code too.
4) Disabled the background painting with gc->DrawRectangle(). Now only thing being done in DrawBackground() is drawing text.
5) Tried different positions to draw the text with different strings.

Nothing appears at all.

sam_des

PB
wxWorld Domination!
wxWorld Domination!
Posts: 1274
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxGraphicsContex Text Drawing

Postby PB » Wed Aug 30, 2017 4:19 pm

FWIW, I have tried this (wxWidgets trunk, Windows 10), which is pretty much the same as the code you posted

Code: Select all

#include <wx/wx.h>
#include <wx/dcbuffer.h>
#include <wx/graphics.h>

class MyCanvas : public wxPanel
{
public:
    MyCanvas(wxWindow* parent)
        : wxPanel(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE)
    {       
        SetBackgroundStyle(wxBG_STYLE_PAINT);
        Bind(wxEVT_PAINT, &MyCanvas::OnPaint, this);               
    }
private:   
    void OnPaint(wxPaintEvent&)
    {
        wxBufferedPaintDC dc(this);
        wxGraphicsContext* gc = wxGraphicsContext::Create(dc);
        wxRect rc = GetClientRect();
        wxColour bkColor(*wxBLACK);
        wxColour textColor(*wxGREEN);
        wxFont font(10, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_BOLD);

        gc->SetBrush(wxBrush(bkColor) );
        gc->SetPen(wxPen(bkColor, 1, wxPENSTYLE_SOLID));
        gc->DrawRectangle(rc.x, rc.y, rc.width, rc.height);

        gc->SetFont(font, textColor);     
        gc->DrawText( _("SOME TEXT"), rc.width/2, rc.height/2 );

        delete gc;
    }
};

class MyApp : public wxApp
{
public:
    virtual bool OnInit()
    {     
        wxFrame* f = new wxFrame(NULL, wxID_ANY, _("Test"));
        new MyCanvas(f);
        f->Show();
        return true;
    }
}; wxIMPLEMENT_APP(MyApp);
and it works as expected for me:
wxgc.png
wxgc.png (2.3 KiB) Viewed 229 times


Assuming m_PlotLabelColor.IsOk() returns true, the only thing that comes to my mind, and I do not even know if it is possible, is that your font cannot be used with wxGC. However unlikely, does this fail:

Code: Select all

bool gfFontError = gc->CreateFont(m_PlotLabelFont, m_PlotLabelColor).IsNull();

sam_des
In need of some credit
In need of some credit
Posts: 4
Joined: Wed Aug 30, 2017 4:55 am

Re: wxGraphicsContex Text Drawing

Postby sam_des » Wed Aug 30, 2017 6:03 pm

This is my partial code,

Some definitions,

Code: Select all

wxBitmap                m_Buffer;

m_WidgetBkColor   = wxColor( 200, 200, 200 );
m_PlotBkColor       = wxColor( 255, 255, 255 );
m_PlotLabelColor   = wxColor( 0, 0, 0 );

m_PlotLabelFont     = wxFont( 18, wxSWISS, wxFONTSTYLE_NORMAL, wxNORMAL, false, _("Elephant") );


Actual code,

Code: Select all

void PlotWidget::OnPaint( wxPaintEvent& event )
{
    wxBufferedPaintDC dc( this, m_Buffer );
}

void PlotWidget::RedrawInBuffer()
{
    wxSize sz = GetClientSize();

    m_Buffer.Create( sz.GetWidth(), sz.GetHeight() );

    wxBufferedDC bdc;
    bdc.SelectObject( m_Buffer );
    bdc.Clear();

    DrawBackground( &bdc );
   
    Refresh();
}

void PlotWidget::DrawBackground( wxBufferedDC* dc )
{
   wxGraphicsContext* gc = wxGraphicsContext::Create( *dc );

    wxRect rc = GetClientRect();
   
    gc->SetBrush( wxBrush(m_WidgetBkColor) );
    gc->SetPen( wxPen(m_WidgetBkColor, 1, wxSOLID) );

    gc->DrawRectangle( rc.x, rc.y, rc.width, rc.height );

    gc->SetFont( m_PlotLabelFont, m_PlotLabelColor );

    gc->DrawText( _("SOME TEXT"), rc.width/2, rc.height/2 );
   
    delete gc;
}


Code works as expected when I use, wxBufferedDC instead of wxGraphicsContext. Also GC works ok with drawing lines, rects etc.

_sam_des

New Pagodi
Filthy Rich wx Solver
Filthy Rich wx Solver
Posts: 201
Joined: Tue Jun 20, 2006 6:47 pm
Contact:

Re: wxGraphicsContex Text Drawing

Postby New Pagodi » Wed Aug 30, 2017 7:32 pm

That seems to be a little complicated to me. (Also, unless I'm missing something you never seem to draw anything in your paint handler). I would just create a graphics context in the paint handler and draw to it there. Like so:

Code: Select all

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWidgets headers)
#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif

#include <wx/graphics.h>
#include <wx/dcbuffer.h>

class widget: public wxWindow
{
    public:
        widget(wxWindow *parent, wxWindowID id=wxID_ANY,
                   const wxPoint &pos=wxDefaultPosition,
                   const wxSize &size=wxDefaultSize,
                   long style=0, const wxString &name="widget");

    private:
        void OnPaint( wxPaintEvent& event );

        wxColour m_WidgetBkColor,m_PlotBkColor,m_PlotLabelColor;
        wxFont m_PlotLabelFont;
};

widget::widget(wxWindow *parent, wxWindowID id, const wxPoint &pos,
                       const wxSize &size, long style, const wxString &name)
            :wxWindow(parent, id, pos, size, style|wxFULL_REPAINT_ON_RESIZE, name)
{
    m_WidgetBkColor   = wxColor( 200, 200, 200 );
    m_PlotBkColor       = wxColor( 255, 255, 255 );
    m_PlotLabelColor   = wxColor( 0, 0, 0 );
    m_PlotLabelFont     = wxFont( 18, wxSWISS, wxFONTSTYLE_NORMAL, wxNORMAL, false, _("Elephant") );

    SetBackgroundStyle(wxBG_STYLE_PAINT);
    Bind( wxEVT_PAINT, &widget::OnPaint, this );
}


void widget::OnPaint( wxPaintEvent& event )
{
    wxAutoBufferedPaintDC dc(this);

    wxGraphicsContext* gc = wxGraphicsContext::Create( dc );

    wxRect rc = GetClientRect();

    gc->SetBrush( wxBrush(m_WidgetBkColor) );
    gc->SetPen( wxPen(m_WidgetBkColor, 1, wxSOLID) );

    gc->DrawRectangle( rc.x, rc.y, rc.width, rc.height );

    gc->SetFont( m_PlotLabelFont, m_PlotLabelColor );

    gc->DrawText( _("SOME TEXT"), rc.width/2, rc.height/2 );

    delete gc;
}

class MyFrame : public wxFrame
{
    public:
        MyFrame( wxWindow* parent, int id = wxID_ANY, wxString title = "Demo"
                , wxPoint pos = wxDefaultPosition, wxSize size = wxDefaultSize
                , int style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
};


MyFrame::MyFrame( wxWindow* parent, int id, wxString title, wxPoint pos
                 , wxSize size, int style )
        :wxFrame( parent, id, title, pos, size, style )
{
    new widget( this );
}

class MyApp : public wxApp
{
    public:
        virtual bool OnInit()
        {
            MyFrame* frame = new MyFrame(NULL);
            frame->Show();
            return true;
        }
};

wxIMPLEMENT_APP(MyApp);


But I'm guessing the reason you're using a buffer is that the actual drawing will ultimately be much more complicated and time consuming so you want to cache a bitmap and only recompute it when needed. If that's the case, here's one possible way to do that:

Code: Select all

class widget: public wxWindow
{
    public:
        widget(wxWindow *parent, wxWindowID id=wxID_ANY,
                   const wxPoint &pos=wxDefaultPosition,
                   const wxSize &size=wxDefaultSize,
                   long style=0, const wxString &name="widget");

    private:
        void OnPaint( wxPaintEvent& event );
        void OnSize(wxSizeEvent& event);

        wxColour m_WidgetBkColor,m_PlotBkColor,m_PlotLabelColor;
        wxFont m_PlotLabelFont;
        wxBitmap m_Buffer;
        bool m_dirty;
};

widget::widget(wxWindow *parent, wxWindowID id, const wxPoint &pos,
                       const wxSize &size, long style, const wxString &name)
            :wxWindow(parent, id, pos, size, style|wxFULL_REPAINT_ON_RESIZE, name)
{
    m_WidgetBkColor   = wxColor( 200, 200, 200 );
    m_PlotBkColor       = wxColor( 255, 255, 255 );
    m_PlotLabelColor   = wxColor( 0, 0, 0 );
    m_PlotLabelFont     = wxFont( 18, wxSWISS, wxFONTSTYLE_NORMAL, wxNORMAL, false, _("Elephant") );

    SetBackgroundStyle(wxBG_STYLE_PAINT);
    Bind( wxEVT_PAINT, &widget::OnPaint, this );
    Bind( wxEVT_SIZE, &widget::OnSize, this );
}

void widget::OnSize( wxSizeEvent& event )
{
    m_dirty=true;
    event.Skip();
}

void widget::OnPaint( wxPaintEvent& event )
{
    if(m_dirty)
    {
        wxSize sz = GetClientSize();

        m_Buffer = wxBitmap( sz.GetWidth(), sz.GetHeight() );

        wxMemoryDC dc(m_Buffer);

        wxGraphicsContext* gc = wxGraphicsContext::Create( dc );

        wxRect rc = GetClientRect();

        gc->SetBrush( wxBrush(m_WidgetBkColor) );
        gc->SetPen( wxPen(m_WidgetBkColor, 1, wxSOLID) );

        gc->DrawRectangle( rc.x, rc.y, rc.width, rc.height );

        gc->SetFont( m_PlotLabelFont, m_PlotLabelColor );

        gc->DrawText( _("SOME TEXT"), rc.width/2, rc.height/2 );

        delete gc;

        m_dirty=false;
    }

    wxPaintDC dc(this);
    dc.DrawBitmap(m_Buffer,0,0);
}

sam_des
In need of some credit
In need of some credit
Posts: 4
Joined: Wed Aug 30, 2017 4:55 am

Re: wxGraphicsContex Text Drawing

Postby sam_des » Thu Aug 31, 2017 5:52 pm

Hi,

Drawing is quite complicated & require fast update, so I am using the buffered draw. Everything drawn onto a memory buffer/bitmap & Paint Event simply copies the buffer to screen. Just for testing, I tried drawing text directly from Paint Event, but without success.

To reiterate, everything works fine when I don't use the GraphicsContext, which I require to draw the anti-aliased lines and which I can do, but fail with text. Since my problem is associated only with DrawText(), I've temporarily moved all my TextDrawing functionality to non-GraphicsContext drawing.
But its only partial solution,

_sam_des

PB
wxWorld Domination!
wxWorld Domination!
Posts: 1274
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxGraphicsContex Text Drawing

Postby PB » Thu Aug 31, 2017 6:16 pm

Did you try what I suggested, i.e., whether the code I posted works for you and whether your wxFont can be is successfully converted into graphic font and with what results?

Seems like you missed posts by NewPagodi and me...

iwbnwif
Super wx Problem Solver
Super wx Problem Solver
Posts: 256
Joined: Tue Mar 19, 2013 8:52 pm

Re: wxGraphicsContex Text Drawing

Postby iwbnwif » Thu Aug 31, 2017 6:21 pm

Since my problem is associated only with DrawText(), I've temporarily moved all my TextDrawing functionality to non-GraphicsContext drawing.


Actually, I have found this to be a better solution.

It is possible to draw using both a 'normal' wxDC and a wxGCDC onto the same DC. I found that the text looks better when drawn with the wxDC as opposed to the wxGCDC because in the latter case it appears to be anti-aliased twice (once by the text drawing and again by the graphics context).

Also, if you ever need to drawing orthographic lines such as borders, gridlines etc. it best to use the straightforward DC because you can be sure that they are 1 pixel wide.
wxWidgets 3.10, TDM MinGW64 5.1.0, g++ 4.8.2, Ubuntu 16.04LTS, Windows 10, CodeLite + wxCrafter
Some people, when confronted with a GUI problem, think "I know, I'll use Eclipse RCP". Now they have two problems.


Return to “Component Writing”

Who is online

Users browsing this forum: No registered users and 1 guest