スケールはスライダーと言ったほうが分かりやすいかもしれません。よくスライダーと呼ばれるものを、GTK ではスケールと呼びます。
次のファイルを scale.c というファイル名で任意の場所に保存してください。
/*************************************
scale.c
copyright : vivacocoa.jp
last modified: Mar. 19, 2025
************************************/
#include <gtk/gtk.h>
guchar r, g, b;
static void
color (GtkWidget *widget, gpointer data)
{
if (g_strcmp0 (gtk_widget_get_name (widget), "red") == 0)
{
r = gtk_range_get_value (GTK_RANGE (widget));
gtk_widget_queue_draw (data);
}
if (g_strcmp0 (gtk_widget_get_name (widget), "green") == 0)
{
g = gtk_range_get_value (GTK_RANGE (widget));
gtk_widget_queue_draw (data);
}
if (g_strcmp0 (gtk_widget_get_name (widget), "blue") == 0)
{
b = gtk_range_get_value (GTK_RANGE (widget));
gtk_widget_queue_draw (data);
}
}
static void
draw (GtkDrawingArea *area, cairo_t *cr, int width, int height, gpointer data)
{
GdkRGBA color;
gchar *rgb;
rgb = g_strdup_printf ("rgb (%d,%d,%d)", r, g, b);
gdk_rgba_parse (&color, rgb);
g_free (rgb);
gdk_cairo_set_source_rgba (cr, &color);
cairo_paint (cr);
}
static void
activate (GApplication *app, gpointer data)
{
GtkWidget * win = gtk_application_window_new (GTK_APPLICATION (app));
GtkWidget * vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
GtkWidget * area = gtk_drawing_area_new ();
GtkWidget * grid = gtk_grid_new ();
GtkWidget * lred = gtk_label_new ("Red");
GtkWidget * lgreen = gtk_label_new ("Green");
GtkWidget * lblue = gtk_label_new ("Blue");
GtkWidget * red = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0, 255, 1);
GtkWidget * green = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0, 255, 1);
GtkWidget * blue = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0, 255, 1);
gtk_window_set_child (GTK_WINDOW (win), vbox);
gtk_window_set_title (GTK_WINDOW (win), "Scale");
gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
gtk_box_append (GTK_BOX (vbox), area);
gtk_box_append (GTK_BOX (vbox), grid);
gtk_grid_attach (GTK_GRID (grid), lred, 0, 0, 1, 1);
gtk_grid_attach (GTK_GRID (grid), lgreen, 0, 1, 1, 1);
gtk_grid_attach (GTK_GRID (grid), lblue, 0, 2, 1, 1);
gtk_grid_attach (GTK_GRID (grid), red, 1, 0, 1, 1);
gtk_grid_attach (GTK_GRID (grid), green, 1, 1, 1, 1);
gtk_grid_attach (GTK_GRID (grid), blue, 1, 2, 1, 1);
gtk_widget_set_hexpand (area, TRUE);
gtk_widget_set_vexpand (area, TRUE);
gtk_widget_set_size_request (area, 100, 100);
gtk_label_set_xalign (GTK_LABEL (lred), 1.0);
gtk_label_set_xalign (GTK_LABEL (lgreen), 1.0);
gtk_label_set_xalign (GTK_LABEL (lblue), 1.0);
gtk_widget_set_hexpand (red, TRUE);
gtk_widget_set_name (red, "red");
gtk_widget_set_name (green, "green");
gtk_widget_set_name (blue, "blue");
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (area), draw, NULL, NULL);
g_signal_connect (red, "value-changed", G_CALLBACK (color), area);
g_signal_connect (green, "value_changed", G_CALLBACK (color), area);
g_signal_connect (blue, "value_changed", G_CALLBACK (color), area);
gtk_window_present (GTK_WINDOW (win));
}
int
main (int argc, char **argv)
{
GtkApplication *app;
int stat;
app = gtk_application_new ("jp.vivacocoa.scale", G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
stat = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return stat;
}
以下のとおりです。Windows の場合は通常版でも ARM64版 でも mingw64 で行ってください。
// コンパイル
cc `pkg-config --cflags gtk4` scale.c -o scale `pkg-config --libs gtk4`
もしくは
gcc $(pkg-config --cflags gtk4) -o scale scale.c $(pkg-config --libs gtk4)
もしくは
gcc scale.c -o scale `pkg-config --cflags --libs gtk4`
// 実行
./scale
それぞれのスケールを動かして、いろいろな色を作れます。
光の三原色になっています。いろいろと試してみてください。
/*************************************
scale.c
copyright : vivacocoa.jp
last modified: Mar. 19, 2025
************************************/
#include <gtk/gtk.h>
static cairo_surface_t *surface = NULL;
static void
color (GtkWidget *widget, gpointer data)
{
static double r, g, b;
if (g_strcmp0 (gtk_widget_get_name (widget), "red") == 0)
{
r = gtk_range_get_value (GTK_RANGE (widget));
gtk_widget_queue_draw (data);
}
if (g_strcmp0 (gtk_widget_get_name (widget), "green") == 0)
{
g = gtk_range_get_value (GTK_RANGE (widget));
gtk_widget_queue_draw (data);
}
if (g_strcmp0 (gtk_widget_get_name (widget), "blue") == 0)
{
b = gtk_range_get_value (GTK_RANGE (widget));
gtk_widget_queue_draw (data);
}
cairo_t *cr;
cr = cairo_create (surface);
cairo_set_source_rgb (cr, r, g, b);
cairo_paint (cr);
cairo_destroy (cr);
}
static void
resize (GtkWidget *widget, int width, int height, gpointer data)
{
if (surface)
{
cairo_surface_destroy (surface);
surface = NULL;
}
if (gtk_native_get_surface (gtk_widget_get_native(widget)))
{
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
gtk_widget_get_width (widget),
gtk_widget_get_height (widget));
color (widget, widget);
}
}
static void
func (GtkDrawingArea *area, cairo_t *cr, int width, int height, gpointer data)
{
cairo_set_source_surface (cr, surface, 0, 0);
cairo_paint (cr);
}
static void
activate (GApplication *app, gpointer data)
{
GtkWidget * win = gtk_application_window_new (GTK_APPLICATION (app));
GtkWidget * vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
GtkWidget * area = gtk_drawing_area_new ();
GtkWidget * grid = gtk_grid_new ();
GtkWidget * lred = gtk_label_new ("Red");
GtkWidget * lgreen = gtk_label_new ("Green");
GtkWidget * lblue = gtk_label_new ("Blue");
GtkWidget * red = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0.0, 1.0, 0.01);
GtkWidget * green = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0.0, 1.0, 0.01);
GtkWidget * blue = gtk_scale_new_with_range (GTK_ORIENTATION_HORIZONTAL, 0.0, 1.0, 0.01);
gtk_window_set_child (GTK_WINDOW (win), vbox);
gtk_window_set_title (GTK_WINDOW (win), "Scale");
gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
gtk_box_append (GTK_BOX (vbox), area);
gtk_box_append (GTK_BOX (vbox), grid);
gtk_grid_attach (GTK_GRID (grid), lred, 0, 0, 1, 1);
gtk_grid_attach (GTK_GRID (grid), lgreen, 0, 1, 1, 1);
gtk_grid_attach (GTK_GRID (grid), lblue, 0, 2, 1, 1);
gtk_grid_attach (GTK_GRID (grid), red, 1, 0, 1, 1);
gtk_grid_attach (GTK_GRID (grid), green, 1, 1, 1, 1);
gtk_grid_attach (GTK_GRID (grid), blue, 1, 2, 1, 1);
gtk_widget_set_hexpand (area, TRUE);
gtk_widget_set_vexpand (area, TRUE);
gtk_widget_set_size_request (area, 100, 100);
gtk_label_set_xalign (GTK_LABEL (lred), 1.0);
gtk_label_set_xalign (GTK_LABEL (lgreen), 1.0);
gtk_label_set_xalign (GTK_LABEL (lblue), 1.0);
gtk_widget_set_hexpand (red, TRUE);
gtk_widget_set_name (red, "red");
gtk_widget_set_name (green, "green");
gtk_widget_set_name (blue, "blue");
g_signal_connect_after (area, "resize", G_CALLBACK (resize), NULL);
gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (area), func, NULL, NULL);
g_signal_connect (red, "value-changed", G_CALLBACK (color), area);
g_signal_connect (green, "value_changed", G_CALLBACK (color), area);
g_signal_connect (blue, "value_changed", G_CALLBACK (color), area);
gtk_window_present (GTK_WINDOW (win));
}
int
main (int argc, char **argv)
{
GtkApplication *app;
int stat;
app = gtk_application_new ("jp.vivacocoa.scale", G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
stat = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return stat;
}
Debian、Fedora、Kali でビルドしたアプリはどこに移動させてもダブルクリックで起動できます。 また違う Linuxに移動させても起動できます。
Ubuntu、Mint ではダブルクリックで起動できなかったと思います (Ubuntu、Mint はインストールしていません)。
さらに、Arm64 版でビルドしたアプリは x86_64 版では起動しないのではないかと思われます。 (x86_64 環境がないので試していません。)
mkdir scale.app
mv scale scale.app
もしくは
cp scale scale.app
以上で scale というアプリができていると思います。 これをダブルクリックで起動させてもターミナルは起動しません。どこへ移動させても起動できます。 他の Mac に移動させた場合は起動できません。
ビルドしたアプリはどこへ移動させても起動しますが、同時にコマンドプロンプトも起動します。 これを回避するには mingw64 で次のようにビルドするときに -mwindows オプションをつけます。
gcc scale.c -o scale `pkg-config --cflags --libs gtk4` -mwindows
これでビルドされた scale.exe はどこに移動させてもダブルクリックで起動することができますし、 コマンドプロンプトが起動することもありません。ただし違う Windows に移動させた場合は起動できません。