[英]How to draw in a GTK3 area with scroll bars
我正在构建一个嵌套的 GTK 应用程序:有 GtkNotebook - GtkGrid - GtkGrid - GtkFrame - GtkDrawingArea。
在 GtkDrawingArea 中(我通过尺寸请求固定尺寸)我创建了图纸,并且我已经建立了通过滚轮进行缩放的可能性。
从逻辑上讲,当我“放大”时,表面会变大,并且需要滚动条来查看整个绘图。
我怎样才能得到这些? 我尝试了 GtkLayout 和 GtkSrolledWindow 的不同组合,但它们没有用。 我在 Internet 上没有找到任何有用的示例。
获得可滚动绘图区域的方法是什么? 我应该从哪里开始挖掘? 任何提示都非常感谢!
谢谢你。
顺便说一句:我正在使用 Debian、GTK3、C 和开罗
MCVE:我创建了这个例子。 它绘制一个矩形,您可以使用滚轮对其进行缩放。 这发生在 300x300 帧内。 我想要这个带有滚动条的框架。 任何想法如何做到这一点?
此代码可以使用编译
gcc `pkg-config --cflags gtk+-3.0` -lm -o cf cf.c `pkg-config --libs gtk+-3.0`
参见c:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <gtk/gtk.h>
#define ZOOMING_STEP 1.2
typedef struct m_data
{
double scaling_factor;
cairo_surface_t *circle_surface_p, *final_surface_p;
GtkWidget *window_p;
} m_data_struct;
static void activate(GtkApplication *, gpointer);
static gboolean zoom_it(GtkWidget *, GdkEvent *, gpointer);
static gboolean configure_it(GtkWidget *, GdkEventConfigure *, gpointer);
static gboolean draw_it(GtkWidget *, cairo_t *, gpointer);
int main(int argc, char **argv)
{
GtkApplication *app_p;
m_data_struct my_data;
int status;
my_data.scaling_factor = 1.0/11.0;
my_data.final_surface_p = NULL;
app_p = gtk_application_new("calc.foil", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app_p, "activate", G_CALLBACK(activate), &my_data);
status = g_application_run(G_APPLICATION(app_p), 0, NULL);
g_object_unref(app_p);
}
static void activate(GtkApplication *app_p, gpointer g_data_p)
{
GtkWidget *frame_p, *notebook_p, *grid0_p, *grid1_p, *drawing_area_p;
m_data_struct *my_data_p;
cairo_t *cr_p;
my_data_p = (m_data_struct *)g_data_p;
my_data_p->window_p = gtk_application_window_new(app_p);
gtk_window_set_title(GTK_WINDOW(my_data_p->window_p), "Fot Calculation");
gtk_container_set_border_width(GTK_CONTAINER(my_data_p->window_p), 8);
notebook_p = gtk_notebook_new();
gtk_container_add(GTK_CONTAINER(my_data_p->window_p), notebook_p);
grid0_p = gtk_grid_new();
gtk_notebook_append_page(GTK_NOTEBOOK(notebook_p), grid0_p,
gtk_label_new("First Tab"));
grid1_p = gtk_grid_new();
gtk_grid_attach(GTK_GRID(grid0_p), grid1_p, 2, 2, 2, 50);
frame_p = gtk_frame_new("Rectangle");
drawing_area_p = gtk_drawing_area_new();
gtk_widget_set_size_request(frame_p, 300, 300);
g_signal_connect(drawing_area_p, "configure-event",
G_CALLBACK(configure_it), g_data_p);
g_signal_connect(drawing_area_p, "draw", G_CALLBACK(draw_it), g_data_p);
g_signal_connect(drawing_area_p, "scroll-event", G_CALLBACK(zoom_it),
g_data_p);
gtk_widget_set_events(drawing_area_p,
gtk_widget_get_events(drawing_area_p)
| GDK_SCROLL_MASK);
gtk_container_add(GTK_CONTAINER(frame_p), drawing_area_p);
gtk_grid_attach(GTK_GRID(grid1_p), frame_p, 1, 0, 1, 2);
my_data_p->circle_surface_p
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 3000, 3000);
cr_p = cairo_create(my_data_p->circle_surface_p);
cairo_set_line_width(cr_p, 10);
cairo_rectangle(cr_p, 100, 100, 2900, 2900);
cairo_set_source_rgb(cr_p, 0, 0, 0);
cairo_stroke(cr_p);
gtk_widget_show_all(my_data_p->window_p);
}
static gboolean zoom_it(GtkWidget *widget_p,
GdkEvent *event_p,
gpointer g_data_p)
{
if (((GdkEventScroll *)event_p)->direction == GDK_SCROLL_UP)
{
((m_data_struct *)g_data_p)->scaling_factor *= ZOOMING_STEP;
configure_it(widget_p, (GdkEventConfigure *)event_p, g_data_p);
gtk_widget_queue_draw(widget_p);
}
if (((GdkEventScroll *)event_p)->direction == GDK_SCROLL_DOWN)
{
((m_data_struct *)g_data_p)->scaling_factor /= ZOOMING_STEP;
configure_it(widget_p, (GdkEventConfigure *)event_p, g_data_p);
gtk_widget_queue_draw(widget_p);
}
return TRUE;
}
static gboolean configure_it(GtkWidget *widget_p,
GdkEventConfigure *event_p,
gpointer g_data_p)
{
cairo_t *cr_p;
m_data_struct * my_data_p;
my_data_p = (m_data_struct *)g_data_p;
if (my_data_p->final_surface_p)
cairo_surface_destroy(my_data_p->final_surface_p);
my_data_p->final_surface_p
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 300, 300);
cr_p = cairo_create(my_data_p->final_surface_p);
cairo_scale(cr_p, my_data_p->scaling_factor, my_data_p->scaling_factor);
cairo_set_source_surface(cr_p, my_data_p->circle_surface_p, 0, 0);
cairo_paint(cr_p);
cairo_destroy(cr_p);
return TRUE;
}
static gboolean draw_it(GtkWidget *widget_p,
cairo_t *cr_p,
gpointer g_data_p)
{
cairo_set_source_surface(cr_p, ((m_data_struct *)g_data_p)->final_surface_p,
0, 0);
cairo_paint(cr_p);
return FALSE;
}
要生成可滚动的 GTK 绘图区域 (GtkDrawingArea),可以采用滚动的 window (GtkScrolledWindow)。 绘图区域是滚动的 window (gtk_container_add) 的子项。
但是,要滚动绘图区域,我需要在每次更改它时指定它的大小(gtk_widget_set_size_request)。 当然,只有当它的大小大于滚动的 window 的大小时,滚动才有意义。
最后我想用滚轮放大我的开罗画。 这仅在鼠标下的点固定时才有效。 所以我需要调整滚动的 window (GtkAdjustment) 不让绘图在鼠标下移动。 除非缩小到非常低的水平。
但是,当绘图区域发生更改时,我无法找到这些调整的设置位置,因此我必须在放大时手动进行。
我以现在可以正常工作的方式更改了示例。 代码运行完成:cf.c:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include <gtk/gtk.h>
#define ZOOMING_STEP 1.2
#define SCALING_FACTOR_INIT 1.0/10.0
typedef struct m_data
{
double scaling_factor;
cairo_surface_t *rectangle_surface_p, *final_surface_p;
GtkWidget *window_p, *drawing_area_p;
GtkAdjustment *hadjust_p, *vadjust_p;
} m_data_struct;
static void activate(GtkApplication *, gpointer);
static gboolean zoom_it(GtkWidget *, GdkEvent *, gpointer);
static gboolean configure_it(GtkWidget *, GdkEventConfigure *, gpointer);
static gboolean draw_it(GtkWidget *, cairo_t *, gpointer);
int main(int argc, char **argv)
{
GtkApplication *app_p;
m_data_struct my_data;
int status;
my_data.scaling_factor = SCALING_FACTOR_INIT;
my_data.final_surface_p = NULL;
app_p = gtk_application_new("calc.foil", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app_p, "activate", G_CALLBACK(activate), &my_data);
status = g_application_run(G_APPLICATION(app_p), 0, NULL);
g_object_unref(app_p);
}
static void activate(GtkApplication *app_p, gpointer g_data_p)
{
GtkWidget *frame_p, *notebook_p, *grid0_p, *grid1_p, *drawing_area_p;
GtkWidget *scrolled_window_p, *frame0_p;
m_data_struct *my_data_p;
cairo_t *cr_p;
my_data_p = (m_data_struct *)g_data_p;
my_data_p->window_p = gtk_application_window_new(app_p);
gtk_window_set_title(GTK_WINDOW(my_data_p->window_p), "Fot Calculation");
gtk_container_set_border_width(GTK_CONTAINER(my_data_p->window_p), 8);
notebook_p = gtk_notebook_new();
gtk_container_add(GTK_CONTAINER(my_data_p->window_p), notebook_p);
grid0_p = gtk_grid_new();
gtk_notebook_append_page(GTK_NOTEBOOK(notebook_p), grid0_p,
gtk_label_new("First Tab"));
grid1_p = gtk_grid_new();
gtk_grid_attach(GTK_GRID(grid0_p), grid1_p, 2, 2, 2, 50);
frame_p = gtk_frame_new("Rectangle");
gtk_frame_set_shadow_type(GTK_FRAME(frame_p), GTK_SHADOW_NONE);
frame0_p = gtk_frame_new(NULL);
scrolled_window_p = gtk_scrolled_window_new(NULL, NULL);
my_data_p->hadjust_p
= gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW
(scrolled_window_p));
my_data_p->vadjust_p
= gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW
(scrolled_window_p));
drawing_area_p = gtk_drawing_area_new();
gtk_widget_set_size_request(scrolled_window_p, 300, 300);
g_signal_connect(drawing_area_p, "configure-event",
G_CALLBACK(configure_it), g_data_p);
g_signal_connect(drawing_area_p, "draw", G_CALLBACK(draw_it), g_data_p);
g_signal_connect(drawing_area_p, "scroll-event", G_CALLBACK(zoom_it),
g_data_p);
gtk_widget_set_events(drawing_area_p,
gtk_widget_get_events(drawing_area_p)
| GDK_SCROLL_MASK);
my_data_p->drawing_area_p = drawing_area_p;
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window_p),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_container_add(GTK_CONTAINER(scrolled_window_p), drawing_area_p);
gtk_container_add(GTK_CONTAINER(frame_p), frame0_p);
gtk_container_add(GTK_CONTAINER(frame0_p), scrolled_window_p);
gtk_grid_attach(GTK_GRID(grid1_p), frame_p, 1, 0, 1, 2);
my_data_p->rectangle_surface_p
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 3000, 3000);
cr_p = cairo_create(my_data_p->rectangle_surface_p);
cairo_set_line_width(cr_p, 50);
cairo_rectangle(cr_p, 100, 100, 1375, 1375);
cairo_rectangle(cr_p, 1525, 1525, 1375, 1375);
cairo_set_source_rgb(cr_p, 0, 0, 0);
cairo_stroke(cr_p);
gtk_widget_show_all(my_data_p->window_p);
}
static gboolean zoom_it(GtkWidget *widget_p,
GdkEvent *event_p,
gpointer g_data_p)
{
m_data_struct *my_data_p;
GdkEventScroll *this_event_p;
gdouble new_x, new_y;
int do_zoom = 0;
my_data_p = (m_data_struct *)g_data_p;
this_event_p = (GdkEventScroll *)event_p;
if (this_event_p->direction == GDK_SCROLL_UP)
{
my_data_p->scaling_factor *= ZOOMING_STEP;
gtk_adjustment_set_upper(my_data_p->hadjust_p,
gtk_adjustment_get_upper(my_data_p->hadjust_p)
* ZOOMING_STEP
+ 1); /* we need to calc the new upper
to set value, +1 for
inaccuracy */
gtk_adjustment_set_upper(my_data_p->vadjust_p,
gtk_adjustment_get_upper(my_data_p->vadjust_p)
* ZOOMING_STEP
+ 1);
new_x = this_event_p->x * ZOOMING_STEP;
new_y = this_event_p->y * ZOOMING_STEP;
do_zoom = 1;
}
if (this_event_p->direction == GDK_SCROLL_DOWN)
{
double sf;
sf = my_data_p->scaling_factor / ZOOMING_STEP;
if (sf >= SCALING_FACTOR_INIT / (1 + (ZOOMING_STEP - 1) / 2))
/* zoom out max till level 0 but
preventing inability not to zoom
to level 0 due to inaccurancy */
{
my_data_p->scaling_factor = sf;
new_x = this_event_p->x / ZOOMING_STEP;
new_y = this_event_p->y / ZOOMING_STEP;
do_zoom = 1;
}
}
if (do_zoom)
{
gtk_adjustment_set_value
(my_data_p->hadjust_p,
new_x
+ gtk_adjustment_get_value(my_data_p->hadjust_p)
- this_event_p->x);
gtk_adjustment_set_value
(my_data_p->vadjust_p,
new_y
+ gtk_adjustment_get_value(my_data_p->vadjust_p)
- this_event_p->y);
configure_it(widget_p, (GdkEventConfigure *)event_p, g_data_p);
gtk_widget_queue_draw(widget_p);
}
return TRUE;
}
static gboolean configure_it(GtkWidget *widget_p,
GdkEventConfigure *event_p,
gpointer g_data_p)
{
cairo_t *cr_p;
m_data_struct *my_data_p;
my_data_p = (m_data_struct *)g_data_p;
if (my_data_p->final_surface_p)
cairo_surface_destroy(my_data_p->final_surface_p);
my_data_p->final_surface_p
= cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
3000 * my_data_p->scaling_factor,
3000 * my_data_p->scaling_factor);
gtk_widget_set_size_request(my_data_p->drawing_area_p,
3000 * my_data_p->scaling_factor,
3000 * my_data_p->scaling_factor);
cr_p = cairo_create(my_data_p->final_surface_p);
cairo_scale(cr_p, my_data_p->scaling_factor, my_data_p->scaling_factor);
cairo_set_source_surface(cr_p, my_data_p->rectangle_surface_p, 0, 0);
cairo_paint(cr_p);
cairo_destroy(cr_p);
return TRUE;
}
static gboolean draw_it(GtkWidget *widget_p,
cairo_t *cr_p,
gpointer g_data_p)
{
cairo_set_source_surface(cr_p, ((m_data_struct *)g_data_p)->final_surface_p,
0, 0);
cairo_paint(cr_p);
return FALSE;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.