gtkmm : 用 cairo 绘制文本

Posted

技术标签:

【中文标题】gtkmm : 用 cairo 绘制文本【英文标题】:gtkmm : Drawing text with cairo 【发布时间】:2021-08-15 12:54:31 【问题描述】:

我想在一个使用 Gtkmm 的应用程序中用 Cairo 绘制一个简单的文本。我想在单击Gtk::FontButton 时(换句话说,当signal_font_set 信号发出时)直接给出字体样式(可以是Pango::FontDescriptionPango::Context 等等...)以使用Cairo 绘制文本)。在下面的示例中,我有一个Gtk::HeaderBar,其中包含一个Gtk::FontButton,它在单击时将Glib::RefPtr<<Pango::Context>> 发送到绘图类。我想要这样的东西:

MyWindow.cpp:

#include <iostream>
#include "MyWindow.h"

MyWindow::MyWindow() 
    
    set_default_size(1000, 1000);
    set_position(Gtk::WIN_POS_CENTER);

    header.set_show_close_button(true);
    header.pack_start(fontButton);;

    set_titlebar(header);

    fontButton.signal_font_set().connect([&] 
        drawingArea.select_font(fontButton.get_pango_context());
    );

    scrolledWindow.add(drawingArea);
    add(scrolledWindow);
    show_all();

MyDrawing.h:

#ifndef DRAWING_H
#define DRAWING_H

#include <gtkmm.h>
#include <cairo/cairo.h>

class MyDrawing : public Gtk::Layout


public:

     MyDrawing();
    ~MyDrawing() override;

    void select_font(Glib::RefPtr<Pango::Context> p_pangoContext);

private:
    bool draw_text(const Cairo::RefPtr<::Cairo::Context>& p_context);

    Glib::RefPtr<Pango::Context> m_pangoContext;
;

#endif // DRAWING_H

MyDrawing.cpp:

#include <iostream>
#include <utility>
#include "MyDrawing.h"
#include <cairomm/context.h>
#include <cairomm/surface.h>


MyDrawing::MyDrawing() 

    this->signal_draw().connect(sigc::mem_fun(*this, &MyDrawing::draw_text));


MyDrawing::~MyDrawing() = default;

bool MyDrawing::draw_text(const Cairo::RefPtr<::Cairo::Context> &p_context) 

    auto layout = create_pango_layout("hello ");
    if(m_pangoContext) 
        layout->set_font_description(m_pangoContext->get_font_description());
    
    else 
        Pango::FontDescription fontDescription;
        layout->set_font_description(fontDescription);
    
    p_context->save();
    p_context->set_font_size(30);
    p_context->set_source_rgb(0.1, 0.1, 0.1);
    p_context->move_to(40, 40);
    layout->show_in_cairo_context(p_context);
    p_context->restore();
    return true;


void MyDrawing::select_font(Glib::RefPtr<Pango::Context> p_pangoContext) 
    this->m_pangoContext = std::move(p_pangoContext);
    queue_draw();

当我手动设置Pango::FontDescription 时:

Pango::FontDescription fontDescription;
fontDescription.set_weight(Pango::WEIGHT_BOLD);
fontDescription.set_style(Pango::STYLE_ITALIC);
layout->set_font_description(fontDescription);

有效:

【问题讨论】:

如果我正确理解您的问题,您是否希望在MyDrawing::draw_text 中设置字体描述?我认为这不是工作代码? 我编辑了帖子。 更清楚了,谢谢!另外,如果有更多代码(请尝试使其下次可重现),我可以在这里重现该问题。 【参考方案1】:

这是一种可行的方法:您可以从Gtk::FontButton::get_font_name 获取字体名称,而不是使用Pango::Context,然后从中创建Pango::FontDescription。这是一个显示这一点的最小示例:

#include <iostream>
#include <gtkmm.h>

class MyDrawing : public Gtk::Layout


public:

    MyDrawing();

    void set_font(const std::string& p_selectedFont);

private:

    bool draw_text(const Cairo::RefPtr<::Cairo::Context>& p_context);

    std::string                 m_selectedFont;
    Glib::RefPtr<Pango::Layout> m_pangoLayout;
    
;

MyDrawing::MyDrawing()

    signal_draw().connect(sigc::mem_fun(*this, &MyDrawing::draw_text));

    m_pangoLayout = Pango::Layout::create(get_pango_context());
    m_pangoLayout->set_text(
        "This text's appearance should change\n"
        "when font description changes."
    );


void MyDrawing::set_font(const std::string& p_selectedFont)

    // Record the font selected by the user (as a string... Ugh!):
    m_selectedFont = p_selectedFont;
    std::cout << "Selected font: " << m_selectedFont << std::endl;

    // Request a redraw:
    queue_draw();


bool MyDrawing::draw_text(const Cairo::RefPtr<::Cairo::Context>& p_context)

    // Create a font description from what was selected by the user earlier,
    // and set it:
    const Pango::FontDescription descriptionm_selectedFont;
    m_pangoLayout->set_font_description(description);

    p_context->save();
    p_context->set_font_size(30);
    p_context->set_source_rgb(0.1, 0.1, 0.1);
    p_context->move_to(40, 40);
    m_pangoLayout->show_in_cairo_context(p_context);
    p_context->restore();

    return true;


class MyWindow : public Gtk::ApplicationWindow


public:

    MyWindow();

private:

    Gtk::HeaderBar  m_headerBar;
    Gtk::FontButton m_fontButton;
    MyDrawing       m_drawingArea;

;

MyWindow::MyWindow()

    m_headerBar.set_show_close_button(true);
    m_headerBar.pack_start(m_fontButton);;

    set_titlebar(m_headerBar);

    m_fontButton.signal_font_set().connect(
        [this]()
        
            m_drawingArea.set_font(m_fontButton.get_font_name());
        
    );

    add(m_drawingArea);
    show_all();


int main(int argc, char *argv[])

    auto app = Gtk::Application::create(argc, argv, "org.gtkmm.examples.base");
  
    MyWindow window;
    window.show_all();
  
    return app->run(window);

我不是 Pango 专家,所以我不知道是否有更好的方法使用您的初始策略。此外,表示字体名称的字符串似乎需要遵循一些约定。来自Pango::FontDescription::FontDescription(const Glib::ustring&amp; font_name) (Gtkmm 3.24) 的文档:

font_name 的格式必须为“[FAMILY-LIST] [STYLE-OPTIONS] [SIZE]”, 其中 FAMILY-LIST 是一个以逗号分隔的家庭列表(可选) 以逗号结尾,STYLE_OPTIONS 是一个空格分隔的列表 每个 WORD 描述风格、变体、重量或 拉伸,而 SIZE 是一个十进制数(大小以磅为单位)。任何一个 选项可能不存在。如果 FAMILY-LIST 不存在,则 生成的字体描述的 family_name 字段将是 初始化为 0。如果缺少 STYLE-OPTIONS,则所有样式选项 将设置为默认值。如果缺少 SIZE,则 生成的字体描述将设置为 0。

因此您可能需要自己进行一些测试,以确保这适用于所有字体。就我而言,我测试过的所有 10-15 种字体似乎都可以正常工作。

【讨论】:

以上是关于gtkmm : 用 cairo 绘制文本的主要内容,如果未能解决你的问题,请参考以下文章

如何在 gtkmm DrawingArea 中绘制 poppler 文档

如何摆脱 Gtkmm 中的模糊像素?

如何在 Haskell 中使用 Cairo 绘制 X11 Drawable

使用 cairo 检查路径是不是简单且封闭

使用 Gdk Cairo 上下文绘制椭圆

使用 Cairo 绘制杂乱纹理