iota_11
@iota_11

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Gtk Gladeアプリ Gladeパレットにカスタムコントロールを入れたい

解決したいこと

このパレット部分にカスタムコントールを入れることができるようなのですがやり方知っている方いますか?

Screenshot from 2021-09-09 16-01-36.png

 実現したいこと

class ComboBoxEX : ComboBox
{

}

カスタムコントーロールクラスを合わせて載せたいです。

 悩んでいるところ

Screenshot from 2021-09-09 16-02-00.png

pkg-config --variable=catalogdir
pkg-config --variable=moduledir

catalogdirを入れる必要があるのか?
Gladeの設定でパスを設定するだけでいいのか?

自分で試したこと

0

1Answer

普段はxmlを手で打っているのでgladeを使わないのですが、暇なので試してみました。
とりあえず、まずはCで。

カスタムウィジェットのソース

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

#define	HOGE_TYPE_DRAWABLE	hoge_drawable_get_type()
G_DECLARE_FINAL_TYPE(HogeDrawable, hoge_drawable, HOGE, DRAWABLE, GtkDrawingArea)

HogeDrawable * hoge_drawable_new();

/* ---------------------------------------------------------------------- */

struct _HogeDrawable {
	GtkDrawingArea parent;
};
struct _HogeDrawableClass {
	GtkDrawingArea parent_class;
};

HogeDrawable * hoge_drawable_new()
{
	return HOGE_DRAWABLE(g_object_new(HOGE_TYPE_DRAWABLE, NULL));
}

static void hoge_drawable_init(HogeDrawable *self)
{
	g_print("%s(%d): trace.\n", __FILE__, __LINE__);
}

static gboolean hoge_drawable_draw(GtkWidget *widget, cairo_t *cr)
{
	int width, height;

	width = gtk_widget_get_allocated_width(widget);
	height = gtk_widget_get_allocated_height(widget);

	cairo_set_source_rgb(cr, 0, 1, 0);
	cairo_rectangle(cr, 0, 0, width, height);
	cairo_fill(cr);

	return FALSE;
}

static void hoge_drawable_class_init(HogeDrawableClass *klass)
{
	GtkWidgetClass *widget_klass = GTK_WIDGET_CLASS(klass);

	g_print("%s(%d): trace.\n", __FILE__, __LINE__);
	widget_klass->draw = hoge_drawable_draw;
}

G_DEFINE_TYPE(HogeDrawable, hoge_drawable, GTK_TYPE_DRAWING_AREA)

/* ---------------------------------------------------------------------- */

void hoge_glade_init()
{
	g_print("%s(%d): trace.\n", __FILE__, __LINE__);
	hoge_drawable_get_type();
}

/* ---------------------------------------------------------------------- */

#if 0
/* 一応、ソースコード単体で動くかどうかテストしておく。 */

int main(int argc, char *argv[])
{
	GtkWidget *window;
	GtkWidget *drawable;

	gtk_init(&argc, &argv);

	window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

	drawable = hoge_drawable_new();
	gtk_container_add(GTK_CONTAINER(window), drawable);
	gtk_widget_show(drawable);

	g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);

	gtk_widget_show(window);

	gtk_main();
	return 0;
}
#endif

モジュール

基本的に、カスタムウィジェットのコードは ダイナミックリンクライブラリ(soファイル)にしてgladeから読み込めるようにしなければなりません。(gladeでは、これを「モジュール」と呼んでいるよう)

また、gladeの初期化時に、カスタムウィジェットのタイプの登録をするために、g_type_register_staticなどの関数を呼ぶ必要があります。
C言語の場合、上記のソースコードのようにGTK+のマクロを使っていれば、<なんちゃら>_get_typeを呼べばOKです。

というわけで、上記のソースコードを元に、ダイナミックリンクライブラリを作ります。

gcc -shared -fPIC -o libhoge.so hoge_drawable.c `pkg-config --cflags gtk+-3.0`

