Por Jean Hertel, 16/08/2020, na categoria Dicas
Na última atualização do adriconf eu decidi que queria mudar o jeito que os usuários utilizam a aplicação e para isso decidi implementar várias mudanças.
Uma destas mudanças foi remover completamente todas as caixas de diálogos e substitui-las por algo mais simples. Eu gosto muito das transições de tela do Android pois elas são suaves e não dão a impressão de que algo ainda esteja executando em outra tela como costuma ocorrer com diálogos modais. Mas como implementar uma transição de telas usando apenas GTKmm?
O GTK+ (e o GTKmm por extensão) possuem um excelente componente chamado Stack. Com este componente podemos criar várias telas mostrando sempre uma por vez. Na documentação oficial os exemplos sempre utilizam um GTKStackSwitcher para dar as usuários a opção de mudar facilmente entre as telas mas em nosso caso fica mais fácil chamarmos a API set_visible_child.
Vamos ver um exemplo em ação:
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk+" version="3.22"/>
<object class="GtkWindow" id="mainWindow">
<property name="width_request">200</property>
<property name="height_request">200</property>
<property name="can_focus">False</property>
<child>
<object class="GtkStack" id="ourStack">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="transition_type">slide-right</property>
<child>
<object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkButton" id="button1">
<property name="label" translatable="yes">To Screen 2</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="name">screen1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkButton" id="button2">
<property name="label" translatable="yes">Back to screen 1</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="name">screen2</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<child type="titlebar">
<placeholder/>
</child>
</object>
</interface>
Com estes componentes podemos agora criar algum código:
#include "gtkmm.h"
int main(int argc, char *argv[]) {
auto app = Gtk::Application::create(argc, argv, "nice.test");
// Load our glade file
auto gladeBuilder = Gtk::Builder::create();
gladeBuilder->add_from_resource("/test/test.glade");
Gtk::Window *mainWindow;
Gtk::Stack *stack;
Gtk::Button *button1, *button2;
// Get our widgets
gladeBuilder->get_widget("mainWindow", mainWindow);
gladeBuilder->get_widget("ourStack", stack);
gladeBuilder->get_widget("button1", button1);
gladeBuilder->get_widget("button2", button2);
// Setups what happens with our application
button1->signal_clicked().connect([stack]() {
stack->set_visible_child("screen2");
});
button2->signal_clicked().connect([stack]() {
stack->set_visible_child("screen1");
});
return app->run(*mainWindow);
}
Com este código teremos uma tela similar a esta abaixo:
Você deve ter notado que o efeito de transição está sempre indo para a direita.
Podemos controlar isso com a propriedade transition_type
do Gtk::Stack.
Um outro ponto que devemos observar é em relação ao id que utilizamos na
mudança de telas. Se você olhar o código poderá observar que os Gtk::Box
possuem id de box1
e box2
porem quando vamos invocar o método
set_visible_child
utilizamos os nomes screen1
e screen2
.
O motivo disso é que o objeto Gtk::Stack pode apenas ter filhos
de um determinado tipo e portanto sempre vai encapsular objetos do tipo errado.
Resolvemos isso definindo a propriedade name
nas propriedades de packing
do objeto.