16.8 对话框

GUI应用程序的一个重要组成部分就是与用户交互并通知用户重要的事件。通常,你会为此创建一个临时的带有OK和Cancel按钮的窗口。如果信息非常重要,它需要一个立即响应(如删除一个文件),你就希望能够阻止用户访问任何其他窗口,直到他做出了一个选择(这类窗口被称为模式对话框)。

我们在这里讲述的就是对话框。GTK+提供了一个从GtkWindow派生的特殊对话框构件,可以让编程变得更加容易。

16.8.1 GtkDialog

正如你所看到的,GtkDialog是GtkWindow的一个子类,因此它继承了GtkWindow的所有函数和属性:

16.8 对话框 - 图1

GtkDialog将窗口分为两个区域,一个放构件的内容,一个放底部的按钮。你可以在创建对话框时指定你想要的按钮和其他对话框设置。

16.8 对话框 - 图2

这个函数创建了一个完整的带有标题和按钮的对话框窗口。第二个参数parent应指向应用程序的主窗口,这样GTK+才可以确保对话框是一直连接到主窗口的。当主窗口被最小化时,它也会跟着最小化。

flags参数决定了对话框可以拥有的属性组合:

❑ GTK_DIALOG_MODAL;

❑ GTK_DIALOG_DESTROY_WITH_PARENT;

❑ GTK_DIALOG_NO_SEPARATOR。

你可以将这些标记用按位或操作符组合起来,例如,(GTK_DIALOG_MODAL|GTK_DIALOG_NO_SEPARATOR)既是一个模式对话框,又是一个在主窗口区域和按钮区域之间没有分割线的对话框。

其余的参数是一个以NULL结尾的按钮和相应的响应代码列表。你将在后面看到gtk_dialog_run函数时明白响应代码的含义。通常,你会从GTK+定义好的一系列按钮中进行选择,这些按钮中也有定义好的图标。

下面显示了创建一个带有OK和Cancel按钮的对话框的代码,它会根据按下的按钮分别返回GTK_RESPONSE_ACCEPT和GTK_RESPONSE_REJECT:

16.8 对话框 - 图3

我们在这里选择创建两个按钮,但是对话框并没有限制可以放置的按钮数目。此外,你可以从一组响应类型标记中进行选择。accept和reject标记没有被标准GNOME使用,因此你可以随意在应用程序中使用它们(记住,在你的应用程序中,accept应意味着接受)。其他在这里可以使用的标记包括OK和CANCEL,具体请见下一节中的GtkResponseType枚举类型。

当然,你需要向对话框中添加内容,这个GtkDialog包含一个现成的GtkVBox来容纳构件。你直接从这个对象获得一个指针:

16.8 对话框 - 图4

你以通常的方式使用这个GtkVBox,比如通过gtk_box_pack_start或者其他类似的函数。

一旦创建好一个对话框,下一步就是将它展现给用户,并等待响应。这可以使用下面两种方法来完成:一种是模式的方法,它阻止除对话框以外的一切输入;一种是非模式的方法,它像对待其他窗口一样对待对话框。让我们先看看运行一个模式对话框。

16.8.2 模式对话框

模式对话框强制用户首先响应,然后才能进行任何其他动作。它对以下这些情况很有用:用户将要做一件有严重后果的事情,或报告错误和警告信息。

你可以通过设置GTK_DIALOG_MODAL标记和调用gtk_widget_show函数,使一个对话框变为模式对话框。但还有一个更好的方法。gtk_dialog_run通过阻止程序的进一步执行,直到一个按钮被按下,来帮你解决这个难题。

当用户按下一个按钮(或者对话框被关闭)时,gtk_dialog_run返回一个int类型的结果来表明用户按下了哪个按钮。GTK+通常定义一个枚举类型来描述可能的值:

16.8 对话框 - 图5

现在我们可以解释传递给gtk_dialog_new_with_buttons的结果代码了。结果代码是在按钮被按下时,gtk_dialog_run返回的一个GtkResponseType值。如果对话框被关闭(例如用户点击了关闭图标),你将得到一个GTK_RESPONSE_NONE的结果。

switch结构非常适合于执行这个逻辑流程:

16.8 对话框 - 图6

16.8 对话框 - 图7

这就是GTK+中简单的模式对话框的所有内容了。正如你所看到的,这不需要你花费多少精力或编写多少代码。最后你只需用gtk_widget_destroy进行清理。

但当你需要一个非模式对话框时,事情就不是那么简单了。你不能使用gtk_dialog_run,而是必须将对话框的按钮与回调函数连接。

16.8.3 非模式对话框

你已看到如何用gtk_dialog_run来创建一个模式(阻塞)对话框了。非模式对话框的工作方式稍有不同,尽管它们是用同一种方法创建的。你不是调用gtk_dialog_run,而是将一个回调函数连接到GtkDialog的“response”信号(这个信号在按钮被按下或窗口被关闭时发出)。

将回调函数连接到信号是按通常的方式来完成的,但有一点不同:回调函数有一个额外的response参数,它起着和gtk_dialog_run返回值相同的作用。下面的代码片断显示了一个非模式对话框的基本用法:

16.8 对话框 - 图8

非模式对话框会致使复杂度增加,因为用户没有被强制立即响应对话框,他可以最小化对话框并将它忘掉。你需要考虑,如果用户在关闭第一个对话框之前又试图第二次打开这个对话框时,你该如何做。你要做的就是检查对话框指针是否为NULL,如果不是就调用gtk_window_present来重新显示已存在的对话框。你可以在本章最后一节中看到它的实际使用情况。

16.8.4 GtkMessageDialog

对于非常简单的对话框来说,即使GtkDialog也显得过于复杂了:

16.8 对话框 - 图9

通过使用GtkMessageDialog,你仅用一行代码就可以创建一个消息对话框。

16.8 对话框 - 图10

这个函数创建了一个带有图标、标题和可配置按钮的完整对话框。参数type根据对话框的目的设置它的图标和标题,例如,警告类型有一个三角警示图标。你最常碰到的简单对话框有下面4种可能的类型值:

❑ GTK_MESSAGE_INFO;

❑ GTK_MESSAGE_WARNING;

❑ GTK_MESSAGE_QUESTION;

❑ GTK_MESSAGE_ERROR。

你还可以选择一个GTK_MESSAGE_OTHER值,它用于前述对话框类型都不适用的情况。对于GtkMessageDialog,你可以传递一个GtkButtonsType而不是分别列出每个按钮,如表16-4所示。

表 16-4

16.8 对话框 - 图11

剩下的都是对话框的文本了,你可以使用替换字符串来构造它,就像在printf中一样。在本例中,我们询问用户是否确实要删除一个文件:

16.8 对话框 - 图12

这个对话框如图16-14所示。

16.8 对话框 - 图13

图 16-14

GtkMessageDialog是传递信息或询问yes/no类型问题的最简单方法。你将在下一节为CD应用程序创建GUI时用到它。