C++ 中的 GTK:根据控制台输入更改标签

GTK in C++: Changing a Label based on console input

为了证明我的意思,我写了这段代码,没有大部分 gtk 混乱:

//more gtk declaration stuff above
int access;
access = 0;

int tries;
tries = 0;

string input;
input = "";

string code;
code = "";

while(access != 1 && tries < 4){
    directions((gpointer)lbl); //change label to "type 'finger'"
    cin >> input;

    if(input.compare("finger") = 0){
        while(code.compare("1") != 0 && tries < 4){
            fpcheck((gpointer)lbl); //change label "Enter the secret code ('1')"
            cin >> code;
            if(code.compare("1") != 0){
                retry((gpointer) lbl);//change label "Try again!"
                tries ++;       
            }
            else{
                fprecog((gpointer) lbl); //change label "Recognized!"
                access = 1;
            }
        }
    }
}
if(access = 1)
    //change label "Access Granted!"
else
    //change label "No access."

gtk_main();
return 0;

显然这不会完全起作用,因为 gtk_main() 没有被调用到最后。控制台的东西 运行 没问题,但是 window 直到最后才会弹出,所以用户不知道该怎么做,如果我提前放 gtk_main()上,程序卡在 gtk_main() 循环中,所以什么也不会发生。

这种流程在 GTK 中通常是如何完成的?我已经尝试了一些 gtk_thread 的东西来打破 main,但是这显然已被弃用,所以我尽量不使用它。

输入必须由非 gtk_main() 的线程读取,因为输入不是来自 GUI。实际上,它将是一个插入 beaglebone black 的设备,但我认为这是一个更简单的类似情况。

将使用的实际输入方法是 1) 指纹传感器,它根据通过 UART 通道发送和接收的字节执行操作,以及 2) 在 BeagleBone 上使用 OpenCV 方法的 USB 摄像头和面部识别脚本Black 运行ning Debian,联网到笔记本电脑上做密集的 opencv 工作。目前我只是想让它与 FP 传感器一起使用。通过我们的界面,我们可以调用一个 FP 传感器方法,returns 一个 int,并根据该 int 做一些事情。

我需要能够根据返回的 int 更改 GTK 标签,然后在标签显示后调用另一个方法。

下面是我尝试集成的代码片段:

