首页 > 解决方案 > 如何绘制区域选择框

问题描述

我正在使用 GTK3 和 CAIRO 创建一个简单的应用程序。我想暂时显示一个矩形区域来选择绘图区域中的某个区域,但上下文仍然存在。部分代码如下所示。

#include <gtk/gtk.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

cairo_surface_t *surface=NULL;
GtkWidget *drawing_area;
int tmpx, tmpy;

int main(int argc, char *argv[]);
void main_app(GtkApplication *app);
gint configure_event(GtkWidget *widget, GdkEventConfigure *event, gpointer data);
gint draw_event(GtkWidget *widget, cairo_t *cr, gpointer data);
gboolean motion_notify_event(GtkWidget *widget, EdkEventMotion *event, gpointer data);
void select_region(int x, int y);
gboolean button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer data);
gboolean button_release_event(GtkWidget *widget, GdkEventButton *event, gpointer data);

int main(int argc, char *argv[])
{
  int status;
  GtkApplication *app;

  app = gtk_application_new("sample", G_APPLICATION_FLAG_NONE);
  g_signal_connect(app, "activate", G_CALLBACK(main_app), app);
  status = g_application_run(G_APPLICATION(app),argc,argv);
  g_object_unref(app);

  return status;
}

void main_app(GtkApplication *app)
{
  GtkWidget *window, *vbox;

  vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL,0);

  window = gtk_application_window_new(app);
  gtk_window_set_title(GTK_WINDOW(window),"sample");
  gtk_window_set_default_size(GTK_WINDOW(window),100,100);
  gtk_window_set_resizable(GTK_WINDOW(window),TRUE);
  gtk_container_add(GTK_CONTAINER(window),vbox);  

  drawing_area = gtk_drawing_area_new();
  gtk_widget_set_size_request(drawing_area,100,100);
  gtk_box_pack_start(GTK_BOX(vbox),drawing_area,TRUE,TRUE,0);
  g_signal_connect(G_OBJECT(drawing_area), "configure_event", G_CALLBACK(configure_event),NULL);
  g_signal_connect(G_OBJECT(drawing_area), "draw", G_CALLBACK(draw_event),NULL);
  g_signal_connect(G_OBJECT(drawing_area), "motion_notify_event", G_CALLBACK(motion_notify_event),NULL);
  g_signal_connect(G_OBJECT(drawing_area), "button_press_event", G_CALLBACK(button_press_event),NULL);
  g_signal_connect(G_OBJECT(drawing_area), "button_release_event", G_CALLBACK(button_release_event),NULL);
  gtk_widget_set_events(drawing_area, GDK_EXPOSURE_MASK|GDK_BUTTON_RELEASE_MASK|GDK_LEAVE_NOTIFY_MASK|GDK_BUTTON_PRESS_MASK|GDK_POINTER_MOTION_MASK|GDK_POINTER_MOTION_HINT_MASK);
  gtk_widget_show_all(window);
}

gint configure_event(GtkWidget *widget, GdkEventConfigure *event, gpointer data)
{
  GtkAllocation allocation;
  cairo_t *cr;

  gtk_widget_get_allocation(widget, &allocation);

  if(surface==NULL){
    cairo_surface_destroy(surface);
  }
  surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height);
  cr = cairo_create(surface);
  cairo_set_source_surface(cr, surface, 0, 0);
  cairo_set_source_rgb(cr, 1, 1, 1);
  cairo_paint(cr);
  cairo_destroy(cr);

  return TRUE;
}

gint draw_event(GtkWidget *widget, cairo_t *cr, gpointer data)
{
  cairo_set_source_surface(cr, surface, 0, 0);
  cairo_paint(cr);
  gtk_widget_queue_draw(drawing_area);

  return FALSE;
}

gboolean motion_notify_event(GtkWidget *widget, EdkEventMotion *event, gpointer data)
{
  int x,y;
  GdkModifierType state;

  if(event->is_hint){
    gdk_window_get_device_position(event->window, event->device, &x, &y, &state);
  }else{
    x = event->x;
    y = event->y;
    state = event->state;
  }
  
  if(GDK_BUTTON1_MASK){
    select_region(x,y);
  }

  return TRUE;
}

void select_region(int x, int y)
{
  gint x_left, x_right, y_top, y_bottom;
  cairo_t *cr;

  x_left = (tmpx < x) ? tmpx : x;
  x_right = (tmpx > x) ? tmpx : x;
  y_top = (tmpy < y) ? tmpy : y;
  y_bottom = (tmpy > y) ? tmpy : y;

  cr = cairo_create(surface);
  cairo_set_source_rgb(cr, 0, 0, 0);
  cairo_rectangle(cr, x_left, y_top, x_right - x_left, y_bottom - y_top);
  cairo_stroke(cr);
  cairo_destroy(cr); 
}

gboolean button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer data)
{
  tmpx = event->x;
  tmpy = event->y;
}

gboolean button_release_event(GtkWidget *widget, GdkEventButton *event, gpointer data)
{
  // None
}

运行这段代码,在绘图区域的某个位置按住鼠标左键从左上滑到右下,会得到下图。

在此处输入图像描述

这看起来很自然,但我想要的始终只是最外层的线。我不想要里面的剩余线条。另外,我希望保留红色矩形,但是当释放鼠标按钮时,所有线条都应该消失。我将不胜感激任何人可以给我的任何想法。

标签: cgtk3cairo

解决方案


推荐阅读