Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Перерисовка методами Invalidate и ShowWindow  (Прочитано 23714 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Tuborg
Команда клуба

ee
Offline Offline

« : 13-06-2007 13:11 » 

Есть некая программа загружающая из файла числа и выводящая их на график на окне программы.

Вариант первый. Окно программы описано неким классом Win_CCDlg наследованного от CDialog. Нрафик выводится в стандартный контрол Rectangle. Всё работает на ура, Invalidate вызываемый при чтении файла нормально вызывает отрисовку Win_CCDlg.

Вариант второй. Окно программы описано другим классом СPageControl, наследованного от CDialog. В CPageControl содержится объект - стандартный контрол CTabCtrl c несколькими страницами описываемыми классом Win_CCDlg и наследованного через CTabSheet::CDialog.

Т.е. главная форма CPageControl на ней CTabCtrl на ней СTabSheet на ней CDialog

Теперь о трудностях. во втором варианте вызов Invalidate хоть и обращается нормально к Win_CCDlg::OnPaint но посуществу отрисовки не происходит... картинка просто статически замирает. Rectangle хоть внутри программы и перерисовывается но на самой форме этого не видно. Если пощёлкаю страничками CTabCtrl'a то на каждое перелистывание на Rectangle всё таки происходит перерисовка... или скажем я возьму форму и потаская по экрану таким образом что Rectangle уйдёт за область экрана, а потом вернётся....

В поисках решения заменил в месте где читается файл вызов функции Win_CCDlg::Invalidate() на парочку Win_CCDlg::ShowWindow(SW_HIDE) и Win_CCDlg::ShowWindow(SW_SHOW).... Всё стало перерисовываться как надо (в смысле на каждое прочтение из файла порции данных) но очень уж мелькает всё.

Вопрос: Как сделать так чтобы Invalidate и OnPaint не только работали с перерисовкой внутренних структур окон, но и ещё чтобы результат стал виден? И почему когда один CDialog всё тоже самое работает нормально?
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #1 : 14-06-2007 03:33 » 

Tuborg,
вызови для окна, которое нужно перерисовать,
   Invalidate(0);//пометка прямоугольника окна как невалидного
   UpdateWindow();//прямой вызов оконной процедуры с сообщением WM_PAINT

если не поможет, то код OnPaint() окна-пациента - в студию )
« Последнее редактирование: 14-06-2007 03:35 от Алексей1153++ » Записан

Tuborg
Команда клуба

ee
Offline Offline

« Ответ #2 : 14-06-2007 10:39 » 

Не помогает. OnPaint не меняю при переходе от простого CDialog к окну с вкладками.
Но пожалуй приведу пример OnPaint (тебе я его уже высылал кстати)

Цитата
void CWin_CCDlg::OnPaint()
{
   CDC     CMemDC1, CMemDC2, CMemDC3;
   CBitmap pBitmap1, pBitmap2, pBitmap3, *pOldBitmap;   
   
   if (IsIconic())   {... }
   else
   {
      
      CRect FrameRect;
      CWnd *pWnd1=this->GetDlgItem(IDC_GRAPH_FRAME1); // Прямоугольник1 типа Rectangle
      (Код для прямоугольника 2 и 3 удаляю так как всё также)
      
      if(graphComplete){ // Флаг который выставляется процедурой чтения данных из файла
                                                // после того как порция данных была преобразована в график во
                                                // внутренних структурах класса отвечающих за график
 
         CPaintDC dc1(pWnd1); // Берём DC от Прямоугольник1

         pWnd1->GetWindowRect(FrameRect);// Привожу координаты прямоугольника
         this->ScreenToClient(FrameRect);       // к координатам окна

         CMemDC1.CreateCompatibleDC(&dc1); // Создаю MemDC для способа быстрой перерисовки
                                                                                 // Буду рисовать на MemDC а потом поточечно копировать на DC прямоугольника 1

        if (CMemDC1) {
          //Делаю на DC битмап для рисования, а точнее чтоб потом проще было на реальный
                        //DC копировать
          pBitmap1.CreateCompatibleBitmap(&dc1, FrameRect.Width()-1, FrameRect.Height()-1);
          pOldBitmap = (CBitmap*)CMemDC1.SelectObject(pBitmap1);
         
          
             //ch_Graph->DrawGraph(&dc1, FrameRect.Width(),
FrameRect.Height(),1,ch_Graph->GetSeriesQuantity()+1); // Это если хотим рисовать не через память, а напрямую в DC

           ch_Graph->DrawGraph(&CMemDC1, FrameRect.Width(), FrameRect.Height(),1,ch_Graph->GetSeriesQuantity()+1);  // Вызов процедуры вывода графика на указанный DC
          
          // копируем биты из памяти на DC прямоугольника
          dc1.BitBlt(0, 0,FrameRect.Width()-2, FrameRect.Height()-2, &CMemDC1, 0, 0, SRCCOPY);
          // возвращаем старый bitmap
         CMemDC1.SelectObject(&pOldBitmap);
          // освобождаем контекст
         DeleteDC(CMemDC1);
        }
      }   

   CDialog::OnPaint();

   }
}

