动画 gif 图像在我的无模式 Gtk::D ialog 中没有动画



我的目标是展示一个简短的"请稍候"对话框中的动画gif(微调器)。

我的问题是,当我不使用Gtk:Dialog::run()时,gif将不会被动画化,而当我使用Gtk:Dialog::run()方法时,它会完全阻止我随后运行的代码。由于我的对话框中没有任何按钮,它会无限期地挂在那里。有办法绕过吗?我没有成功地让动画gif在非模态对话框中工作,即不使用run()方法。

我正在使用gtkmm 3.0

使用g++ examplewindow.cc main.cc -o main `pkg-config gtkmm-3.0 --cflags --libs`编译

main.cc

#include "examplewindow.h"
#include <gtkmm/application.h>
#include <iostream>
int main(int argc, char *argv[])
{
auto app = Gtk::Application::create("org.gtkmm.example");
ExampleWindow window;    
//Shows the window and returns when it is closed.
//return app->make_window_and_run<ExampleWindow>(argc, argv);
return app->run(window);
}

示例windows.h

#ifndef GTKMM_EXAMPLEWINDOW_H
#define GTKMM_EXAMPLEWINDOW_H
#include <gtkmm.h>
class ExampleWindow : public Gtk::Window
{
public:
ExampleWindow();
virtual ~ExampleWindow();
protected:
//Signal handlers:
void on_button_clicked();
//Child widgets:
Gtk::Box m_VBox;
Gtk::Box m_ButtonBox;
Gtk::Button m_Button;
};
#endif //GTKMM_EXAMPLEWINDOW_H

示例窗口.cc

#include "examplewindow.h"
#include <iostream>
ExampleWindow::ExampleWindow()
: m_VBox(Gtk::Orientation::ORIENTATION_VERTICAL),
m_ButtonBox(Gtk::Orientation::ORIENTATION_VERTICAL),
m_Button("Show Dialog")
{
set_title("Test animated gif");
set_default_size(800, 600);
add(m_VBox);
m_VBox.pack_start(m_ButtonBox);
m_ButtonBox.pack_start(m_Button);
m_Button.set_hexpand(true);
m_Button.set_halign(Gtk::Align::ALIGN_CENTER);
m_Button.set_valign(Gtk::Align::ALIGN_CENTER);
m_Button.grab_focus();
m_Button.signal_clicked().connect(sigc::mem_fun(*this, &ExampleWindow::on_button_clicked));
show_all_children();
}
ExampleWindow::~ExampleWindow()
{
}
void ExampleWindow::on_button_clicked()
{
Gtk::Dialog m_Dialog;
m_Dialog.set_transient_for(*this);
m_Dialog.set_size_request(200, 200);
m_Dialog.set_decorated(false);
Gtk::Image imageLoading = Gtk::Image();
imageLoading.property_pixbuf_animation() = Gdk::PixbufAnimation::create_from_file("gtkmm_logo.gif");
m_Dialog.get_vbox()->pack_start(imageLoading);
m_Dialog.show_all();
m_Dialog.run();
/******** This, below, never gets executed as run() is blocking the program...********/

// Dummy "long" operation
for (int i = 0; i <= 2010101010; i++)
{
if (i == 2010101010)
std::cout << "Done" << std::endl;
}
m_Dialog.response(Gtk::RESPONSE_ACCEPT);
m_Dialog.hide();
}

让我们看看最初的问题。您在上面创建了一个名为show()的对话框,执行了一些长时间运行的过程,然后关闭了该对话框。该过程有效,但您的程序在处理过程中冻结。为什么?

图形界面通过处理消息(事件)来工作。有些事件是通过计时器运行的,例如告诉动画转到下一帧的事件。有些是根据需要生成的,例如告诉图像绘制当前帧的那些。这些事件需要被触发和处理才能生效。您通过调用show_all()触发了相应的事件,但没有给程序处理这些事件的机会。

您使用了单击按钮来启动长时间运行的进程。该单击是由主事件处理循环处理的事件。然后,该循环等待单击得到完全处理,然后再转到下一个事件。但是,处理程序中有一个长时间运行的进程。主事件循环必须等待该过程完成,然后才能处理新的事件,例如显示和动画化图像的事件。在你销毁对话框之前,你从未给过它一个完成任务的机会。

调用对话框的run()方法通过为对话框启动新的事件循环部分修复了这种情况。因此,即使主事件循环仍然被单击处理程序阻止,也可以处理新的事件。对话框的事件循环接收到显示动画所需的事件,因此程序再次响应。不幸的是,run()阻止了您的长期运行过程,所以我们的情况并没有好转


最简单的修复方法是不再完全阻止主事件循环。您可以让长时间运行的进程定期允许通过Gtk::Main::iteration()处理事件。此函数调用主事件循环的迭代,使程序能够保持响应。给它传递一个false参数,以便它只在有事件要处理的情况下处理事件(而不是等待事件发生)。

for (unsigned long i = 0; i <= 2010101010; i++)
{
if (i == 2010101010)
std::cout << "Done" << std::endl;
// Periodically process events
if ( i % 10000 == 0 )                    // <---- after some suitable amount of work
if ( !Gtk::Main::iteration(false) )  // <---- allow events to be processed
// Abort the work.
break;
}

返回值应该告诉你是否应该退出,但我在测试中没有做到这一点(与文档相比,返回值似乎有相反的含义)。也许对话本身让应用程序保持了活力?呃,这可能是下一个问题,一旦这个部分开始工作。


其他方法会将长时间运行的进程从点击处理程序中移出。如果您让点击处理程序快速结束,那么主事件循环就可以在没有额外提示的情况下完成它的工作。然而,这需要进行一些调整,以便Gtk::Dialog比对on_button_clicked()的调用更持久。这有点重构,但可能值得花时间。我将提供两个选项(无代码)。

  1. 您可以让您的工作在多个超时信号上进行操作。将长时间运行的进程分成更小的块,每个块的大小适合回调。(这有多大?不确定。现在,让我们说最多几毫秒。)让按钮点击事件启动第一个超时信号,其优先级允许GUI更新。(我记得,PRIORITY_DEFAULT_IDLE应该有效。)对于间隔,如果不过度混淆Gtk+,我会尝试0。(我没有尝试过,但这似乎是合理的。)如果0间隔有效,那么明智的做法可能是使用connect_once()而不是connect(),并让每个块在下一个块中安排另一个超时。最后一块将负责关闭对话框。

  2. 您可以将长时间运行的进程移到另一个线程。多线程编程有自己的一系列问题,有时还需要大量的设置,但这是它非常适合的。如果长时间运行的进程位于与主事件循环不同的线程中,则操作系统将负责确保每个线程都有一定的CPU时间。长时间运行的进程可能会缓慢运行,主事件循环将能够同时处理事件,而无需您进行特殊干预。


最后一句话:
如果你的对话是为了与用户进行单向交流,那么它看起来更像是独白而不是对话。对不起,更像是一扇普通的窗户,而不是一个对话框。此外,我将确保您了解Gtk::ProgressBar;通常用于显示长时间运行的操作的进度"只是一种选择;偏爱自己的形象是可以理解的。

相关内容

  • 没有找到相关文章

最新更新