我有一个应用程序,其中有一个登录屏幕。有一个用于登录的按钮。按下时,
GtkButton
应设置为不敏感以向用户提供反馈。
点击按钮后,通过 CURL 完成登录请求。因为这是同步完成的,所以在发送 CURL 请求之前不会重绘按钮(因此不会(还)显得不敏感)。
由于此 CURL 请求最多可能需要 5 秒,我希望用户获得按钮已单击且无法再次单击的反馈。
如何让按钮点击后不敏感,而不必等待重绘?或者还有其他我没有看到的方法吗?
static void on_login_pressed(GtkWidget *widget, GdkEvent *event, gpointer data)
{
gtk_widget_set_sensitive(GTK_WIDGET(login_cred_screen->login_button), FALSE);
//gtk_widget_queue_draw(GTK_WIDGET(login_cred_screen->login_button)); //have tried this, does not work right away
//this is where I need the button to be redrawn
g_signal_emit_by_name(login_cred_screen->login_button, "login-button-clicked"); //after this is where the CURL request is done
}
您必须强制 GTK 运行事件循环并清除所有未决事件,其中之一是由
gtk_widget_set_sensitive
触发的重绘,但还没有时间处理。这是一个使用 GTK3 的完整工作示例:
#include <unistd.h> // sleep()
#include <gtk/gtk.h>
void simulate_long_curl_request(GtkWidget *widget)
{
sleep(5);
gtk_widget_set_sensitive(widget, true);
}
static void on_login_pressed(GtkWidget *loginButton, GdkEvent *event, gpointer data)
{
gtk_widget_set_sensitive(loginButton, false);
// Force GTK to treat pending events in the event loop
// before moving on. This includes your `set_sensitive`
// call the line before...
while(gtk_events_pending())
{
gtk_main_iteration();
}
simulate_long_curl_request(loginButton);
}
void on_activate(GtkApplication *application, gpointer user_data)
{
// Setup application window:
GtkWidget *loginWindow;
loginWindow = gtk_application_window_new(application);
gtk_window_set_title(GTK_WINDOW(loginWindow), "Login window");
gtk_window_set_default_size(GTK_WINDOW(loginWindow), 200, 200);
// Setup login button:
GtkWidget *loginButton;
loginButton = gtk_button_new_with_label("Login");
g_signal_connect(loginButton, "clicked", G_CALLBACK(on_login_pressed), NULL);
// Add button to window:
gtk_container_add(GTK_CONTAINER(loginWindow), loginButton);
// Run application:
gtk_widget_show_all(loginWindow);
}
int main(int argc, char **argv)
{
// Setup application:
GtkApplication *application;
application = gtk_application_new("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect(application, "activate", G_CALLBACK(on_activate), NULL);
const int status = g_application_run(G_APPLICATION(application), argc, argv);
g_object_unref(application);
return status;
}
您可以在这里阅读有关主循环的信息。你提到了
gtk_widget_queue_draw
是如何不起作用的。该功能的描述说(我强调):
通过在小部件窗口及其所有子窗口上调用
使由区域定义的小部件区域无效。 一旦主循环变得空闲(大致在处理完当前批事件之后),窗口将接收所有已失效区域联合的公开事件。gdk_window_invalidate_region()
所以这个函数并没有真正重绘,它只是向主循环发送一个请求,一旦可以重绘就重绘。对
gtk_widget_set_sensitive
的调用很可能在内部调用 gtk_widget_queue_draw
.
不过,请小心使用此解决方案,如下所示:
while(gtk_events_pending())
{
gtk_main_iteration();
}
将强制处理所有事件,包括键盘事件等...