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.
Post Reply
sam_des
Earned a small fee
Earned a small fee
Posts: 18
Joined: Wed Aug 30, 2017 4:55 am

wxGraphicsContex Text Drawing

Post by sam_des »

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: 19115
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: wxGraphicsContex Text Drawing

Post by doublemax »

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
Earned a small fee
Earned a small fee
Posts: 18
Joined: Wed Aug 30, 2017 4:55 am

Re: wxGraphicsContex Text Drawing

Post by sam_des »

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
Part Of The Furniture
Part Of The Furniture
Posts: 4193
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxGraphicsContex Text Drawing

Post by PB »

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 18439 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
Earned a small fee
Earned a small fee
Posts: 18
Joined: Wed Aug 30, 2017 4:55 am

Re: wxGraphicsContex Text Drawing

Post by sam_des »

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
Super wx Problem Solver
Super wx Problem Solver
Posts: 466
Joined: Tue Jun 20, 2006 6:47 pm
Contact:

Re: wxGraphicsContex Text Drawing

Post by New Pagodi »

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
Earned a small fee
Earned a small fee
Posts: 18
Joined: Wed Aug 30, 2017 4:55 am

Re: wxGraphicsContex Text Drawing

Post by sam_des »

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
Part Of The Furniture
Part Of The Furniture
Posts: 4193
Joined: Sun Jan 03, 2010 5:45 pm

Re: wxGraphicsContex Text Drawing

Post by PB »

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: 282
Joined: Tue Mar 19, 2013 8:52 pm

Re: wxGraphicsContex Text Drawing

Post by iwbnwif »

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.1.2, MinGW64 8.1.0, g++ 8.1.0, Ubuntu 19.04, 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.
K.Nick
Knows some wx things
Knows some wx things
Posts: 27
Joined: Wed Aug 17, 2022 9:08 am

Re: wxGraphicsContex Text Drawing

Post by K.Nick »

Although this thread is rather old by now, I seem to have bumped into the same problem:
paths and circles being drawn fine on a wxGraphicsContext while drawing text seemingly not working

Code: Select all

wxGraphicsContext *gc = wxGraphicsContext::Create( dc ); 
wxGraphicsPath path = gc->CreatePath();
for (int k=0; k<5; k++)	// circles
{
	path.AddCircle( center.m_x, center.m_y, radius*(k)/4 );
}
for (int k=0; k<180; k+=30) 	// radials
{
	path.MoveToPoint(-radius*std::cos(k*M_PI/180.0)+center.m_x, -radius*std::sin(k*M_PI/180.0)+center.m_y);
	path.AddLineToPoint(radius*std::cos(k*M_PI/180.0)+center.m_x, radius*std::sin(k*M_PI/180.0)+center.m_y);
}
gc->StrokePath(path);
gc->DrawText(wxString::Format("This text comes from wxGraphicsContext"), 20.0, 20.0);	// this won't appear 
I found that the reason for text seemingly not being drawn is the default font color being the same as the background color. (In my opinion a highly questionable default setting still present wxWidgets 3.2.1.)

To solve this just add

Code: Select all

gc->SetFont(*wxNORMAL_FONT, wxColor(*wxBLACK));
before any calls to DrawText().

This works for me.
Post Reply