123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563 |
- \documentclass[10pt]{article}
- \usepackage{a4}
- \usepackage{epsfig}
- \usepackage{listings}
- \usepackage{tabularx}
- \lstset{language=Delphi}%
- \lstset{basicstyle=\sffamily\small}%
- \lstset{commentstyle=\itshape}%
- \lstset{keywordstyle=\bfseries}%
- %\lstset{blankstring=true}%
- \newif\ifpdf
- \ifx\pdfoutput\undefined
- \pdffalse
- \else
- \pdfoutput=1
- \pdftrue
- \fi
- \begin{document}
- \title{Programming GTK in Free Pascal:\\ Menus
- %and Marshallers
- }
- \author{Florian Kl\"ampfl\\and\\Micha\"el Van Canneyt}
- \date{September 2000}
- \maketitle
- \section{Introduction}
- In the third article on programming the GTK toolkit, the us of menus in GTK
- is explored.
- %two topics are
- %explored: The programming of menus and the use of marshallers.
- Menus can be built in essentially 2 ways; the easier way through the
- use of a itemfactory, and the more complex way, doing all necessary calls
- manually. The advantages of both ways are discussed.
- %Marshallers can be used to replace the default signal handling mechanisms
- %of GTK. The use of marshallers will be demonstrated by building a small
- %object which will have custom handlers for certain events.
- \section{Menus the easy way: The item factory}
- The easy way to construct a menu is to use an item factory. An Item factory
- gets as input an array of records, which describe a menu structure, and
- returns a completely built menu, ready to be added to a window.
- The great advantage of an item factory is that it is easy to use; a
- disadvantage is that
- \begin{enumerate}
- \item There is less control over the produced menu items; e.g.
- displaying a menu item with a small icon is not possible.
- \item The callbacks of the constructed menu is different from the usual
- signal model, making it difficult to combine a menu entry with a
- speedbutton. There are also 2 types of callback, so type checking is not
- possible.
- \item In Pascal, constant records must be specified using the names of the
- members; this makes the array with the menu items to be rendered quite
- complicated.
- \end{enumerate}
- To create a menu, first the item factory must be created. The function to do
- this is defined as follows:
- \begin{lstlisting}{}
- gtk_item_factory_new(container_type:TGtkType;
- path:Pgchar;
- accel_group:PGtkAccelGroup):PGtkItemFactory;
- \end{lstlisting}
- The three arguments to this function have the following meaning:
- \begin{description}
- \item[container\_type] This identifies the kind of menu that will be
- rendered. It can have one of the following values:
- \begin{description}
- \item[GTK\_MENU\_BAR\_TYPE] A menu bar will be created to hold all items.
- \item[GTK\_MENU\_TYPE] A menu that can be used as a popup menu, or that can be
- attached as a sub-menu to another menu, will be created.
- \item[GTK\_OPTION\_MENU\_TYPE] Makes everything in a drop-down style menu which
- can be used to select one value.
- \end{description}
- \item[path] is the name of the menu to be generated.
- \item[accel\_group] Is a pointer to a group of accelerators. All
- accellerators for the generated menu will be attached to this group.
- \end{description}
- The accelerator group needed for the item factory can be constructed
- using a simple call to \lstinline|gtk_accel_group_new|; this function
- takes no arguments, and returns a pointer to a new accelerator group.
- To actually create the menu, a call to
- \lstinline|gtk_item_factory_create_items| is needed; This procedure is
- defined as follows:
- \begin{lstlisting}{}
- gtk_item_factory_create_items(ifactory:PGtkItemFactory;
- n_entries:guint;
- entries:PGtkItemFactoryEntry;
- callback_data:gpointer);
- \end{lstlisting}
- The first argument to this call, \lstinline|ifactory|, is the itemfactory;
- the second argument, \lstinline|n_entries|, is the number of items in the
- array of records describing the menu. The third argument, \lstinline|entries|,
- is the actual array describing the menu. The last argument
- \lstinline|callback_data| is a pointer that will be passed to the menu
- callbacks.
- The menu structure that should be created by the item factory is an
- array of records of the type \lstinline|TGtkItemFactoryEntry|.
- This record is defined as follows:
- \begin{lstlisting}{}
- TGtkItemFactoryEntry = record
- path : Pgchar;
- accelerator : Pgchar;
- callback : TGtkItemFactoryCallback;
- callback_action : guint;
- item_type : Pgchar;
- end;
- \end{lstlisting}
- The fields have the following meaning:
- \begin{description}
- \item[path]
- The first entry is the path of the menu item. This indicates the place of
- the menu entry in the whole menu. For instance, the menu item \textbf{New}
- in the menu \textbf{File} would be designated by \lstinline|'/File/New'|.
- So, the slash is used to separate the menu levels.
- To make one of the letters of the menu item name active, so the item can be
- selected by pressing the letter (on the keyboard) when the menu is opened,
- the key to be used should be preceded by an underscore.
- In e.g. \lstinline|'/File/_New'|, the letter \textbf{N} could be used to
- select the \textbf{New} item if the \textbf{File} menu is active.
- \item[accelerator] To make a shortcut to the menu item so it can be
- activated at all times, the shortcut name can be specified in the
- \lstinline|accelerator| field. This can be any key, together with some
- modifiers. e.g. \lstinline|'<control>N'| will make the key combination
- 'CTRL-N' a shortcut.
- The accelerator should be speciefied as normal text. A list of possible
- modifiers can be found in table \ref{tab:modifiers}.
- \begin{table}[ht]
- \begin{center}
- \caption{List of modifier strings for shortcut keys}\label{tab:modifiers}
- \begin{tabular}{cc}
- Modifier & alias \\ \hline
- \lstinline|<control>| & \lstinline|<ctl>|, \lstinline|<ctrl>| \\
- \lstinline|<shift>| & \lstinline|<shft>| \\
- \lstinline|<alt>| & \lstinline|<mod1>| \\ \hline
- \end{tabular}
- \end{center}
- \end{table}
- \item[callback] Contains a pointer to the function that should be called
- when the menu item is activated. The type of the menu handler is not the
- same as a normal signal handler; The actual callback should be of the type
- \lstinline|TGtkItemFactoryCallback1|:
- \begin{lstlisting}{}
- procedure (callback_data:gpointer;
- callback_action:guint;
- widget:PGtkWidget);cdecl;
- \end{lstlisting}
- Which is not the same as the type of the \lstinline|callback| field, so
- a typecast will always be necessary.
- \item[callback\_action] This is passed on to the callback in the
- \lstinline|callback_action| parameter.
- \item[item\_type] is the type of menu item. Several types can be used; the
- complete list can be found in \ref{tab:menutypes}, but the must important
- ones are \lstinline|'<Item>'|, which specifies a normal menu item,
- and \lstinline|'<Branch>'|, which indicates a sub-menu.
- \begin{table}[ht]
- \begin{center}
- \caption{Possible menu item types}\label{tab:menutypes}
- \begin{tabularx}{\textwidth}{lX}%
- Item type & Menu kind \\ \hline
- \lstinline|'<Item>'| & indicates a normal item. An empty string or \lstinline|Nil|
- have the same meaning. \\
- \lstinline|'<CheckItem>'| & a check menu item. \\
- \lstinline|'<ToggleItem>'| & a toggle menu item (same as check menu). \\
- \lstinline|'<RadioItem>'| & a radio item. \\
- \lstinline|'<Separator>'| & a separator bar. \\
- \lstinline|'<Branch>'| & an item to hold a submenu.\\
- \lstinline|'<LastBranch>'| & an item to hold a submenu, but right aligned.\\ \hline
- \end{tabularx}
- \end{center}
- \end{table}
- \end{description}
- Now all elements to create a menu are introduced, and the menu can be
- created. The following definitions should now be clear:
- \begin{lstlisting}{}
- Var
- Window : PGtkWidget;
- MenuBar : PGtkWidget;
- Type
- FC = TGtkItemFactoryCallback;
- Const
- NrMenuItems = 21;
- TheMenu : Array[1..NrMenuItems] of TGtkItemFactoryEntry = (
- (path:'/_File';Accelerator:Nil;
- Callback:Nil;Callback_action:1;item_type:'<Branch>'),
- (path:'/File/_New';Accelerator:'<ctrl>N';
- Callback:FC(@Menu);Callback_action:1;item_type:Nil),
- { ... }
- \end{lstlisting}
- Here the \lstinline|FC| type is introduced to make the typecast of the
- \lstinline|Menu| handler easier; the
- \lstinline|TheMenu| constant is not given completely, since it is too long
- and not instructive. The complete structure can be found in the sources
- accompanying this article.
- Using the above definitions, the menu can now be constructed:
- \begin{lstlisting}{}
- Procedure MakeMenu;
- Var
- Factory : PGtkItemFactory;
- Accel : PGtkAccelGroup;
- begin
- Accel:=gtk_accel_group_new;
- Factory :=gtk_item_factory_new(GTK_MENU_BAR_TYPE,'<main>',accel);
- gtk_item_factory_create_items(Factory,NrMenuItems,@TheMenu,Nil);
- gtk_window_add_accel_group(GTK_Window(Window),accel);
- MenuBar:=gtk_item_factory_get_widget (Factory, '<main>');
- end;
- \end{lstlisting}
- The \lstinline|gtk_window_add_accel_group| call attaches the accelerator
- group that was filled up by the item factory to the window.
- The \lstinline|gtk_item_factory_get_widget| call finally fetches the
- object created by the item factory and stores it in a widget variable.
- The \lstinline|Menu| callback used in the menus is defined as follows:
- \begin{lstlisting}{}
- procedure menu(Data : GPointer;
- Action : Guint;
- Widget : pGtkWidget); cdecl;
-
- Var
- TheLabel : PgtkWidget;
- LabelText : Pchar;
- S : AnsiString;
-
- begin
- TheLabel:=g_list_nth_data(
- gtk_container_children(
- GTK_CONTAINER(Widget)),0);
- gtk_label_get(gtk_Label(theLabel),@LabelText);
- S := 'Chosen menu : ' + Strpas(Labeltext);
- gtk_label_set_text(GTK_LABEL(DisplayLabel),pchar(S));
- end;
- \end{lstlisting}
- The \lstinline|DisplayLabel| is a label located on the window, it is used to
- give some feedback on the used menu. The code to extract the menu name from
- the menu widget passed to the handler will be explained later on.
- The result of all this is shown in figure \ref{fig:ex1}.
- \begin{figure}
- \caption{The menu made by the item factory.}\label{fig:ex1}
- \epsfig{file=gtk3ex/ex1.png}
- \end{figure}
- As can be seen from the code above, the creation of a menu using an item
- factory in GTK is not so hard. The drawback of the above method lies mainly
- in the fact that Pascal handles constant records differently than C, which
- makes the array that describes the menu structure rather difficult to read.
- The second drawback is that there is little control over the created items.
- \section{Menus the hard way: manually}
- When creating menus manually, mainly 4 objects are involved:
- \begin{itemize}
- \item The menu items themselves. To a menu item, a menu can be assiciated,
- creating a sub-menu.
- \item Menus, which contain a collection of menu items,
- \item A accelerator group. This will be used to keep a collection of
- shortcut keys for the menu items.
- \item A menu bar, which can hold several menu items and their associated
- menus.
- \end{itemize}
- The last object is optional, if e.g. a pop-up menu is wanted.
- To create a menu in a window, the following steps are involved:
- \begin{enumerate}
- \item Create an accellerator group. The accelerator group should be
- connected to the window. \label{stepone}
- \item Create a menu bar, and attach it to the window.
- \item For each menu that should appear in a menu bar, do the following:
- \begin{itemize}
- \item Create a menu item, which will be shown in the menu bar.
- \item Create a menu to hold the items that should pop up when the menu is
- activated.
- \end{itemize}
- \item To each menu created in the previous step, add as many menu items as
- needed. Add an accelarator to the group created in step \ref{stepone}.
- \end{enumerate}
- To make these steps easier (each of them involves quite some calls to GTK
- functions) some functions will be introduced that make this easier.
- The first function is the most simple one; it attaches a separator to a
- menu:
- \begin{lstlisting}{}
- Function AddSeparatorToMenu(Menu:PgtkMenu):PgtkMenuItem;
- begin
- Result:=pgtkmenuitem(gtk_menu_item_new);
- gtk_menu_append(Menu,pgtkWidget(result));
- gtk_widget_show(PgtkWidget(result));
- end;
- \end{lstlisting}
- The function takes one parameter, \lstinline|Menu|, the menu to which the
- separator will be attached. A separator is created by simply creating an
- empty menu item. Creating a new (empty) menu item is done with the
- \lstinline|gtk_menu_item_new| call.
- With the \lstinline|gtk_menu_append| call, the newly created item is then
- added to the menu. Lastly, the item is shown; it will not become actually
- visible till the menu is activated. If this is omitted, it will also not
- be visible when the menu is activated.
- Adding a menu with a shortcut key to a menu is a little more involved. Some
- more elements are needed:
- \begin{enumerate}
- \item The menu to which to attach the menu item.
- \item The accelarator group to which the accelerator key should be added.
- \item The caption of the menu. An underscore character will indicate the
- letter of themenu that will be used as a shortcut to activate the item.
- \item The shortcut for the menu item. An empty string means no shortcut.
- \item A callback function which will be called when the menu item is
- activated, and callback data which will sent to the callback.
- \end{enumerate}
- All these elements are found in the declaration of the following function:
- \begin{lstlisting}{}
- Function AddItemToMenu (Menu : PGtkMenu;
- ShortCuts : PGtkAccelGroup;
- Caption : AnsiString;
- ShortCut : AnsiString;
- CallBack : TgtkSignalFunc;
- CallBackdata : Pointer
- ) : PGtkMenuItem;
- Var
- Key,Modifiers : guint;
- LocalAccelGroup : PGtkAccelGroup;
- TheLabel : PGtkLabel;
-
- begin
- \end{lstlisting}
- The variables declared in this function will be explained as the code is
- presented.
- First of all, a menu item must be created. Since a caption for the menu is
- provided, the \lstinline|gtk_menu_item_new_with_label| will be used to
- create a menu that has a label as a child:
- \begin{lstlisting}{}
- Result:=pgtkmenuitem(gtk_menu_item_new_with_label(''));
- TheLabel:=GTK_LABEL(GTK_BIN(Result)^.child);
- Key:=gtk_label_parse_uline(TheLabel,Pchar(Caption));
- \end{lstlisting}
- After the menu item is created, the child label is fetched. The label caption is
- then set using the \lstinline|gtk_label_parse_uline| function. This function
- will search a text for underscore characters, remove them from the text, and
- then set the label's caption with the result. All letters which had an
- underscore character prepended will be underlined in the label.
- The function returns the first letter that had an underscore prepended. It
- is stored, so it can be used to make an accelerator:
- \begin{lstlisting}{}
- If Key<>0 then
- begin
- LocalAccelGroup:=gtk_menu_ensure_uline_accel_group(Menu);
- gtk_widget_add_accelerator(PGtkWidget(result),'activate_item',
- LocalAccelGroup,Key,
- 0,TGtkAccelFlags(0));
- end;
- \end{lstlisting}
- The call to \lstinline|gtk_menu_ensure_uline_accel_group| returns the
- accelarator group associated with the menu. If no group existed yet, one
- will be created. The \lstinline|gtk_widget_add_accelerator| call takes the
- following parameters:
- \begin{itemize}
- \item A pointer to a widget to which the accelerator should be attached.
- \item The name of the signal which will be triggered when the shortcut
- is activated.
- \item The accelerator group to which the shortcut should be installed,
- usually this will be the accelerator group for the window to which the
- widget is attached, but in this case this is the accelerator group of the
- menu (which will only be active when the menu is actually shown)
- \item The key from the shortcut.
- \item The modifiers that should be pressed together with the key. For the
- menu, this should be 0, since just the key should be hit.
- \item The accelerator flags.
- \end{itemize}
- After the menu item was created and it's underlined key was made into an
- accelerator, the menu can be attached to the menu:
- \begin{lstlisting}{}
- gtk_menu_append(Menu,pgtkWidget(result));
- \end{lstlisting}
- If a shortcut key was passed along to the procedure, can be added to the
- window's accelerator group with the following code:
- \begin{lstlisting}{}
- If (ShortCut<>'') and (ShortCuts<>Nil) then
- begin
- gtk_accelerator_parse (pchar(ShortCut), @key, @modifiers);
- gtk_widget_add_accelerator(PGtkWidget(result),'activate_item',
- ShortCuts,Key,
- modifiers, GTK_ACCEL_VISIBLE);
- end;
- \end{lstlisting}
- The call to \lstinline|gtk_accelerator_parse| will parse a string which
- describes a shortcut key, and returns the corresponding key and modifiers,
- which can then be passed on to the \lstinline|gtk_widget_add_accelerator|
- call.
- After the accellerator has been installed, the only thing that remains to be
- done is to connect the callback to the activation of the menu:
- \begin{lstlisting}{}
- If CallBack<>Nil then
- gtk_signal_connect(PGtkObject(result),'activate',
- CallBack,CallBackdata);
- gtk_widget_show(PgtkWidget(result));
- end;
- \end{lstlisting}
- As the last line in the procedure, the newly created menu item is shown.
- If the menu isn't visible yet, this will do nothing, but will ensure that
- the item is also visible when the menu is visible.
- Now a menu-item and a separator can be added to a menu. What remains to be
- done is to add a menu to a menu bar. This is done in the following
- procedure, which is given in its entirety:
- \begin{lstlisting}{}
- Function AddMenuToMenuBar(MenuBar : PGtkMenuBar;
- ShortCuts : PGtkAccelGroup;
- Caption : AnsiString;
- CallBack : TgtkSignalFunc;
- CallBackdata : Pointer;
- AlignRight : Boolean;
- Var MenuItem : PgtkMenuItem
- ) : PGtkMenu;
- Var
- Key : guint;
- TheLabel : PGtkLabel;
- begin
- MenuItem:=pgtkmenuitem(gtk_menu_item_new_with_label(''));
- If AlignRight Then
- gtk_menu_item_right_justify(MenuItem);
- TheLabel:=GTK_LABEL(GTK_BIN(MenuItem)^.child);
- Key:=gtk_label_parse_uline(TheLabel,Pchar(Caption));
- If Key<>0 then
- gtk_widget_add_accelerator(PGtkWidget(MenuItem),'activate_item',
- Shortcuts,Key,
- GDK_MOD1_MASK,GTK_ACCEL_LOCKED);
- Result:=PGtkMenu(gtk_menu_new);
- If CallBack<>Nil then
- gtk_signal_connect(PGtkObject(result),'activate',
- CallBack,CallBackdata);
- gtk_widget_show(PgtkWidget(MenuItem));
- gtk_menu_item_set_submenu(MenuItem, PgtkWidget(Result));
- gtk_menu_bar_append(MenuBar,PgtkWidget(MenuItem));
- \end{lstlisting}
- The code for this procedure quite similar as the previous one. The main
- differences are:
- \begin{itemize}
- \item The result is not a menuitem, but a whole menu. The menuitem that is
- displayed in the menu bar itself is returned in the \lstinline|MenuItem|
- parameter.
- \item The shortcut key for the underlined item is added to the window's
- accelerator group, and has the \textsc{Alt} key (or \textsf{Mod1}) as
- the modifier key.
- \item the created menu is attached to the menu item as a sub menu, and it is
- the menu-item which is attached to the menu bar.
- \end{itemize}
- With the above calls, a menu can be constructed with a simple set of calls:
- \begin{lstlisting}{}
- FileMenu:=AddMenuToMenuBar(MenuBar,accel,'_File',Nil,
- Nil,False,TempMenuItem);
- AddItemToMenu(FileMenu,accel,'_New','<control>N',
- TgtkSignalFunc(@menu),DisplayLabel);
- AddItemToMenu(FileMenu,accel,'_Open','<control>O',
- TgtkSignalFunc(@menu),DisplayLabel);
- AddItemToMenu(FileMenu,accel,'_Save','<control>S',
- TgtkSignalFunc(@menu),DisplayLabel);
- AddSeparatorToMenu(PGtkMenu(FileMenu));
- AddItemToMenu(FileMenu,accel,'_Quit','<control>Q',
- TgtkSignalFunc(@destroy),Nil);
- { ... }
- \end{lstlisting}
- The complete list of calls to create the menu can be found in the sources
- accompagnying this article.
- The second program is of course bigger than the first, due to all the code
- to create the menus. Nevertheless, the manual way of creating has it's
- advantages: it's quite easy to extend the AddItemToMenu to add a bitmap to
- the menu entry as well. Using a itemfactory, there is (currently) no way to
- add images to a menu.
- Adding a bitmap to a menu is quite easy, and requires only a few extra
- lines of code. The key point is that the gtkmenuitem object is just an empty
- container (it descends from gtkbin), which does not display anything by itself. The
- \lstinline|gtk_menu_item_new_with_label| call creates a menu item and puts a
- gtklabel in it to display the menu item caption. Instead of a label object,
- almost any other object can be put in the item. This fact is used in the
- following code to add a bitmap in front of the menu caption, in a new
- procedure to be called \lstinline|AddImageItemToMenu|:
- \begin{lstlisting}{}
- Result:=pgtkmenuitem(gtk_menu_item_new);
- hbox:=PGtkHBox(gtk_hbox_new(false,0));
- gtk_container_add(pgtkcontainer(result),pgtkWidget(hbox));
- pixmap:=gdk_pixmap_create_from_xpm(Nil,@BitmapData,Nil,pchar(BitMap));
- Image := PgtkPixMap(gtk_pixmap_new(Pixmap,BitmapData));
- gtk_box_pack_start(PGtkBox(hbox),pgtkWidget(image),false,false,0);
- TheLabel:=PgtkLabel(gtk_label_new(''));
- gtk_box_pack_start(PGtkBox(hbox),pgtkWidget(TheLabel),True,True,0);
- Key:=gtk_label_parse_uline(TheLabel,Pchar(Caption));
- \end{lstlisting}
- In the first line, a plain menu item is created with
- \lstinline|gtk_menu_item_new|. In the following two lines,
- a \lstinline|GTKHBox| is added to the menu item, and a reference to the box
- is stored in the \lstinline|hbox| variable.
- Then, a pixmap is created from a filename. The filename is passed in the
- \lstinline|BitMap| parameter to our routine. Using the newly created pixmap,
- an Image is created, which can then be added to the box.
- Finally, a regular GTK label is created to hold the caption of the menu
- item, and added to the box. After that the procedure continues as for a
- normal menu.
- The complete code for the above \lstinline|AddImageItemToMenu| routine can
- be found in the sources of the third example, accompagnying this article.
- The result can be seen in figure \ref{fig:pixmenu}
- \begin{figure}[ht]
- \caption{The menu with bitmaps}\label{fig:pixmenu}
- \epsfig{file=gtk3ex/ex3.png}
- \end{figure}
- Some notes regarding this algorithm are in order:
- \begin{enumerate}
- \item It would be possible to have not a filename passed to the routine, but
- directly pass a pixmap object as well; for instance when using a toolbar,
- toolbuttons corresponding to the menu entries could share the same pixmaps
- as the menu entries.
- \item Some alignment issues may arise when the menu contains items with and
- without bitmaps. The above code does not address these issues. To solve
- them, the regular menu items should also be constructed e.g. using a hbox or a
- table with an empty cell. Also, an algorithm to determine whether any item of
- the menu has an image would be needed.
- \item The shortcut key is no longer shown in the menu widget; The reason for
- this is unknown to the authors of this article; unfortunately the lack of
- documentation on GTK prevents the implementation of a remedy.
- \item The menu callback can no longer retrieve the menu text using a
- straightforward approach, since the label displaying the caption is
- no longer the only child widget of the menu item. The callback has been
- adapted for this in the example.
- \end{enumerate}
- Taking into account the above arguments should make it possible to write
- better menu-creating routines which would replace the item factory
- completely, and which would enable the use of bitmaps in menu items.
- \end{document}
|