c - 如何绘制区域选择框
问题描述
我正在使用 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
}
运行这段代码,在绘图区域的某个位置按住鼠标左键从左上滑到右下,会得到下图。
这看起来很自然,但我想要的始终只是最外层的线。我不想要里面的剩余线条。另外,我希望保留红色矩形,但是当释放鼠标按钮时,所有线条都应该消失。我将不胜感激任何人可以给我的任何想法。
解决方案
推荐阅读
- javascript - 为什么我们能够在 react 组件的构造函数中绑定函数?
- java - 使用会话为每个新用户创建访问计数器
- android - Kotlin - 局部变量与全局变量
- scheduler - Web2py Scheduler 在开始从不同 UI 启动的新任务之前等待任务完成
- javascript - 编写模块导入的不同方式
- javascript - 通过ajax动态输入直到嚎叫 - 输入不起作用
- java - 使用带有 Spring Boot 2 的实体管理器时,没有类型为“javax.persistence.EntityManager”的合格 bean
- javascript - 如何在 c# 中使用 chromium 网络浏览器获取 javascript 的返回值
- php - WHMCS 自定义域注册模块
- node.js - Firebase Cloud Firestore 如何设置 snapShotOptions