delphimenuc++buildermenuitemc++builder-2010

Radio item in TMainMenu not using dots but checkmarks


Using standard VCL. If menu item in TMainMenu has RadioItem and a GroupItem is assigned, normally, it uses a dot to indicate the Checked property - one of the radioitems is checked and that is indicated by a dot. RadioItem property switches from checkmark to dots. This is how I want it to behave.

Standard menu with dot as radio indicator

However, if I assign TImageList to the TMainMenu, the dot becomes a checkmark instead even though RadioItem property is set to true.

Checkmark if TImageList is used

This seems like a bug in Delphi/C++ Builder, but maybe there is something I missed. As long as the image list is not assigned to the menu, the checkmarks are shown as dots instead.

Is there a way to assign image list to main menu but still have radio items behave like radio items (have dot, instead of checkmark)?

Also, if it is a bug, is it fixed in subsequent Delphi/C++ Builder versions (I am using the RAD Studio 2010)?

I am not looking for workarounds like "assign your own dot image", or "use third party main menu component". Only standard VCL components. The reason why is because third party components usually don't care for accessibility (support for screen readers) and I need support for that.

Unrelated to the question, when HighDPI is used the checkmark is stretch drawn from a smaller image with jagged lines, indicating it is an enlarged bitmap. However, the dot remains smooth. So clearly some difference in drawing there.

Jagged edges of the checkmark

Example code:

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
TMainMenu *mm;
TImageList *il;

//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
struct
    {
    TComponent* operator()(TComponent* fOwner, const UnicodeString &fCaption, const UnicodeString &fName, bool fDefault, bool fRadioItem, int fImgIndex, int fGroupIndex, bool fChecked)
        {
        TMenuItem* mi  = new TMenuItem(fOwner);
        mi->Name       = fName;
        mi->Caption    = fCaption;
        mi->Default    = fDefault;
        mi->RadioItem  = fRadioItem;
        mi->ImageIndex = fImgIndex;
        mi->GroupIndex = fGroupIndex;
        mi->Checked    = fChecked;

        if (fOwner->InheritsFrom(__classid(TMainMenu)))
            {
            static_cast<TMainMenu*>(fOwner)->Items->Add(mi);
            }
        else if (fOwner->InheritsFrom(__classid(TMenuItem)))
            {
            static_cast<TMenuItem*>(fOwner)->Add(mi);
            }

        return mi;
        }
    } AddMenuItem;

TComponent* own;
mm = new TMainMenu(this);
il = new TImageList(this);

own = AddMenuItem(mm, "File", "mmFile", 0, 0, -1, 0, 0);
      AddMenuItem(own, "Radio 1",  "mmFileRadio1", 0, 1, -1, 1, 1);
      AddMenuItem(own, "Radio 2",  "mmFileRadio2", 0, 1, -1, 1, 0);

//mm->Images = il;      // Comment this line = dot, uncomment this line = checkmark
}

Solution

  • Since nobody is answering, I am answering my own question. If anyone has a better reply, feel free to add and I will gladly mark it as a reply.

    Basically I solved the problem by not assigning TImageList to the main menu, which avoids the problem and draws radio items with the circle. If there is a need to add images later, I'll have to look for other solutions, but for now this works.