쉬운 예로 윈도우 XP, Vista가 부팅될 때 지렁이가 지나가는 그런 프로그래스바죠.
Win32 공용컨트롤 6.0 에는 그런 마퀴 형태의 프로그래바를 지원하는데 MFC 의 CProgressCtrl에서는 그런 마퀴 관련 API가 노출되어 있지 않습니다.
실제로 프로그래스바 공용 컨트롤이 어떻게 구현되어 있는지 wine 을 통해 살펴봅시다.
아래의 소스는 wine 에 구현되어 있는 progress common control 의 일부입니다.
338 static LRESULT PROGRESS_Draw (PROGRESS_INFO *infoPtr, HDC hdc)
339 {
340 int barSize;
341 DWORD dwStyle;
342 BOOL barSmooth;
343 const ProgressDrawProc* drawProcs;
344 ProgressDrawInfo pdi;
345
346 TRACE("(infoPtr=%p, hdc=%p)\n", infoPtr, hdc);
347
348 pdi.hdc = hdc;
349 //pdi.theme = GetWindowTheme (infoPtr->Self);
350 pdi.theme = infoPtr->hTheme;
351
352 /* get the required bar brush */
353 if (infoPtr->ColorBar == CLR_DEFAULT)
354 pdi.hbrBar = GetSysColorBrush(COLOR_HIGHLIGHT);
355 else
356 pdi.hbrBar = CreateSolidBrush (infoPtr->ColorBar);
357
358 if (infoPtr->ColorBk == CLR_DEFAULT)
359 pdi.hbrBk = GetSysColorBrush(COLOR_3DFACE);
360 else
361 pdi.hbrBk = CreateSolidBrush(infoPtr->ColorBk);
362
363 /* get the window style */
364 dwStyle = GetWindowLongW (infoPtr->Self, GWL_STYLE);
365
366 /* get client rectangle */
367 GetClientRect (infoPtr->Self, &pdi.rect);
368 if (!pdi.theme) {
369 FrameRect( hdc, &pdi.rect, pdi.hbrBk );
370 InflateRect(&pdi.rect, -1, -1);
371 }
372 else
373 {
374 RECT cntRect;
375 int part = (dwStyle & PBS_VERTICAL) ? PP_BARVERT : PP_BAR;
376
377 GetThemeBackgroundContentRect (pdi.theme, hdc, part, 0, &pdi.rect,
378 &cntRect);
379
380 /* Exclude content rect - content background will be drawn later */
381 ExcludeClipRect (hdc, cntRect.left, cntRect.top,
382 cntRect.right, cntRect.bottom);
383 if (IsThemeBackgroundPartiallyTransparent (pdi.theme, part, 0))
384 DrawThemeParentBackground (infoPtr->Self, hdc, NULL);
385 DrawThemeBackground (pdi.theme, hdc, part, 0, &pdi.rect, NULL);
386 SelectClipRgn (hdc, NULL);
387 CopyRect (&pdi.rect, &cntRect);
388 }
389
390 /* compute some drawing parameters */
391 barSmooth = (dwStyle & PBS_SMOOTH) && !pdi.theme;
392 drawProcs = &((pdi.theme ? drawProcThemed : drawProcClassic)[(barSmooth ? 0 : 4)
393 + ((dwStyle & PBS_VERTICAL) ? 2 : 0)]);
394 barSize = get_bar_size( dwStyle, &pdi.rect );
395 if (pdi.theme)
396 {
397 GetWindowRect( infoPtr->Self, &pdi.bgRect );
398 ScreenToClient( infoPtr->Self, (POINT*)&pdi.bgRect );
399 ScreenToClient( infoPtr->Self, (POINT*)&pdi.bgRect.right );
400 }
401
402 if (!barSmooth)
403 pdi.ledW = get_led_size( infoPtr, dwStyle, &pdi.rect);
404 pdi.ledGap = get_led_gap( infoPtr );
405
406
407
408 if (dwStyle & PBS_MARQUEE)
409 {
410 const int ledW = !barSmooth ? (pdi.ledW + pdi.ledGap) : 1;
411 const int leds = (barSize + ledW - 1) / ledW;
412 const int ledMEnd = infoPtr->MarqueePos + MARQUEE_LEDS;
413
414 if (ledMEnd > leds)
415 {
416 /* case 1: the marquee bar extends over the end and wraps around to
417 * the start */
418 const int gapStart = max((ledMEnd - leds) * ledW, 0);
419 const int gapEnd = min(infoPtr->MarqueePos * ledW, barSize);
420
421 drawProcs[0]( &pdi, 0, gapStart);
422 drawProcs[1]( &pdi, gapStart, gapEnd);
423 drawProcs[0]( &pdi, gapEnd, barSize);
424 }
425 else
426 {
427 /* case 2: the marquee bar is between start and end */
428 const int barStart = infoPtr->MarqueePos * ledW;
429 const int barEnd = min (ledMEnd * ledW, barSize);
430
431 drawProcs[1]( &pdi, 0, barStart);
432 drawProcs[0]( &pdi, barStart, barEnd);
433 drawProcs[1]( &pdi, barEnd, barSize);
434 }
435 }
436 else
437 {
438 int barEnd = get_bar_position( infoPtr, dwStyle, &pdi.rect,
439 infoPtr->CurVal);
440 if (!barSmooth)
441 {
442 const int ledW = pdi.ledW + pdi.ledGap;
443 barEnd = min (((barEnd + ledW - 1) / ledW) * ledW, barSize);
444 }
445 drawProcs[0]( &pdi, 0, barEnd);
446 drawProcs[1]( &pdi, barEnd, barSize);
447 }
448
449 /* delete bar brush */
450 if (infoPtr->ColorBar != CLR_DEFAULT) DeleteObject (pdi.hbrBar);
451 if (infoPtr->ColorBk != CLR_DEFAULT) DeleteObject (pdi.hbrBk);
452
453 return 0;
위와 같이, 생각에는 6.0미만의 공용 컨트롤에는 저 마퀴관련한 스타일을 처리하는 부분이 없나봅니다.
이쯤에서 살펴볼 것이, MFC에서 마퀴 프로그래스바를 사용하는 2가지 방법입니다.
먼저 첫번째는 MFC로 프로그래스바를 만들되 마퀴가 나타나도록 하는 것입니다.
이것의 단점은 XP 이상의 OS에서만 구현이된다는 것입니다. 2000 같은 경우는 아무것도 하지않는 프로그래스바로 나오게 되죠.
110 const UINT PBS_MARQUEE = 0x08;
111 const UINT PBM_SETMARQUEE = (WM_USER+10);
112 HWND hWnd = GetDlgItem(IDC_PROG)->GetSafeHwnd();
113 LONG_PTR style = GetWindowLongPtr(hWnd, GWL_STYLE);
114 style |= PBS_MARQUEE;
115 SetWindowLongPtr(hWnd, GWL_STYLE, style);
116 ::SendMessage(hWnd,(UINT) PBM_SETMARQUEE,(WPARAM) TRUE,(LPARAM)50 );
실제 코드는 위와 같습니다. IDC_PROG 가 프로그래스 컨트롤이라면 저렇게만 해주면 마퀴의 형태를 가지게 됩니다. 다만 부드럽게 나타나지는 않습니다. ^^;
참, 말씀드렸다시피 저렇게 한 후, manifest 넣어야지 됩니다.
두번째로 살펴볼 것이, AVI 를 리소스로 사용하여 에니메이션 컨트롤로 구현하는 것입니다. 이것의 단점은 프로그래스바 에니메이션이 제작된 AVI의 크기가 fixed 된 것이기 때문에 크기를 바꿀 수 없다는 것이지요.
하지만 OS를 가리지 않고 부드럽게 잘 표현된다는 것이 장점입니다. 밑에 테스트 프로그램에서 사용된 프로그래스 바는 VS8의 리소스에서 추출한 AVI 입니다.