Используя GTKMM, я расширяю виджет DrawingArea , полагая, что внешний процесс предоставляет ему изображения. Мой CameraDrawingArea отобразит изображения в нужном размере, используя Cairo .
Каждый раз, когда изображение поступает, я сохраняю его и вызываю метод invalidate
, который в конечном итоге заканчивается вызовом on_draw
, где я могу изменить размер и отобразить изображение.
Моя проблема заключается в следующем:
- Первые 10 или 20 изображений отображаются так, как я ожидал.
- Через некоторое время изображения продолжают поступать из процесса провайдера, я продолжаю звонить
invalidate
- но
on_draw
больше не вызывается.
Чтобы показать это здесь, я упростил код, чтобы не было ничего внешнего для класса и никакой связи с другими библиотеками. Я заменил процесс предоставления изображений методом for-loop и отображением изображения, напечатав простой текст в середине области виджета:
- В конструкторе я запускаю новый
std::thread
для вызова метода doCapture
в том же экземпляре. Я также настроил описание шрифта, чтобы использовать его позже.
- Метод
doCapture
является глупым пожирателем ЦП, который ничего не делает, кроме время от времени вызова метода refreshDrawing
, если keepCapturing
не равен false
.
refreshDrawing
делает недействительным прямоугольник всего окна посредством вызова invalidate
.
- Магия Gtk предполагает вызов
on_draw
и предоставление Каирского контекста для рисования чего угодно. В моем случае для целей тестирования я рисую коричневое центрированное целое число.
- Деструктор класса останавливает поток, устанавливая для
keepCapturing
значение false, и ожидает завершения с join
.
#include "camera-drawing-area.hpp"
#include <iostream>
CameraDrawingArea::CameraDrawingArea():
captureThread(nullptr) {
fontDescription.set_family("Monospace");
fontDescription.set_weight(Pango::WEIGHT_BOLD);
fontDescription.set_size(30 * Pango::SCALE);
keepCapturing = true;
captureThread = new std::thread([this] {
doCapture();
});
}
void CameraDrawingArea::doCapture() {
while (keepCapturing) {
float f = 0.0;
for (int n = 0; n < 1000; n++) {
for (int m = 0; m < 1000; m++) {
for (int o = 0; o < 500; o++) {
f += 1.2;
}
}
}
std::cout << "doCapture - " << f << std::endl;
refreshDrawing();
}
}
void CameraDrawingArea::refreshDrawing() {
auto win = get_window();
if (win) {
win->invalidate(false);
std::cout << "refreshDrawing" << std::endl;
}
}
bool CameraDrawingArea::on_draw(const Cairo::RefPtr<Cairo::Context>& cr) {
std::cout << "on_draw" << std::endl;
static char buffer[50];
static int n = 0;
sprintf(buffer, "-%d-", n++);
Gtk::Allocation allocation = get_allocation();
const int width = allocation.get_width();
const int height = allocation.get_height();
auto layout = create_pango_layout(buffer);
layout->set_font_description(fontDescription);
int textWidth, textHeight;
layout->get_pixel_size(textWidth, textHeight);
cr->set_source_rgb(0.5, 0.2, 0.1);
cr->move_to((width - textWidth) / 2, (height - textHeight) / 2);
layout->show_in_cairo_context(cr);
cr->stroke();
return true;
}
CameraDrawingArea::~CameraDrawingArea() {
keepCapturing = false;
captureThread->join();
free(captureThread);
}
И это мой заголовочный файл:
#ifndef CAMERA_DRAWING_AREA_HPP
#define CAMERA_DRAWING_AREA_HPP
#include <gtkmm.h>
#include <thread>
class CameraDrawingArea : public Gtk::DrawingArea {
public:
CameraDrawingArea();
virtual ~CameraDrawingArea();
protected:
bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr) override;
private:
bool keepCapturing;
void doCapture();
void refreshDrawing();
std::thread* captureThread;
Pango::FontDescription fontDescription;
};
#endif
Проблема проявляется следующим образом:
- При запуске приложения оно точно отображает 1, 2, 3 ...
- Между 5-й и 20-й итерацией (она случайная, но редко выходит за эти диапазоны), она прекращает обновление.
- Из-за
cout
я вижу, что refreshDrawing
вызывается, убедитесь, что invalidate
также вызывается, но on_draw
нет.
Кроме того, если я остановлю приложение до того, как оно перестанет обновляться, то оно закончится красиво. Но если я остановлю приложение после того, как оно перестанет обновляться, я увижу это сообщение ниже (значение идентификатора меняется):
GLib-CRITICAL **: 10:05:04.716: Source ID 25 was not found when attempting to remove it
Я совершенно уверен, что я делаю что-то не так, но не знаю, что. Любая помощь будет оценена.
Я также проверил следующие вопросы, но они, похоже, не связаны с моим делом: