简体   繁体   中英

Override VCL class/component protected method - How to code and use?

I am rewriting old existing code and I'm giving the icons an overhaul. I used to have bitmaps assigned to TMenuItem s but I'm changing that in favor of ImageIndex and a TImageList with colordepth 32bit, containing icons with an alpha channel. The ImageList is created and populated with icons at design time. The ImageIndex are assigned during program startup and changed if/when appropriate.

I noticed that when a MenuItem is disabled ( enabled = false ), the resulting image doesn't look great (at all) and I read that this is due to VCL . Mentioned link also links to Delphi code that can convert an icon to its greyscale values.

I'm not fluent in Delphi nor changing VCL components, subclassing them, inheriting from them etc. I normally simply use what is available without changing it. so I'm starting with some basic questions:

Here's a very simple attempt to inherit from TImage and override DoDraw(), to make it never disable the icon in the first place (decipering the Delphi code to greyscale can be done in a second step)

class MyTImageList : public TImageList
    {
    public:

    __fastcall MyTImageList(Classes::TComponent* AOwner)
        : TImageList(AOwner) {} ;

    virtual __fastcall DoDraw(int Index, TCanvas *Canvas, int X, int Y, unsigned int Style, bool Enabled = true)
        {
        return TImageList::DoDraw(Index, Canvas, X, Y, Style) ;
        }
    };

FYI: I use C++ Builder 2009 It does not compile, error: [BCC32 Error] Main.h(1018): E2113 Virtual function '_fastcall TMainForm::MyTImageList::DoDraw(int,TCanvas *,int,int,unsigned int,bool)' conflicts with base class 'TCustomImageList'

Since I'm very insecure about inheriting from VCL component classes I'm not sure if I'm dealing with a typo or something very constructively wrong ? Kindly enlighten me.

Assuming this compiles I'm actually not sure how to proceed further either. Because the ImageList is created at design time, and used throughout the code. For this change to work I have to work with ' MyTimageList '.

So, do I create MyTimageList during Form construction and Assign() the content of the design-time-ImageList, or is there a more efficient way to avoid copying over everything ?

Actually, thinking about the latter question more, I could simply use the internal ImageList of the design time Imagelist instance .

Here is a C++ translation of the Delphi code:

class MyTImageList : public TImageList
{
protected:
    virtual void __fastcall DoDraw(int Index, Graphics::TCanvas *Canvas, int X, int Y, unsigned Style, bool Enabled = true);

public:
    __fastcall MyTImageList(Classes::TComponent* AOwner, TImageList *DesignImageList);
};

__fastcall MyTImageList::MyTImageList(Classes::TComponent* AOwner, TImageList *DesignImageList)
    : TImageList(AOwner)
{
    ColorDepth = DesignImageList->ColorDepth;
    Handle = DesignImageList->Handle; // Use the internally kept List of the design time ImageList
    ShareImages = true;
}

unsigned __fastcall GetRGBColor(TColor Value)
{
    unsigned Result = ColorToRGB(Value);
    switch (Result)
    {
        case clNone: Result = CLR_NONE; break;
        case clDefault: Result = CLR_DEFAULT; break;
    }
    return Result;
}

void __fastcall MyTImageList::DoDraw(int Index, TCanvas *Canvas, int X, int Y, unsigned Style, bool Enabled)
{
    if ((Enabled) || (ColorDepth != cd32Bit))
    {
        TImageList::DoDraw(Index, Canvas, X, Y, Style, Enabled);
    }
    else if (HandleAllocated())
    {
        IMAGELISTDRAWPARAMS Options = {0};
        Options.cbSize = sizeof(Options);
        Options.himl = (HIMAGELIST) Handle;
        Options.i = Index;
        Options.hdcDst = Canvas->Handle;
        Options.x = X;
        Options.y = Y;
        Options.cx = 0;
        Options.cy = 0;
        Options.xBitmap = 0;
        Options.yBitmap = 0;
        Options.rgbBk = GetRGBColor(BkColor);
        Options.rgbFg = GetRGBColor(BlendColor);
        Options.fStyle = Style;
        Options.fState = ILS_SATURATE; // Grayscale for 32bit images

        ImageList_DrawIndirect(&Options);
    }
}

OK, the answer is simple, and it needed some trial and error to get there, because the documentation I had access to was not clear about that. (Eg also wrong about the TCanvas pointer).

The function/method returns void . THAT's what was missing in the originally posted code and what caused the error. I got following code to work nicely.

class MyTImageList : public TImageList
    {
    public:
    __fastcall MyTImageList(Classes::TComponent* AOwner, TImageList *DesignImageList)
        : TImageList(AOwner)
        {
        Handle = DesignImageList->Handle ; // Use the internally kept List of the design time ImageList
        ShareImages = true;
        }

    protected:
    virtual __fastcall void DoDraw(int Index, TCanvas *Canvas, int X, int Y, unsigned int Style, bool Enabled = true)
        {
        return TImageList::DoDraw(Index, Canvas, X, Y, Style, true /*Enabled*/) ; // Always draw enabled
        }
    };

This issue is closed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM