Проблема с установкой цвета текста и фона бегущей строки
От: RussianFellow Россия http://russianfellow.livejournal.com
Дата: 18.01.17 10:54
Оценка:
Есть у меня поток hThread, в который в качестве данных посылается структура myStruct, в которой есть поле isthreadfinished типа bool, которое показывает, завершился ли этот поток или нет.
Есть таймер ID_TIMER_1, которому соответствует функция CMyClass::OnTimer, которая выводит бегущую строку с интервалом в полсекунды и завершает вывод бегущей строки, как только поток hThread завершит свою работу:

void  CMyClass::OnTimer(UINT uTime)
{
  if (myStruct.isthreadfinished==true)
  // если поток завершён
  {
    KillTimer(ID_TIMER_1);
    timerTest = false;
    timerCount = 0;
    m_IDC_STATIC1.SetWindowTextA(" Расчёт выполнен");
    CloseHandle(hThread);
    // прочие действия;
    return;
  }
  if (timerCount>=6)  timerCount = 0;
  if (timerCount==0)  m_IDC_STATIC1.SetWindowTextA(" Расчёт выполняется");
  if (timerCount==1)  m_IDC_STATIC1.SetWindowTextA(" Расчёт выполняется .");
  if (timerCount==2)  m_IDC_STATIC1.SetWindowTextA(" Расчёт выполняется . .");
  if (timerCount==3)  m_IDC_STATIC1.SetWindowTextA(" Расчёт выполняется . . .");
  if (timerCount==4)  m_IDC_STATIC1.SetWindowTextA(" Расчёт выполняется . . . .");
  if (timerCount==5)  m_IDC_STATIC1.SetWindowTextA(" Расчёт выполняется . . . . .");
  timerCount++;
}


В обычном случае, когда переменная m_IDC_STATIC1 относится к типу CStatic, всё работает нормально--бегущая строка чёрного цвета появляется на фоне стандартного диалога (оттенок серого цвета).

Но я захотел сменить цвет текста и цвет фона бегущей строки--чтобы эта строка была красного цвета, а цвет фона, на котором она появляется--зелёного цвета. Для этого я создал класс CMyStatic2 как потомок класса CStatic, в котором я переопределил метод OnPaint():

файл MyStatic2.h :

#include <afxwin.h>

class CMyStatic2 : public CStatic
{
  protected:
  void OnPaint();
  DECLARE_MESSAGE_MAP()
  public:
  // открытые члены класса CMyStatic;
};


файл MyStatic2.cpp :

#include "stdafx.h"
#include "MyStatic2.h"

BEGIN_MESSAGE_MAP (CMyStatic2, CStatic)
  ON_WM_PAINT()
END_MESSAGE_MAP()

void CMyStatic2::OnPaint()
{
  const MSG *msg = GetCurrentMessage();
  DefWindowProc(msg->message,msg->wParam,msg->lParam);
  RECT  rect;
  CClient  dc(this);
  GetClientRect(&rect);
  CBrush  brush(RGB(0,128,0)); // зелёный цвет фона
  dc.SelectObject(&brush);
  dc.FillRect(&rect,&brush);
  dc.SetTextColor(RGB(255,0,0)); // красный цвет текста
}


А переменную m_IDC_STATIC1 в классе CMyClass я сменил с типа CStatic на тип CMyStatic2 .

В результате чего у меня при запуске потока и таймера на одну секунду появляется статитческое поле зелёного цвета, а потом оно меняется на стандартный цвет диалога (оттенок серого цвета) и бегущая строка в этом статическом поле имеет чёрный цвет.

В чём причина этого? Как исправить эту ошибку--то есть как сделать так, чтобы это статическое поле всегда имело зелёный цвет, а бегущая строка в нём всегда имела красный цвет?
Re: Проблема с установкой цвета текста и фона бегущей строки
От: AlexGin Беларусь  
Дата: 18.01.17 11:44
Оценка:
Здравствуйте, RussianFellow, Вы писали:

RF>
RF>void  CMyClass::OnTimer(UINT uTime)
RF>{
RF>  if (myStruct.isthreadfinished==true)
RF>  // если поток завершён
RF>  {
RF>    KillTimer(ID_TIMER_1);
RF>    timerTest = false;
RF>    timerCount = 0;
RF>    m_IDC_STATIC1.SetWindowTextA(" Расчёт выполнен");
RF>    CloseHandle(hThread);
RF>    // прочие действия;
RF>    return;
RF>  }
RF>  if (timerCount>=6)  timerCount = 0;
RF>  if (timerCount==0)  m_IDC_STATIC1.SetWindowTextA(" Расчёт выполняется");
RF>  if (timerCount==1)  m_IDC_STATIC1.SetWindowTextA(" Расчёт выполняется .");
RF>  if (timerCount==2)  m_IDC_STATIC1.SetWindowTextA(" Расчёт выполняется . .");
RF>  if (timerCount==3)  m_IDC_STATIC1.SetWindowTextA(" Расчёт выполняется . . .");
RF>  if (timerCount==4)  m_IDC_STATIC1.SetWindowTextA(" Расчёт выполняется . . . .");
RF>  if (timerCount==5)  m_IDC_STATIC1.SetWindowTextA(" Расчёт выполняется . . . . .");
RF>  timerCount++;
RF>}
RF>


Почему бы не сделать так:
...
std::string sTextOut = " Расчёт выполняется";
if (timerCount>=6)  
    timerCount = 0;

for (int i = 0; i < timerCount; i++)
    sTextOut += " .";

m_IDC_STATIC1.SetWindowTextA(sTextOut.c_str());
timerCount++;


По конкретному вопросу вот пример:
https://www.codeproject.com/Articles/1035/Using-colors-in-CEdit-and-CStatic
Отредактировано 18.01.2017 12:19 AlexGin . Предыдущая версия .
Re: Проблема с установкой цвета текста и фона бегущей строки
От: anatolym  
Дата: 18.01.17 11:46
Оценка: 4 (1)
Здравствуйте, RussianFellow, Вы писали:

Возможно SetWindowTextA не вызывает перерисовку функцией OnPaint. Очень на то похоже. При иницализации OnPaint вызывается один раз и рисует зеленый прямоугольник. А как только срабатывает таймер SetWindowTextA рисует используя системные цвета.
Тебе тогда надо не SetWindowTextA вызывать, а посылать сообщение для перерисовки, в котором у тебя кстати сам текст не выводится.

П.С.
Кстати, строка у тебя не бегущая
Отредактировано 18.01.2017 11:47 anatolym . Предыдущая версия .
Re[2]: Проблема с установкой цвета текста и фона бегущей стр
От: anatolym  
Дата: 18.01.17 12:44
Оценка:
Здравствуйте, anatolym, Вы писали:

A>Здравствуйте, RussianFellow, Вы писали:


A>Возможно SetWindowTextA не вызывает перерисовку функцией OnPaint. Очень на то похоже. При иницализации OnPaint вызывается один раз и рисует зеленый прямоугольник. А как только срабатывает таймер SetWindowTextA рисует используя системные цвета.

A>Тебе тогда надо не SetWindowTextA вызывать, а посылать сообщение для перерисовки, в котором у тебя кстати сам текст не выводится.

П.С.
Таймеры, наследование, жуть какая
А на WPF это все можно сделать на языке разметки.
    <DockPanel LastChildFill="True" Margin="5" TextBlock.FontSize="20">
        <TextBlock Panel.ZIndex="1" Background="Green" Foreground="Yellow">Operation in progress</TextBlock>
        <TextBlock Text=".............." x:Name="Dots" Margin="-100 0 0 0" Background="Green" Foreground="Yellow">
            <TextBlock.Triggers>
                <EventTrigger RoutedEvent="TextBlock.Loaded">
                    <BeginStoryboard>
                        <Storyboard TargetName="Dots" TargetProperty="Margin">
                            <ThicknessAnimation To="0 0 0 0" RepeatBehavior="Forever" Duration="0:0:2"></ThicknessAnimation>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </TextBlock.Triggers>
        </TextBlock>
    </DockPanel>


Выглядит так ссылка
Отредактировано 18.01.2017 13:22 anatolym . Предыдущая версия .
Re[2]: Проблема с установкой цвета текста и фона бегущей строки
От: RussianFellow Россия http://russianfellow.livejournal.com
Дата: 18.01.17 13:10
Оценка:
Здравствуйте, anatolym, Вы писали:

A>Здравствуйте, RussianFellow, Вы писали:


A>Возможно SetWindowTextA не вызывает перерисовку функцией OnPaint. Очень на то похоже. При иницализации OnPaint вызывается один раз и рисует зеленый прямоугольник. А как только срабатывает таймер SetWindowTextA рисует используя системные цвета.

A>Тебе тогда надо не SetWindowTextA вызывать, а посылать сообщение для перерисовки, в котором у тебя кстати сам текст не выводится.

Да, всё верно--у меня по SetWindowTextA не вызывалась перерисовка OnPaint.

Я решил проблему следующим образом:

в класс CMyStatic2 добавил следующее:

public:
char s[50];
void setText(char *s);

void CMyStatic2::setText(char *s)
{
strcpy(this->s,s);
}

В функции CMyStatic::OnPaint я написал:

CBrush brush(RGB(0,128,0)); // цвет фона--зелёный
dc.SelectObject(&brush);
dc.FillRect(&rect,&brush);
dc.SetTextColor(RGB(255,0,0)); // цвет текста--красный
dc.SetBkColor(RGB(0,128,0)); // цвет фона при тексте--зелёный
dc.DrawTextA(s,strlen(s),&rect,0);

А в функции CMyClass::OnTimer вместо

if (timeCount==0) m_IDC_STATIC1.setWindowTextA(" Расчёт выполняется");

я написал:

if (timeCount==0)
{
m_IDC_STATIC1.setText(" Расчёт выполняется");
m_IDC_STATIC1.RedrawWindow();
}

(И так для всех случаях timeCount, а также для случая, когда надо вывести надпись " Расчёт выполнен").

В результате у меня всё работает правильно!



P.S. Чем отличается CWnd::RedrawWindow от CWnd::UpdateWindow ?
Re[3]: Проблема с установкой цвета текста и фона бегущей строки
От: anatolym  
Дата: 18.01.17 13:47
Оценка:
Здравствуйте, RussianFellow, Вы писали:

RF>А в функции CMyClass::OnTimer вместо


RF>if (timeCount==0) m_IDC_STATIC1.setWindowTextA(" Расчёт выполняется");


RF>я написал:


RF>if (timeCount==0)

RF>{
RF> m_IDC_STATIC1.setText(" Расчёт выполняется");
RF> m_IDC_STATIC1.RedrawWindow();
RF>}

RF>(И так для всех случаях timeCount, а также для случая, когда надо вывести надпись " Расчёт выполнен").


Это можно упаковать в цикл, как предложил выше AlexGin. Ибо дублирование не есть гуд.


RF>P.S. Чем отличается CWnd::RedrawWindow от CWnd::UpdateWindow ?


Это не знаю, или не помню MFC последний раз давно видел, и слава богу.
Re: Проблема с установкой цвета текста и фона бегущей строки
От: Carc Россия Aml Pages — оперативный блокнот http://www.amlpages.com/home.php
Дата: 18.01.17 13:49
Оценка:
Не забываем dc.SetBkMode(TRANSPARENT) перед прорисовкой, чтобы не затирал фон текстом.
Aml Pages Home
Re: Проблема с установкой цвета текста и фона бегущей строки
От: Evgeniy Skvortsov Россия  
Дата: 18.01.17 14:10
Оценка: +1
Здравствуйте, RussianFellow, Вы писали:

  Код
void CMyStatic2::OnPaint()
{
  const MSG *msg = GetCurrentMessage();
  DefWindowProc(msg->message,msg->wParam,msg->lParam);
  RECT  rect;
  CClient  dc(this);
  GetClientRect(&rect);
  CBrush  brush(RGB(0,128,0)); // зелёный цвет фона
  dc.SelectObject(&brush);
  dc.FillRect(&rect,&brush);
  dc.SetTextColor(RGB(255,0,0)); // красный цвет текста
}


Можно конечно и так, но намного проще не отрисовку полностью руками делать, а просто обрабатывать WM_ONCTLCOLOR в самом диалоге.
И не нужно никаких лишних классов.
HBRUSH CMFCApplication3Dlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) {
    HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
    if (pWnd->GetDlgCtrlID() == IDC_STATIC1) {
        pDC->SetTextColor(RGB(255, 0, 0));
        pDC->SetBkColor(RGB(0, 128, 0));
    }
    return hbr;
}


WM_PAINT перекрывают обычно если нужно как-то кардинально изменить внешний вид контрола, а если просто цвет изменить, то WM_ONCTLCOLOR — самое то.
Отредактировано 18.01.2017 14:32 Evgeniy Skvortsov . Предыдущая версия . Еще …
Отредактировано 18.01.2017 14:14 Evgeniy Skvortsov . Предыдущая версия .
Re[3]: Проблема с установкой цвета текста и фона бегущей строки
От: Evgeniy Skvortsov Россия  
Дата: 18.01.17 14:30
Оценка:
Здравствуйте, RussianFellow, Вы писали:

RF>P.S. Чем отличается CWnd::RedrawWindow от CWnd::UpdateWindow ?


CWnd::UpdateWindow — вызывает функцию API UpdateWindow(), которая тупо шлёт окну сообщение WM_PAINT, и оно перерисовывается полностью.
CWnd::RedrawWindow — вызывает функцию API RedrawWindow(), у которой несколько параметров и комбинаций флагов.
MFC вызывает её с какими-то значениями по умолчанию, видимо такие значения не вызывают полную перерисовку окна.
Re[3]: Проблема с установкой цвета текста и фона бегущей строки
От: aloch Россия  
Дата: 18.01.17 15:05
Оценка:
Здравствуйте, RussianFellow, Вы писали:


RF>P.S. Чем отличается CWnd::RedrawWindow от CWnd::UpdateWindow ?


В MSDN почитать слабо?


http://files.rsdn.org/1366/MCP(rgb).jpg
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.