【问题标题】:Cairo in scrollable drawing area可滚动绘图区中的开罗
【发布时间】:2012-06-21 05:43:45
【问题描述】:

我在 Ubuntu 11.04 (Natty) 上使用 gtk+-3.2.4。我正在尝试使用 Cairo 绘制 GtkDrawingArea 并使绘图区域可滚动。代码运行没有错误,但没有完成绘图。我做错了什么?

// gcc -Wextra -o scrol `pkg-config --cflags --libs gtk+-3.0` scrol1.c

#include <gtk/gtk.h>

#define WINDOW_WIDTH  800
#define WINDOW_HEIGHT 600

static gboolean draw_cb (GtkWidget *widget, GdkEventExpose *event) 
{
  cairo_t *cr;
  cr = gdk_cairo_create (gtk_widget_get_window (widget));
  cairo_set_source_rgb(cr, 1, 1, 1);
  cairo_paint(cr);
  cairo_set_source_rgb (cr, 0.42, 0.65, 0.80);
  cairo_set_line_width (cr,6);
  cairo_rectangle (cr, 3, 3, 100, 100);
  cairo_stroke (cr); 
  cairo_destroy(cr);
  return FALSE;
}

int main (int argc, char *argv[])
{
  gtk_init (&argc, &argv);
  GtkWidget *window;
  GtkWidget *grid;
  GtkWidget *swindow;
  GtkWidget *viewport;
  GtkWidget *darea;

  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  grid = gtk_grid_new();
  swindow = gtk_scrolled_window_new (NULL,NULL);
  viewport = gtk_viewport_new (NULL,NULL);
  darea = gtk_drawing_area_new();

  gtk_container_add (GTK_CONTAINER(viewport), darea);
  gtk_container_add (GTK_CONTAINER(swindow), viewport);
  gtk_grid_attach (GTK_GRID(grid), swindow, 0, 1, 1, 2);
  gtk_container_add (GTK_CONTAINER(window), grid);

  g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
  g_signal_connect (darea, "draw", G_CALLBACK(draw_cb),  NULL);

  gtk_widget_show_all (window);
  gtk_main ();
  return 0;
  }

【问题讨论】:

  • “但未完成绘图”究竟是什么意思?你在屏幕上看到了什么?
  • 我只是得到一个灰色的窗口。它应该有一个白色背景上的蓝色矩形。

标签: cairo gtk3


【解决方案1】:

这是您的代码创建的窗口的屏幕截图:

我想你希望看到一个正方形。但是,您所看到的只是该正方形的左上角。这是因为绘图区域请求的空间非常小,导致窗口很小。这意味着您的精彩作品正在被剪裁以适合这个最小尺寸的窗口。您可以做几件事:

  1. 设置包含绘图区域的滚动窗口的最小尺寸:

    gtk_widget_set_size_request( swindow, 500, 500 );
    

    这将导致一个 500 x 500 像素的绘图区域可见(这比正方形所需的要多得多)。但是,如果您将窗口放大,则绘图区域将不会填满它。

  2. 将滚动窗口设置为占据它可以获得的所有水平和垂直空间:

    gtk_widget_set_hexpand( swindow, TRUE );
    gtk_widget_set_vexpand( swindow, TRUE );
    

    如果您只是这样做,则窗口最初看起来与您原始代码中的窗口相同。但是,如果您手动调整窗口大小,您会看到滚动窗口(以及绘图区域)会扩展以填充窗口中的所有空间。如果你把它展开得足够多,你会看到你的正方形。

如果您将上述两者结合起来,您将获得一个最初约为 500x500 像素的窗口。如果你调整它的大小,那么绘图区域将扩大以填满窗口。

您还可以添加一个gtk_widget_set_size_request 调用来设置绘图区域小部件的大小。如果您将其设置为大于滚动窗口的大小,那么您将获得滚动条。

