На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Обратите внимание:
1. Прежде чем начать новую тему или отправить сообщение, убедитесь, что вы не нарушаете правил форума!
2. Обязательно воспользуйтесь поиском. Возможно, Ваш вопрос уже обсуждали. Полезные ссылки приведены ниже.
3. Темы с просьбой выполнить какую-либо работу за автора в этом разделе не обсуждаются.
4. Используйте теги [ code=cpp ] ...текст программы... [ /code ] для выделения текста программы подсветкой.
5. Помните, здесь телепатов нет. Старайтесь формулировать свой вопрос максимально грамотно и чётко: Как правильно задавать вопросы
6. Запрещено отвечать в темы месячной и более давности без веских на то причин.

Полезные ссылки:
user posted image FAQ Сайта (C++) user posted image FAQ Форума user posted image Наши Исходники user posted image Поиск по Разделу user posted image MSDN Library Online (Windows Driver Kit) user posted image Google

Ваше мнение о модераторах: user posted image B.V.
Модераторы: B.V.
  
> Мерцание дочернего EDIT , Показ процентов на прогресс контроле
    Просьба помочь избавиться от мерцания при перерисовке дочернего контрола вывода процентов на прогресс-баре.
    Если скорость прогресса не высока (THREAD_PAUSE>40), то мерцаний не видно. А если меньше, например, 10 как выставлено в примере, то выглядит не очень симпатично.



    ExpandedWrap disabled
      #include <tchar.h>
      #include <windows.h>
      #include <commctrl.h>
      #include <sstream>
      #include <string>
      //#include <stdio.h>
      //#include <richedit.h>
       
      #define TIMER_PAUSE 5           // пауза таймера - как часто проверять значение счётчика
      #define THREADS_NUMBER 1        // кол-во одновременно запущенных тридов, тут не нужно
      #define ITERATIONS_NUMBER 101   //сколько раз выполнить трид, должно быть 100 (%), сейчас специально выставлено 101
      #define THREAD_PAUSE 10         // пауза в триде - скорость счётчика
      #define PROGRESS_MAX 100        //
      #define EXIT_ERR(mess)  {MessageBox(NULL, TEXT(mess), TEXT("Error"), MB_OK); return 0;}// выход из программы при ошибке
       
      const enum
      {
          ID_PROGRESS_1=100,
          ID_EDIT_1,
          ID_TIMER_1
      };
       
      DWORD GL_COUNTER=0;//счётчик
          
      LRESULT APIENTRY WndProc(HWND, UINT, WPARAM, LPARAM);
      LRESULT APIENTRY EditSubclassProc(HWND, UINT, WPARAM, LPARAM);
      template <typename T> std::string to_string (const T &x);// INT, указатель в STRING
      DWORD WINAPI ThreadProc(CONST LPVOID);
       
      int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
       
      {
          HWND hMainWnd;
          HANDLE hThreads[THREADS_NUMBER];
          CONST HANDLE hMutex = CreateMutex(NULL, FALSE, NULL);
          TCHAR szClassName[] = TEXT("MyClass");
          MSG msg;
          WNDCLASSEX wc;
       
          wc.cbSize       =sizeof(wc);
          wc.style        =CS_HREDRAW | CS_VREDRAW;
          wc.lpfnWndProc  =WndProc;
          wc.cbClsExtra   =0;
          wc.cbWndExtra   =0;
          wc.hInstance    =hInstance;
          wc.hIcon        =LoadIcon(NULL, IDI_APPLICATION);
          wc.hCursor      =LoadCursor(NULL, IDC_ARROW);
          wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
          wc.lpszMenuName =NULL;
          wc.lpszClassName=szClassName;
          wc.hIconSm      =LoadIcon(NULL, IDI_APPLICATION);
       
          if (!RegisterClassEx(&wc)) EXIT_ERR("Cannot register the class")
          hMainWnd = CreateWindow(szClassName, TEXT("Application"), WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX, 0, 0, 700, 500, (HWND)NULL, (HMENU)NULL, (HINSTANCE)hInstance, NULL);
          if (!hMainWnd) EXIT_ERR("Cannot creat the Main Win")
          ShowWindow(hMainWnd, nCmdShow);
          if (!SetTimer(hMainWnd, ID_TIMER_1, TIMER_PAUSE, (TIMERPROC) NULL)) EXIT_ERR("Cannot creat the Timer")
          hThreads[0]=CreateThread(NULL, 0, &ThreadProc, hMutex, 0, NULL);
          if (!hThreads[0]) EXIT_ERR("Cannot creat the Thread")
       
          while (GetMessage(&msg, NULL, 0, 0))
          {
              TranslateMessage(&msg);
              DispatchMessage(&msg);
          }
          CloseHandle(hThreads[0]);
          CloseHandle(hMutex);
          return msg.wParam;
      }
       
      LRESULT APIENTRY WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
      {
          static HWND hWndEdit, hProgBar;
       
          switch (msg)
          {
              case WM_CREATE:
                  // прогресс
                  hProgBar=CreateWindowEx(0, PROGRESS_CLASS, NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | PBS_SMOOTH, 60, 40, 140, 40, hWnd, (HMENU)ID_PROGRESS_1, NULL, NULL);
                  SendMessage(hProgBar, PBM_SETRANGE, 0, (LPARAM)MAKELONG(0, PROGRESS_MAX));// мин и макс
                  SendMessage(hProgBar, PBM_SETSTEP, (WPARAM)1, 0);// шаг - по умолчанию 10
                  SendMessage(hProgBar, PBM_SETBARCOLOR, 0, (LPARAM)RGB(0, 255, 0));
                  SendMessage(hProgBar, PBM_SETBKCOLOR, 0, (LPARAM)RGB(255,255,255));
                  // дочерний от прогресса контрол для показа процентов
                  hWndEdit=CreateWindow(TEXT("EDIT"), TEXT(""), WS_VISIBLE | WS_CHILD| ES_READONLY | SS_CENTER, 50, 10, 40, 20, hProgBar, (HMENU)ID_EDIT_1, (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE)/*зачем это?*/, NULL);
                  SetWindowLongPtr(hProgBar, GWL_USERDATA, SetWindowLongPtr(hProgBar, GWL_WNDPROC, (LPARAM)EditSubclassProc));// вешаем новый обработчик и одновременно запоминаем адрес первого (вносим в DATA)
                  break;
              case WM_TIMER:
                  switch (wParam)
                  {
                      case ID_TIMER_1:
                      if (SendMessage(hProgBar, PBM_GETPOS, 0, 0)!=GL_COUNTER)
                      {
                          SendMessage(hProgBar, PBM_SETPOS, GL_COUNTER, 0);
                          SetWindowText(hWndEdit, (to_string(GL_COUNTER)+"%").c_str());
                      }
                      return 0;
                  }
                  break;
              case WM_CHAR:
                  switch (LOWORD(wParam))
                  {
                      if (wParam == 13)
                      {
                          MessageBox(hWnd,(to_string(hWnd)+" : ").c_str(),TEXT("MessageBox"),MB_OK);
                          return 0;
                      }
                  }
                  break;
              case WM_CLOSE:
                  DestroyWindow(hWnd);
                  break;
              case WM_DESTROY:
                  SetWindowLongPtr(hWndEdit,GWLP_WNDPROC,(LPARAM)GetWindowLongPtr(hWndEdit,GWLP_WNDPROC));
                  PostQuitMessage(0);
                  break;
              default:
                  return DefWindowProc(hWnd, msg, wParam, lParam);
          }
          return DefWindowProc(hWnd, msg, wParam, lParam);
      }
       
      LRESULT APIENTRY EditSubclassProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
      {// обработчик событий №2- контрол прогресс бара на которм дочерний EDIT с процентами
          switch(msg)
          {
              case WM_COMMAND:// перерисовать EDIT что бы текст с процентами отрисовывался правильно
                  if(HIWORD(wParam)==EN_CHANGE)//(иначе на прозрачном фоне бардак)
                  {
                      RECT rect;//
                      GetClientRect(HWND(lParam), &rect);
                      InvalidateRect(HWND(lParam), &rect, TRUE);
                      MapWindowPoints(HWND(lParam), hWnd, (POINT *) &rect, 2);
                      RedrawWindow(hWnd, &rect, NULL, RDW_ERASE | RDW_INVALIDATE);//*/
      //              ShowWindow(HWND(lParam),SW_HIDE);// можно сделать проще всего двумя стироками
      //              ShowWindow(HWND(lParam),SW_SHOW);// но так мерцает вроде сильнее
                  }
                  break;
              case WM_CTLCOLORSTATIC:
                  SetBkMode((HDC)wParam, TRANSPARENT);// это делает фон под шрифтом прозрачным
      //          return (LRESULT)CreateSolidBrush(RGB(255, 255, 255));// это устанавлмвает цвет полностью фона
                  return (LRESULT)GetStockObject(NULL_BRUSH);// это делает фон прозрачным
          }
      //  PostMessage(GetParent(GetParent(hWnd)), msg, wParam, lParam);
          return CallWindowProc((WNDPROC)GetWindowLongPtr(hWnd, GWL_USERDATA), hWnd, msg, wParam, lParam);
      }
      template <typename T>
      std::string to_string(const T &x)
      {
          std::stringstream buf;
          buf << x;
          return buf.str();
      }
      DWORD WINAPI ThreadProc(CONST LPVOID lpParam)
      {
          const HANDLE hMutex = (CONST HANDLE)lpParam;
          DWORD i;
          for(i = 0; i < ITERATIONS_NUMBER; i++)
          {
              WaitForSingleObject(hMutex, INFINITE);
              GL_COUNTER++;
              ReleaseMutex(hMutex);
              Sleep(THREAD_PAUSE);
          }
          ExitThread(0);
      }
      Скорее просто уменьшите количество обновлений в таймере (TIMER_PAUSE = 100 // 1000 / 100 = 10 раз в секунду). Этого вполне достаточно. Не надо обновлять компоненты слишком часто (все равно кадров у монитора 50 - 100). У вас же перерисовывается 200 раз (TIMER_PAUSE = 5 // 1000 / 5 = 200).
        macomics, да, вы правы.
        Только при обновлении в 100 мс и при высокой скорости прогресса его движение получается не очень плавным. А вот при 50 нормально. И мерцание пропало полностью. По крайней мере на моём компе.
        Спасибо!
          Timon K, я бы попытался сделать другое.
          Использовал бы PostMessage для изменения прогресса.
          Не стал бы читать прогресс. И пользоваться таймером.
          ---
          Можно при изменении счётчика считать процент (запоминая предыдущий).
          При значимом изменении процента слать сообщение эдиту прямо
          из ThreadProc.
            ЫукпШ, а безопасно управлять контролами напрямую из другого потока?
              Посредством сообщений - да.
              Точно помню, что прогрессом из рабочего
              потока я управлял.
              ---
              Вот сейчас (на всякий случай) попробовал - в Эдит
              из другого потока выводится строка посредством SendMessage.
              Устойчиво работает.
              Сообщение отредактировано: ЫукпШ -
                Мерцание вызвано частыми перерисовками. Лечится не только уменьшением частоты обновлений, но и применением двойной буферизации. Системная двойная буферизация включается стилем WS_EX_COMPOSITED для родительского окна, должно помочь
                  Да, отлично, спасибо всем!
                  От мерцания избавились.
                  А как сделать так, что бы цвет текста тоже менялся (например, на белый) при наползании на него заливки прогресса?
                    Например, рисовать заливку самостоятельно используя xor.
                      Цитата macomics @
                      Например, рисовать заливку самостоятельно используя xor.

                      Сделал так.
                      При событии PAINT:
                      1. Залил прямоугольник в желаемом месте и под желаемый размер заливкой пустого прогресс (белый)
                      2. Нарисовал посередине текст (статус прогресса в процентах) цветом для пустого прогресса (чёрный), с прозрачным фоном. Предварительно задал желаемый шрифт и вычислил длину текущего текста в пикселях.
                      3. Залил прямоугольник на тех же начальных координатах, той жы высоты, но ширина = статусу прогресса заливкой прогресса (например, красным).
                      4. Нарисовал текст с теми же координатами, что и в пункте 2, только такой длины, что бы текст обрывался там, где кончается заливка - текущий статус прогресса. Цвет шрифта белый с прозрачным фоном. При этом, если заливка ещё не наползла на показ процентов, то длина текста = 0 и он не затирает уже имеющийся чёрный.
                      При событии TIMER:
                      1. Проверяю, не изменился ли счётчик (глобальная переменная, менять может, например, трид в котором функция работы с устройством через USB).
                      2. Если изменился, нужно перерисовать, вызываю InvalidateRect, который снова посылает сообщение PAINT. Прогресс меняет статус.

                      Вроде пока нормально работает отдельным приложением, но в теле своего проекта ещё не проверял.
                        Цитата Timon K @
                        А как сделать так, что бы цвет текста тоже менялся (например, на белый) при наползании на него заливки прогресса?

                        Рисуем в памяти две копии прогресс-бара.
                        Не залитую и 100% залитую системной заливкой.
                        В оба образа выводим одну и ту же цифру процента
                        по одинаковым координатам, но своего цвета.
                        Вычисляем процент выполнения в пикселах и копируем
                        этот процент залитого образа в окно. Остальное
                        копируем из не залитого.
                        ---
                        По моему это не удобно.
                        Лучше поверх прогресс-бара вывести маленькое окно
                        и туда выводить цифры.
                        Вот так:
                        user posted image
                        Сообщение отредактировано: ЫукпШ -
                          ЫукпШ, так в том теперь и фишка, что я хочу сделать со сменой цвета.
                          Вот так у меня получилось.


                          Прикреплённая картинка
                          Прикреплённая картинка

                          Прикреплённая картинка
                          Прикреплённая картинка
                          Сообщение отредактировано: Timon K -
                            При желании можно и рамку сделать с закругленными краями и заливку с градиентом. Это уже при наличии времени поэкспериментировать.
                            Прикреплённая картинка
                            Прикреплённая картинка

                            Прикреплённая картинка
                            Прикреплённая картинка
                            0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                            0 пользователей:


                            Рейтинг@Mail.ru
                            [ Script execution time: 0,0397 ]   [ 20 queries used ]   [ Generated: 3.05.24, 19:23 GMT ]