Пробовал два способа прорисовки. Первый указанный рисует через MemDC, пробовал откатиться к рисованию через обычный dc (закомментированно красным). Если dc делаю не от прямоугольника (pWnd1) а от самого диалога :
CPaintDC dc1(pWnd1); // Берём DC от Прямоугольник1
CPaintDC dc1(this); // Берём DC от самого диалога
то прорисовка нормальная происходит, только вот рисуется прямо на диалоге поверх всех кнопок, а хотелось бы внутри прямоугольника pWnd1
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #3 : 14-06-2007 10:49 » 

CPaintDC dc1(this);
 - обязательно только так . Иначе не нарисуется.

причём, делать это нужно бы сразу тут -
Код:
   if (IsIconic())   {... }
   else
   {
     CPaintDC dc(this); //<<<<---

то есть во избежание ошибок далее...

А то , что поверх кнопок - так это мы обсуждали уже ) Делай контрол, производный от CWnd (исчезнет 98% проблем и копировать ничего не придётся), или хардкорно обрезай координаты для выводимого ПРЯМО НА ДИАЛОГ прямоугольника

« Последнее редактирование: 14-06-2007 10:52 от Алексей1153++ » Записан

Tuborg
Команда клуба

ee
Offline Offline

« Ответ #4 : 14-06-2007 11:46 » 

1. Раньше на обычном CDialog такое обращение нормально работало.
2. Данное обращение также нормально работает если использовать вместо Invalidate ShowWindow
« Последнее редактирование: 14-06-2007 11:50 от Tuborg » Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #5 : 14-06-2007 11:49 » 

Tuborg, ) А сейчас всё ещё рисуется ? )

опаньки, а что за флаг такой - graphComplete ? Он точно установился ?


ооо, вот  и проблема -
   CDialog::OnPaint();

ЭТО НЕЛЬЗЯ , это и есть перерисовка по дефолту диалога

либо CDialog::OnPaint(); , либо CPaintDC(this).   Одно из двух надо
« Последнее редактирование: 14-06-2007 11:55 от Алексей1153++ » Записан

Tuborg
Команда клуба

ee
Offline Offline

« Ответ #6 : 14-06-2007 11:50 » 

Да, если использовать ShowWindow. Что делает такого ShowWindow, чего не делает Invalidate?
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #7 : 14-06-2007 11:57 » 

ShowWindow вызовет UpdateWindow (если окно не было видно до этого)
Записан

Tuborg
Команда клуба

ee
Offline Offline

« Ответ #8 : 14-06-2007 12:08 » 

Как же без OnPaint'a жить то? он же мне всякие кнопочки рисует? а CPaintDC(this) не могу на это пойти... у меня три прямоугольника с тремя графиками и я толжен от каждого такого прямоугольника взять CPaintDC...  а не от всего диалога

Если же я добавлю UpdateWindow к Invalidate всё равно такого эффекта, как от ShowWindow не будет
« Последнее редактирование: 14-06-2007 12:10 от Tuborg » Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #9 : 14-06-2007 13:42 » new

Tuborg, )))   Да всё нормально. CPaintDC dc(this) необходим - тут создаётся контекст для диалога. Без него - никак.
 Далее -
>>>у меня три прямоугольника с тремя графиками и я толжен от каждого такого прямоугольника взять CPaintDC

1) во первых, если бы ты сделал свой контрол, тебя бы это не заботило.
2) во врторых - раз ты хочешь рисовать на этих прямоугольниках, но не хочешь делать контролы, то тебе надо рисовать именно на контекте диалога. Но - в определённых местах, ограниченных твоими прямоугольниками

-------------------

для пояснения -
данный код:
Код:
void CWin_CCDlg::OnPaint()
{
   //некий код
   //...
...
...
   CDialog::OnPaint();
}
полностью аналогичен случаю, если бы OnPaint() в классе CWin_CCDlg вообще не было. Ведь всё равно просто вызывается функция родительского класса и нарисует поверх дефолт.

а если убрать вызов CDialog::OnPaint(); , заменить его на
Код:
void CWin_CCDlg::OnPaint()
{
    CPaintDC dc(this);
   //некий код
   //...
...
...
   //CDialog::OnPaint(); //не вызывать!!!
}

то тут контекст создаётся в переопределённой тобой функции CWin_CCDlg::OnPaint(), на котором ты можешь рисовать, и он не будет перекрыт изображением на контексте родителя

И кнопочки нарисуются, и всё такое.
« Последнее редактирование: 14-06-2007 13:48 от Алексей1153++ » Записан

Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines