我正在建立一个离线的闪米特根数据库程序来练习MySQL,并决定将GTK3用于GUI。
我遇到的问题是GtkListStore不断崩溃程序,因为它分配了太多内存。
我发现当我加载Triliteral根时,程序很好但是当我清除liststore并再次加载Triliteral根时,它会分配比所需更多的内存。
无论如何,问题是:我如何正确地释放Liststore?我无数次在网上搜索过,无法找到答案,所以我放弃了,并在这里问。
以下是该计划的代码。
appmain.c
#ifdef __linux__
#include <stdio.h>
#include <stdlib.h>
#include <mysql/mysql.h>
#include <gtk/gtk.h>
#include <glib.h>
#include <string.h>
#elif defined(_WIN32) || defined(WIN32) || defined(_WIN64)
#include <windows.h>
#include <winsock.h>
#endif
#include "widgets.h"
/*
rootid - INT -> must be primary key = PRIMARY KEY (rootid) NOT NULL AUTO_INCREMENT
rootwords - VARCHAR(4)
rootmeanings - VARCHAR(1024)
create table syriacroots (rootid INT AUTO_INCREMENT NOT NULL, rootwords VARCHAR(4), rootmeanings VARCHAR(1024), PRIMARY KEY (rootid));
*/
int main(int argc, char **argv)
{
gtk_init(&argc, &argv);
/* pshaqa is Syriac-Aramaic for solution, create and allocate memory for all the data our app needs */
struct mainApp *pshaqa = malloc( sizeof(struct mainApp) );
if (!pshaqa) {
printf("ERROR: main::pshaqa - **** malloc returned NULL ****\n");
goto end;
}
// start up and assert connection to database.
/* removed mysql sensitive code */
/* create the main window */
pshaqa->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
setup_mainwindow(pshaqa->window);
/* create page 1 which will handle the roots information and the listboxes */
GtkWidget *scrolledwindow = gtk_scrolled_window_new(NULL, NULL);
gtk_container_add(GTK_CONTAINER(pshaqa->window), scrolledwindow);
/* create notebook-style page control for the program */
pshaqa->notebook = gtk_notebook_new();
gtk_container_add(GTK_CONTAINER(scrolledwindow), pshaqa->notebook);
GtkWidget *vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
GtkWidget *lblRoot = gtk_label_new("Semitic Roots Control");
gtk_widget_set_tooltip_text(GTK_WIDGET(lblRoot), "Notebook Area that concerns modifying the Syriac Roots database.");
/* page 2 will handle quit, about, and rebuilding the roots */
GtkWidget *vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 1);
GtkWidget *lblInfo = gtk_label_new("Information");
gtk_widget_set_tooltip_text(GTK_WIDGET(lblInfo), "Misc. Info Area to Quit the application, About the application, or Rebuild the Syriac roots list.");
/* add the new pages to the notebook itself */
gtk_notebook_append_page(GTK_NOTEBOOK(pshaqa->notebook), vbox, lblRoot);
gtk_notebook_append_page(GTK_NOTEBOOK(pshaqa->notebook), vbox2, lblInfo);
/* create list store and tree iterator */
pshaqa->areaRoots.liststore = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
//GtkTreeIter treeiter;
/* set up initial liststore info */
//gtk_list_store_append(pshaqa->areaRoots.liststore, &treeiter);
//gtk_list_store_set(pshaqa->areaRoots.liststore, &treeiter, 0, "click on roots button to set the list", 1, "", -1);
/* setup our tree view and add it to the window */
GtkWidget *treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(pshaqa->areaRoots.liststore));
/* setup the cell renderer so we can hold our text then setup the columns on the treeview */
/*GtkCellRenderer *cellrendNum = gtk_cell_renderer_text_new();
pshaqa->areaRoots.treeviewcolumn = gtk_tree_view_column_new_with_attributes("Root ID", cellrendNum, "text", 0, NULL);
g_object_set(cellrendNum, "editable", TRUE, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), pshaqa->areaRoots.treeviewcolumn);
g_signal_connect(cellrendNum, "edited", G_CALLBACK(on_idcell_edited), pshaqa->areaRoots.liststore);*/
/* create and setup the Root string column */
GtkCellRenderer *cellrendRoot = gtk_cell_renderer_text_new();
pshaqa->areaRoots.treeviewcolumn = gtk_tree_view_column_new_with_attributes("Literal Root", cellrendRoot, "text", 0, NULL);
//g_object_set(cellrendRoot, "editable", TRUE, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), pshaqa->areaRoots.treeviewcolumn);
//g_signal_connect(cellrendRoot, "edited", G_CALLBACK(on_rootcell_edited), pshaqa->areaRoots.liststore);
//g_signal_connect(treeview, "row-deleted", G_CALLBACK(on_row_deleted), pshaqa->areaRoots.liststore);
/* create and setup the Root meaning column */
//GtkCellRenderer *cellrendMeaning = gtk_cell_renderer_text_new();
pshaqa->areaRoots.treeviewcolumn = gtk_tree_view_column_new_with_attributes("Meaning", cellrendRoot, "text", 1, NULL);
g_object_set(cellrendRoot, "editable", TRUE, NULL);
gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), pshaqa->areaRoots.treeviewcolumn);
g_signal_connect(cellrendRoot, "edited", G_CALLBACK(on_meaningcell_edited), pshaqa->areaRoots.liststore);
/* make Biliteral Roots button */
pshaqa->areaRoots.btnBi = gtk_button_new_with_label("Biliteral Roots");
/* TODO: make void* array and pass the root struct along with liststore */
g_signal_connect(GTK_BUTTON(pshaqa->areaRoots.btnBi), "clicked", G_CALLBACK(biroots_clicked), pshaqa->areaRoots.liststore);
gtk_box_pack_start(GTK_BOX(vbox), pshaqa->areaRoots.btnBi, TRUE, TRUE, 0);
gtk_widget_set_tooltip_text(GTK_WIDGET(pshaqa->areaRoots.btnBi), "Button that loads the Biliteral Syriac Roots");
/* make Trilieral roots button */
pshaqa->areaRoots.btnTri = gtk_button_new_with_label("Triliteral Roots");
g_signal_connect(GTK_BUTTON(pshaqa->areaRoots.btnTri), "clicked", G_CALLBACK(triroots_clicked), pshaqa->areaRoots.liststore);
gtk_box_pack_start(GTK_BOX(vbox), pshaqa->areaRoots.btnTri, TRUE, TRUE, 0);
gtk_widget_set_tooltip_text(GTK_WIDGET(pshaqa->areaRoots.btnTri), "Button that loads the Triliteral Syriac Roots");
/* make Quadliteral roots button */
pshaqa->areaRoots.btnQuad = gtk_button_new_with_label("Quadliteral Roots");
g_signal_connect(GTK_BUTTON(pshaqa->areaRoots.btnQuad), "clicked", G_CALLBACK(quadroots_clicked), pshaqa->areaRoots.liststore);
gtk_box_pack_start(GTK_BOX(vbox), pshaqa->areaRoots.btnQuad, TRUE, TRUE, 0);
gtk_widget_set_tooltip_text(GTK_WIDGET(pshaqa->areaRoots.btnQuad), "Button that loads the Quadliteral Syriac Roots");
gtk_box_pack_start(GTK_BOX(vbox), treeview, TRUE, TRUE, 0);
gtk_widget_show_all(pshaqa->window);
gtk_main();
if (pshaqa)
free(pshaqa);
pshaqa = NULL;
end:
return 0;
}
void window_destroy(GtkWidget *widget, gpointer data)
{
gtk_main_quit();
}
void biroots_clicked(GtkWidget *btn, gpointer data)
{
GtkTreeIter treeiter;
/* clear the entire listing to update for new list */
gtk_list_store_clear(GTK_LIST_STORE(data));
const char *atwate[] = {"ܐ","ܒ","ܓ","ܕ","ܗ","ܘ","ܙ","ܚ","ܛ","ܝ","ܟ","ܠ","ܡ","ܢ","ܣ","ܥ","ܦ","ܨ","ܩ","ܪ","ܫ","ܬ"};
const unsigned char nloop = sizeof( atwate ) / sizeof( *atwate );
gchar roots[5];
unsigned char i, j;
for (i=0; i < nloop; i++) {
for (j=0; j < nloop; j++) {
sprintf(roots, "%s%s", atwate[i], atwate[j]);
gtk_list_store_append(GTK_LIST_STORE(data), &treeiter);
gtk_list_store_set(GTK_LIST_STORE(data), &treeiter, 0, roots, 1, "", -1);
}
}
}
void triroots_clicked(GtkWidget *btn, gpointer data)
{
GtkTreeIter treeiter;
/* clear the entire listing to update for new list */
gtk_list_store_clear(GTK_LIST_STORE(data));
const char *atwate[] = {"ܐ","ܒ","ܓ","ܕ","ܗ","ܘ","ܙ","ܚ","ܛ","ܝ","ܟ","ܠ","ܡ","ܢ","ܣ","ܥ","ܦ","ܨ","ܩ","ܪ","ܫ","ܬ"};
const unsigned char nloop = sizeof( atwate ) / sizeof( *atwate );
gchar roots[7];
unsigned char i, j, n;
for (i=0 ; i<nloop ; i++) {
for (j=0 ; j<nloop ; j++) {
for (n=0 ; n<nloop ; n++) {
sprintf(roots, "%s%s%s", atwate[i], atwate[j], atwate[n]);
gtk_list_store_append(GTK_LIST_STORE(data), &treeiter);
gtk_list_store_set(GTK_LIST_STORE(data), &treeiter, 0, roots, 1, "", -1);
}
}
}
}
void quadroots_clicked(GtkWidget *btn, gpointer data)
{
GtkTreeIter treeiter;
/* clear the entire listing to update for new list */
gtk_list_store_clear(GTK_LIST_STORE(data));
const char *atwate[] = {"ܐ","ܒ","ܓ","ܕ","ܗ","ܘ","ܙ","ܚ","ܛ","ܝ","ܟ","ܠ","ܡ","ܢ","ܣ","ܥ","ܦ","ܨ","ܩ","ܪ","ܫ","ܬ"};
const unsigned char nloop = sizeof( atwate ) / sizeof( *atwate );
gchar roots[9];
unsigned char i, j, n, t;
for (i=0 ; i<nloop ; i++) {
for (j=0 ; j<nloop ; j++) {
for (n=0 ; n<nloop ; n++) {
for (t=0 ; t<nloop ; t++) {
sprintf(roots, "%s%s%s%s", atwate[i], atwate[j], atwate[n], atwate[t]);
gtk_list_store_append(GTK_LIST_STORE(data), &treeiter);
gtk_list_store_set(GTK_LIST_STORE(data), &treeiter, 0, roots, 1, "", -1);
}
}
}
}
}
void on_meaningcell_edited(GtkWidget *cellrenderer, gchar *path, gchar *text, gpointer data)
{
GtkTreeModel *model = (GtkTreeModel *)data;
GtkTreePath *treepath = gtk_tree_path_new_from_string(path);
GtkTreeIter treeiter;
gtk_tree_model_get_iter(model, &treeiter, treepath);
gtk_list_store_set(GTK_LIST_STORE(model), &treeiter, 1, text, -1);
}
void on_row_deleted(GtkTreeModel *tree_model, GtkTreePath *path, gpointer user_data)
{
if (path)
gtk_tree_path_free(path);
path = NULL;
}
void setup_mainwindow(GtkWidget *x)
{
gtk_window_set_default_size(GTK_WINDOW(x), 800, 300);
gtk_window_set_title(GTK_WINDOW(x), "Syriac Database Program");
g_signal_connect(x, "destroy", G_CALLBACK(window_destroy), NULL);
}
widgets.h
#ifndef WIDGETSZ
#define WIDGETSZ
#ifdef __linux__
#include <gtk/gtk.h>
#elif defined(_WIN32) || defined(WIN32) || defined(_WIN64)
#include <windows.h>
#include <winsock.h>
#endif
struct root {
unsigned int iID;
char strRoot[5]; // size in database = 4
char *strMeaning; // size in database = 1024
};
struct page1 {
GtkWidget
*btnBi,
*btnTri,
*btnQuad
;
GtkListStore *liststore;
GtkTreeViewColumn *treeviewcolumn;
};
struct page2 {
GtkWidget *btnQuit, *btnAbout, *btnRebuild;
};
struct mainApp {
GtkWidget
*aboutdialog,
*window,
*treeview,
*notebook
;
struct page1 areaRoots;
struct page2 areaInfo;
};
/* callback funcs */
void window_destroy(GtkWidget*, gpointer);
void biroots_clicked(GtkWidget*, gpointer);
void triroots_clicked(GtkWidget*, gpointer);
void quadroots_clicked(GtkWidget*, gpointer);
//void on_idcell_edited(GtkWidget*, gchar*, gchar*, gpointer);
//void on_rootcell_edited(GtkWidget*, gchar*, gchar*, gpointer);
void on_meaningcell_edited(GtkWidget*, gchar*, gchar*, gpointer);
void on_row_deleted(GtkTreeModel*, GtkTreePath*, gpointer);
/* Widget setup funcs */
void setup_mainwindow(GtkWidget*);
#endif /* WIDGETSZ */