作ったライブラリは、

  • pkg-config --variable=moduledir gladeui-2.0を実行して出力されるディレクトリ
  • GLADE_MODULE_SEARCH_PATH環境変数で設定されたディレクトリ
  • (おそらく)システムで普通に読めるディレクトリ(/usr/libとか)

のいずれかに置きます。

カタログ

カタログファイルは、以下のとおりです。

<?xml version="1.0" encoding="utf-8"?>
<glade-catalog name="hoge_drawable"
	library="libhoge.so"
	depends="gtk+"
	>

	<init-function>hoge_glade_init</init-function>

	<glade-widget-classes>
		<glade-widget-class
				name="HogeDrawable"
				generic-name="drawable1"
				title="Hoge Drawable"
				/>
	</glade-widget-classes>

	<glade-widget-group name="hoge"
		title="Hoge"
		>
		<glade-widget-class-ref name="HogeDrawable" />
	</glade-widget-group>
</glade-catalog>

init-function」に、先ほど説明したモジュール内の初期化関数を指定します。
library」に、先ほど作成したダイナミックリンクライブラリの名前を指定します。(これも、ぐぐると色々とあるようだけど、とりあえずフルのファイル名を指定しました。)

このカタログファイルを、

  • pkg-config --variable=catalogdir gladeui-2.0を実行して出力されるディレクトリ
  • GLADE_CATALOG_SEARCH_PATH環境変数で設定されたディレクトリ
  • gladeの設定で指定したディレクトリ

のいずれかに置きます。

これで、gladeでカスタムウィジェットが選べるようになりました。

C++の場合

(おそらく、gtkmmのことだと思うけど)自分はgtkmmは使ったことがないのでコメントできませんが、少なくともその下で動いているのはCのGTK+なので、gtkmmがどのようにg_type_register_staticなどの関数を呼び出しているか調べてみると道が見えるかもしれません。

あと、既に見つけているかもしれませんが、以下のStackoverflowの質問もありました。
https://stackoverflow.com/questions/10826435/how-do-i-add-a-custom-gtkmm-widget-to-glade

お呼びじゃないけど、Pythonの場合

まぁ、自分が主に使うのはPythonなのでw

参考にされているサイトの内容が古いので当てにならないかな、と思いましたが、そのままやってみたらあっさりと動きました。

カスタムウィジェットのソースコード。

# coding: utf-8
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GObject

class PiyoDrawable(Gtk.DrawingArea):
	__gtype_name__ = 'PiyoDrawable'

	def __init__(self, **kwargs):
		super().__init__(**kwargs)

	def do_draw(self, cr):
		width = self.get_allocated_width()
		height = self.get_allocated_height()

		cr.set_source_rgb(0, 0, 1)
		cr.rectangle(0, 0, width, height)
		cr.fill()

を、モジュールパスに置き、PYTYHONPATH環境変数もその場所を指定しておく。
で、カタログファイルを

<?xml version="1.0" encoding="utf-8"?>
<glade-catalog
	name="piyo"
	library="gladepython"
	depends="gtk+"
	>
	<init-function>glade_python_init</init-function>
	<glade-widget-classes
		>
		<glade-widget-class
			title="Piyo Drawable"
			name="PiyoDrawable"
			generic-name="piyo_drawable"
			/>
	</glade-widget-classes>
	<glade-widget-group
		name="python"
		title="Python"
		>
		<glade-widget-class-ref name="PiyoDrawable" />
	</glade-widget-group>
</glade-catalog>

というように書いてカタログパスに置けばOKでした。

0Like

Comments

  1. @iota_11

    Questioner

    質問に答えていただきありがとうございます。しかも具体的な内容でとても助かります。ありがとうございます。この内容を参考にしながらC#で実現してみようと思っています。
    実現したらQiitaに投稿します。
    よろしくお願いします。

Your answer might help someone💌