how to manually move pages between notebooks in gtk4

I am working on an app that uses gtk bindings for ui elements, and I cannot figure out how to so something that seems like it should be simple. I want to be able to move the information contained in a notebook page to another notebook (eg move Page 1 from notebook_1 to notebook_2).

I tried to do this with the following code snippet:

page = gtk_notebook_get_current_page(notebook_1)
child = gtk_notebook_get_nth_page(notebook_1, page)

call gtk_notebook_remove_page(notebook_1, page)
label = gtk_label_new("Test")
nb = gtk_notebook_append_page(notebook_2, child, test)

When I try to run this, I get an error in the console:

(:87313): Gtk-CRITICAL **: 19:58:29.515: gtk_notebook_append_page: assertion ‘GTK_IS_WIDGET (child)’ failed

And nb is -1, indicating the operation failed.

I thought that maybe the remove page was destroying the child object, so I omitted that line. But then I get the following error in the console

(:87293): Gtk-WARNING **: 19:56:50.684: Duplicate child name in GtkStack: (null)

(:87293): Gtk-CRITICAL **: 19:56:50.684: gtk_widget_set_parent: assertion '_gtk_widget_get_parent (widget) == NULL' failed

When I run this nb is not -1, but the information in the child does not show in notebook_2.

I feel like I am missing something basic here, but I don’t know what. I tried a few other things such as attaching the child to a scrolled window, and also reproduced the error using c code (instead of bindings). If anyone has any tips on how to do this or direction on how to further troubleshoot, I’d appreciate it.

Update – here is a full c app that give me the problem, that I hacked together from an old gtk2? notebook example I found on the web. When I run it and click on the move page button, it does not work. I do not really know c, so apologies if this is a mess, but it does reproduce the problem FWIW.

It seems like what I want to do isn’t possible – when I remove the old page it is probably wiping the reference to the child, but when I don’t remove the old page it complains that the child exists somewhere else.

#include <gtk/gtk.h>

GtkWidget *notebook_1;
GtkWidget *notebook_2;
    
/* move a page from notebook_1 to notebook_2 */
void move_page (GtkButton *button)
{
    gint page;
    GtkWidget *child;
    GtkWidget *label;
    GtkWidget *scroll_win;
    
    
    page = gtk_notebook_get_current_page(notebook_1);
    child = gtk_notebook_get_nth_page(notebook_1, page);
    label = gtk_notebook_get_tab_label(notebook_1, child);
    gtk_notebook_remove_page (notebook_1, page);
    
    
    gtk_notebook_append_page(GTK_NOTEBOOK (notebook_2), GTK_WIDGET(child), label);
    
    /* If I use this instead of child, no errors are thrown in the console and the
       label info is transferred to notebook_2
    scroll_win = gtk_scrolled_window_new();   
    gtk_notebook_append_page(notebook_2, scroll_win, label);
    */ 
    gtk_widget_queue_draw(GTK_WIDGET(notebook_1));
    
}


static void
activate (GtkApplication* app,
          gpointer        user_data)
{
    GtkWidget *window;
    GtkWidget *button;
    GtkWidget *table;

    GtkWidget *frame;
    GtkWidget *label;
    GtkWidget *checkbutton;
    int i;
    char bufferf[32];
    char bufferl[32];
    char istr[32];
    
    
    
    window = gtk_application_window_new (app);
    
    
    gtk_window_set_default_size (GTK_WINDOW (window), 400,400);
    table = gtk_grid_new();
    gtk_window_set_child (window, table);
    
    /* Create a new notebook, place the position of the tabs */
    notebook_1 = gtk_notebook_new ();
    gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook_1), GTK_POS_TOP);
    gtk_grid_attach(GTK_GRID (table), notebook_1, 0,0,6,1);
    gtk_widget_show(notebook_1);
    
    /* lets append a bunch of pages to the notebook */
    for (i=0; i < 5; i++) {
        sprintf(bufferf, "Append Frame %d", i+1);
        sprintf(bufferl, "Page %d", i+1);
        
        frame = gtk_frame_new (bufferf);
        gtk_widget_set_margin_start(frame, 10);
        gtk_widget_set_margin_end(frame, 10);
        gtk_widget_set_margin_top(frame, 10);
        gtk_widget_set_margin_bottom(frame, 10);
        gtk_widget_set_size_request (frame, 100, 75);
        gtk_widget_show (frame);
        
        label = gtk_label_new (bufferf);

        label = gtk_label_new (bufferl);
        gtk_notebook_append_page (GTK_NOTEBOOK (notebook_1), frame, label);
    }
    
    
    /* now lets add a page to a specific spot */
    checkbutton = gtk_check_button_new_with_label ("Check me please!");
    gtk_widget_set_size_request(checkbutton, 100, 75);
    gtk_widget_show (checkbutton);
    
    label = gtk_label_new ("Add spot");
    label = gtk_label_new ("Add page");
    gtk_notebook_insert_page (GTK_NOTEBOOK (notebook_1), checkbutton, label, 2);
    
    /* Now finally lets prepend pages to the notebook */
    for (i=0; i < 5; i++) {
        sprintf(bufferf, "Prepend Frame %d", i+1);
        sprintf(bufferl, "PPage %d", i+1);
        
        frame = gtk_frame_new (bufferf);
        gtk_widget_set_margin_start(frame, 10);
        gtk_widget_set_margin_end(frame, 10);
        gtk_widget_set_margin_top(frame, 10);
        gtk_widget_set_margin_bottom(frame, 10);
        gtk_widget_set_size_request (frame, 100, 75);
        gtk_widget_show (frame);
        
        label = gtk_label_new (bufferf);

        
        label = gtk_label_new (bufferl);
        gtk_notebook_prepend_page (GTK_NOTEBOOK(notebook_1), frame, label);
    }
    
    /* Set what page to start at (page 4) */
    gtk_notebook_set_current_page (GTK_NOTEBOOK(notebook_1), 3);
    
    
    button = gtk_button_new_with_label ("move page");
    g_signal_connect (button, "clicked",
                               G_CALLBACK (move_page),
                               NULL);
    gtk_grid_attach(GTK_GRID(table), button, 6,1,1,1);
    gtk_widget_show(button);

    
    notebook_2 = gtk_notebook_new();
    gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook_2), GTK_POS_TOP);
    gtk_grid_attach(GTK_GRID (table), notebook_2, 0,2,6,1);
    gtk_widget_show(notebook_2);
    

    gtk_notebook_set_group_name(notebook_2,"group");


    for (i=0; i < 5; i++) {
      sprintf(istr, "N2 %d", i);
      

        frame = gtk_frame_new (istr);
        gtk_widget_set_margin_start(frame, 10);
        gtk_widget_set_margin_end(frame, 10);
        gtk_widget_set_margin_top(frame, 10);
        gtk_widget_set_margin_bottom(frame, 10);
        gtk_widget_set_size_request (frame, 100, 75);
        gtk_widget_show (frame);
        
        label = gtk_label_new (istr);
        gtk_notebook_prepend_page (GTK_NOTEBOOK(notebook_2), frame, label);
    }

    gtk_notebook_popup_enable(notebook_2);

    gtk_widget_show(table);
    gtk_widget_show(window);


}
int
main (int    argc,
      char **argv)
{
  GtkApplication *app;
  int status;

  app = gtk_application_new ("org.gtk.example", G_APPLICATION_DEFAULT_FLAGS);
  g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
  status = g_application_run (G_APPLICATION (app), argc, argv);
  g_object_unref (app);

  return status;
}
 

Welcome!

The error message:

 "gtk-notebook-append-page: assertion 'GTK-IS-WIDGET (child)' failed" indicates that a GtkWidget cannot be cast into a GtkWidget.

Therefore, please check whether all GtkWidgets have been created as a GtkWidget.

GtkWidget *child = gtk_....._new();

GtkWidget *label = gtk_label_new();  ect

The widgets must be cast accordingly if they are to be used in a function.

Example:

gtk_label_set_label(GTK_LABEL(label),"my Text");

More code would be necessary for a more detailed troubleshooting.

Have fun programming.

1

Before I come to my reply, I would like to point out once again that consistent cast seems to be a problem of the given programme!!
Please check again thoroughly.

The other problem is that the function

gtk-notebook-remove-page (GTK-NOTEBOOK(notebook), page);

Also deletes the connected GtkWidget “child” or decrement the reference pointer by 1.

I solved the sample as follows:

/* move a page from notebook_1 to notebook_2 */
void move_page (GtkButton *button)
{
    gint page;
    GtkWidget *child;
    GtkWidget *label;
    GtkWidget *scroll_win;


    page = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook_1));
    g_print("Current_page ist %in",page);
    child = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook_1), page);

    if (GTK_IS_WIDGET(child))
                g_print("child is GtkWidget %in",page);
        else
                g_print("child is not GtkWidget %in",page);

    g_object_ref(G_OBJECT(child));

    label = gtk_notebook_get_tab_label(GTK_NOTEBOOK(notebook_1), child);
    gtk_notebook_remove_page (GTK_NOTEBOOK(notebook_1), page);

    if (GTK_IS_WIDGET(child))
                g_print("child is GtkWidget %in",page);
        else
                g_print("child is not GtkWidget %in",page);



    gtk_notebook_append_page(GTK_NOTEBOOK (notebook_2), child, label);

    /* If I use this instead of child, no errors are thrown in the console and the
       label info is transferred to notebook_2
    scroll_win = gtk_scrolled_window_new();
    gtk_notebook_append_page(notebook_2, scroll_win, label);
    */
    gtk_widget_queue_draw(GTK_WIDGET(notebook_1));

}

That’s how it worked for me.

You can comment out g_object_ref(G_OBJECT(child)); times, you can do so, you also see how I came to it.

Have fun programming.

1

So I figured out a way to make this work, for the most part. If I connect to the “page_closed” signal and move the page in the callback, it works.

Unfortunately I seem to lose the label information, but no warnings/errors in the console and the page information is moved. Updated solution in C below:

#include <gtk/gtk.h>

GtkWidget *notebook_1;
GtkWidget *notebook_2;



void remove_page (GtkNotebook *nbook, GtkWidget *child, gint page)
{

    GtkWidget *label;
    GtkWidget *scroll_win;
    
    label = gtk_notebook_get_tab_label(nbook, child);

    gtk_notebook_append_page(GTK_NOTEBOOK (notebook_2), GTK_WIDGET(child), GTK_LABEL(label));
    

}    



/* move a page from notebook_1 to notebook_2 */
void move_page (GtkButton *button)
{
    gint page;
    GtkWidget *child;
    GtkWidget *label;
    GtkWidget *scroll_win;
    
    
    page = gtk_notebook_get_current_page(notebook_1);
    child = gtk_notebook_get_nth_page(notebook_1, page);
    label = gtk_notebook_get_tab_label(notebook_1, child);
    gtk_notebook_remove_page (notebook_1, page);
    
    
}


