2013-06-10 31 views
10

Tôi đang chuyển một số mã từ Windows sang XLib. Trong mã cửa sổ, tôi có thể buộc vẽ lại bằng cách gọi InvalidateRect và sau đó xử lý thông báo WM_PAINT tương ứng. Tuy nhiên, tôi đang gặp khó khăn trong việc tìm hiểu làm thế nào để làm điều này trong X11/XLib. Tôi thấy có một thông báo Expose nhưng không chắc chắn nếu đó là điều tương tự.Tương đương với "Invalid Rect"/"WM_PAINT" trong X11

Nếu quan trọng, tôi cần thực hiện điều này để buộc cửa sổ hiển thị ở tốc độ khung hình nhất định cho chương trình dựa trên OpenGL.

+0

Ngoài ra nếu có ai có thể đề xuất tham chiếu XLib tuyệt vời, tôi thực sự sẽ đánh giá cao nó. Sách hướng dẫn XLib trên X.org dường như không giúp ích nhiều cho người mới bắt đầu, ít nhất là không dành cho tôi. – pauld

+0

Có điều tương tự. Tôi khuyên bạn không nên sử dụng Xlib thô. Sử dụng bộ công cụ hiện đại như Qt, gtk hoặc wX. –

+0

Ngoài ra, mặc dù Expose sẽ hoạt động, tôi khuyên bạn nên gọi lại chức năng vẽ lại của bạn trực tiếp. Nó dễ dàng hơn và đơn giản hơn. –

Trả lời

4

Bạn cần xử lý Sự kiện phơi bày. This tutorial giải thích với một ví dụ làm thế nào để xử lý các sự kiện Expose:

#include <stdio.h> 
#include <stdlib.h> 
#include <X11/Xlib.h> 
#include <X11/Xutil.h> 
#include <X11/Xos.h> 
#include <X11/Xatom.h> 
#include <X11/keysym.h> 
/*Linux users will need to add -ldl to the Makefile to compile 
*this example. 
*/ 
Display *dis; 
Window win; 
XEvent report; 
GC green_gc; 
XColor green_col; 
Colormap colormap; 
/* 
Try changing the green[] = below to a different color. 
The color can also be from /usr/X11R6/lib/X11/rgb.txt, such as RoyalBlue4. 
A # (number sign) is only needed when using hexadecimal colors. 
*/ 
char green[] = "#00FF00"; 

int main() { 
    dis = XOpenDisplay(NULL); 
    win = XCreateSimpleWindow(dis, RootWindow(dis, 0), 1, 1, 500, 500, 0, BlackPixel (dis, 0), BlackPixel(dis, 0)); 
    XMapWindow(dis, win); 
    colormap = DefaultColormap(dis, 0); 
    green_gc = XCreateGC(dis, win, 0, 0); 
    XParseColor(dis, colormap, green, &green_col); 
    XAllocColor(dis, colormap, &green_col); 
    XSetForeground(dis, green_gc, green_col.pixel); 

    XSelectInput(dis, win, ExposureMask | KeyPressMask | ButtonPressMask); 

    XDrawRectangle(dis, win, green_gc, 1, 1, 497, 497); 
    XDrawRectangle(dis, win, green_gc, 50, 50, 398, 398); 
    XFlush(dis); 

    while (1) { 
    XNextEvent(dis, &report); 
     switch (report.type) { 
     case Expose: 
      fprintf(stdout, "I have been exposed.\n"); 
       XDrawRectangle(dis, win, green_gc, 1, 1, 497, 497); 
       XDrawRectangle(dis, win, green_gc, 50, 50, 398, 398); 
       XFlush(dis); 
      break; 
      case KeyPress: 
     /*Close the program if q is pressed.*/ 
       if (XLookupKeysym(&report.xkey, 0) == XK_q) { 
       exit(0); 
       } 
      break; 
     } 
    } 

return 0; 
} 

tôi có thể đã hiểu lầm câu hỏi. Nếu bạn muốn tạo các sự kiện phơi bày trong ứng dụng của mình, bạn có thể tạo và thiết lập expose event và gửi nó bằng cách sử dụng XSendEvent.