while(key != 'x')
    {
        imshow("main_display", welcome);
        key = waitKey(1);  //poll keyboard at active screen

        //key = getkey();  //TODO: poll from TFT instead

        switch(key)
        {
            case 'i': //Identify User
                imshow("main_display", press_finger);
                waitKey(1);
                printf("\n---IDENTIFY USER---\n");
                post_log(1, 0);

                do_reg = true;
                Ret = GT_LED_On(LS);
                printf("\nPress Finger");

                //something to force console text before loop starts...?

                Timer.InitTimer();
                while(GT_IsPressFinger(LS) == 0 && ((Timer.ElapsedTime_ms() < TIMEOUT))) {}
                if(Timer.ElapsedTime_ms() >= TIMEOUT)
                {
                    printf("\nCapture TIMEOUT\n");
                    Ret = GT_LED_Off(LS);
                    post_log(6, user_id);
                    imshow("main_display", fps_timeout);
                    waitKey(1000);
                    do_reg = false;
                    break;  //??????????????????????????? GOTO???
                }
                printf("\nCapturing...Standby...\n");
                imshow("main_display", hold_finger);
                waitKey(1);
                Ret = GT_CaptureFinger(LS, 0);

基本上,我们正在尝试使用实际的 GUI 框架而不是 imshow(),并且由于设备已经由于 OpenCV 而具有 GTK,因此坚持使用 GTK 会很好。这个控制台问题试图弄清楚如何在简单的上下文中用 gtk window 的标签更改替换 imshow()。

我想你要找的是Glib IO Channel。如果将其绑定到标准输入文件描述符,则在用户按下回车键时会触发信号。然后你应该可以使用 cin 来获取文本。

如果您的目的是获取某种类型的密码,您可以考虑 using a dialog 捕获用户输入。

好的,在 Blake 的帮助下,我想我找到了一个解决方案,但我不知道它是否是最好的。

为了在 gtk_main() 发生时获取输入并在发生时调用函数,我在标准输入文件描述符上添加了一个 glib io 调用以检测 cin 样式输入。我使用我的其他代码作为回调函数。感谢 Blake 在这部分的帮助。

然后,为了实际更新这个新的迷你线程中的文本,我创建了一个 update() 函数来调用 main_iteration(),同时循环 gtk_main() 一次。 Here's documentation on that. 我不知道这样使用是否安全,或者是否有更好的解决方案,但程序现在完成了我想要它做的事情。

这是完整的代码以供将来参考。

#include <gtk/gtk.h>
#include <unistd.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include <glib.h>


using namespace std;

void update(){
while (gtk_events_pending ())
gtk_main_iteration ();}

void fpcheck(/*GtkWidget *widget, GdkEvent *event,*/ gpointer window) {
    gchar const *text = "<span font='32' weight='bold' color='#DDDDDD'>Enter the Secret\nCode. ('1')</span>";
    gtk_label_set_markup(GTK_LABEL(window), text);
}

void fprecog(/*GtkWidget *widget, GdkEvent *event,*/ gpointer window) {
    gchar const *text2 = "<span font='32' weight='bold' color='#DDDDDD'>Fingerprint Recognized!</span>";
    gtk_label_set_markup(GTK_LABEL(window), text2);
}

void directions(/*GtkWidget *widget, GdkEvent *event,*/ gpointer window){
    gchar const *text3 = "<span font='32' weight='bold' color='#DDDDDD'>Type 'finger'.</span>";
    gtk_label_set_markup(GTK_LABEL(window), text3);
}

void retry(/*GtkWidget *widget, GdkEvent *event,*/ gpointer window){
    gchar const *text4 = "<span font='32' weight='bold' color='#DDDDDD'>Try Again.</span>";
    gtk_label_set_markup(GTK_LABEL(window), text4);
}

void accessed(/*GtkWidget *widget, GdkEvent *event,*/ gpointer window){
    gchar const *text5 = "<span font='32' weight='bold' color='#DDDDDD'>Access Granted!</span>";
    gtk_label_set_markup(GTK_LABEL(window), text5);
}

void denied(/*GtkWidget *widget, GdkEvent *event,*/ gpointer window){
    gchar const *text6 = "<span font='32' weight='bold' color='#DDDDDD'>Access Denied.</span>";
    gtk_label_set_markup(GTK_LABEL(window), text6);
}


gboolean callback(GIOChannel *gio, GIOCondition condition, gpointer lbl){
    int access;
    access = 0;

    int tries;
    tries = 0;

    string input;
    input = "";

    string code;
    code = "";

    while(access != 1 && tries < 4){
        directions((gpointer)lbl); //change label to "type 'finger'"
        update();
        cin >> input;

        if(input.compare("finger") == 0){
            while(code.compare("1") != 0 && tries < 4){
                fpcheck((gpointer)lbl); //change label "Enter the secret code ('1')"
                update();
                cin >> code;
                if(code.compare("1") != 0){
                    retry((gpointer) lbl);//change label "Try again!"
                    update();
                    tries ++;       
                }
                else{
                    fprecog((gpointer) lbl); //change label "Recognized!"
                    update();
                    access = 1;
                }
            }
        }
    }
    if(access == 1)
        accessed((gpointer)lbl);
        //change label "Access Granted!"
    else
        denied((gpointer)lbl);
        //change label "No access."
}


int main(int argc, char *argv[]){

    GtkWidget *window; //main window
    GtkWidget *lbl; //text
    GdkColor color = {0, 0x0, 0x0, 0x0}; //window color

    gtk_init(&argc, &argv);

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL); //init window
    //gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); //window pos on screen
    gtk_window_set_resizable(GTK_WINDOW(window), FALSE); //user cant resize //doesnt work
    //gtk_window_set_default_size(GTK_WINDOW(window), 800, 480); //window size

    gtk_widget_modify_bg(window, GTK_STATE_NORMAL, &color); //set color to window
    gtk_window_set_decorated(GTK_WINDOW(window), FALSE); //borderless
    gtk_widget_show(window);

    lbl = gtk_label_new(NULL); //label init
    gtk_container_add(GTK_CONTAINER(window), lbl);
    gtk_widget_set_size_request(lbl,800,480); //sets area that text can be //breaks alignment
    gtk_misc_set_alignment(GTK_MISC(lbl), .5, .5); //alignment
    gtk_label_set_line_wrap_mode(GTK_LABEL(lbl), PANGO_WRAP_WORD_CHAR); //sets line wrap on

    gchar const *str = "<span font='32' weight='bold' color='#DDDDDD'>Press Enter to begin.</span>"; //label text, uses pango markup
    gtk_label_set_markup(GTK_LABEL(lbl), str); //add pango str to label
    gtk_label_set_angle(GTK_LABEL(lbl), -90);

    gtk_widget_show(lbl);

    //fpcheck((gpointer)lbl);
    //g_signal_connect(G_OBJECT(window), "key-press-event", G_CALLBACK(fpcheck), (gpointer) lbl); //calls fpcheck to change label 
    //g_signal_connect(G_OBJECT(window), "key-release-event", G_CALLBACK(fprecog), (gpointer) lbl);     
    //fprecog((gpointer)lbl);

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

    //gtk_widget_show_all(window); //build the window all at once

    //label says "Ready"

    GIOChannel *gio;
    gio = g_io_channel_unix_new(STDIN_FILENO);
    guint ret;
    ret = g_io_add_watch(gio, G_IO_IN, callback, (gpointer)lbl);

    gtk_main();

    return 0;
}