开发者

Creating Ribbon Styled Applications

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 glow effects and colors in the TRibbon dont look as impressive as the ones used in Wordpad or Paint in Windows 7.

  • Secondly if you want to create Ribbon Styled interfaces, I noticed that there is no Ribbon style menus or popup menus independent of the TRibbon. For the actual Ribbon there is, but if say for continuity purposes you wanted the Ribbon style popup menus assigned to a TListbox or TListView for example, there doesnt appear to be one.

  • Thirdly, sometimes when a Ribbon Action is disabled, it still shows the Hot glow effect as if hovering over the Action, even though it is disabled.

  • Finally I find it very fiddly trying to place container components such as a TCombobox in a group. It is really awkward sizing the controls and position etc.

I guess my point is that using the standard Delphi TRibbon components appears to be not the best approach both visually and useably. How can I make a Ribbon styled Application look and work as neatly as the Microsoft ones do just like I said before the way that Wordpad and Paint do in Windows 7?

Have a look at this comparison screenshot to get a better idea:

Creating Ribbon Styled Applications

The Delphi Ribbon seems incomplete, unless I am expecting too much. I believed the Ribbon Components are to provide your Application with a better experience for the end user both visually and better workspace etc.

What suggestions could you give to enhance or make the TRibbon work and look like the Microsoft ones?

I dont use Ribbon Style Interfaces all the time so purchasing 3rd Party Components is not something I really want to do. I have looked at the TMS and DevExpress ones but for the price of them, th开发者_Python百科ey dont look as good either. The TMS ones look worse than the standard Delphi TRibbon.


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.


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

  • implement IUICommandHandler
  • author a ribbon XML file
  • compile the ribbon XML file with the ribbon compiler
  • 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>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