PureBasic - форум

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » PureBasic - форум » Вопросы по PureBasic » Графический Progress Bar на WINAPI


Графический Progress Bar на WINAPI

Сообщений 1 страница 9 из 9

1

Всем здравствуйте.
Я нарисовал свой прогресс, на котором помимо шкалы отображаются проценты. При чём, текст с процентами меняет цвет при наползании на него шкалы. В этом фишка, мне это нравится, я доволен.
Но есть проблема. На пурике реализовать это получилось достаточно просто встроенными функциями.
Но мне нужно на С++. И дело не в самом конвертировании как такового кода в си, с этим проблем нет.
Дело в самой графике. Т.е., это дело нужно отрисовать на WINAPI.
И тут у меня большая проблема, я никак не могу вникнуть. Может кто разбирается в WINAPI - рисовании и поможет? Не на с++, на пурике, но что бы через WINAPI.

Код:
EnableExplicit

Enumeration
  #MAIN_WIN
  #G_IMG_1
  #IMG_PR_1
  #IMG_PR_2
  #IMG_PR_GR
  #PER_FONT
  #TIMER_1
EndEnumeration

#PR_BKG_CL=$FFFFFF; цвет фона прогресса (белый)
#PR_FRT_CL=$0000FF; цвет заливки прогресса
#PR_TXT_BKG=0; цвет текста на фоне
#PR_TXT_FRT=$FFFFFF; цвет текста на заливке
#PR_FONT_NAME$="Courier"; шрифт
#PR_FONT_SIZE=12; размер шрифта
#PR_FONT_FLAGS=0;#PB_Font_Bold

#PR_X=120; координаты и размеры прогресса
#PR_Y=80
#PR_WIDTH=150
#PR_HEIGHT=30

#COUNTER_FR=100; скорость счётчика
#TIMER_FR=25; частота проверки счётчика и обновления прогресса
#PERCENT_FR=1; выводить (показывать) проценты кратно этому значению

Global GL_COUNTER_1=0
Define event, ex_res, mutex_1, thread_1

Macro macro_errorend (val_a, val_b)
  ex_res=creat_img_progress (val_a, val_b)
  If ex_res
    MessageRequester("ERROR", "Errorcode: "+Str(ex_res), #PB_MessageRequester_Ok)
    End
  EndIf
EndMacro

Procedure th_counter (mutex)
  Repeat
    LockMutex(Mutex)
    If GL_COUNTER_1=100
;      GL_COUNTER_1=0; обнулить счётчик
    Else
      GL_COUNTER_1+1
    EndIf
    UnlockMutex(Mutex)
    Delay (#COUNTER_FR)
  ForEver
EndProcedure

Procedure creat_img_progress (pr_percent, text_out$)
  Protected w, h, p.f
  p=#PR_WIDTH/100*pr_percent
  pr_percent=p
  If Not IsGadget (#G_IMG_1)
    If Not CreateImage(#IMG_PR_1, #PR_WIDTH, #PR_HEIGHT)
      ProcedureReturn 11
    EndIf
    If Not CreateImage(#IMG_PR_2, #PR_WIDTH, #PR_HEIGHT)
      ProcedureReturn 12    
    EndIf
    If Not ImageGadget(#G_IMG_1, #PR_X, #PR_Y, #PR_WIDTH, #PR_HEIGHT, ImageID(#IMG_PR_1));, #PB_Image_Border)
      ProcedureReturn 13
    EndIf
  EndIf

  If Not StartDrawing(ImageOutput(#IMG_PR_1))
    ProcedureReturn 21
  EndIf
  DrawingFont(FontID(#PER_FONT)) 
  w=TextWidth(text_out$); вычислить длину текста
  h=TextHeight(text_out$);вычислить высоту текста
  DrawingMode(#PB_2DDrawing_Transparent)
  Box(0, 0, #PR_WIDTH, #PR_HEIGHT, #PR_FRT_CL)
  DrawText(#PR_WIDTH/2-w/2, #PR_HEIGHT/2-h/2, text_out$, #PR_TXT_FRT)
  StopDrawing()
  If Not StartDrawing(ImageOutput(#IMG_PR_2))
    ProcedureReturn 22
  EndIf
  DrawingMode(#PB_2DDrawing_Transparent)
  DrawingFont(FontID(#PER_FONT)) 
  Box(0, 0, #PR_WIDTH, #PR_HEIGHT, #PR_BKG_CL)
  DrawText(#PR_WIDTH/2-w/2, #PR_HEIGHT/2-h/2, text_out$, #PR_TXT_BKG)
  If GrabImage (#IMG_PR_1, #IMG_PR_GR, 0, 0, pr_percent, #PR_HEIGHT)
    DrawImage (ImageID (#IMG_PR_GR), 0, 0)
  EndIf
  StopDrawing() 
  SetGadgetState (#G_IMG_1, ImageID (#IMG_PR_2))
  ProcedureReturn 0
EndProcedure

Procedure WinCallback(hWnd, uMsg, wParam, lParam) 
  Static old_percent_val=0
  Protected ex_res, hdc, hbr
  Protected ps.PAINTSTRUCT, rec.RECT

  Select uMsg
    Case #WM_PAINT
      hdc=BeginPaint_(hWnd, @ps);обведём рамкой прогресс средствами WINAPI

      rec\left=#PR_X-1
      rec\top=#PR_Y-1
      rec\right=#PR_X+#PR_WIDTH+2
      rec\bottom=#PR_Y+#PR_HEIGHT+2
      hbr=CreateSolidBrush_(RGB(0, 128, 128))
      FrameRect_(hdc, @rec, hbr);

      rec\left=#PR_X-2
      rec\top=#PR_Y-2
      rec\right=#PR_X+#PR_WIDTH+1
      rec\bottom=#PR_Y+#PR_HEIGHT+1
      hbr=CreateSolidBrush_(RGB(0, 0, 0))
      FrameRect_(hdc, @rec, hbr);

	  	ValidateRect_(hWnd, #Null);
      EndPaint_(hWnd, @ps);
      DeleteObject_(hbr)

    Case #WM_TIMER;
      Select wParam 
        Case #TIMER_1; проверим изменение счётчика и обновим прогресс если требуется
          If GL_COUNTER_1<>old_percent_val
            If Not GL_COUNTER_1%#PERCENT_FR Or GL_COUNTER_1=100
              macro_errorend (GL_COUNTER_1, Str(GL_COUNTER_1)+"%")
            EndIf
            old_percent_val=GL_COUNTER_1
          EndIf
      EndSelect 
  EndSelect
  ProcedureReturn #PB_ProcessPureBasicEvents 
EndProcedure

If OpenWindow(#MAIN_WIN, 0, 0, 400, 200, "2DDrawing Example", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  SetWindowCallback(@WinCallback())
  AddWindowTimer(#MAIN_WIN, #TIMER_1, #TIMER_FR)
  mutex_1=CreateMutex()
  thread_1=CreateThread(@th_counter(), mutex_1); оздадим трид для счётчика
  LoadFont(#PER_FONT, #PR_FONT_NAME$, #PR_FONT_SIZE, #PR_FONT_FLAGS)
  macro_errorend (0, "0%")
  Repeat
    event = WaitWindowEvent()
  Until event = #PB_Event_CloseWindow
EndIf



0

2

Может, разобраться на сях  поможет это?
http://abreojosensamblador.epizy.com/?T … =0&i=1

0

3

Например так, но с наложением текста надо подумать.

Код:
#include <windows.h>

#define cdXPos          128
#define cdYPos          128
#define cdXSize         320
#define cdYSize         200
#define cdColFondo      0        // COLOR_BTNFACE + 1
#define cdVBarTipo      0
#define cdVBtnTipo      WS_VISIBLE+WS_OVERLAPPEDWINDOW
#define cdMainIcon      100

// Prototipos de funciones
static LRESULT WINAPI MainWndProc(HWND, UINT, WPARAM, LPARAM);

// Variables globales
char             *szClaseName = TEXT ("ClaseTextoVentana") ;
char             *szTitle = TEXT ("Texto en nuestra ventana") ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     HWND         hWnd ;
     MSG          msg ;
     WNDCLASS     wndclass ;
     
     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = (WNDPROC) MainWndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject(LTGRAY_BRUSH);
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szClaseName ;
     wndclass.hInstance     = hInstance; //GetModuleHandle (NULL) ;
     wndclass.hIcon         = LoadIcon(hInstance, (LPCTSTR) cdMainIcon);
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     
     if (!RegisterClass (&wndclass)) {
          MessageBox (NULL, TEXT ("This program requires Windows NT!"),
                      TEXT ("Error"), MB_ICONERROR) ;
          return 0 ;
     }
     
     hWnd = CreateWindow (szClaseName,
                          szTitle,
                          cdVBtnTipo,
                          cdXPos, cdYPos,
                          cdXSize, cdYSize,
                          NULL, NULL, hInstance, NULL) ;
     if (!hWnd) return FALSE;

     ShowWindow (hWnd, iCmdShow) ;
     UpdateWindow (hWnd) ;
     
     while (GetMessage (&msg, NULL, 0, 0)) {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
     }
     return msg.wParam ;
}
  
static LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
   HDC            hdc;
   PAINTSTRUCT    ps;
   RECT           rct;
   COLORREF       clrold;
   
   switch (message) {
     default:
          return DefWindowProc(hWnd, message, wParam, lParam);
     case WM_PAINT :
          hdc = BeginPaint (hWnd, &ps);//начало рисования

//Задать размеры прямоугольника
          rct.left=0;
          rct.top=0;
          rct.right=320;
          rct.bottom=100;


          int bk=SetBkMode(hdc,TRANSPARENT);//для рисования текста позрачный фон
          HBRUSH hb=CreateSolidBrush(RGB(0,0,255));//Создать кисть синего цвета для рисования прямоугольника
          SelectObject(hdc,hb);
          SelectObject(hdc,GetStockObject(NULL_PEN));//для прямоугольника "пустое" перо
    Rectangle(hdc,0,0,160,100);//нарисовать часть прямоугольника синего цвета
          DeleteObject(hb);//удалить созданную кисть
//теперь для белого
          hb=CreateSolidBrush(RGB(255,255,255));
          SelectObject(hdc,hb);
          SelectObject(hdc,GetStockObject(NULL_PEN));
    Rectangle(hdc,160,0,320,100);
          DeleteObject(hb);
//нарисовать текст
          DrawText (hdc, szTitle, -1, &rct, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
          EndPaint (hWnd, &ps);//завершение работы
          
          break ;
     case WM_DESTROY :
          DestroyWindow (hWnd);
          PostQuitMessage(0);
          break ;
   }
   return 0 ;
}

0

4

egons, так в тексте и дело.
Если не заморачиваться с цветом текста (оставить его просто чёрным, например), то и не нужно заморачиваться с рисованием, достаточно на штатный прогресс сверху поместить статик-контрол с текстом и с прозрачным фоном, сделав его дочерним от прогресс-контрола. И всё отлично работает.
А мне хочется именно так, что бы цвет текста при заливке прогресса так же плавно превращался в белый, например.
Как я сделал в пурике.
1. Создал два изображения шириной и высотой равной желаемому размеру прогресса.
2. Первое изображение полностью закрасил заливкой прогресс бара желаемого цвета. В центре нарисовал текст белым цветом. Текст - это процент, соответствующий статусу прогресса.
3. Второе изображение закрасил белым, как при пустом прогрессе. В центре отрисовал текст чёрным цветом.
4. Во второе изображение помещаем копию первого, но только нужной длины, соответствующей статусу прогресса.
5. Вывожу на экран через ImageGadget.
6. Снова к пункту 2, если меняется значение счётчика, что бы отрисовать новый статус в прогессе.
В пурике оказалось всё очень просто.
Но от WINAPI пока голова пухнет...

0

5

Timon написал(а):

egons, так в тексте и дело.

Есть такая функция - SetROP2. но я не сталкивался, и не знаю как использовать.

Если соответствовать стилю, то я бы создал два битмапа(CreateCompatibleBitmap), на первом рисовал прямоугольники, на втором на черном фоне нарисовал текст.
Потом копировал изображения с помощью Bitblt: первую картинку с кодом операции SRCCOPY, вторую - с SRCINVERT.
Только с цветами надо думать, как их использовать.

Отредактировано egons (16.04.2024 19:43:47)

0

6

Timon написал(а):

текст с процентами меняет цвет при наползании на него шкалы.

Timon написал(а):

это дело нужно отрисовать на WINAPI.

Посмотрите процедуру DrawProgressBar_ListIconGadget() в файле Controls_CB.pbi http://pbtorrent.ucoz.ru/pbsc/Source_pbTorrent_1_2.zip

0

7

Timon
У меня в проге ChkDskGui есть файл ListProgress.pb, посмотри, он вроде весь на WinAPI. Не помню где взял его, может на старом форуме там было вроде 2 примера от Петра, один без меняющегося цвета, другой с меняющимся. Помню что много там переделывал, так как надо было имитировать заполненность дисков, края кайму сделать.

0

8

Спасибо, будем посмотреть.

0

9

Всё оказалось достаточно просто, нужно было, как и всегда, пораскинуть мозгами.
Теперь можно творить всё что угодно с этим прогрессом. И вставлять куда угодно.
Сделал пока на пурике, завтра если время будет на с++ переведу.

Всем большое спасибо за участие и пинки в нужных направлениях!

0


Вы здесь » PureBasic - форум » Вопросы по PureBasic » Графический Progress Bar на WINAPI