static void
activate (GtkApplication* app,
          gpointer        user_data)
{
    GtkWidget *window;
    GtkWidget *button;
    GtkWidget *table;

    GtkWidget *frame;
    GtkWidget *label;
    GtkWidget *checkbutton;
    int i;
    char bufferf[32];
    char bufferl[32];
    char istr[32];
    
    
    
    window = gtk_application_window_new (app);
    
    
    gtk_window_set_default_size (GTK_WINDOW (window), 400,400);
    table = gtk_grid_new();
    gtk_window_set_child (window, table);
    
    /* Create a new notebook, place the position of the tabs */
    notebook_1 = gtk_notebook_new ();
    gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook_1), GTK_POS_TOP);
    gtk_grid_attach(GTK_GRID (table), notebook_1, 0,0,6,1);
    gtk_widget_show(notebook_1);
    
    /* lets append a bunch of pages to the notebook */
    for (i=0; i < 5; i++) {
        sprintf(bufferf, "Append Frame %d", i+1);
        sprintf(bufferl, "Page %d", i+1);
        
        frame = gtk_frame_new (bufferf);
        gtk_widget_set_margin_start(frame, 10);
        gtk_widget_set_margin_end(frame, 10);
        gtk_widget_set_margin_top(frame, 10);
        gtk_widget_set_margin_bottom(frame, 10);
        gtk_widget_set_size_request (frame, 100, 75);
        gtk_widget_show (frame);
        
        label = gtk_label_new (bufferf);

        label = gtk_label_new (bufferl);
        gtk_notebook_append_page (GTK_NOTEBOOK (notebook_1), frame, label);
    }
    
    
    /* now lets add a page to a specific spot */
    checkbutton = gtk_check_button_new_with_label ("Check me please!");
    gtk_widget_set_size_request(checkbutton, 100, 75);
    gtk_widget_show (checkbutton);
    
    label = gtk_label_new ("Add spot");
    label = gtk_label_new ("Add page");
    gtk_notebook_insert_page (GTK_NOTEBOOK (notebook_1), checkbutton, label, 2);
    
    /* Now finally lets prepend pages to the notebook */
    for (i=0; i < 5; i++) {
        sprintf(bufferf, "Prepend Frame %d", i+1);
        sprintf(bufferl, "PPage %d", i+1);
        
        frame = gtk_frame_new (bufferf);
        gtk_widget_set_margin_start(frame, 10);
        gtk_widget_set_margin_end(frame, 10);
        gtk_widget_set_margin_top(frame, 10);
        gtk_widget_set_margin_bottom(frame, 10);
        gtk_widget_set_size_request (frame, 100, 75);
        gtk_widget_show (frame);
        
        label = gtk_label_new (bufferf);

        
        label = gtk_label_new (bufferl);
        gtk_notebook_prepend_page (GTK_NOTEBOOK(notebook_1), frame, label);
    }
    
    /* Set what page to start at (page 4) */
    gtk_notebook_set_current_page (GTK_NOTEBOOK(notebook_1), 3);
    
    
    button = gtk_button_new_with_label ("move page");
    g_signal_connect (button, "clicked",
                               G_CALLBACK (move_page),
                               NULL);
    gtk_grid_attach(GTK_GRID(table), button, 6,1,1,1);
    gtk_widget_show(button);

    
    notebook_2 = gtk_notebook_new();
    gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook_2), GTK_POS_TOP);
    gtk_grid_attach(GTK_GRID (table), notebook_2, 0,2,6,1);
    gtk_widget_show(notebook_2);
    

    gtk_notebook_set_group_name(notebook_2,"group");


    for (i=0; i < 5; i++) {
      sprintf(istr, "N2 %d", i);
      

        frame = gtk_frame_new (istr);
        gtk_widget_set_margin_start(frame, 10);
        gtk_widget_set_margin_end(frame, 10);
        gtk_widget_set_margin_top(frame, 10);
        gtk_widget_set_margin_bottom(frame, 10);
        gtk_widget_set_size_request (frame, 100, 75);
        gtk_widget_show (frame);
        
        label = gtk_label_new (istr);
        gtk_notebook_prepend_page (GTK_NOTEBOOK(notebook_2), frame, label);
    }

    gtk_notebook_popup_enable(notebook_2);

    g_signal_connect (notebook_1, "page_removed",
                               G_CALLBACK (remove_page),
                               NULL);


    gtk_widget_show(table);
    gtk_widget_show(window);


}
int
main (int    argc,
      char **argv)
{
  GtkApplication *app;
  int status;

  app = gtk_application_new ("org.gtk.example", G_APPLICATION_DEFAULT_FLAGS);
  g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
  status = g_application_run (G_APPLICATION (app), argc, argv);
  g_object_unref (app);

  return status;
}

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật