Как вручную перемещать страницы между блокнотами в gtk4

Я работаю над приложением, которое использует привязки gtk для элементов пользовательского интерфейса, и не могу понять, как сделать что-то, что кажется простым. Я хочу иметь возможность перемещать информацию, содержащуюся на странице блокнота, в другой блокнот (например, переместить страницу 1 из блокнота_1 в блокнот_2).

Я попытался сделать это с помощью следующего фрагмента кода:

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)

Когда я пытаюсь запустить это, я получаю ошибку в консоли:

(:87313): Gtk-CRITICAL **: 19:58:29.515: gtk_notebook_append_page: утверждение «GTK_IS_WIDGET (дочерний)» не выполнено

И nb равно -1, что означает, что операция не удалась.

Я подумал, что, возможно, страница удаления уничтожает дочерний объект, поэтому пропустил эту строку. Но затем я получаю следующую ошибку в консоли

(:87293): Gtk-WARNING **: 19:56:50.684: Повторяющееся дочернее имя в GtkStack: (ноль)

(:87293): Gtk-CRITICAL **: 19:56:50.684: gtk_widget_set_parent: assertion '_gtk_widget_get_parent (widget) == NULL' не удалось

Когда я запускаю этот параметр, значение nb не равно -1, но информация в дочернем блоке не отображается в блокноте_2.

Я чувствую, что мне здесь не хватает чего-то основного, но я не знаю, чего именно. Я попробовал еще несколько вещей, таких как прикрепление дочернего элемента к прокручиваемому окну, а также воспроизвел ошибку, используя код C (вместо привязок). Если у кого-нибудь есть какие-либо советы о том, как это сделать или указания по дальнейшему устранению неполадок, я буду признателен.

Обновление - вот полное приложение C, которое вызывает у меня проблему, которое я собрал из старого gtk2? Пример блокнота, который я нашел в сети. Когда я запускаю его и нажимаю кнопку перемещения страницы, он не работает. Я действительно не знаю c, так что извините, если это беспорядок, но это воспроизводит проблему FWIW.

Кажется, то, что я хочу сделать, невозможно: когда я удаляю старую страницу, она, вероятно, стирает ссылку на дочернюю страницу, но когда я не удаляю старую страницу, она жалуется, что дочерняя страница существует где-то еще.

#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;
}
 
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
68
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Добро пожаловать!

Сообщение об ошибке:

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

Поэтому проверьте, все ли GtkWidget созданы как GtkWidget.

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

GtkWidget *label = gtk_label_new();  ect

Виджеты должны быть преобразованы соответствующим образом, если они будут использоваться в функции.

Пример:

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

Для более детального устранения неполадок потребуется больше кода.

Получайте удовольствие от программирования.

Спасибо за прием и предложение! Я использовал привязки Фортрана в своем приложении GTK, поэтому я не привык к кастингу. К лучшему или худшему, но в Фортране все однотипно (c_ptr), поэтому облажаться сложно. В любом случае, я обновил свой пост полным примером на языке C — перед публикацией я взломал его, чтобы убедиться, что это не проблема с привязкой. Попробовал кастовать как вы советовали, но проблему это не решило. Я дважды подтвердил это, добавив в блокнот_2 пустое окно. Думаю, если бы у меня была проблема с кастингом, это тоже пошло бы не так, но это не так.

jeremy123456 03.09.2024 22:09

Итак, я нашел способ заставить эту работу работать по большей части. Если я подключусь к сигналу «page_closed» и перемещу страницу в обратном вызове, это сработает.

К сожалению, я теряю информацию о метке, но в консоли нет предупреждений/ошибок, а информация о странице не перемещается. Обновленное решение в C ниже:

#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;
}
Ответ принят как подходящий

Прежде чем перейти к ответу, я хотел бы еще раз отметить, что постоянство актерского состава, похоже, является проблемой данной программы!! Пожалуйста, проверьте еще раз тщательно.

Другая проблема заключается в том, что функция

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

Также удаляет подключенный «дочерний» GtkWidget или уменьшает указатель ссылки на 1.

Я решил образец следующим образом:

/* 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 %i\n",page);
    child = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook_1), page);

    if (GTK_IS_WIDGET(child))
                g_print("child is GtkWidget %i\n",page);
        else
                g_print("child is not GtkWidget %i\n",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 %i\n",page);
        else
                g_print("child is not GtkWidget %i\n",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));

}

Вот как это сработало для меня.

Комментировать можно g_object_ref(G_OBJECT(child)); раз, можно, вы тоже видите, как я к этому пришел.

Получайте удовольствие от программирования.

Еще раз спасибо за ответ! Я подтвердил, что эта строка кода устраняет мою первоначальную проблему, и я вижу, что «основной» вещью, которой мне не хватало, была концепция g_object_ref/unref. Я не встречал этого в примерах, которые использовал в качестве основы для своего кода, но, просматривая исходный код gtk, он есть повсюду.

jeremy123456 04.09.2024 22:05

Приятно, что я смог решить вашу проблему, но почему бы вам не подтвердить это кнопкой?

Holger 05.09.2024 09:07

Другие вопросы по теме