Using the standard Delphi TRibbon components I noticed they are not that brilliant.
Firstly they dont look as nice as the Microsoft ones, for example the gl
i use the Windows Ribbon Framework - the native component that ships with Windows (7).
Here's a super-short primer on the Windows Ribbon Framework from Delphi; copy-paste of important parts of code, without much explanation:
procedure TfrmTicketDetail.ShowScenicRibbon;
begin
try
Fframework := UIRibbon.CoUIRibbonFramework.Create;
Fframework.Initialize(Self.Handle, Self); //Give the ribbon the hwnd, and our implementation of uiapplication for callbacks
OleCheck(Fframework.LoadUI(hInstance, 'APPLICATION_RIBBON'));
except
on e:Exception do
begin
if DebugHook > 0 then
raise;
Exit;
end;
end;
end;
But it starts to get hairy, since you have to follow Microsoft's API.
{IUIApplication}
function OnViewChanged(viewId: SYSUINT; typeID: UI_VIEWTYPE; const view: IUnknown;
verb: UI_VIEWVERB; uReasonCode: SYSINT): HResult; stdcall;
function OnCreateUICommand(commandId: SYSUINT; typeID: UI_COMMANDTYPE;
out commandHandler: IUICommandHandler): HResult; stdcall;
function OnDestroyUICommand(commandId: SYSUINT; typeID: UI_COMMANDTYPE;
const commandHandler: IUICommandHandler): HResult; stdcall;
And then you have to implement them:
function TfrmTicketDetail.OnViewChanged(viewId: SYSUINT;
typeID: UI_VIEWTYPE; const view: IUnknown; verb: UI_VIEWVERB;
uReasonCode: SYSINT): HResult;
var
cy: integer;
begin
Result := S_OK;
//viewID: The ID for the view. Only a value of zero is valid.
if viewID <> 0 then
Exit;
//typeID: The only declared typeID is UI_VIEWTYPE_RIBBON
if typeID <> UI_VIEWTYPE_RIBBON then
Exit;
case verb of //there are only 4 verbs: create, destroy, size, error
UI_VIEWVERB_CREATE:
begin
{ The view was resized.
In the case of the Ribbon view, the application should call
GetHeight() to determine the height of the Ribbon.}
(view as IUIRibbon).GetHeight(cy);
bvTopSpacer.Height := cy;
end;
UI_VIEWVERB_SIZE:
begin
{ The view was resized.
In the case of the Ribbon view, the application should call
GetHeight() to determine the height of the Ribbon.}
(view as IUIRibbon).GetHeight(cy);
bvTopSpacer.Height := cy;
end;
UI_VIEWVERB_DESTROY: {nop};
UI_VIEWVERB_ERROR: {nop};
end;
Result := S_OK;
end;
function TfrmTicketDetail.OnCreateUICommand(commandId: SYSUINT;
typeID: UI_COMMANDTYPE; out commandHandler: IUICommandHandler): HResult;
begin
commandHandler := Self; //this form will handle all commands on the ribbon;
Result := S_OK;
end;
function TfrmTicketDetail.OnDestroyUICommand(commandId: SYSUINT; typeID: UI_COMMANDTYPE;
const commandHandler: IUICommandHandler): HResult;
begin
Result := E_NOTIMPL;
end;
And then you also have to
IUICommandHandler
include the compiled ribbon as a resource:
{$RESOURCE '..\Resource\UIRibbon\Ribbon_frmTicketDetails.res'}
Here's a dump of the ribbon xml i have for my app:
<?xml version="1.0" encoding="utf-8"?>
<Application xmlns="http://schemas.microsoft.com/windows/2009/Ribbon">
<!-- Commands are like actions, with a name, a numeric ID, caption (LabelTitle), Large and Small images, etc -->
<Application.Commands>
<Command Name="cmdNew" Id="0xE100" Symbol="ID_CMD_NEW" LabelTitle="New document" />
<Command Name="cmdSaveAs" Id="0xE102" Symbol="ID_CMD_SAVEAS" LabelTitle="Save as" />
<Command Name="cmdOpen" Id="0xE103" Symbol="ID_CMD_OPEN" LabelTitle="Open" />
<Command Name="cmdExit" Id="0xE104" Symbol="ID_CMD_EXIT" LabelTitle="Exit" />
<Command Name="cmdUndo" Id="0xE105" Symbol="ID_CMD_UNDO" LabelTitle="Undo" />
<Command Name="cmdCut" Id="0xE110" Symbol="ID_CMD_CUT" LabelTitle="Cut" />
<Command Name="cmdCopy" Id="0xE111" Symbol="ID_CMD_COPY" LabelTitle="Copy" />
<Command Name="cmdPaste" Id="0xE112" Symbol="ID_CMD_PASTE" LabelTitle="Paste" />
<Command Name="cmdDelete" Id="0xE113" Symbol="ID_CMD_DELETE" LabelTitle="Delete" />
<Command Name="cmdZoom" Id="0xE114" Symbol="ID_CMD_ZOOM" LabelTitle="Zoom" />
<Command Name="tabHome" LabelTitle="Home" />
<Command Name="grpActions" LabelTitle="Actions" />
<Command Name="cmdSaveAndClose" Id="1101" Symbol="ID_ACTION_SAVEANDCLOSE" LabelTitle="Save and Close">
<Command.TooltipTitle>Save and Close (Alt+S)</Command.TooltipTitle>
<Command.TooltipDescription>Saves the current ticket and closes the detail screen.</Command.TooltipDescription>
<Command.LargeImages>
<Image Source="SaveAndClose.bmp" />
</Command.LargeImages>
</Command>
<Command Name="cmdBack" Id="1102" LabelTitle="Back" />
<Command Name="cmdControlPanel" Id="1103" LabelTitle="Control Panel" />
<Command Name="cmdSave" Id="1104" LabelTitle="Save" />
<Command Name="grpShow" Id="1201" LabelTitle="Show" />
<Command Name="cmdShowTicket" Id="1202" LabelTitle="Ticket" ></Command>
<Command Name="cmdShowDiaryEntries" Id="1203" LabelTitle="Diary Entries" >
<Command.LargeImages>
<Image Source="PencilLog_32x32.bmp" />
</Command.LargeImages>
</Command>
<Command Name="cmdShowAttachments" Id="1204" LabelTitle="Attachments" />
<Command Name="cmdShowAuditLog" Id="1205" LabelTitle="Audit Log" />
<Command Name="cmdShowAdditional" Id="1206" LabelTitle="Additional" />
<Command Name="grpActivity" LabelTitle="Activity" />
<Command Name="cmdStartWorking" Id="1301" LabelTitle="Start Working"></Command>
<Command Name="cmdStopWorking" Id="1302" LabelTitle="Stop Working"></Command>
<Command Name="cmdPrint" Id="1303" LabelTitle="Print" >
<Command.LargeImages>
<Image Source="Printer - 256x256.bmp" />
</Command.LargeImages>
<Command.SmallImages>
<Image Source="Printer_16x16.bmp" />
</Command.SmallImages>
</Command>
<Command Name="cmdDuplicateTicket" Id="1304" LabelTitle="Duplicate Ticket" >
<Command.SmallImages>
<Image Source="DuplicateTicket16.bmp" />
</Command.SmallImages>
</Command>
<Command Name="grpTicketStatus" LabelTitle="Ticket Status" />
<Command Name="cmdCloseTicket" Id="1402" LabelTitle="Close Ticket" />
<Command Name="cmdOnHold" Id="1403" LabelTitle="On Hold" />
<Command Name="cmdReadyForInstall" Id="1404" LabelTitle="Ready for install" />
<Command Name="cmdReopenTicket" Id="1405" LabelTitle="Reopen Ticket" />
</Application.Commands>
<!-- Above is all the commands (i.e. Actions). Now we get to the tool on screen (i.e. a DFM) -->
<Application.Views>
<Ribbon>
<!-- Items that appear under the "round button" menu -->
<Ribbon.ApplicationMenu>
<ApplicationMenu CommandName="cmdFileMenu">
<MenuGroup>
<Button CommandName="cmdNew" />
<Button CommandName="cmdOpen" />
<Button CommandName="cmdSave" />
<Button CommandName="cmdSaveAs" />
</MenuGroup>
<MenuGroup>
<Button CommandName="cmdExit" />
</MenuGroup>
</ApplicationMenu>
</Ribbon.ApplicationMenu>
<!--What commands to add to the quick access toolbar
Right now only Save and Undo, just for fun-->
<Ribbon.QuickAccessToolbar>
<QuickAccessToolbar>
<QuickAccessToolbar.ApplicationDefaults>
<Button CommandName="cmdSave" />
<Button CommandName="cmdUndo" />
</QuickAccessToolbar.ApplicationDefaults>
</QuickAccessToolbar>
</Ribbon.QuickAccessToolbar>
<!-- And now finally the actual tabs -->
<Ribbon.Tabs>
<!--Our one and only tab is "Home" -->
<Tab CommandName="tabHome">
<Tab.ScalingPolicy>
<ScalingPolicy>
<ScalingPolicy.IdealSizes>
<Scale Group="grpActions" Size="Medium"/>
<Scale Group="grpShow" Size="Medium"/>
<Scale Group="grpActivity" Size="Medium"/>
<Scale Group="grpTicketStatus" Size="Medium"/>
</ScalingPolicy.IdealSizes>
<Scale Group="grpActions" Size="Small"/>
<Scale Group="grpShow" Size="Small"/>
<Scale Group="grpActivity" Size="Small"/>
<Scale Group="grpTicketStatus" Size="Small"/>
</ScalingPolicy>
</Tab.ScalingPolicy>
<!-- Home\Actions -->
<Group CommandName="grpActions" SizeDefinition="FourButtons">
<Button CommandName="cmdSaveAndClose" />
<Button CommandName="cmdBack" />
<Button CommandName="cmdControlPanel" />
<Button CommandName="cmdSave" />
</Group>
<!-- Home\Show group -->
<Group CommandName="grpShow" SizeDefinition="FiveButtons">
<ToggleButton CommandName="cmdShowTicket" />
<ToggleButton CommandName="cmdShowDiaryEntries" />
<ToggleButton CommandName="cmdShowAttachments" />
<ToggleButton CommandName="cmdShowAuditLog" />
<ToggleButton CommandName="cmdShowAdditional" />
</Group>
<!-- Home\Activity group, with a custom sizing definition
so i get my "FourButtons-TwoBigTwoSmall" look -->
<Group CommandName="grpActivity" >
<SizeDefinition>
<ControlNameMap>
<ControlNameDefinition Name="button1"/>
<ControlNameDefinition Name="button2"/>
<ControlNameDefinition Name="button3"/>
<ControlNameDefinition Name="button4"/>
</ControlNameMap>
<GroupSizeDefinition Size="Large">
<ControlSizeDefinition ControlName="button1" ImageSize="Large" IsLabelVisible="true" />
<ControlSizeDefinition ControlName="button2" ImageSize="Large" IsLabelVisible="true" />
<ColumnBreak ShowSeparator="true"/>
<ControlSizeDefinition ControlName="button3" ImageSize="Large" IsLabelVisible="true" />
<ControlSizeDefinition ControlName="button4" ImageSize="Large" IsLabelVisible="true" />
</GroupSizeDefinition>
<GroupSizeDefinition Size="Medium">
<ControlSizeDefinition ControlName="button1" ImageSize="Large" IsLabelVisible="true" />
<ControlSizeDefinition ControlName="button2" ImageSize="Large" IsLabelVisible="true" />
<ColumnBreak ShowSeparator="true"/>
<Row>
<ControlSizeDefinition ControlName="button3" ImageSize="Small" IsLabelVisible="true" />
</Row>
<Row>
<ControlSizeDefinition ControlName="button4" ImageSize="Small" IsLabelVisible="true" />
</Row>
</GroupSizeDefinition>
<GroupSizeDefinition Size="Small">
<Row>
<ControlSizeDefinition ControlName="button1" ImageSize="Small" IsLabelVisible="true" />
<ControlSizeDefinition ControlName="button3" ImageSize="Small" IsLabelVisible="false" />
</Row>
<Row>
<ControlSizeDefinition ControlName="button2" ImageSize="Small" IsLabelVisible="true" />
<ControlSizeDefinition ControlName="button4" ImageSize="Small" IsLabelVisible="false" />
</Row>
</GroupSizeDefinition>
</SizeDefinition>
<Button CommandName="cmdStartWorking" />
<Button CommandName="cmdStopWorking" />
<Button CommandName="cmdPrint" />
<Button CommandName="cmdDuplicateTicket" />
</Group>
<!-- Home\Ticket Status group -->
<Group CommandName="grpTicketStatus" SizeDefinition="FourButtons">
<Button CommandName="cmdCloseTicket" />
<Button CommandName="cmdOnHold" />
<Button CommandName="cmdReadyForInstall" />
<Button CommandName="cmdReopenTicket" />
</Group>
</Tab>
</Ribbon.Tabs>
<!-- End of the actual tabs -->
</Ribbon>
</Application.Views>
</Application>
For a native look and feel, check the Windows Ribbon Framework for Delphi.
This is an Open Source wrapper around the Windows Ribbon Framework available since Windows 7 (and Vista after some official update is installed). This is the API used by the Windows 7 Word Pad.
Note also that you have two kind of layout: Office 2007 and Office 2010. The Delphi VCL Ribbon implements Office 2007 style, whereas the Windows Seven WordPad uses an Office 2010 style.
In some of our projects for some clients, we used TMS software Ribbon components. The code is a bit over-sized (a lot of duplicates or bad written stuff like component persistence) but it works and renders well, supporting both 2007 and 2010 Ribbon styles. For our Clients, rendering was what mattered. For our Open Source framework, we published a dual solution for building a Ribbon-like GUI, generated from code: it will use either standard VCL components for a basic layout, either the TMS components for a full Office 2007/2010 rendering. We just defined some classes, implemented by either libraries. If you use the generic components as defined in SQLite3ToolBar (i.e. the TSynForm, TSynToolBar, TSynToolButton, TSynPopupMenu, TSynPage, TSynPager, TSynBodyPager
and TSynBodyPage
classes) and SynTaskDialog (for TSynButton
) in your own code, the USETMSPACK conditional will do all the magic for you.
We didn't use yet the Ribbon component as was introduced in Delphi 2009. Its action-driven design won't make it easy to interface with the event-driven design of our User Interface handling, and we have to confess that this component has rather bad reputation (at least in the Delphi 2009 version).
The great Windows Ribbon Framework for Delphi won't fit our need of a on-the-fly generated Ribbon from code. Its design, from the Microsoft implementation itself, is to create the UI from an XML resource, linked at compilation... so it won't fit our needs, but it probably fit yours, for a more "static" application UI design.
If you use a Office-like Ribbon in your application, be aware of the Office UI Licensing.
The pragmatic answer is to use another component set. The TMS Software version appears good but I use the DevExpress ExpressBars one which works very well for me.