73330
Gtkmmでプログラミング用のテキストエディタを作成していたのですが、その際にフォントをmonospaceにしたにもかかわらず、下の画像のように'{',
'}'のような記号の前のスペースが狭くなってしまいます。この画像において、2行目と4行目は4スペース、3行目が8スペースになっています。  
[![画像の説明をここに入力](https://i.stack.imgur.com/6e9Yp.png)](https://i.stack.imgur.com/6e9Yp.png)  
どのようにすれば、このスペースを他の文字と同じ幅にできるでしょうか。よろしくお願いいたします。
CC BY-SA 4.0
2021-01-15T12:55:50.473
73325
2021-01-15T21:13:21.233
2021-01-15T14:10:22.777
32650
32650
question
c++ c gtk
Gtkmm: TextViewのフォントをmonospaceに設定してもスペース幅が一定にならない
ちょっと試してみましたが、自分の結論としては「フォントの問題」かなぁ、と思います。

以下のソースコードを書いてみました。  
C++で書くのはめんどいので、Pythonで許してください(笑)  
まぁでも、GTKを知っていればどの言語でもある程度理解はできると思います。

```

    # coding: utf-8
    
    import gi
    gi.require_version('Gtk', '3.0')
    gi.require_version('PangoCairo', '1.0')
    from gi.repository import Gtk, PangoCairo, Pango
    
    TEXT = '''int main(void) {
        if(true) {
            {}
        }
        }f
    }
    '''
    
    class App(Gtk.Application):
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            #self.font_desc = None
            self.font_desc = Pango.FontDescription.from_string('Monospace 10')
    
        def do_activate(self):
            builder = Gtk.Builder.new_from_string('''
    <interface>
        <object class="GtkWindow" id="window">
            <property name="default-width">400</property>
            <property name="default-height">300</property>
            <child>
                <object class="GtkBox" id="vbox">
                    <property name="visible">true</property>
                    <property name="orientation">vertical</property>
                    <property name="homogeneous">false</property>
                    <child>
                        <object class="GtkButton" id="button">
                            <property name="visible">true</property>
                            <property name="label">Font</property>
                            <signal name="clicked" handler="on_clicked" />
                        </object>
                    </child>
                    <child>
                        <object class="GtkPaned" id="paned">
                            <property name="visible">true</property>
                            <property name="orientation">vertical</property>
                            <child>
                                <object class="GtkDrawingArea" id="drawing_area">
                                    <property name="visible">true</property>
                                    <signal name="draw" handler="on_draw" />
                                </object>
                                <packing>
                                    <property name="shrink">true</property>
                                    <property name="resize">true</property>
                                </packing>
                            </child>
                            <child>
                                <object class="GtkTextView" id="text_view">
                                    <property name="visible">true</property>
                                    <property name="monospace">true</property>
                                </object>
                                <packing>
                                    <property name="shrink">true</property>
                                    <property name="resize">true</property>
                                </packing>
                            </child>
                        </object>
                        <packing>
                            <property name="expand">true</property>
                            <property name="fill">true</property>
                        </packing>
                    </child>
                </object>
            </child>
        </object>
    </interface>
    ''', -1)
            for obj in builder.get_objects():
                if isinstance(obj, Gtk.Buildable):
                    setattr(self, Gtk.Buildable.get_name(obj), obj)
            builder.connect_signals(self)
    
            self.text_view.get_buffer().set_text(TEXT)
            #self.text_view.get_buffer().insert_markup(self.text_view.get_buffer().get_start_iter(), '<span font_desc="Ubuntu Mono 10">' + TEXT + '</span>', -1)
    
            self.window.set_application(self)
            self.window.present()
    
        def on_draw(self, widget, cr):
            cr.save()
    
            layout = widget.create_pango_layout(TEXT)
            if self.font_desc is not None:
                layout.set_font_description(self.font_desc)
            PangoCairo.show_layout(cr, layout)
    
            cr.restore()
    
        def on_clicked(self, button):
            dialog = Gtk.FontChooserDialog(modal=True, transient_for=self.window, destroy_with_parent=True)
            response = dialog.run()
            if response != Gtk.ResponseType.OK:
                dialog.destroy()
                return
            self.font_desc = dialog.get_font_desc()
            print('font = %s.' % repr(self.font_desc.to_string()), flush=True)
            dialog.destroy()
            self.drawing_area.queue_draw()
    
    if __name__ == '__main__':
        App().run()
    
    
```

で、これをubuntu20.10で実行してみた結果です。

[![ubuntu20.10での実行結果](https://i.stack.imgur.com/ciFoe.png)](https://i.stack.imgur.com/ciFoe.png)

なんと、「` }`」の後ろに文字(「`f`」)を追加しただけで、変化します。

試しに、`GtkDrawingArea`でPangoでの描画をしてみましたが、ご覧の通り同様の現象が見受けられるので、`GtkTextView`の問題というよりかは低レイヤーのPangoの問題のようです。

で、`GtkDrawingArea`の方はボタンでフォントを変えられるようにしてあるので、「Ubuntu Mono
10」を選択してみた結果が、以下のとおりです。

[![フォントを変えてみた結果](https://i.stack.imgur.com/WMJt5.png)](https://i.stack.imgur.com/WMJt5.png)

ご覧のとおり、問題なく表示されます。  
ちなみに、ソースコードのコメントのように`GtkTextView`の方でも明示的に「Ubuntu Mono
10」フォントを指定してみても問題なく表示されます。  
また、フォントを「Ubuntu Mono 10」ではなく「VL ゴシック 10」にしても問題ありません。

他の環境で試せればなぁ…、と考え、そういえばWindowsのmsys2でも動かせたなぁと思いついて、ちょっと特殊な環境ですが試してみました。

[![Windowsでの結果](https://i.stack.imgur.com/dtgRl.png)](https://i.stack.imgur.com/dtgRl.png)

こちらはデフォルトのMonospaceフォントでも問題はありません。

とはいえ、フォントは環境によって違ってくるのでプログラム内部で指定するのはアレですし、やれることはせいぜいユーザにフォントを選ばせるようにしておくことぐらいではないでしょうか。  
もし質問者さんの環境もubuntuであれば、ubuntuのコミュニティに問い合わせてみるものいいかもしれません。
CC BY-SA 4.0
2021-01-15T21:13:21.233
73330
2021-01-15T21:13:21.233
15473
73325
answer