Как нарисовать новую линию в области Gtk::DrawingArea, сохраняя при этом предыдущие линии, которые уже были нарисованы?
Я использую C++11 с цепочкой инструментов GNU с gtkmm3, на Ubuntu 12.04 LTS 32 bit. Я играл с некоторыми примерами для gtkmm3 в Программирование с помощью gtkmm 3.
На основании 17.2.1. Пример там я унаследовал от Gtk::DrawingArea
(MyDrawingArea
здесь) и преодолеть on_draw()
Обработчик событий выглядит следующим образом:
MyDrawingArea.hpp
...
protected:
bool on_draw ( const Cairo::RefPtr<Cairo::Context>& cr ) override;
MyDrawingArea.cpp
bool MyDrawingArea::on_draw( const Cairo::RefPtr<Cairo::Context>& cr )
{
Gtk::Allocation allocation = get_allocation( );
const int width = allocation.get_width( );
const int height = allocation.get_height( );
int coord1{ height - 3 };
cr->set_line_width( 3.0 );
this->get_window( )->freeze_updates( );
cr->set_source_rgb( 0, 0.40, 0.60 );
cr->move_to( 0, coord1 );
cr->line_to( width, coord1 );
cr->stroke( );
cr->set_source_rgb( 1, 0.05, 1 );
cr->move_to( mXStart, coord1 );
cr->line_to( mXStart, mYAxis * 1.5 );
cr->show_text( to_string( mYAxis ) );
cr->stroke( );
mXStart += 5;
this->get_window( )->thaw_updates( );
return true;
}
Моя цель - нарисовать простую гистограмму, основанную на вычислениях, которые я делаю в небольшом тестовом приложении. Идея заключается в том, чтобы каждый раз on_draw()
событие вызвано, следующий бар будет перемещен на 5 единиц вправо на mXAxis
и вертикальная линия будет проведена на основе нового mYaxis
значение, которое рассчитывается на основе результатов нового расчета.
Когда я хочу перекрасить свой график и вызвать событие MyDrawingArea::on_draw(), я вызываю MyDrawingArea.show_all() из моего приложения после завершения расчета и установки новых осей x и y.
Тем не менее, это не работает, как я ожидал: MyDrawingArea.show_all()
делает недействительным все окно рисования и рисует с нуля: новая линия графика появляется на своем месте, но предыдущие стираются. Я тоже пробовал MyDrawingArea.queue_draw()
, который имел тот же эффект. Но я хочу сохранить результаты предыдущего графика, чтобы получить профиль результатов расчета, так как я вычисляю с разными значениями.
Эта реализация также вызывает нижнюю линию на моем графике (моя ось x на графике)- нарисованная первым stroke()
вызов в моем примере кода, который будет отображаться заново при каждом вызове on_draw() - хотя это не должно быть необходимым, так как эта строка сохраняется в течение всей жизни MyDrawingArea
- не должно быть необходимости делать недействительными, а затем перерисовывать его на каждом новом on_draw()
событие, как мой код в настоящее время делает, потому что я еще не нашел способ справиться с этим.
Я очень новичок в Каире, так что я уверен, что, возможно, я делаю это совершенно неправильно, но явной, ориентированной на задачи документации, похоже, немного - я не нашел ничего, что объясняло бы, как это сделать, хотя я уверен, что это это довольно просто.
Что мне нужно сделать, чтобы нарисовать новую линию на Gtk::DrawingArea
, сохраняя при этом предыдущие линии графика, которые уже были нарисованы на предыдущих проходах, и устанавливая графические элементы, которые будут сохраняться в течение всего срока действия Gtk::DrawingArea
виджет. Очевидно, используя show_all()
или же queue_draw()
и делать все это в on_draw()
Событие не путь.
1 ответ
В общем, вы должны нарисовать весь виджет, и Cairo обрежет рисунок в заранее заданную грязную область. См. Также справочное руководство по GTK для сигнала "GtkWidget::draw" для советов по повышению производительности:
Обработчик сигнала получит cr с областью клипа, уже установленной в грязную область виджета, то есть в область, которая требует перерисовки. Сложные виджеты, которые хотят избежать полного перерисовывания, могут получить полные экстенты области клипа с помощью gdk_cairo_get_clip_rectangle(), или они могут получить более детальное представление грязной области с помощью cairo_copy_clip_rectangle_list().
Таким образом, вы можете перерисовать только ту область, которую хотите, с помощью gtk_widget_queue_draw_area().