+0

Ok. Vì vậy, trong cửa sổ tôi gọi là 'InvalidateRect' mà sau này kích hoạt các cửa sổ để gửi một thông điệp' WM_PAINT', tại thời điểm đó tôi làm cho cảnh mở gl của tôi. Vì vậy, trong X11, tôi sẽ gọi 'XSendEvent' với thông điệp 'Expose' và sau đó có một vòng lặp sự kiện xử lý thông điệp' Expose' và hiển thị cảnh mở? – pauld

+0

@pauld Không chắc tôi theo bạn. X11 sử dụng hệ thống sự kiện để thông báo cho ứng dụng về các sự kiện khác nhau. Bạn nói với nó sự kiện nào bạn muốn xử lý.Nếu bạn muốn hiển thị cảnh của mình khi hiển thị các sự kiện, thì bạn cần phải thêm mã hiển thị trong trình xử lý sự kiện đó. Tôi không thấy lý do tại sao bạn sẽ tạo ra sự kiện phơi bày cho ứng dụng của bạn. –

+1

Ok tôi nghĩ tôi hiểu. Trong cửa sổ, tôi có thể vẽ vào cửa sổ _only_ trong một tin nhắn 'WM_PAINT'. Trong X11, có vẻ như tôi có thể vẽ lên cửa sổ bất cứ khi nào tôi muốn, không chỉ để đáp lại một sự kiện 'Expose'. Vì vậy, trong trường hợp đó, tôi không cần phải tạo ra các sự kiện phơi bày, tôi chỉ có thể vẽ khi tôi đã sẵn sàng. – pauld

4

Để mở rộng một chút về câu trả lời hữu ích do BЈовић,

Với nguyên Xlib bạn có thể vẽ bất cứ lúc nào trong một chủ đề duy nhất, bởi vì tất cả các chức năng Xlib xác định đầy đủ màn hình, cửa sổ, và bối cảnh. AFAIK, với đa luồng tất cả các phiên cược đều bị tắt.

Bạn cũng phải có trình xử lý sự kiện Expose và chọn cho những sự kiện đó nếu bạn đang ở trong môi trường máy tính để bàn. Và nó sẽ không làm tổn thương để có một ngay cả khi bạn đang viết một chương trình toàn màn hình.

Hầu hết các bộ công cụ không linh hoạt và chỉ vẽ trong trình xử lý sự kiện được chỉ định (nhưng đẹp hơn nhiều theo nhiều cách khác) và có một số tương đương với Windows InvalidateRect. Trong Xlib thô bạn nhận được hiệu ứng tương tự bằng cách gửi cho mình một sự kiện phơi bày. Làm như vậy sẽ không dẫn đến bất kỳ vấn đề hiệu suất thực tế nào và sẽ làm cho mã dễ hiểu hơn bởi các lập trình viên khác và dễ dàng hơn trong việc chuyển đổi cổng, vì vậy bạn cũng có thể làm như vậy.

Ngoài ra còn có các chức năng XClearArea và XClearWindow sẽ tạo ra các sự kiện phơi sáng cho bạn, nhưng trước tiên chúng xóa một phần/tất cả với màu nền, có thể dẫn đến nhấp nháy.

Với OpenGL nó trở nên phức tạp hơn một chút vì bạn cũng phải làm việc với GLX. Tôi có chương trình OpenGL/Xlib rất đơn giản trực tuyến tại số http://cs.anu.edu.au/~hugh.fisher/3dteach/ có thể hữu ích làm ví dụ.

+3

Sử dụng 'XClearArea (disp, win, 0, 0, 1, 1, true)' để xóa một ảnh vùng pixel là đủ để gây ra sự kiện 'Expose' mà không thêm nhấp nháy. Bạn có thể muốn làm theo 'XClearArea()' ngay lập tức với một 'XFlush()', nếu bạn không thấy các sự kiện 'Expose' ngay lập tức. – Harvey