Mfc 有些控件没有绘制,看起来是随机的

Mfc 有些控件没有绘制,看起来是随机的,mfc,Mfc,我试着为自己编写一个小的MFC应用程序,来测试我正在训练的一些人工智能 因此,我添加了一个图片控件和一个静态控件,可以在主窗口的OnPaint()方法中自由绘制内容 当只绘制一次应用程序时,它似乎可以工作,但我现在添加了一个循环,在停止之前多次执行OnPaint() 在这个循环中,其他一些控件不显示,例如“我的所有按钮”都消失了,一些滑块有时甚至丢失,但其他时候,它们就在那里 我的代码是这样的: void CKiUebung1Dlg::onbn单击按钮() { m_bisging=真; OnPa

我试着为自己编写一个小的MFC应用程序,来测试我正在训练的一些人工智能

因此,我添加了一个图片控件和一个静态控件,可以在主窗口的OnPaint()方法中自由绘制内容

当只绘制一次应用程序时,它似乎可以工作,但我现在添加了一个循环,在停止之前多次执行OnPaint()

在这个循环中,其他一些控件不显示,例如“我的所有按钮”都消失了,一些滑块有时甚至丢失,但其他时候,它们就在那里

我的代码是这样的:

void CKiUebung1Dlg::onbn单击按钮()
{
m_bisging=真;
OnPaint();
如果(m_fDiagramData.size()=0;--i)
{
std::this_线程::sleep_for(std::chrono::毫秒(1000));
m_fDiagramData.push_back((float)rand()/rand_MAX);
无效(NULL,TRUE);
OnPaint();
}
m_bisging=假;
OnPaint();
}
void CKiUebung1Dlg::OnPaint()
{
if(IsIconic())
{
CPaintDC dc(this);//Gerätekontext zum Zeichnen
SendMessage(WM_ICONERASEBKGND,reinterpret_cast(dc.GetSafeHdc()),0);
//ClientRecheck zentrieren中的符号
int cxIcon=GetSystemMetrics(SM_cxIcon);
int cycon=GetSystemMetrics(SM_cycon);
正确无误;
GetClientRect(&rect);
intx=(rect.Width()-cxIcon+1)/2;
int y=(rect.Height()-cycon+1)/2;
//符号zeichnen
dc.DrawIcon(x,y,m_hIcon);
}
其他的
{
CDialogEx::OnPaint();
}
{
constexpr const int border=5;
CPaintDC&m_cDiagram;
正确的l_CPO;
m_cDiagram.GetClientRect(&l_cpo);
常量整数宽度(l_cPos.width()-边框*2-2)、高度(l_cPos.height()-边框*2-12);
常量int numPoints(m_fDiagramData.size());
点*点(新点[numPoints]);
对于(int i(numPoints-1);i>=0;--i)
{
常数整数
x((浮点)i/(小数点-1)*宽度+边框+1),
y(高度-m_fDiagramData[i]*高度+边框+9);
点[i]={x,y};
}
dc.多段线(点、numPoints);
静态CString运行(_T(“”);
if(m_bisgong){go+=\u T(“.”);if(go.GetLength()>300)go=\u T(“.”;}
否则继续=_T(“”);
浮点fprog(0);如果(m_fDiagramData.size()>0)fprog=m_fDiagramData.back();
CString prog;prog.Format(_T(“Progress%03.2f%%”),fprog*100);if(m_bisging)prog+=go;
m_cDiagram.SetWindowTextW(prog);
m_cDiagram.RedrawWindow();
删除[]点;
}
}
这是循环未运行时的外观:

以下是循环运行时的外观:

是对消息的响应,不应直接调用

WM_PAINT
调用
CWnd::OnPaint
,后者调用,后者依次调用/api。此消息+响应序列应保持原样

因此,
CPaintDC dc(this)
必须在
OnPaint
内部出现一次,并且只能出现一次,而不能出现在其他任何地方。覆盖
OnPaint
,如下所示:

void CMyDialog::OnPaint()
{
CDialogEx::OnPaint();//这将调用CPaintDC(this);
//可选:
CClientDC(this);//CClientDC可以在有效窗口中的任何位置使用
//使用dc进行绘图
}
//或
void CMyDialog::OnPaint()
{
CPaintDC dc(本);
//使用dc进行绘图
}
您也不需要过时的
if(IsIconic()){…}
条件

要强制窗口重新绘制自身,请调用(与相同的操作)

invalidate(NULL,TRUE)
是重新绘制窗口的请求。系统将查看此请求,并在有机会时向该窗口发送
WM_PAINT
消息。因此,对
invalidate
的调用可能无法以您期望的方式在顺序程序中进行处理。例如,连续第二次调用
invalidate
将不会产生任何效果。窗口已标记为要更新

for(int i(9);i>=0;--i)
{
std::this_线程::sleep_for(std::chrono::毫秒(1000));
m_fDiagramData.push_back((float)rand()/rand_MAX);
无效(NULL,TRUE);
OnPaint();
}
应从上述代码中删除
OnPaint()
。尽管如此,动画在单个线程中是不可能的(至少不是以这种方式)。程序忙于循环,无法处理
WM_PAINT
和其他消息

因此,您需要一个额外的线程,或者只需使用
SetTimer
,并响应\u WM\u TIMER()/
OnTimer
上的
,即可制作动画。例如:

int计数器=0;
开始消息映射(CMyDialog、CDialogEx)
关于油漆
关于\u WM\u计时器()
...
结束消息映射()
void CMyDialog::OnPaint()
{
CPaintDC dc(本);
csts;
s、 格式(L“%02d”,计数器);
dc.TextOut(0,0,s);
}
void CMyDialog::animate()
{
计数器=0;
设置计时器(1,1000,空);
}
void CMyDialog::OnTimer(UINT\u PTR n)
{
如果(n==1)
{
Invalidate();//强制重新绘制
计数器++;
如果(计数器==10)
计时器(1);
}
}

您似乎很难理解失效/绘制是如何工作的。 您应该首先阅读的文档是:

虽然许多开发人员建议只在
WM_PAINT
处理中进行绘制(
OnPaint()
在MFC中),但这并不总是最好的解决方案,因为此消息优先级较低,绘制可能不会立即进行(有一种“起伏”的感觉),并且您可能会得到“闪烁”的效果

相反,我有时建议将绘画与绘画相结合:

  • WM_PAINT
    处理中使用绘画。这应该绘制整个客户端区域(或者如果您想要更“优化”的实现,则只绘制其中无效的部分)