当前位置--> 首 页 --> 文 章 -->Linux Develop
|
|
※阅读文章※ |
GTK+ FAQ--4. 用GTK+来开发作者:不祥 [文章出自: www.fanqiang.com] -------------------------------------------------------------------------------- 4. 开发GTK+软体 4.1 我要怎麽样开始? 在安装GTK+後, 有些东西可以让您轻松上手. 有个GTK+入门导引. 它会介绍如何用C来写软体. 这份入门导引尚未包含所有关於物件的资讯. 用如何使用的范例程式可看看gtk/testgtk.c (及相关程式), 它包含在GTK+ distribution里面. 看看范例会给您心里有点底子, 那些物件能做什麽事. 4.2 GTK中的物件有那些? GTK+入门导引列出包含以下物件: GtkObject +GtkData | +GtkAdjustment | `GtkTooltips `GtkWidget +GtkContainer | +GtkBin | | +GtkAlignment | | +GtkEventBox | | +GtkFrame | | | `GtkAspectFrame | | +GtkHandleBox | | +GtkItem | | | +GtkListItem | | | +GtkMenuItem | | | | `GtkCheckMenuItem | | | | `GtkRadioMenuItem | | | `GtkTreeItem | | +GtkViewport | | `GtkWindow | | +GtkColorSelectionDialog | | +GtkDialog | | | `GtkInputDialog | | `GtkFileSelection | +GtkBox | | +GtkButtonBox | | | +GtkHButtonBox | | | `GtkVButtonBox | | +GtkHBox | | | +GtkCombo | | | `GtkStatusbar | | `GtkVBox | | +GtkColorSelection | | `GtkGammaCurve | +GtkButton | | +GtkOptionMenu | | `GtkToggleButton | | `GtkCheckButton | | `GtkRadioButton | +GtkCList | `GtkCTree | +GtkFixed | +GtkList | +GtkMenuShell | | +GtkMenuBar | | `GtkMenu | +GtkNotebook | +GtkPaned | | +GtkHPaned | | `GtkVPaned | +GtkScrolledWindow | +GtkTable | +GtkToolbar | `GtkTree +GtkDrawingArea | `GtkCurve +GtkEditable | +GtkEntry | | `GtkSpinButton | `GtkText +GtkMisc | +GtkArrow | +GtkImage | +GtkLabel | | `GtkTipsQuery | `GtkPixmap +GtkPreview +GtkProgressBar +GtkRange | +GtkScale | | +GtkHScale | | `GtkVScale | `GtkScrollbar | +GtkHScrollbar | `GtkVScrollbar +GtkRuler | +GtkHRuler | `GtkVRuler `GtkSeparator +GtkHSeparator `GtkVSeparator 4.3 GTK+是否是thread safe? 我要如何写一个multi-threaded GTK+软体? 虽然GTK+, 像许多X toolkits, 不是thread safe, 这并不禁止GTK+开发multi-threaded软体. Rob Browning (rlb@cs.utexas.edu)描述在GTK+中使用threading的技巧(稍经整理过): 基本上有两个方法, 第一个简单, 第二个复杂. 第一个, 您确定所有GTK+ (or X)互动都是由同一个所处理, 只能有一个thread. 任何其它thread想要画什麽东西都要告诉这个"GTK+" thread, 然後让它处理实际的工作. 第二种方法允许您呼叫GTK+ (or X)函数从许多thread, 但需要小心处理同步问题. 基本的想法是您产生一个X protection mutex, 而且没人可以在第一次要求这个mutex之前呼叫X函数. 这会造成一点负担, 不过比起完全thread saft GTK+, 它可以让您比较有效率. 您得决定thread locking的型式. 您也必须确认该thread呼叫gtk_main时, gtk_main正好有处理lock. 下一件事要担心的是, 当您进入gtk_main, 既然您有抓好global mutex, 那麽所有callbacks都会抓住它. 这意味著如果callback有去呼叫到会要求这个mutex时, 该callback必须释放它. 否则它会打死结. 而且, 当返回时, 您必须再去抓这个mutex. 为了要使除了gtk_main以外其它的threads可以存取mutex, 我们也需要注册一个工作函数以让我们定期可以释放这个mutex. GTK+干嘛不内定thread safe? 复杂, 难懂, 及人力资源. threaded程式比例是很小的, 要让thread safety正确会大量浪费宝贵的资源, 而这资源可用来做许多主要的工作. 在GTK+之外要让GTK+ thread safe倒是不错, 但这不是目前的工作. 而且处理不当, 它也会造成许多GTK+的东西比较没有效率. 不管如何, 这不是个很重要的工作, 因为已经有很多很好的相关工作存在了. 4.4 当我改变多个物件时要如何避免重画及重定大小? 使用gtk_container_disable_resize及gtk_container_enable_resize 在您改变许多东西的部份前後加上. 这会加快许多速度, 因为它会避免重画及重定大小. 4.5 要如何接取一个double click event (例如在list widget中)? Tim Janik写给gtk-list (稍经修改过): 定义一个signal handler: gint signal_handler_event(GtkWiget *widget, GdkEvenButton *event, gpointer func_data) { if (GTK_IS_LIST_ITEM(widget) && (event->type==GDK_2BUTTON_PRESS || event->type==GDK_3BUTTON_PRESS) ) { printf("I feel %s clicked on button %d\", event->type==GDK_2BUTTON_PRESS ? "double" : "triple", event->button); } return FALSE; } 然後接object到该handler: { /* list, list item init stuff */ gtk_signal_connect(GTK_OBJECT(list_item), "button_press_event", GTK_SIGNAL_FUNC(signal_handler_event), NULL); /* and/or */ gtk_signal_connect(GTK_OBJECT(list_item), "button_release_event", GTK_SIGNAL_FUNC(signal_handler_event), NULL); /* something else */ } Owen Taylor wrote也写: 单一按钮按下会在按下前被收到, 如果您这样做, 将会收到一个"clicked" signal. (这在所有工具中都几乎都这样做, 因为电脑可不怎麽在行於"读心".) 4.6 在GtkList中要如何找出selection? 取得selection的程式像这样: GList *sel; sel = GTK_LIST(list)->selection; 这是GList的定义(quoting glist.h): typedef struct _GList GList; struct _GList { gpointer data; GList *next; GList *prev; }; GList结构是个很简单的doubly linked lists. 有好几个g_list_*()函数来修改linked list, 都在glib.h. GTK_LIST(MyGtkList)->selection是由gtk_list_*()函数来维护的, 而且不应该被修改. GtkList的selection_mode决定GtkList的selection机制, GTK_LIST(AnyGtkList)->selection: selection_mode GTK_LIST()->selection contents ------------------------------------------------------ GTK_SELECTION_SINGLE) selection is either NULL or contains a GList* pointer for a single selected item. GTK_SELECTION_BROWSE) selection is NULL if the list contains no widgets, otherwise it contains a GList* pointer for one GList structure. GTK_SELECTION_MULTIPLE) selection is NULL if no listitems are selected or a a GList* pointer for the first selected item. that in turn points to a GList structure for the second selected item and so on GTK_SELECTION_EXTENDED) selection is NULL. GtkList资料栏结构GTK_LIST(MyGtkList)->selection指向GtkListItem的第一个被选物件. 所以您如果想知道那些被选起来了, 可以用这招: 初始化设定: { gchar *list_items[]={ "Item0", "Item1", "foo", "last Item", }; guint nlist_items=sizeof(list_items)/sizeof(list_items[0]); GtkWidget *list_item; guint i; list=gtk_list_new(); gtk_list_set_selection_mode(GTK_LIST(list), GTK_SELECTION_MULTIPLE); gtk_container_add(GTK_CONTAINER(AnyGtkContainer), list); gtk_widget_show (list); for (i = 0; i < nlist_items; i++) { list_item=gtk_list_item_new_with_label(list_items[i]); gtk_object_set_user_data(GTK_OBJECT(list_item), (gpointer)i); gtk_container_add(GTK_CONTAINER(list), list_item); gtk_widget_show(list_item); } } 要知会selection: { GList *items; items=GTK_LIST(list)->selection; printf("Selected Items: "); while (items) { if (GTK_IS_LIST_ITEM(items->data)) printf("%d ", (guint) gtk_object_get_user_data(items->data)); items=items->next; } printf("\n"); } 4.7 当文字太长时是否可能换行? GTK的行为(no clipping)是导因於它尝试省用X的资源. Label物件没有自己的X window - 它们就是画自己的内容到其父视窗中. 当然可能在画文字前裁切一翻, 不过这会导致速度上的处罚. 当然可以这样做, 从长期眼光来看, 最好的解决方案是把gtk label改变成有X windows. 短期来看, 要把label widget放进另一个widget, 并且有其自己的视窗 - 一个可行的候选者已经在了 - viewport widget. viewport = gtk_viewport (NULL, NULL); gtk_widget_set_usize (viewport, 50, 25); gtk_viewport_set_shadow_type (GTK_VIEWPORT(viewport), GTK_SHADOW_NONE); gtk_widget_show(viewport); label = gtk_label ("a really long label that won't fit"); gtk_container_add (GTK_CONTAINER(viewport), label); gtk_widget_show (label); 如果您正在这样搞一大票物件, 可以复制gtkviewport.c, 然後拿掉adjustment及shadow功能. (您可以叫它GtkClipper). 4.8 为什麽当按钮按下时, 内文不动? 这里有patch可以让它变成这样... From: Peter Mattis 按钮按下去, 内容不动的原因, 是因为我不认为这是实际上该发生的事. 我对按钮的看法是人们是正面看下去. 这就是, 使用者介面躺在平面上, 而您是正看下去. 当按钮按下去, 它是离开您. 要完全正确, 我想子物件应该要缩小一点点. 但我看不出有任何理由要移一点点到左边. 记住, 子物件是应该接在按钮上面. 这看起来怪怪的, 好像子物件要离开按钮的表面. 特别一书, 我的确曾一时做过这个, 但想一想不太妥当就把它移除掉了. 4.9 要如何在选单中定义一个separation? 看看 入门导引要怎样产生选单. 而要产生separation line, 只要插入一个空的选项: menuitem = gtk_menu_item_new(); gtk_menu_append(GTK_MENU(menu), menuitem); gtk_widget_show(menuitem); 4.10 要怎麽样把选单放在右边, 像Help? 用以下这招: menu_path = gtk_menu_factory_find (factory, " gtk_menu_item_right_justify(menu_path->widget); 4.11 我要如何使我的视窗modal? / 我要如何使一个单一视窗作用? 在您产生您的视窗後, 用gtk_grab_add(my_window). 关闭後用gtk_grab_remove(my_window). 4.12 我的物件怎麽不会更新(例如progressbar)? 您可能是没有将控制权交回给gtk_main. 大部份绘图更新的动作是放在queue当中, 会被gtk_main所处理. 您可以强迫drawing queue被处理, 用这招: while (gtk_events_pending()) gtk_main_iteration(); 以上片段是执行所有等候判断的事件及高优先权的idle函数. 然後立即返回. (drawing是由高优先权的idle函数所完成的). -------------------------------------------------------------------------------- 文章加入时间: 2004-11-17 14:56:30 责任编辑: w9 (2616 人次查阅) |