On Monday, October 06, 2008 12:29 PM Jesper Stenlund wrote:
Subiect: Ang. RE: GUI-questions
> 
> I have tried the "ActionBars" and "Actionlists" but I found them a bit
> hard to work with and I also have some dynamic menuitems.
> But I think I should try that solution once more to see if I can get
it
> to
> work.

Turning "normal" menus into ActionBars works, and if it's done in a
procedure (ie: not from the form's FormCreate) it can nicely handle
changing menu structures. The trick here is to build the whole menu and
then call the procedure to turn it into ActionBars so you can call it
from FormCreate and from any other place after a menu structure change.
To make things easier I used a custom action class (TMenuAction) that's
linked to a TMenuItem and forwards the click. Here's the definition:

<code>
  TMenuAction = class(TCustomAction)
  protected
    M:TMenuItem;
    procedure Notification(AComponent: TComponent; Operation:
TOperation); override;
  public
    constructor Create(Owner:TComponent; Menu:TMenuItem);reintroduce;
    destructor Destroy;override;
    procedure MyClick(Sender:TObject);
    procedure MyUpdate(Sender:TObject);
  end;

constructor TMenuAction.Create(Owner: TComponent; Menu: TMenuItem);
begin
  inherited Create(Owner);
  M := Menu;
  if Assigned(M) then M.FreeNotification(Self);
  Caption := M.Caption;
  ImageIndex := M.ImageIndex;
  OnExecute := MyClick;
  OnUpdate := MyUpdate;
end; 
</code>

As you can see the TMenuAction implementation is truly "naive" but it
works nice. Also notice the Constructor, it's designed so new
TMenuAction's can be generated with little coding. It's just a simple
wrapper that reroutes "OnExcute" calls to the menu item's OnClick and
makes it so OnUpdate gets the "enabled" state from the initial menu
item.

Now I'll give you two other snippets of code from my own code. Hopefully
those would be enough to get you started (even those the code is
out-of-context and will probably fail to compile because of missing
names):

<code>
    function CreateMenuItem(const Base:TMenuItem; const
Root:TActionClientItem; const Tag:Integer):TActionClientItem;
    begin
      if Assigned(Root) then
        Result := Root.Items.Add
      else
        Result := AM.ActionBars[0].Items.Add;
      Result.Caption := Base.Caption;
      Result.ImageIndex := Base.ImageIndex;
      Result.Visible := True;
      Result.Tag := Tag;
    end;

    function CreateTerminalItem(const Base:TMenuItem; const
Root:TActionClientItem; Tag:Integer):TActionClientItem;
    var Actn:TMenuAction;
    begin
      if Base.Caption = '-' then
        begin
          // Building an separator
          if Assigned(Root) then
            Result := Root.Items.Add
          else
            Result := AM.ActionBars[0].Items.Add;
          Result.Caption := '-';
          Result.Visible := True;
          Result.Tag := Tag;
        end
      else
        begin
          // Building an terminal node
          Actn := TMenuAction.Create(Self, Base);
          Actn.ActionList := AM;
          Actn.OnUpdate := Actn.MyUpdate;

          if Assigned(Root) then
            begin
              Root.Items.AutoHotKeys := False;
              Result := Root.Items.Add;
            end
          else
            begin
              AM.ActionBars[0].Items.AutoHotKeys := False;
              Result := AM.ActionBars[0].Items.Add;
            end;
          Result.Action := Actn;
          Result.Visible := True;
          Result.Tag := Tag;
        end;
    end; 
</code>

I can't copy-paste the whole code out of my applications because it
includes a lot of business logic, comments and function names in
romanian. If you can't make it work with the tiny bits of code I managed
to extract, just ask I'd be happy to code a demo that's free of business
logic and is 100% english.

> The components that's not rendered is a mystery.
> It is a standard TEdit placed in a standard TGroupBox that is placed
on
> a
> TTabSheet.
> But a TPanel placed inside the same Groupbox is rendered just perfect.
> 
> The problem also occurs on a TListBox placed inside a TGroupBox and a
> TEdit placed directly on the tabsheet.
> A derived ListView still have the old grey colour on the
columnheaders.
> I
> think that colour should be a little bit more white.
> 
> But if I create a new application and put the same type of components
> on a
> tabsheet it all looks perfect.
> I have looked it over again and again and I can't figure out the
> difference between the components in my "old application" and the
> components in my new "test application".
> 
> Tha actual PageControl is placed on a form that is derived in several
> levels, but I can't see why that should be a problem?
> 

My guess is that there's something wrong with the parent control. I have
no idea how to fix it, but I can give you some debugging pointers.

(1) Try to isolate the parent that's disabling theeming. To do this
locate one form where the problem manifests itself (the form where you
have a page control that's not rendering properly). Select the control,
hit "escape" to select it's parent and place an TButton there. Use the
escape key so you can place buttons on every parent at every
hierarchical level until you reach the form. Run the application.
Hopefully you'll see the control where buttons start loosing theeming.

(2) Once you've got an control that's not theeming properly you may
start looking for the problem. Look at the control's implementation
(most likely in StdCtrls.pas) and start placing breakpoints in the
procedures involved in painting: WMEraseBkgnd, CNCtlColorBtn, and other
procedures that use the ThemeServices. Hopefully tracing the code would
show you how the parent disables theeming and that in turn would make
fixing the problem easy.

--
Good luck,
Cosmin Prund

_______________________________________________
Delphi mailing list -> Delphi@elists.org
http://lists.elists.org/cgi-bin/mailman/listinfo/delphi

Reply via email to