【发布时间】:2020-06-25 19:02:46
【问题描述】:
我正在为家用 CNC 铣床的数字读出器/控制器编写一些代码,目标是带有 TFT/LCD 的 Pi,我选择使用我知道的 C 和 GTK +3,我知道的比较少(在黑暗中摸索,突然想到)。
控制器的一个页面(通过来自主应用程序/GTK 计时器事件的更新调用安排,具体取决于活动页面)应该呈现 3 个(或其他)按钮,并带有按钮状态的可视指示符。按钮图像从 .png 文件加载。
在创建时,我加载选择/取消选择的图像并存储在每个按钮的结构中。刷新时,我会更改选定/取消选定图像的状态,并使用适当的图像更新按钮图像。或者这就是理论。在初始化时,我默认取消选择图像。我可以很容易地更改为选中,但随后调用取消选中的图像会导致 GTK 错误消息。
调用函数 play_init() 来创建页面内容(前缀“play...” - 这将是一个模板“页面”,以测试不同的 GTK 方法 - 这是为了解决在不同版本中实现的相同问题在不破坏主要代码库的情况下)。
每个“页面”都会创建一个容器,main() 将其附加到 GTK 笔记本上,因此此启动代码无需担心窗口设置 - 其他地方。
在下面的代码部分中,我修改了一些代码并添加了调试代码以默认为取消选择,然后更改为已选择,返回为取消选择等等,所有这些都带有“我在这里”调试语句。这是为了避免指针超出范围等任何问题,以尝试了解我哪里出错了。我知道这与设置按钮图像有关,但无法弄清楚我在这里错过了什么。确实,图像选择应该(是)在包含的事件框事件处理程序中进行管理......但是在这里转储调试代码只是有助于将事情保持在一起。
所有调试文本(1、2、3、4、5 等)只是为了让我可以找到代码开始失败的点。我最近添加了 gtk_button_set_image(.., NULL) 以尝试在设置新图像之前“卸载”图像。纳达,没有变化。
/****************************************************
* Local type definitions
****************************************************/
enum buttons {START, PAUSE, STOP};
typedef enum buttons button_t;
struct play_eb_buttons
{
GtkWidget *button; // Button holding the button image
GtkWidget *im_selc; // "Selected" image
GtkWidget *im_deselc; // "De-selected" image
GtkWidget *eb; // Event box containing button
GtkWidget *parent; // Points to the parent of the event box
bool selc; // New selection state
bool last_selc; // Previous selection state
};
typedef struct play_eb_buttons play_eb_button_t;
/****************************************************
* Code Implementation ** INTERNALS **
****************************************************/
void playSetSelcState(play_eb_button_t *button, bool selc_state)
{
button->selc = selc_state;
if ((button->selc == true ) && (button->last_selc == false ))
{
printf("Setting image (selc) 0x%llX\n", button->im_selc);
gtk_button_set_image(GTK_BUTTON(button->button), button->im_selc);
}
else if ((button->selc == false ) && (button->last_selc == true))
{
printf("Setting image (deselc) 0x%llX\n", button->im_deselc);
gtk_button_set_image(GTK_BUTTON(button->button), button->im_deselc);
}
button->last_selc = button->selc;
}
gint playgreen_press_callback( GtkWidget *widget, GdkEvent *event, gpointer callback_data )
{
printf("Green callback invoked\n");
playSetSelcState(&play_eb_button[START], true);
playSetSelcState(&play_eb_button[PAUSE], false);
playSetSelcState(&play_eb_button[STOP], false);
return TRUE;
}
gint playyellow_press_callback( GtkWidget *widget, GdkEvent *event, gpointer callback_data )
{
printf("Yellow callback invoked\n");
playSetSelcState(&play_eb_button[START], false);
playSetSelcState(&play_eb_button[PAUSE], true);
playSetSelcState(&play_eb_button[STOP], false);
return TRUE;
}
gint playred_press_callback( GtkWidget *widget, GdkEvent *event, gpointer callback_data )
{
printf("Red callback invoked\n");
playSetSelcState(&play_eb_button[START], false);
playSetSelcState(&play_eb_button[PAUSE], false);
playSetSelcState(&play_eb_button[STOP], true);
return TRUE;
}
void playCreateButton( GtkWidget *parent, char *selc, char *deselc, char *name, int col, int row, GCallback func, play_eb_button_t *button )
{
GtkWidget *label;
button->button = gtk_button_new();
button->eb = gtk_event_box_new();
button->parent = parent;
button->selc = false;
button->last_selc = false;
button->im_selc = gtk_image_new_from_file(selc);
button->im_deselc = gtk_image_new_from_file(deselc);
gtk_widget_set_vexpand(button->im_selc, TRUE);
gtk_widget_set_vexpand(button->im_deselc, TRUE);
printf("1\n");
gtk_button_set_image(GTK_BUTTON(button->button), NULL);
gtk_button_set_image(GTK_BUTTON(button->button), button->im_deselc);
printf("2\n");
gtk_button_set_image(GTK_BUTTON(button->button), NULL);
gtk_button_set_image(GTK_BUTTON(button->button), button->im_selc);
printf("3\n");
gtk_button_set_image(GTK_BUTTON(button->button), NULL);
gtk_button_set_image(GTK_BUTTON(button->button), button->im_deselc);
printf("4\n");
gtk_button_set_image(GTK_BUTTON(button->button), NULL);
gtk_button_set_image(GTK_BUTTON(button->button), button->im_selc);
printf("5\n");
gtk_button_set_image(GTK_BUTTON(button->button), NULL);
gtk_button_set_image(GTK_BUTTON(button->button), button->im_deselc);
printf("6\n");
gtk_button_set_image(GTK_BUTTON(button->button), NULL);
gtk_container_add(GTK_CONTAINER(button->eb), button->button);
gtk_grid_attach(GTK_GRID(parent), button->eb, col,row, 1, 1);
g_signal_connect (button->eb, "button_press_event", G_CALLBACK (func), NULL);
// eb = gtk_event_box_new();
// label = gtk_label_new(name);
// gtk_container_add(GTK_CONTAINER(eb), label);
// gtk_widget_set_name(label, "buttons");
// gtk_grid_attach(GTK_GRID(parent), eb, col+1, row, 1, 1);
// g_signal_connect (eb, "button_press_event", G_CALLBACK (func), NULL);
printf("'%s' at 0x%16llX and 0x%16llX\n", name, button->im_selc, button->im_deselc);
}
/****************************************************
* Code Implementation ** EXTERNALS **
****************************************************/
/*
* play_init()
*
* Setup for the complete DRO page for the GUI
*/
void play_init()
{
GtkWidget *grid;
play_container = gtk_event_box_new();
grid = gtk_grid_new();
gtk_container_add(GTK_CONTAINER(play_container), grid);
gtk_widget_modify_bg(grid, GTK_STATE_NORMAL, &colour_black);
playCreateButton(grid, "push-button-green.png" ,"push-button-green-dselc.png", "Run!", 0, 1, (GCallback)playgreen_press_callback, &play_eb_button[START]);
playCreateButton(grid, "push-button-yellow.png","push-button-yellow-dselc.png", "Pause", 0, 2, (GCallback)playyellow_press_callback, &play_eb_button[PAUSE]);
playCreateButton(grid, "push-button-red.png" ,"push-button-red-dselc.png", "STOP", 0, 3, (GCallback)playred_press_callback, &play_eb_button[STOP]);
playSetSelcState(&play_eb_button[START], true);
playSetSelcState(&play_eb_button[START], false);
}
我机器的输出(主机:HP Z600,运行 Ubuntu 20.04)
Hostname = 'mike-HP-Z600-Workstation'
Initialising
State = Connecting
1
2
3
(SiegDROsGtk3:556896): Gtk-CRITICAL **: 19:42:24.182: gtk_button_set_image: assertion 'image == NULL || GTK_IS_WIDGET (image)' failed
4
(SiegDROsGtk3:556896): Gtk-CRITICAL **: 19:42:24.182: gtk_button_set_image: assertion 'image == NULL || GTK_IS_WIDGET (image)' failed
5
(SiegDROsGtk3:556896): Gtk-CRITICAL **: 19:42:24.182: gtk_button_set_image: assertion 'image == NULL || GTK_IS_WIDGET (image)' failed
6
'Run!' at 0x 56446A49E2B0 and 0x 56446A49E420
1
2
3
(SiegDROsGtk3:556896): Gtk-CRITICAL **: 19:42:24.185: gtk_button_set_image: assertion 'image == NULL || GTK_IS_WIDGET (image)' failed
4
(SiegDROsGtk3:556896): Gtk-CRITICAL **: 19:42:24.185: gtk_button_set_image: assertion 'image == NULL || GTK_IS_WIDGET (image)' failed
5
(SiegDROsGtk3:556896): Gtk-CRITICAL **: 19:42:24.185: gtk_button_set_image: assertion 'image == NULL || GTK_IS_WIDGET (image)' failed
6
'Pause' at 0x 56446A49E700 and 0x 56446A49E870
1
2
3
(SiegDROsGtk3:556896): Gtk-CRITICAL **: 19:42:24.187: gtk_button_set_image: assertion 'image == NULL || GTK_IS_WIDGET (image)' failed
4
(SiegDROsGtk3:556896): Gtk-CRITICAL **: 19:42:24.187: gtk_button_set_image: assertion 'image == NULL || GTK_IS_WIDGET (image)' failed
5
(SiegDROsGtk3:556896): Gtk-CRITICAL **: 19:42:24.187: gtk_button_set_image: assertion 'image == NULL || GTK_IS_WIDGET (image)' failed
6
'STOP' at 0x 56446A49E870 and 0x 56446A49E2B0
Setting image (selc) 0x56446A49E2B0
(SiegDROsGtk3:556896): Gtk-CRITICAL **: 19:42:24.187: gtk_button_set_image: assertion 'image == NULL || GTK_IS_WIDGET (image)' failed
Setting image (deselc) 0x56446A49E420
(SiegDROsGtk3:556896): Gtk-CRITICAL **: 19:42:24.188: gtk_button_set_image: assertion 'image == NULL || GTK_IS_WIDGET (image)' failed
Setting image (selc) 0x56446A49E2B0
(SiegDROsGtk3:556896): Gtk-CRITICAL **: 19:42:26.806: gtk_button_set_image: assertion 'image == NULL || GTK_IS_WIDGET (image)' failed
Graphics terminated
Closing
我已经通过这个尝试了 GDB,并观察了 eb_button 数组,期待损坏或其他东西,但该结构很好。错误消息表明图像在调用“3”之前受到影响(图像指针保持非空)
如果我让事件处理程序代码运行,我可能会遇到其他 GTK 错误,这些错误都是围绕相同的调用结构来设置按钮图像...
(SiegDROsGtk3:556962): Gtk-CRITICAL **: 19:48:22.637: gtk_button_set_image: assertion 'image == NULL || GTK_IS_WIDGET (image)' failed
Setting image (selc) 0x558A215F72B0
(SiegDROsGtk3:556962): Gtk-CRITICAL **: 19:48:25.225: gtk_button_set_image: assertion 'image == NULL || GTK_IS_WIDGET (image)' failed
Setting image (deselc) 0x558A215F7420
Setting image (selc) 0x558A215F72B0
(SiegDROsGtk3:556962): Gtk-CRITICAL **: 19:48:30.341: gtk_button_set_image: assertion 'image == NULL || GTK_IS_WIDGET (image)' failed
Setting image (deselc) 0x558A215F7420
(SiegDROsGtk3:556962): GLib-GObject-CRITICAL **: 19:48:32.898: g_object_ref: assertion 'G_IS_OBJECT (object)' failed
(SiegDROsGtk3:556962): Gtk-CRITICAL **: 19:48:32.898: gtk_widget_get_parent: assertion 'GTK_IS_WIDGET (widget)' failed
Setting image (selc) 0x558A215F72B0
(SiegDROsGtk3:556962): Gtk-CRITICAL **: 19:48:35.458: gtk_button_set_image: assertion 'image == NULL || GTK_IS_WIDGET (image)' failed
Setting image (deselc) 0x558A215F7420
(SiegDROsGtk3:556962): Gtk-CRITICAL **: 19:48:38.022: gtk_button_set_image: assertion 'image == NULL || GTK_IS_WIDGET (image)' failed
Setting image (selc) 0x558A215F72B0
在没有初始化调试的情况下运行它,按钮都被取消选择,我可以选择例如绿色,并以正确的选择图像突出显示;选择例如黄色按钮,绿色不取消选择(得到该错误),黄色成功选择。按 Reg 和黄色不会取消选择(得到错误),但红色会。在某些时候,我会完全丢失按钮图像,或者有时会得到一个未加载图像的默认图像。
看起来好像对 gtk_button_set_image 的连续调用正在破坏预加载的图像。
显然我在做一些愚蠢的事情,但我无法找到一个明智的谷歌搜索结果来说明我做错了什么。
帮忙?!
【问题讨论】: