问题代码,创建了一个选择文件的文件选择按钮
GtkWidget *fileSelBtn = gtk_file_chooser_button_new("Choose File",GTK_FILE_CHOOSER_ACTION_OPEN);
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(fileSelBtn), g_get_user_special_dir(G_USER_DIRECTORY_DOCUMENTS));
g_signal_connect(fileSelBtn,"selection-changed",G_CALLBACK(on_sel_file),NULL);
这是正常的代码,但是设置了默认目录后发生了程序运行崩溃。程序在启动时直接闪退。崩溃。
如果文件选择按钮选择的是目录就没有问题
GtkWidget *folderSelBtn = gtk_file_chooser_button_new("Choose File",GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER);
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(folderSelBtn), g_get_user_special_dir(G_USER_DIRECTORY_DOCUMENTS));
g_signal_connect(folderSelBtn,"selection-changed",G_CALLBACK(on_sel_folder),NULL);原因就是在选择回调函数上。文件选择回调函数直接没有判断选择有效性就给其他字符数组赋值了。当选择为空,获取的文件名字返回NULL时就出现了问题。
static void on_sel_file(GtkFileChooserButton *widget,gpointer user_data){
gchar* filePath = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
//设置选择的目录
memset(g_filePath,0,sizeof(g_filePath));
strcpy(g_filePath,filePath);
//释放空间
g_free(filePath);
}为什么会返回空文件呢?因为gtk_file_chooser_set_current_folder会直接触发一次文件选择信号"selection-changed",所以对于选择文件的文件选择按钮就会触发,但是并没有选择任何文件,所以就造成了崩溃。
对于选择目录的文件选择按钮。gtk_file_chooser_set_current_folder也会触发文件选择信号,但是是选择了文件的。所以即使没有判断选择有效性,也不会导致崩溃。
解决办法是在回调函数里判断选择有效性就行了。
问题
g_signal_connect明明是设置在gtk_file_chooser_set_current_folder后面才连接的回调函数,那么为什么gtk_file_chooser_set_current_folder一执行就直接调用了回调函数造成了崩溃呢?
我问了deepseek ai,它解释了原因:
您观察到的现象确实有些反直觉,但这是由 GTK 的信号处理机制决定的。让我解释原因并提供解决方案:
原因分析
GTK 的信号处理队列:
- 当
gtk_file_chooser_set_current_folder()被调用时,GTK 内部会生成一个 "selection-changed" 信号 - 这个信号会被放入 GTK 的事件队列中,不会立即处理
- 信号的实际触发是在主循环下一次迭代时才会执行
- 当
信号连接的时机:
- 虽然您在设置文件夹后才连接信号处理器
- 但信号处理器会在主循环处理队列中的信号时被调用
- 因此即使连接在后,也会捕获到之前操作产生的信号