GtkWidget 不会立即重绘

问题描述 投票:0回答:1

我有一个应用程序,其中有一个登录屏幕。有一个用于登录的按钮。按下时,

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 gtk3 gdk
1个回答
0
投票

您必须强制 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();
}

将强制处理所有事件,包括键盘事件等...

© www.soinside.com 2019 - 2024. All rights reserved.