这个词在编程领域,尤其是在C语言中,几乎可以肯定是 “重绘” (Repaint / Redraw) 的一个拼写错误或者不地道的翻译。Redecoration 在英语中通常指“重新装修”,比如重新装修房间,而“重绘”才是指在屏幕上重新绘制图形或界面。

我将重点解释 C语言中的“重绘” (Repaint) 是什么,以及它在不同场景下的实现方式。
C语言中的“重绘” (Repaint)
“重绘”是一个图形用户界面编程中的核心概念,它的意思是:当窗口或屏幕的一部分内容因为被其他窗口遮挡、窗口大小改变、数据更新等原因而变得无效时,操作系统会通知应用程序,要求它重新绘制这部分区域。
在C语言中,实现重绘主要依赖于图形库,因为标准C语言本身不包含任何图形或窗口管理功能,不同的图形库处理重绘的方式也不同。
下面我们来看几个主流C语言图形库中与“重绘”相关的概念和实现。

Windows API (Win32)
在Windows平台上,使用原生Win32 API开发GUI时,重绘是通过消息机制来驱动的。
-
核心消息:
WM_PAINT- 当窗口的某个区域需要被重绘时,Windows会向该窗口的窗口过程 发送一个
WM_PAINT消息。 - 你的程序必须在窗口过程中处理这个消息,即编写重绘逻辑。
- 当窗口的某个区域需要被重绘时,Windows会向该窗口的窗口过程 发送一个
-
关键函数:
BeginPaint()和EndPaint()- 在处理
WM_PAINT消息时,你必须先调用BeginPaint()函数,这个函数会获取一个设备上下文 句柄,并清除无效区域。 - 然后你就可以使用GDI(图形设备接口)函数(如
TextOut(),Rectangle(),Ellipse()等)在这个DC上进行绘制。 - 绘制完成后,必须调用
EndPaint()函数来结束这次绘制操作。
- 在处理
-
触发重绘: 除了系统自动发送,你也可以主动触发重绘。
(图片来源网络,侵删)InvalidateRect(): 标记一个矩形区域为“无效”,Windows会在下一次消息循环中为该区域发送WM_PAINT消息。UpdateWindow(): 立即发送WM_PAINT消息,而不是等到下一次消息循环。
示例代码 (Win32):
#include <windows.h>
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
static int cxChar, cyChar; // 用于存储字符大小
switch (message)
{
case WM_CREATE:
// 在窗口创建时初始化一些数据
cxChar = LOWORD(GetDialogBaseUnits());
cyChar = HIWORD(GetDialogBaseUnits());
return 0;
case WM_PAINT: // <--- 核心重绘消息
hdc = BeginPaint(hWnd, &ps); // 开始绘制
// 在这里进行所有的绘制操作
TextOut(hdc, cxChar, cyChar, L"Hello, C World!", 16);
Rectangle(hdc, 10, 10, 200, 100);
EndPaint(hWnd, &ps); // 结束绘制
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
// ... (注册窗口类、创建窗口等代码)
// ...
// 消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
GTK (GIMP Toolkit)
GTK是一个跨平台的GUI库,广泛用于Linux(GNOME桌面环境)和Windows,它使用C语言编写,采用信号 和回调函数 机制。
-
核心回调:
draw信号- 当GTK控件(如
GtkDrawingArea)需要重绘时,它会触发draw信号。 - 你需要连接一个回调函数来处理这个信号。
- 当GTK控件(如
-
关键函数:
gtk_render_*系列函数- 在
draw信号的回调函数中,你会接收到一个cairo_t类型的绘图上下文。 - 你使用Cairo库的函数(如
cairo_move_to,cairo_line_to,cairo_stroke,cairo_text_extents等)来绘制。
- 在
示例代码 (GTK):
#include <gtk/gtk.h>
// draw信号回调函数
static void draw(GtkWidget *widget, cairo_t *cr, gpointer user_data)
{
// 获取控件的大小
gint width, height;
gtk_widget_get_size_request(widget, &width, &height);
// 设置绘图样式
cairo_set_source_rgb(cr, 0, 0, 0); // 黑色
cairo_set_line_width(cr, 5.0);
// 绘制一个矩形
cairo_rectangle(cr, 10, 10, width - 20, height - 20);
cairo_stroke(cr);
// 绘制文本
cairo_set_font_size(cr, 20);
cairo_move_to(cr, 20, 40);
cairo_show_text(cr, "Hello, GTK World!");
}
int main(int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *drawing_area;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
drawing_area = gtk_drawing_area_new();
// 连接draw信号
g_signal_connect(drawing_area, "draw", G_CALLBACK(draw), NULL);
gtk_container_add(GTK_CONTAINER(window), drawing_area);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
SDL (Simple DirectMedia Layer)
SDL主要用于游戏开发和多媒体应用,它提供了对底层图形、音频、输入设备的直接访问,SDL的重绘模式更偏向于“主动渲染”。
-
核心模式: 在主循环中主动绘制
- SDL不依赖操作系统级别的重绘消息,你的程序通常在一个
while循环中运行。 - 每一帧,你都需要手动清除屏幕,然后重新绘制所有需要显示的内容。
- 这种模式被称为游戏循环。
- SDL不依赖操作系统级别的重绘消息,你的程序通常在一个
-
关键函数:
SDL_RenderClear(): 用当前清空颜色(通常是黑色)清除渲染目标(整个屏幕)。SDL_RenderCopy(): 将一个纹理(可以是一张图片或文字)复制到渲染目标上。SDL_RenderPresent(): 将渲染后的一帧画面显示到屏幕上。这是最重要的一步,没有它,你绘制的内容用户是看不到的。
示例代码 (SDL):
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h> // 用于渲染文本
int main(int argc, char* argv[])
{
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
SDL_Texture* textTexture = NULL;
SDL_Rect textRect;
SDL_Init(SDL_INIT_VIDEO);
TTF_Init();
window = SDL_CreateWindow("SDL Redraw Example",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640, 480,
SDL_WINDOW_SHOWN);
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
// 加载字体并创建文本纹理
TTF_Font* font = TTF_OpenFont("arial.ttf", 24);
SDL_Surface* textSurface = TTF_RenderText_Solid(font, "Hello, SDL World!", (SDL_Color){255, 255, 255, 255});
textTexture = SDL_CreateTextureFromSurface(renderer, textSurface);
textRect = (SDL_Rect){ 20, 20, textSurface->w, textSurface->h };
SDL_FreeSurface(textSurface);
TTF_CloseFont(font);
// 游戏主循环
int running = 1;
SDL_Event e;
while (running)
{
// 1. 处理事件
while (SDL_PollEvent(&e) != 0)
{
if (e.type == SDL_QUIT)
{
running = 0;
}
}
// 2. 清除屏幕 (这是重绘的第一步)
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); // 设置清空颜色为黑色
SDL_RenderClear(renderer);
// 3. 绘制所有内容
SDL_RenderCopy(renderer, textTexture, NULL, &textRect);
// 在这里可以绘制更多东西...
// 4. 将渲染结果呈现到屏幕上 (这是重绘的最后一步)
SDL_RenderPresent(renderer);
SDL_Delay(16); // 简单的帧率控制 (约60FPS)
}
// 清理资源
SDL_DestroyTexture(textTexture);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
TTF_Quit();
SDL_Quit();
return 0;
}
| 特性 | Windows API (Win32) | GTK | SDL |
|---|---|---|---|
| 重绘驱动方式 | 被动:由操作系统发送 WM_PAINT 消息驱动 |
被动:由控件触发 draw 信号驱动 |
主动:在游戏循环中手动每一帧都重绘 |
| 核心概念 | 窗口过程、设备上下文 | 回调函数、Cairo绘图上下文 | 渲染器、纹理、游戏循环 |
| 关键函数 | BeginPaint(), EndPaint() |
gtk_render_* (在回调中) |
SDL_RenderClear(), SDL_RenderPresent() |
| 适用场景 | 传统Windows桌面应用程序 | 跨平台桌面应用程序(如GIMP) | 游戏、多媒体应用、实时渲染 |
当您在C语言中看到或听到 redecoration 时,请首先想到它应该是 “重绘” (Repaint/Redraw),具体如何实现,取决于您使用的图形库,理解所选库的重绘机制是开发图形界面的关键。
