我有一个用glade设计的Gtk + 3.0用户界面,并在C中用两个列表视图实现(作为GtkTreeView实现)。当我在第二个列表视图中单击一个项目时,我希望在多行文本视图中显示该条目的详细信息。除了使用GtkTextView之外,没有其他选择,即使我需要不到GtkTextView提供的1%(我甚至不需要编辑)。 但是,在我的UI上使用GtkTextView元素时,程序会在列表中的第一次单击时崩溃。当我从代码中删除GtkTextView的更新时,我可以永久地使用UI来玩,不会崩溃。 以下是更新文本视图的代码:
// get stuff from list store
gtk_tree_model_get_iter (GTK_TREE_MODEL (liststore), &iter, tree_path);
gtk_tree_model_get (GTK_TREE_MODEL (liststore), &iter,
ITEM_NAME, &itemName,
ITEM_DESC, &itemDesc,
ITEM_LINK, &itemLink, -1);
// fill a couple of one line GtkEntry first
// ...
// fill the text view
txtBuffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (txtDesc));
gtk_text_buffer_set_text (txtBuffer, itemDesc, -1);
我检查过itemDesc是否为非NULL。我用valgrind对此进行了分析,有趣的是没有检测到明显的内存处理错误但堆栈溢出!我没有使用递归...无论如何,这里是valgrind的输出:
==4879== Stack overflow in thread 1: can't grow stack to 0xffe801ff8
==4879==
==4879== Process terminating with default action of signal 11 (SIGSEGV)
==4879== Access not within mapped region at address 0xFFE801FF8
==4879== at 0x5B36564: g_hash_table_lookup (in /lib/x86_64-linux-gnu/libglib-2.0.so.0.4000.0)
==4879== If you believe this happened as a result of a stack
==4879== overflow in your program's main thread (unlikely but
==4879== possible), you can try to increase the size of the
==4879== main thread stack using the --main-stacksize= flag.
==4879== The main thread stack size used in this run was 8388608.
==4879==
==4879== HEAP SUMMARY:
==4879== in use at exit: 3,946,706 bytes in 45,434 blocks
==4879== total heap usage: 326,942 allocs, 281,508 frees, 25,249,132 bytes allocated
==4879==
==4879== LEAK SUMMARY:
==4879== definitely lost: 3,664 bytes in 32 blocks
==4879== indirectly lost: 12,977 bytes in 542 blocks
==4879== possibly lost: 165,544 bytes in 1,342 blocks
==4879== still reachable: 3,594,265 bytes in 42,477 blocks
==4879== suppressed: 0 bytes in 0 blocks
==4879== Rerun with --leak-check=full to see details of leaked memory
==4879==
==4879== For counts of detected and suppressed errors, rerun with: -v
==4879== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
任何想法都表示赞赏。这是C代码。
#include <gtk/gtk.h>
#include <string.h>
#include <glib.h>
#include <libxml/parser.h>
#include <sqlite3.h>
#include "kpodcast.h"
#include "global.h"
GtkBuilder *builder;
enum {
PODCAST_NAME = 0,
NCOLUMNS
};
enum {
ITEM_NAME = 0,
ITEM_DATE = 1,
ITEM_DESC = 2,
PODCAST_IDX = 3,
ITEM_LINK = 4,
NCOLUMNS2
};
extern GList * all_podcasts;
extern GTimeZone * gTimeZone;
extern sqlite3 * db;
void kleine_callback (GtkWidget *w, gpointer d)
{
GtkWidget *dialog;
dialog = gtk_message_dialog_new (NULL,
GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_INFO, GTK_BUTTONS_CLOSE, "Hallo, Welt!");
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
}
void
on_item_selection_change (GtkTreeSelection * widget, gpointer user_data)
{
GList * selection = gtk_tree_selection_get_selected_rows (widget, NULL);
GtkTreePath * tree_path = NULL;
GtkLabel * txtDesc = NULL;
GtkEntry * txtLink = NULL;
GtkTextBuffer* txtBuffer = NULL;
GtkEntry * txtName = NULL;
GtkListStore * liststore = NULL;
char * message = NULL;
GtkTreeIter iter;
gchar * itemName = NULL;
gchar * itemDesc = NULL;
gchar * itemLink = NULL;
GtkStatusbar * status_bar = GTK_WIDGET (gtk_builder_get_object (builder, "status_bar"));
txtName = GTK_WIDGET (gtk_builder_get_object (builder, "txtItemName"));
txtDesc = GTK_WIDGET (gtk_builder_get_object (builder, "txtItemDesc"));
txtLink = GTK_WIDGET (gtk_builder_get_object (builder, "txtItemLink"));
if (selection != NULL) {
tree_path = (GtkTreePath *) selection->data;
int depth = gtk_tree_path_get_depth (tree_path);
int * idx = gtk_tree_path_get_indices (tree_path);
liststore = GTK_LIST_STORE (gtk_builder_get_object (builder, "liststore_podcast_items"));
gtk_tree_model_get_iter (GTK_TREE_MODEL (liststore), &iter, tree_path);
gtk_tree_model_get (GTK_TREE_MODEL (liststore), &iter,
ITEM_NAME, &itemName,
ITEM_DESC, &itemDesc,
ITEM_LINK, &itemLink, -1);
// set item name
gtk_entry_set_text (txtName, itemName);
//gtk_label_set_text (txtDesc, itemDesc);
// set item description
txtBuffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (txtDesc));
gtk_text_buffer_set_text (txtBuffer, itemDesc, -1);
// set item link
gtk_entry_set_text(txtLink, itemLink);
FREE_POINTER1 (itemName);
FREE_POINTER1 (itemDesc);
FREE_POINTER1 (itemLink);
}
else {
gtk_entry_set_text (txtName, "");
gtk_entry_set_text (txtLink, "");
/*
txtBuffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (txtDesc));
gtk_text_buffer_set_text (txtBuffer, "", -1);
*/
gtk_label_set_text (txtDesc, itemDesc);
}
}
void
on_podcast_selection_change (GtkTreeSelection *widget, gpointer user_data)
{
GList * selection = gtk_tree_selection_get_selected_rows (widget, NULL);
GtkTreePath * tree_path = NULL;
char * message = NULL;
GtkStatusbar * status_bar = GTK_WIDGET (gtk_builder_get_object (builder, "status_bar"));
guint context = gtk_statusbar_get_context_id (status_bar, "some_context_id");
kpodcastPtr podcast = NULL;
GtkListStore * liststore = NULL;
GtkTreeIter iter;
guint item_list_length = 0, jj=0;
if (selection) {
tree_path = (GtkTreePath *) selection->data;
int depth = gtk_tree_path_get_depth (tree_path);
if (depth == 1) { // replace by assert (depth = 1)
//set GtkTreeIter to index
// Add Name and Description to the UI
//
int * idx = gtk_tree_path_get_indices (tree_path);
podcast = (kpodcastPtr) g_list_nth_data (all_podcasts, *idx);
/*
gtk_entry_set_text(txtName, podcast->name);
txtBuffer = gtk_text_buffer_new (NULL);
gtk_text_buffer_set_text (txtBuffer, podcast->desc, -1);
gtk_text_view_set_buffer(txtDesc, txtBuffer);
*/
//
// Get list store
//
liststore = GTK_LIST_STORE (gtk_builder_get_object (builder, "liststore_podcast_items"));
gtk_list_store_clear (liststore);
//
// Add all podcasts
//
item_list_length = g_list_length (podcast->items);
for (jj=0; jj<item_list_length; jj++) {
kpodcastItemPtr item = (kpodcastItemPtr) g_list_nth_data (podcast->items, jj);
GDateTime * gDate = NULL;
char * date;
gDate = g_date_time_new_from_unix_local (item->pubDate);
date = g_date_time_format (gDate, "%Y-%m-%d");
gtk_list_store_append(liststore, &iter);
gtk_list_store_set (liststore, &iter,
ITEM_NAME, item->name,
ITEM_DATE, date,
ITEM_DESC, item->desc,
PODCAST_IDX, *idx,
ITEM_LINK, item->link,
-1);
g_date_time_unref (gDate);
}
}
}
else {
message = g_strdup ("Treepath is NULL.");
gtk_statusbar_push (status_bar, context, message);
//g_printf ("statusbar push returned %d.\n", rc);
g_free (message);
}
g_list_free_full (selection, (GDestroyNotify) gtk_tree_path_free);
}
void
on_action_add_podcast (GtkWidget * widget, gpointer user_data)
{
GtkStatusbar * status_bar = GTK_WIDGET (gtk_builder_get_object (builder, "status_bar"));
if (status_bar == NULL)
printf ("No status bar.\n");
else {
guint context = gtk_statusbar_get_context_id (status_bar, "somectxt");
char * message = g_strdup ("add_podcast clicked.");
guint rc = gtk_statusbar_push (status_bar, context, message);
g_free (message);
}
}
void
on_action_click_download (GtkWidget * widget, gpointer user_data)
{
GtkStatusbar * status_bar = GTK_WIDGET (gtk_builder_get_object (builder, "status_bar"));
if (status_bar == NULL)
printf ("No status bar.\n");
else {
guint context = gtk_statusbar_get_context_id (status_bar, "somectxt");
char * message = g_strdup ("podcast download clicked.");
guint rc = gtk_statusbar_push (status_bar, context, message);
g_free (message);
}
}
void on_button_test_clicked (GtkWidget * w, gpointer d)
{
g_print ("on button test clicked!");
}
void quit (GtkWidget * w, gpointer d)
{
gtk_main_quit ();
}
#ifdef GTKUI
int main (int argc, char *argv[])
#else
int main_ (int argc, char *argv[])
#endif
{
GError * error = NULL;
GtkWidget * window;
GtkListStore * liststore_podcast;
GtkTreeIter iter;
//
// init the podcast stuff
//
// db
if (!init_db ()) {
printf ("DB could not be initialized: %s.", sqlite3_errmsg (db));
return 0;
}
// timezone
gTimeZone = g_time_zone_new_local ();
// init podcasts
if (!init_podcasts ()) {
printf ("Podcasts could not be initialized, leaving.");
return 0;
}
//
// do the GTK+ stuff
//
gtk_init (&argc, &argv);
builder = gtk_builder_new ();
if (!gtk_builder_add_from_file (builder, "kaixN.glade", &error)) {
g_warning ("%s", error->message);
g_free (error);
return 1;
}
liststore_podcast = GTK_LIST_STORE (gtk_builder_get_object (builder, "liststore_podcasts"));
if (liststore_podcast) {
int ll = g_list_length (all_podcasts);
if (ll == 0) {
printf ("Podcast list is empty.\n");
}
else {
int idx = 0;
for (idx = 0; idx < ll; idx++) {
kpodcastPtr podcast = (kpodcastPtr) g_list_nth_data (all_podcasts, idx);
/* Append an empty row to the list store. Iter will point to the new row */
gtk_list_store_append(liststore_podcast, &iter);
gtk_list_store_set (liststore_podcast, &iter,
PODCAST_NAME, podcast->name,
-1);
}
}
}
else {
g_print ("Couldn't get liststore_podcasts.\n");
}
window = GTK_WIDGET(gtk_builder_get_object (builder, "main_window"));
gtk_builder_connect_signals (builder, NULL);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}
非常感谢 启