2

I want to display a customized item, basically a colored table with variable column number and width. I'm using c++ Builder XE2 Rad Studio for this.

So, I created a new class inherting from TGraphicControl overwriting void __fastcall Paint(void).

The Problem: it takes quite some time (between 15 and 30 ms) to draw 12 colored rectangles with text, so I expect to have done something wrong. I suspect ShadowRect to do things one could implement better, but I'm not really sure...

Does anyone see my mistake here?

Code to Draw the Paint() Event:

void __fastcall CustomTrgDrawings::Paint(void){
    ResetCanvasTools();

    ShadowRect(ClientRect,colBG-0x111111,coladdLight,colText,"");

    Canvas->TextOutA(5,8,String().sprintf(L"Logic Box %u",fid));
    Canvas->Font->Style = TFontStyles() << fsBold;
    ShadowRect(nameRec,colBtnBG,coladdLight,colText,fName);
    Canvas->Font->Style = TFontStyles() ;
    ShadowRect(ch1Rec,colBtnBG-0x110011,coladdLight,colText,channels->Strings[fch1Id],true,3,true);
    ShadowRect(ch2Rec,colBtnBG-0x110011,coladdLight,colText,channels->Strings[fch2Id],true,3,true);
    ShadowRect(ch3Rec,colBtnBG-0x110011,coladdLight,colText,channels->Strings[fch3Id],true,3,true);
    ShadowRect(ch4Rec,colBtnBG-0x110011,coladdLight,colText,channels->Strings[fch4Id],true,3,true);
    ShadowRect(norm1Rec,colBtnBG-0x000011,coladdLight,colText,norms->Strings[fnorm1],true,3,true);
    ShadowRect(norm2Rec,colBtnBG-0x000011,coladdLight,colText,norms->Strings[fnorm2],true,3,true);
    ShadowRect(norm3Rec,colBtnBG-0x000011,coladdLight,colText,norms->Strings[fnorm3],true,3,true);
    ShadowRect(norm4Rec,colBtnBG-0x000011,coladdLight,colText,norms->Strings[fnorm4],true,3,true);

    ShadowRect(logicRec,colBtnBG-0x002222,coladdLight,colText,logics->Strings[flogicId],true,3,true);
    ShadowRect(normOutRec,colBtnBG-0x002200,coladdLight,colText,norms->Strings[fnormOut],true,3,true);
}
void CustomTrgDrawings::ResetCanvasTools(){
    Canvas->Brush->Color=clNone;
    Canvas->Brush->Style=bsClear;
    Canvas->Pen->Color=clNone;
    Canvas->Pen->Mode=pmCopy;
    Canvas->Pen->Style=psSolid;
    Canvas->Pen->Width=1;
    Canvas->Font->Color=clBlack;
    Canvas->Font->Size=8;
    Canvas->Font->Style=TFontStyles();
}

void CustomTrgDrawings::ShadowRect(const TRect pos,const TColor bg, const TColor add,const TColor fg, const String text,const bool shadow,const int align,const bool comboIcon){
    int textLen;
    int textX,textY;
    int iconWidth=0;

    Canvas->Brush->Style=bsSolid;
    Canvas->Brush->Color=bg;
    Canvas->Pen->Color=bg-4*add;
    Canvas->Pen->Style=psSolid;
    Canvas->Pen->Width=1;

    Canvas->FillRect(pos);

    if(shadow){
        Canvas->Pen->Color=bg-2*add;
        Canvas->MoveTo(pos.Left,pos.Bottom-1);
        Canvas->LineTo(pos.Right-1,pos.Bottom-1);
        Canvas->LineTo(pos.Right-1,pos.Top);

        Canvas->Pen->Color=bg+2*add;
        Canvas->MoveTo(pos.Right-1,pos.Top);
        Canvas->LineTo(pos.Left,pos.Top);
        Canvas->LineTo(pos.Left,pos.Bottom-1);
    }

    if(comboIcon){
        iconWidth=6;
        Canvas->Pen->Style=psSolid;
        Canvas->Pen->Mode=pmMask;
        Canvas->Pen->Width=3;
        Canvas->Pen->Color=bg-2*add;
        Canvas->MoveTo(pos.Right-iconWidth-5,pos.Top+6);
        Canvas->LineTo(pos.Right-iconWidth/2-5,pos.Top+10);
        Canvas->LineTo(pos.Right-5,pos.Top+6);
    }


    Canvas->Brush->Style=bsClear;
    Canvas->Pen->Color=fg;
    textLen=Canvas->TextWidth(text);

    switch(align%3){     //horizontal position
        case 0:          //left
            textX=3;
            break;
        case 1:          //middle
            textX=((pos.Width()-iconWidth)-textLen)/2;
            break;
        case 2:          //right
            textX=(pos.Width()-iconWidth)-textLen;
            break;
    }
    switch(align/3){    //vertical position
        case 0:         //top
            textY=-1;
            break;
        case 1:         //middle
            textY=(pos.Height()-Canvas->TextHeight(text))/2;
            break;
        case 2:         //bottom       
            textY=pos.Height()-Canvas->TextHeight(text);
            break;
    }

    Canvas->TextOutA(pos.Left+textX,pos.Top+textY,text);
}
Julian
  • 493
  • 4
  • 22
  • Using the profiling tools that come free in Visual Studio 2015 should tell you which part of paint is running hot then come back with that info if you are still stuck. – keith Jul 07 '16 at 18:37
  • @keith: This project is not being written in Visual Studio, it is being written in C++Builder instead. VS's profiling tools will not be much help. You would have to use profiling tools that support C++Builder, such as AQTime. – Remy Lebeau Jul 07 '16 at 18:52
  • 1
    @Julian: not related to your issue, but `Canvas->TextOutA()` should be `Canvas->TextOut()` instead. The VCL headers have `#pragma` statements to deal with the `A/W` mapping issue in C++. Also, the `pos` and `text` parameters of `ShadowRect()` parameters should be `const TRect &` and `const String &` instead of `const TRect` and `const String`. Also, `ResetCanvasTools()` is redundant and should be removed, since `Paint()` and `ShadowRect()` set the property values they need. There is no point in wasting effort resetting properties to default values just to change them again afterwards. – Remy Lebeau Jul 07 '16 at 18:57
  • @RemyLebeau Thanks for your help! Sometimes I forget that passing parameters as values is creating copies using the parameter type's constructors... After removing the reset and using references this is drawn much faster. I have 16 of those items on my form and it takes around 100ms now to draw all of them. I was measuring the time with std::clock since AQtime in XE2 is often crashing the IDE... – Julian Jul 08 '16 at 14:42

0 Answers0