GTK+ 2.0 教学-撷取选取区域

撷取选取区域是一个非同步的过程。开始这个过程,呼叫:

gboolean gtk_selection_convert( GtkWidget *widget,
                                GdkAtom    selection,
                                GdkAtom    target,
                                guint32    time );

这个将选取区域内容转换target指定的目标形式。如果可能,time参数应该为选取区域被触发事件产生的时间。这对确认事件以用户要求它们的顺序产生有帮助。然而,如果不行(例如,转换由 “clicked” 信号触发),你也可以使用GDK_CURRENT_TIME常数。

当选取区域所有者响应要求时,会发送一个 “selection_received” 信号到你的程式。对应的信号处理函式将得到一个指向GtkSelectionData结构的指标,它的定义如下:

struct _GtkSelectionData
{
  GdkAtom selection;
  GdkAtom target;
  GdkAtom type;
  gint    format;
  guchar *data;
  gint    length;
};

selectiontarget值是你在gtk_selection_convert()呼叫中给定的。type是一个atom用来辩识选取区域所有者所传回的资料型态。一些可能值是:”STRING”,由拉丁-1(latin-1)字元组成的字串,”ATOM”,一些atom,”INTEGER”,一个整数,等等。大多数目标只能传回一种类型。format给定其单位(比如字元)的位元数。通常,接收资料时你不必关心这个。data是一个指向传回资料的指标,length指定传回资料的长度,以位元组为单位。如果length是负数,则表示发生错误且选取区域的讯息无法获得。这可能在没有应用程是拥有选取区域时发生,或者你要求了一个应用程式不支持的目标形式。缓冲区实际上总会比length指示的多一个位元组;增加的这一位元组总为0值,这样就不必为了使字串以NULL结尾而另外复制一份。

在下面的范例里,我们撷取特定的目标”TARGETS”,它是一个选取区域内容能被转换的目标列表。

#include <stdlib.h>
#include <gtk/gtk.h>

void selection_received( GtkWidget        *widget,
                         GtkSelectionData *selection_data,
                         gpointer          data );

/* 当用户点击"Get Targets"按钮时呼叫的讯息处理函式 */
void get_targets( GtkWidget *widget,
                  gpointer data )
{
  static GdkAtom targets_atom = GDK_NONE;
  GtkWidget *window = (GtkWidget *)data;

  /* 得到"TARGETS"字串对应的atom */
  if (targets_atom == GDK_NONE)
    targets_atom = gdk_atom_intern ("TARGETS", FALSE);

  /* 要求撷取主选取区域的"TARGETS"目标 */
  gtk_selection_convert (window, GDK_SELECTION_PRIMARY, targets_atom,
			 GDK_CURRENT_TIME);
}

/* 当选取区域所有者传回资料时呼叫的信号处理函式 */
void selection_received( GtkWidget        *widget,
                         GtkSelectionData *selection_data,
		         gpointer          data )
{
  GdkAtom *atoms;
  GList *item_list;
  int i;

  /* **** 重要 **** 检测撷取讯息是否成功  */
  if (selection_data->length < 0)
    {
      g_print ("Selection retrieval failed\n");
      return;
    }
  /* 确认得到的资料为原来要求的形式 */
  if (selection_data->type != GDK_SELECTION_TYPE_ATOM)
    {
      g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
      return;
    }

  /* 列印接收到的atom */
  atoms = (GdkAtom *)selection_data->data;

  item_list = NULL;
  for (i = 0; i < selection_data->length / sizeof(GdkAtom); i++)
    {
      char *name;
      name = gdk_atom_name (atoms[i]);
      if (name != NULL)
	g_print ("%s\n",name);
      else
	g_print ("(bad atom)\n");
    }

  return;
}

int main( int   argc,
          char *argv[] )
{
  GtkWidget *window;
  GtkWidget *button;

  gtk_init (&argc, &argv);

  /* 创建顶层视窗 */

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title (GTK_WINDOW (window), "Event Box");
  gtk_container_set_border_width (GTK_CONTAINER (window), 10);

  g_signal_connect (G_OBJECT (window), "destroy",
	            G_CALLBACK (exit), NULL);

  /* 创建一个按钮,用户按它以撷取目标 */

  button = gtk_button_new_with_label ("Get Targets");
  gtk_container_add (GTK_CONTAINER (window), button);

  g_signal_connect (G_OBJECT (button), "clicked",
		    G_CALLBACK (get_targets), window);
  g_signal_connect (G_OBJECT (window), "selection_received",
		    G_CALLBACK (selection_received), NULL);

  gtk_widget_show (button);
  gtk_widget_show (window);

  gtk_main ();

  return 0;
}

Comments are closed.