有人可以向我展示一个最小的工作示例,使用C语言为Cairo和Gtk3在GtkDrawingArea
中绘制一行。我试图在Gtk3测试文件夹中修改testcairo.c
,但我无法让它工作。请不要在开罗网站上推荐这些教程; Zetcode.com或gnome.org,不是与Gtk3一起使用,也不是最小的工作示例。
答案 0 :(得分:12)
我明白了。关键区别在于对于gtk + 3,您必须从“绘制”信号处理程序中进行绘制。使用gtk + 2,它来自“expose-event”信号处理程序。这是一个最小的工作示例: http://www.gtkforums.com/viewtopic.php?f=3&t=988&p=195286=Drawing+with+Cairo+in+GTK3#p195286
答案 1 :(得分:6)
这是一个完整的工作示例:
确保已安装gtk3-devel
(在Fedora #dnf install gtk3-devel中)
在Ubuntu中:sudo apt install libgtk-3-dev
编译:{{1}}
gcc draw.c pkg-config --cflags gtk+-3.0 --libs gtk+-3.0
-o draw
答案 2 :(得分:3)
任何在2020年进行此操作的人。这是Zetcode示例,可重构为与GTK3一起使用,它可以绘制所需的内容,因此不会出现奇怪的连接。我添加了评论以解释发生了什么。
/* To compile: gcc linetest.c -o linetest `pkg-config --cflags --libs gtk+-3.0`
* C program for basic drawing with GTK+ and cairo.
* Working 2020 example if this got you stuck, http://zetcode.com/gfx/cairo/basicdrawing/
* Note: the above command line uses backticks (`), it's right before 1 on your keyboard.
*/
#include <cairo.h>
#include <gtk/gtk.h>
//function prototypes
static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, gpointer user_data);
static void do_drawing(cairo_t *cr);
static gboolean clicked(GtkWidget *widget, GdkEventButton *event, gpointer user_data);
//end of function prototypes
/* Global variables for storing mouse coordinates,
* count is index of arrays, coordx and coordy are x and y coordinates of the mouse
*/
struct {
int count;
double coordx[100];
double coordy[100];
} glob;
/* Function: on_draw_event
*Parameters: GtkWidget, cairo_t, gpointer
*Use: This is the function we attach to the main method when we want to draw. It calls the do_drawing method.
*Example: g_signal_connect(G_OBJECT(darea), "draw", G_CALLBACK(on_draw_event), NULL);
*/
static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, gpointer user_data)
{
do_drawing(cr);
return FALSE;
}
/* Function: do_drawing
*Parameters: cairo_t
*Use: It sets cairo canvas settings, and draws shapes with a for loop
*Settings: are commented
*Note: printf is used during debugging to find mouse click coordinates :)
*/
static void do_drawing(cairo_t *cr)
{
cairo_set_source_rgb(cr, 0, 0, 0);//Line colour
cairo_set_line_width(cr, 0.5);//Line width
if (glob.count > 1) {
cairo_move_to(cr, glob.coordx[0], glob.coordy[0]);
//printf("from: x:%f, y:%f\n",glob.coordx[0],glob.coordy[0]);
}
//Connect lines.
for (int i = 1; i < glob.count; ++i) {
cairo_line_to(cr, glob.coordx[i], glob.coordy[i]);
//printf("to: x:%f, y:%f\n",glob.coordx[i],glob.coordy[i]);
}
// Draw the above.
cairo_stroke(cr);
//resets array so shape can be drawn again.
glob.count = 0;
}
/* Function: clicked
*Parameters: GtkWidget, GdkEventButton, gpointer
*Use: Registers mouse clicks, 1 is right, 3 is left on laptop. Clicks may be 1, 2 or 3 on a desktop
*Note: printf is used during debugging to find mouse click coordinates :)
*/
static gboolean clicked(GtkWidget *widget, GdkEventButton *event,
gpointer user_data)
{
if (event->button == 1) {
// printf("Right Click");
glob.coordx[glob.count] = event->x;
glob.coordy[glob.count++] = event->y;
// int i;
// for (i =0; i <= glob.count-1; i++) {
// printf("%f\n", glob.coordx[i]);
// }
}
if (event->button == 3) {
//printf("left Click");
gtk_widget_queue_draw(widget);
}
return TRUE;
}
//Main method.
int main(int argc, char *argv[])
{
//widget variables, window and drawing area.
GtkWidget *window;
GtkWidget *darea;
//Set global count 0, so array is at beginning whenver program starts.
glob.count = 0;
//Always have this to start GTK.
gtk_init(&argc, &argv);
//Set new window, set new drawing area.
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
darea = gtk_drawing_area_new();
//Add the drawing area to the window.
gtk_container_add(GTK_CONTAINER(window), darea);
//You need this to register mouse clicks.
gtk_widget_add_events(window, GDK_BUTTON_PRESS_MASK);
//Attaching draw function to the main method.
g_signal_connect(G_OBJECT(darea), "draw",
G_CALLBACK(on_draw_event), NULL);
//You can close window when you exit button.
g_signal_connect(window, "destroy",
G_CALLBACK(gtk_main_quit), NULL);
//Register if left or right mouse click.
g_signal_connect(window, "button-press-event",
G_CALLBACK(clicked), NULL);
//Set window position, default size, and title.
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 400, 300);
gtk_window_set_title(GTK_WINDOW(window), "Lines");
//Show all widgets.
gtk_widget_show_all(window);
//start window
gtk_main();
return 0;
}
答案 3 :(得分:0)
我不明白为什么它不起作用,它应该有用。
http://developer.gnome.org/gtk3/3.2/GtkDrawingArea.html
如您所见,带有cairo的gtk2与gtk3的几乎相同。
答案 4 :(得分:0)
// compila con valac --pkg gtk+-3.0 nombre_archivo.gs
uses
Gtk
Cairo
init
Gtk.init (ref args)
var TestCairo = new Ventana ()
TestCairo.show_all ()
Gtk.main ()
class Ventana : Window
area: Gtk.DrawingArea
init
title = "Test Genie + GTK + Cairo"
set_default_size (400, 400)
window_position = WindowPosition.CENTER
destroy.connect(Gtk.main_quit)
// área de dibujo
area: Gtk.DrawingArea = new Gtk.DrawingArea ()
// conecta el área de dibujo al método dibujar
area.draw.connect (dibujar)
// añade el área de dibujo a la ventana
add (area)
def dibujar (context : Context) : bool
context.set_source_rgba (1, 0, 0, 1)
context.set_line_width (2)
context.move_to (200, 100)
context.line_to (200, 300)
context.move_to (100, 200)
context.line_to (300, 200)
context.stroke ()
return true
中更多Genie + Gtk + Cairo的例子
答案 5 :(得分:0)
是-我同意...看起来应该对我有用。
但是我有一个单独的问题……我试图使用旋转框来控制要绘制多少条“线”(或图案..)。
我已经将一个信号连接到DrawingArea进行“绘制”,但是我不知道如何在旋转发生变化时重新调用“绘制”回调函数?
任何想法?
自己解决了!
需要使用 gtk_widget_queue_draw_area()函数。
main.c:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <gtk/gtk.h>
#include <cairo.h>
GtkWidget *window1;
GtkWidget *fixed1;
GtkWidget *frame1;
GtkWidget *draw1;
GtkWidget *spin1;
GtkWidget *spin2;
GtkBuilder *builder1;
// Neural Network Setup
gint N = 2; // number of layers (hard-coded for now)
gint n1; // number of neurons in first layer
gint n2; // number of neurons in second layer
gint L; // index for tracking each neuron layer
// Graphics Plotting Setup
gdouble W = 500.0; // hard-coded for now
gdouble H = 300.0; // hard-coded for now
gdouble mx = 20.0; // fixed x-margin
gdouble my = 20.0; // fixed y-margin
gdouble X; // total "plotting" width
gdouble Y; // total "plotting" height
gdouble dx; // equal x-spacing between neurons
gdouble dy; // equal y-spacing between neurons
gdouble x;
gdouble y;
gdouble r = 20.0; // radius
/*
- redraw (on event..?)
*/
static gboolean on_draw1_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data)
{
cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
cairo_set_line_width(cr, 1);
int i = 0;
// draw first layer neutrons
L = 0;
dy = Y / (n1 + 1);
x = mx + ((L + 1) * dx); // x-coordinate of given neuron
for (i = 0; i < n1; i++)
{
y = my + ((i + 1) * dy); // y-coordinate of given neuron
cairo_move_to(cr, x + r, y);
cairo_arc(cr, x, y, r, 0.0, 2.0 * M_PI);
cairo_close_path(cr);
}
// draw second layer neutrons
L = 1;
dy = Y / (n2 + 1);
x = mx + ((L + 1) * dx);
for (i = 0; i < n2; i++)
{
y = my + ((i + 1) * dy);
cairo_move_to(cr, x + r, y);
cairo_arc(cr, x, y, r, 0.0, 2.0 * M_PI);
cairo_close_path(cr);
}
cairo_stroke(cr);
//cairo_fill(cr);
// FALSE -> allow further events
return FALSE;
}
int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
builder1 = gtk_builder_new_from_file("main2.ui");
window1 = GTK_WIDGET(gtk_builder_get_object(builder1, "window1"));
fixed1 = GTK_WIDGET(gtk_builder_get_object(builder1, "fixed1"));
draw1 = GTK_WIDGET(gtk_builder_get_object(builder1, "draw1"));
spin1 = GTK_WIDGET(gtk_builder_get_object(builder1, "spin1"));
spin2 = GTK_WIDGET(gtk_builder_get_object(builder1, "spin2"));
g_signal_connect(window1, "destroy", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(G_OBJECT(draw1), "draw", G_CALLBACK(on_draw1_draw), NULL);
gtk_widget_add_events(draw1, 0);
gtk_builder_connect_signals(builder1, NULL);
g_object_unref(builder1);
n1 = 3;
n2 = 2;
gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin1), (gdouble)n1);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin2), (gdouble)n2);
X = W - (2 * mx);
Y = H - (2 * my);
dx = X / (N + 1);
gtk_widget_show_all(window1);
gtk_main();
return 0;
}
void on_spin1_value_changed(GtkSpinButton *b)
{
n1 = gtk_spin_button_get_value_as_int(b);
}
void on_spin2_value_changed(GtkSpinButton *b)
{
n2 = gtk_spin_button_get_value_as_int(b);
}
刀形文件
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface>
<requires lib="gtk+" version="3.20"/>
<object class="GtkAdjustment" id="adjustment1">
<property name="upper">100</property>
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkAdjustment" id="adjustment2">
<property name="upper">100</property>
<property name="step_increment">1</property>
<property name="page_increment">10</property>
</object>
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<child>
<placeholder/>
</child>
<child>
<object class="GtkFixed" id="fixed1">
<property name="width_request">520</property>
<property name="height_request">400</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkSpinButton" id="spin2">
<property name="width_request">100</property>
<property name="height_request">35</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">adjustment2</property>
<property name="climb_rate">1</property>
<signal name="value-changed" handler="on_spin2_value_changed" swapped="no"/>
</object>
<packing>
<property name="x">150</property>
<property name="y">360</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="spin1">
<property name="width_request">100</property>
<property name="height_request">35</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="adjustment">adjustment1</property>
<property name="climb_rate">1</property>
<signal name="value-changed" handler="on_spin1_value_changed" swapped="no"/>
</object>
<packing>
<property name="x">20</property>
<property name="y">360</property>
</packing>
</child>
<child>
<object class="GtkFrame" id="frame1">
<property name="width_request">500</property>
<property name="height_request">300</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="margin_top">10</property>
<property name="margin_bottom">10</property>
<property name="label_xalign">0</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkAlignment">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">10</property>
<property name="margin_right">10</property>
<property name="margin_top">10</property>
<property name="margin_bottom">10</property>
<child>
<object class="GtkDrawingArea" id="draw1">
<property name="width_request">500</property>
<property name="height_request">300</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Neural Network</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</interface>