【讨论】:

    【解决方案2】:

    绘图已完成,但它只是在窗口的左上角。我添加了以下两个调用,对我来说一切都很好:

    gtk_widget_set_hexpand(GTK_WIDGET(swindow), TRUE);  
    gtk_widget_set_vexpand(GTK_WIDGET(swindow), TRUE);
    

    【讨论】:

    • 不,hexpand 和 vexpand 不起作用。当您说“对我来说一切都很好”时,您编译并运行了它并且它有效吗?如果是这样,您的操作系统和 GTK 版本是什么?
    • Debian 测试,libgtk-3-0 版本 3.4.2-1。当我在没有修改的情况下运行代码时,我会得到一个小窗口,顶部/左边缘有蓝色边框,其余部分为白色。当窗口调整为更大时,新区域为灰色。通过我的修改,我可以通过放大窗口看到整个蓝色矩形。
    • 谢谢,很好,我很高兴它有效。其实我弄错了,我有gtk+-3.2.3。但我真的很害怕尝试手动安装 gtk。即使使用 gtk+-3.2.3。我仍然收到烦人的消息:Gtk-Message: Failed to load module "canberra-gtk-module"
    • 我没有收到该消息。其他 gtk 应用程序是否有效?那个缺失的模块听起来你的安装可能被破坏了。
    【解决方案3】:

    尝试从on_draw() 回调中返回TRUE 以阻止默认处理程序;也许默认处理程序在您的绘图上绘制空白空间?

    【讨论】:

      【解决方案4】:
      // gcc -Wextra -o grid1 `pkg-config --cflags --libs gtk+-3.0` grid1.c
      
      #include <gtk/gtk.h>
      
      #define WINDOW_WIDTH  200
      #define WINDOW_HEIGHT 80
      
      static gboolean draw_cb (GtkWidget *widget, GdkEventExpose *event) 
      {
        cairo_t *cr;
        cr = gdk_cairo_create (gtk_widget_get_window (widget));
        cairo_set_source_rgb(cr, 1, 1, 1);
        cairo_paint(cr);
        cairo_set_source_rgb (cr, 0.42, 0.65, 0.80);
        cairo_set_line_width (cr,6);
        cairo_rectangle (cr, 3, 3, 400, 100);
        cairo_stroke (cr);
        cairo_destroy(cr);
        return TRUE;
      }
      
      int main (int argc, char *argv[])
      {
        gtk_init (&argc, &argv);
        GtkWidget *window;
        GtkWidget *grid;
        GtkWidget *swindow;
        GtkWidget *viewport;
        GtkWidget *darea;
      
        window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
        grid = gtk_grid_new();
        swindow = gtk_scrolled_window_new (NULL,NULL);
        viewport = gtk_viewport_new (NULL,NULL);
        darea = gtk_drawing_area_new();
      
        gtk_widget_set_size_request (window, 200, 100);
        gtk_widget_set_size_request (darea, 406, 106);
      
        gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
                                        GTK_POLICY_ALWAYS,
                                        GTK_POLICY_NEVER);
      
        gtk_widget_set_hexpand(GTK_WIDGET(swindow), TRUE);  
        gtk_widget_set_vexpand(GTK_WIDGET(swindow), TRUE);
      
        gtk_container_add (GTK_CONTAINER(viewport), darea);
        gtk_container_add (GTK_CONTAINER(swindow), viewport);
        gtk_grid_attach (GTK_GRID(grid), swindow, 0, 0, 1, 1);                 
        gtk_container_add (GTK_CONTAINER(window), grid);
      
        g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
        g_signal_connect (darea, "draw", G_CALLBACK(draw_cb),  NULL);
      
        gtk_widget_show_all (window);
        gtk_main ();
        return 0;
        }
      

      【讨论】:

        【解决方案5】:

        【讨论】:

        • 那么究竟有什么不同之处呢?是什么让您的代码不适合您?
        • 对我所有的编辑和困惑感到抱歉。你是部分正确的 Uli Schlachter。我需要 gtk_widget_set_hexpand(GTK_WIDGET(swindow), TRUE);和 gtk_widget_set_vexpand(GTK_WIDGET(swindow), TRUE);以及其他一些东西,但我并没有真正说出我希望它如何运作。这是我的错。我发布了完整的代码。
        • 这是一个断开的链接。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多