Từ 1 tới 3 trên tổng số 3 kết quả

Đề tài: Làm sao tạo hiệu ứng hoạt hình đơn giản sử dụng SetTimer

  1. #1
    Ngày gia nhập
    12 2015
    Nơi ở
    Đà Nẵng
    Bài viết
    350

    Mặc định Làm sao tạo hiệu ứng hoạt hình đơn giản sử dụng SetTimer

    Mình có một chương trình, project gồm 2 file
    Header.h
    C++ Code:
    1. #include <windows.h>
    2. #include <tchar.h>
    3. #include <Windowsx.h>
    4. #include <gdiplus.h>
    5. #include <vector>
    6. #include <sstream>
    7.  
    8. //#include <Gdipluspixelformats.h>
    9. #pragma comment(lib, "Gdiplus.lib")
    10. #define WC TEXT("abc")
    11. #define Title TEXT("aaa")
    12. #define mytimer 10000
    13. #define interval 5
    14. using namespace Gdiplus;
    15. using namespace std;
    Source.cpp
    C++ Code:
    1. #include "Header.h"
    2. LRESULT CALLBACK WndProc2(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
    3. int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow)
    4. {
    5.     GdiplusStartupInput gdiplusstartupinput;
    6.     ULONG_PTR gdiplustoken ;
    7.     GdiplusStartup(&gdiplustoken, &gdiplusstartupinput, NULL);
    8.  
    9.     WNDCLASSEX wcex={};
    10.     wcex.cbSize =sizeof(WNDCLASSEX);
    11.     wcex.lpszClassName =WC;
    12.     wcex.hCursor= LoadCursor(NULL, IDC_ARROW);
    13.     wcex.hInstance=hInstance;
    14.     wcex.lpfnWndProc=WndProc2;
    15.  
    16.     if(!RegisterClassEx(&wcex))
    17.     {
    18.         MessageBox(NULL, TEXT("Đăng ký lớp không thành công"), TEXT("Lỗi đăng ký lớp"), NULL);
    19.         return 1;
    20.     }
    21.  
    22.     HWND hWnd=CreateWindow(WC, Title, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,400,300,NULL,NULL, hInstance, NULL);
    23.     if(!hWnd)
    24.     {
    25.         MessageBox(NULL, TEXT("Tạo cửa sổ không thành công"), TEXT("Lỗi tạo cửa sổ"), NULL);
    26.         return 1;
    27.     }
    28.  
    29.     ShowWindow(hWnd, nCmdShow);
    30.     UpdateWindow(hWnd);
    31.  
    32.     MSG msg;
    33.     while(GetMessage(&msg, NULL, 0,0))
    34.     {
    35.         TranslateMessage(&msg);
    36.         DispatchMessage(&msg);
    37.     }
    38.    
    39.     GdiplusShutdown(gdiplustoken);
    40.     return (int)msg.wParam;
    41. }
    42.  
    43. Bitmap* bitmap;
    44. int posX;
    45. LRESULT CALLBACK WndProc2(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    46. {
    47.     switch(msg)
    48.     {
    49.     case WM_CREATE:
    50.         {
    51.             bitmap=new Bitmap(400,200,PixelFormat32bppRGB);
    52.             posX=0;
    53.             //SetTimer(hWnd,mytimer,interval,NULL);
    54.             /*Graphics* g=Graphics::FromImage(bitmap);
    55.             Pen pen(Color::Red,1);
    56.             g->Clear(Color::Aquamarine);
    57.             g->DrawEllipse(&pen,30,50,100,30);*/
    58.         }
    59.         break;
    60.     case WM_PAINT:
    61.         {
    62.             HDC hdc=GetDC(hWnd);
    63.             Graphics g(hdc);
    64.             g.DrawImage(bitmap, 5,5);
    65.         }
    66.         break;
    67.     case WM_DESTROY:
    68.         PostQuitMessage(0);
    69.         break;
    70.     case WM_LBUTTONDOWN:
    71.         {
    72.             posX=0;
    73.             SetTimer(hWnd,mytimer,interval,(TIMERPROC)NULL);
    74.         }
    75.         break;
    76.     case WM_TIMER:
    77.         {
    78.             OutputDebugString("-");
    79.             if(posX<200)
    80.                 posX++;
    81.             else
    82.                 posX=0;
    83.             Graphics* g=Graphics::FromImage(bitmap);
    84.             Pen pen(Color::Red,1);
    85.             g->Clear(Color::Aquamarine);
    86.             g->DrawEllipse(&pen,posX,50,100,30);
    87.             RedrawWindow(hWnd, NULL, NULL, RDW_INVALIDATE);
    88.             return 0;
    89.         }
    90.         break;
    91.     default:
    92.         return DefWindowProc(hWnd, msg, wParam, lParam);
    93.     }
    94.     return 0;
    95. }
    mình muốn có hiệu ứng khi click chuột thì một hình elip di chuyển từ trái sang phải rồi quay về bên trái rồi lại chạy tiếp
    không hiểu sao cái WM_TIMER không xảy ra
    trong một chương trình khác của mình cái WM_TIMER xảy ra như hình ảnh không được cập nhật
    mình yêu cầu phải sử dụng cái Bitmap* bitmap
    nhờ các cao thủ chỉ giáo thêm

  2. #2
    Ngày gia nhập
    02 2014
    Nơi ở
    TP.HCM
    Bài viết
    814

    Logic chương trình bạn thì mình chưa bàn tới, còn cái sai cơ bản của bạn là :
    _ Khi xử lý WM_PAINT ta phải dùng cặp hàm : BeginPaint và EndPaint, Cặp hàm này làm cho vùng Client được hợp lệ trở lại. Về nguyên lý khi một vùng màn hình chưa hợp lệ thì Windows sẽ gởi 1 WM_PAINT tới thủ tục cửa sổ mà đang chứa vùng màn hình đó, do đó nếu bạn dùng cặp hàm khác như mã trên, khi ra khỏi thủ tục cửa sổ thì phần màn hình đó vẫn chưa hợp lệ, Windows lại tiếp tục gởi WM_PAINT khác tới thủ tục cửa sổ - vòng lặp vô tận xảy ra. Và như bạn thấy, cửa sổ bị treo trong vòng lặp đó.

    _ Nếu không dùng cặp hàm trên thì ta phải cho vùng màn hình hợp lệ bằng đường vòng như dùng hàm ValidateRect chẳng hạn.
    _ Cũng cần ghi nhớ muốn vẽ trong khi xử lý các thông điệp khác thì ta lại không dùng BeginPaint và EndPaint mà nên dùng như GetDC-ReleaseDC hay CreateDC-DeleteDC...

    Trước mắt, để không bị treo, bạn nên thay đổi như sau
    C++ Code:
    1.     case WM_PAINT:
    2.     {
    3.         PAINTSTRUCT     ps;
    4.         HDC hdc = BeginPaint(hWnd, &ps);
    5.         Graphics g(hdc);
    6.         g.DrawImage(bitmap, 5, 5);
    7.         EndPaint(hWnd, &ps);
    8.     }
    9.     break;

  3. #3
    Ngày gia nhập
    12 2015
    Nơi ở
    Đà Nẵng
    Bài viết
    350

    Trích dẫn Nguyên bản được gửi bởi MHoang Xem bài viết
    Logic chương trình bạn thì mình chưa bàn tới, còn cái sai cơ bản của bạn là :
    _ Khi xử lý WM_PAINT ta phải dùng cặp hàm : BeginPaint và EndPaint, Cặp hàm này làm cho vùng Client được hợp lệ trở lại. Về nguyên lý khi một vùng màn hình chưa hợp lệ thì Windows sẽ gởi 1 WM_PAINT tới thủ tục cửa sổ mà đang chứa vùng màn hình đó, do đó nếu bạn dùng cặp hàm khác như mã trên, khi ra khỏi thủ tục cửa sổ thì phần màn hình đó vẫn chưa hợp lệ, Windows lại tiếp tục gởi WM_PAINT khác tới thủ tục cửa sổ - vòng lặp vô tận xảy ra. Và như bạn thấy, cửa sổ bị treo trong vòng lặp đó.

    _ Nếu không dùng cặp hàm trên thì ta phải cho vùng màn hình hợp lệ bằng đường vòng như dùng hàm ValidateRect chẳng hạn.
    _ Cũng cần ghi nhớ muốn vẽ trong khi xử lý các thông điệp khác thì ta lại không dùng BeginPaint và EndPaint mà nên dùng như GetDC-ReleaseDC hay CreateDC-DeleteDC...

    Trước mắt, để không bị treo, bạn nên thay đổi như sau
    C++ Code:
    1.     case WM_PAINT:
    2.     {
    3.         PAINTSTRUCT     ps;
    4.         HDC hdc = BeginPaint(hWnd, &ps);
    5.         Graphics g(hdc);
    6.         g.DrawImage(bitmap, 5, 5);
    7.         EndPaint(hWnd, &ps);
    8.     }
    9.     break;
    Rõ rồi , cái thông điệp WM_TIMER không chạy hóa ra là do bị treo
    còn cái vẽ không được để thử lại đã
    Tom Hanks

    - - - Nội dung đã được cập nhật ngày 26-07-2017 lúc 08:31 PM - - -

    Đã vẽ hình được theo mong muốn

Tags của đề tài này

Quyền hạn của bạn

  • Bạn không thể gửi đề tài mới
  • Bạn không thể gửi bài trả lời
  • Bạn không thể gửi các đính kèm
  • Bạn không thể chỉnh sửa bài viết của bạn