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;
}
为了证明我的意思,我写了这段代码,没有大部分 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;
}