21 个解决方案
#1
没有自己的消息循环,恐怕不行啊
#2
用钩子吧
#3
wokao
#4
不会呀,我的非模式对话框就能响应定时器呀!请先说说您是怎么做的,为什么不能响应?
#5
你需要重载主窗口的PreMessageFilter在消息过滤时做判断是不是对话框消息
用IsDialogMessage函数。他会自动将消息给你的对话框
用IsDialogMessage函数。他会自动将消息给你的对话框
#6
同意speakboy(一个菜鸟的自白---我想变成高手!) 的见解,先说说你是怎么做的吧,很可能是其他问题导致的。
#7
我是这样做的,
见:
http://www.csdn.net/Expert/TopicView1.asp?id=947034
见:
http://www.csdn.net/Expert/TopicView1.asp?id=947034
#8
因为你是在CGradientbar中调用的SetTimer,所有windows会把所有的WM_TIMER消息都发送到CGradientbar窗口,但你把对WM_TIMER的响应放到了CStatic中,它是收不到WM_TIMER消息的。我觉得你把ON_WM_TIMER移到CGradientbar中就可以了。
#9
汗....
绝对是这个原因,CWnd::SetTimer是调用::SetTimer(hwnd,...)实现的,timer在把WM_TIMER消息送到消息队列时会用hwnd的值填充MSG结构的hwnd成员,结果DispatchMessage就把WM_TIMER发给hwnd也就是调用SetTimer的窗口的Proc了,其它的窗口收不到。
原贴竟然讨论了那么多...
绝对是这个原因,CWnd::SetTimer是调用::SetTimer(hwnd,...)实现的,timer在把WM_TIMER消息送到消息队列时会用hwnd的值填充MSG结构的hwnd成员,结果DispatchMessage就把WM_TIMER发给hwnd也就是调用SetTimer的窗口的Proc了,其它的窗口收不到。
原贴竟然讨论了那么多...
#10
to webber84(糕鱼昏):
你是如何知道我把对WM_TIMER的响应放到了CStatic中?我不是已经在CGradientbar的cpp里定义了ON_WM_TIMER吗?
BEGIN_MESSAGE_MAP(CGradientbar, CStatic)
//{{AFX_MSG_MAP(CGradientbar)
ON_WM_PAINT()
ON_WM_TIMER()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
to 汗.....
我就是在CGradientbar::Start();里调用的SetTimer(),是这个不对吗?
为什么同样的代码,如果对话框是模式的就可以,非模式的就不可以呢?
要不,谁亲自做一个可以响应对话况或使其子窗口响应各自OnTimer函数的非模式对话框?
你是如何知道我把对WM_TIMER的响应放到了CStatic中?我不是已经在CGradientbar的cpp里定义了ON_WM_TIMER吗?
BEGIN_MESSAGE_MAP(CGradientbar, CStatic)
//{{AFX_MSG_MAP(CGradientbar)
ON_WM_PAINT()
ON_WM_TIMER()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
to 汗.....
我就是在CGradientbar::Start();里调用的SetTimer(),是这个不对吗?
为什么同样的代码,如果对话框是模式的就可以,非模式的就不可以呢?
要不,谁亲自做一个可以响应对话况或使其子窗口响应各自OnTimer函数的非模式对话框?
#11
to iProgram (小癞蛤蟆):
没看清楚你的原贴,不好意思。不过CGradientbar也的确不像是个static的名字,我还以为是一个dialogbar呢。等我回学校一定要试试看。
没看清楚你的原贴,不好意思。不过CGradientbar也的确不像是个static的名字,我还以为是一个dialogbar呢。等我回学校一定要试试看。
#12
作为主对话框的一个成员,然后在主对话框中作一个onTimer,在其中调用m_child.OnTimerEx(timeid),OnTimerEx为m_child的公有成员,就可以,这样就可以了。不过,在调用之前,一定是窗口追chuangjian了
#13
to iProgram : 对不起,我没有看清就回了贴,见笑了。
这是我在一个Modeless Dialog上运行的一个Static控件,处理了WM_TIMER消息,可以运行:
class CMyStatic : public CStatic
{
public:
CMyStatic();
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMyStatic)
protected:
virtual void PreSubclassWindow();
//}}AFX_VIRTUAL
virtual ~CMyStatic() {};
protected:
UINT m_iTimer;
// Generated message map functions
//{{AFX_MSG(CMyStatic)
afx_msg void OnDestroy();
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnTimer(UINT nIDEvent);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CMyStatic::CMyStatic()
{
m_iTimer = (UINT)-1;
}
BEGIN_MESSAGE_MAP(CMyStatic, CStatic)
//{{AFX_MSG_MAP(CMyStatic)
ON_WM_DESTROY()
ON_WM_CREATE()
ON_WM_TIMER()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CMyStatic::PreSubclassWindow()
{
if (m_iTimer == (UINT)-1)
m_iTimer = SetTimer(::GetWindowLong(GetSafeHwnd(), GWL_ID), 500, NULL);
CStatic::PreSubclassWindow();
}
void CMyStatic::OnDestroy()
{
CStatic::OnDestroy();
if (m_iTimer != (UINT)-1)
{
KillTimer(m_iTimer);
m_iTimer = (UINT)-1;
}
}
int CMyStatic::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CStatic::OnCreate(lpCreateStruct) == -1)
return -1;
if (m_iTimer == (UINT)-1)
m_iTimer = SetTimer(::GetWindowLong(GetSafeHwnd(), GWL_ID), 500, NULL);
return 0;
}
void CMyStatic::OnTimer(UINT nIDEvent)
{
CString strStatic;
GetWindowText(strStatic);
TCHAR tchar = strStatic[0];
strStatic.Delete(0);
strStatic += tchar;
SetWindowText(strStatic);
CStatic::OnTimer(nIDEvent);
}
模式对话框是这样创建的:
m_pAboutDlg = new CAboutDlg;
m_pAboutDlg->Create(CAboutDlg::IDD);
m_pAboutDlg->ShowWindow(SW_SHOW);
m_pAboutDlg->UpdateWindow();
CMyStatic作为一个DDX_Control加在对话框上
DDX_Control(pDX, IDC_MYSTATIC, m_myStatic);
不知道是不是和你的情况一致。
这是我在一个Modeless Dialog上运行的一个Static控件,处理了WM_TIMER消息,可以运行:
class CMyStatic : public CStatic
{
public:
CMyStatic();
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMyStatic)
protected:
virtual void PreSubclassWindow();
//}}AFX_VIRTUAL
virtual ~CMyStatic() {};
protected:
UINT m_iTimer;
// Generated message map functions
//{{AFX_MSG(CMyStatic)
afx_msg void OnDestroy();
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnTimer(UINT nIDEvent);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CMyStatic::CMyStatic()
{
m_iTimer = (UINT)-1;
}
BEGIN_MESSAGE_MAP(CMyStatic, CStatic)
//{{AFX_MSG_MAP(CMyStatic)
ON_WM_DESTROY()
ON_WM_CREATE()
ON_WM_TIMER()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CMyStatic::PreSubclassWindow()
{
if (m_iTimer == (UINT)-1)
m_iTimer = SetTimer(::GetWindowLong(GetSafeHwnd(), GWL_ID), 500, NULL);
CStatic::PreSubclassWindow();
}
void CMyStatic::OnDestroy()
{
CStatic::OnDestroy();
if (m_iTimer != (UINT)-1)
{
KillTimer(m_iTimer);
m_iTimer = (UINT)-1;
}
}
int CMyStatic::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CStatic::OnCreate(lpCreateStruct) == -1)
return -1;
if (m_iTimer == (UINT)-1)
m_iTimer = SetTimer(::GetWindowLong(GetSafeHwnd(), GWL_ID), 500, NULL);
return 0;
}
void CMyStatic::OnTimer(UINT nIDEvent)
{
CString strStatic;
GetWindowText(strStatic);
TCHAR tchar = strStatic[0];
strStatic.Delete(0);
strStatic += tchar;
SetWindowText(strStatic);
CStatic::OnTimer(nIDEvent);
}
模式对话框是这样创建的:
m_pAboutDlg = new CAboutDlg;
m_pAboutDlg->Create(CAboutDlg::IDD);
m_pAboutDlg->ShowWindow(SW_SHOW);
m_pAboutDlg->UpdateWindow();
CMyStatic作为一个DDX_Control加在对话框上
DDX_Control(pDX, IDC_MYSTATIC, m_myStatic);
不知道是不是和你的情况一致。
#14
void CTestDlg::OnTimer(UINT nIDEvent)
{
CTime t2 = CTime::GetCurrentTime();;
m_smsg.Format("%d:%d:%d",t2.GetHour(),t2.GetMinute(),t2.GetSecond());
UpdateData(FALSE);
CDialog::OnTimer(nIDEvent);
}
int CTestDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialog::OnCreate(lpCreateStruct) == -1)
return -1;
SetTimer(1,1000,NULL);
return 0;
}
{
CTime t2 = CTime::GetCurrentTime();;
m_smsg.Format("%d:%d:%d",t2.GetHour(),t2.GetMinute(),t2.GetSecond());
UpdateData(FALSE);
CDialog::OnTimer(nIDEvent);
}
int CTestDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialog::OnCreate(lpCreateStruct) == -1)
return -1;
SetTimer(1,1000,NULL);
return 0;
}
#15
有了一些进展。
我要实现的效果是,类似win98启动画面那种位图滚动的效果,把这种效果加在我程序的splash中,于是我做了一个类CGradientbar实现这种滚动效果,CGradientbar中用到了定时器。
我要在CMainFrame::OnCreate中显示这个Splash,因为要在OnCreate加载很多东西,耗时15秒种,因此会在OnCreate进行中,不断把所作的事情显示在splash的一个Static中(这个一直工作正常),起初因为splash只出现在OnCreate中,我直接在OnCreate的堆栈上创建splash对话框,发现定时器无效。后来改在堆上创建(CSplashDlg* m_pSplashDlg作为类成员在.h里声明),定时器依然无效,但我在OnCreate返回之前没有删除splash对象(没有delete m_pSplashDlg;),发现CMainFrame::OnCreate返回之后定时器才开始工作。所以问题不是出在非模式对话框上,问题应该是为什么在CMainFrame::OnCreate函数开始时启动的m_pSplashDlg中的定时器直到CMainFrame::OnCreate返回后才开始工作?
相关代码:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
m_pSplash=new CSplashDlg(this);
m_pSplash->Create(IDD_DIALOG_SPLASH);
m_pSplash->SetWindowPos(&(CWnd::wndTopMost),0,0,380,280,SWP_NOMOVE|SWP_DRAWFRAME);
// m_wndBar是CGradientbar对象,CGradientbar::Start(0做一些初始工作,并启动CGradientbar的定时器
m_pSplash->m_wndBar.Start();
m_pSplash->ShowWindow(SW_SHOW);
m_pSplash->UpdateWindow();
//现在开始做耗时很长的加载工作
........................................................
//其间不断的把工作显示在m_pSplash上:
m_pSplash->GetDlgItem(IDC_STATIC_TODO)->SetWindowText("正在加载xxxxxx");
..........................................................
//delete m_pSplash; //如果此时不delete,return 0后m_pSplash->m_wndBar的定时器才开始工作,TNND
return 0;
}
我要实现的效果是,类似win98启动画面那种位图滚动的效果,把这种效果加在我程序的splash中,于是我做了一个类CGradientbar实现这种滚动效果,CGradientbar中用到了定时器。
我要在CMainFrame::OnCreate中显示这个Splash,因为要在OnCreate加载很多东西,耗时15秒种,因此会在OnCreate进行中,不断把所作的事情显示在splash的一个Static中(这个一直工作正常),起初因为splash只出现在OnCreate中,我直接在OnCreate的堆栈上创建splash对话框,发现定时器无效。后来改在堆上创建(CSplashDlg* m_pSplashDlg作为类成员在.h里声明),定时器依然无效,但我在OnCreate返回之前没有删除splash对象(没有delete m_pSplashDlg;),发现CMainFrame::OnCreate返回之后定时器才开始工作。所以问题不是出在非模式对话框上,问题应该是为什么在CMainFrame::OnCreate函数开始时启动的m_pSplashDlg中的定时器直到CMainFrame::OnCreate返回后才开始工作?
相关代码:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
m_pSplash=new CSplashDlg(this);
m_pSplash->Create(IDD_DIALOG_SPLASH);
m_pSplash->SetWindowPos(&(CWnd::wndTopMost),0,0,380,280,SWP_NOMOVE|SWP_DRAWFRAME);
// m_wndBar是CGradientbar对象,CGradientbar::Start(0做一些初始工作,并启动CGradientbar的定时器
m_pSplash->m_wndBar.Start();
m_pSplash->ShowWindow(SW_SHOW);
m_pSplash->UpdateWindow();
//现在开始做耗时很长的加载工作
........................................................
//其间不断的把工作显示在m_pSplash上:
m_pSplash->GetDlgItem(IDC_STATIC_TODO)->SetWindowText("正在加载xxxxxx");
..........................................................
//delete m_pSplash; //如果此时不delete,return 0后m_pSplash->m_wndBar的定时器才开始工作,TNND
return 0;
}
#16
对你的问题有一些理解了:
WM_CREATE是一个不进队消息,当调用CreateWindow(Ex)创建窗口时,会直接调用窗口过程处理WM_CREATE消息,而且该CreateWindow(Ex)调用直到窗口过程处理WM_CREATE返回后才返回。
CMainFrame的创建是在MFC进入消息循环前进行的,如上所述,它将立即调用CMainFrame::OnCreate,然后直到CMainFrame::OnCreate返回,MFC才从创建CMainFrame的调用中返回,然后进入消息循环。
由于你在非模态对话框显示的过程中,一直没有让CMainFrame::OnCreate返回,结果主线程不能进入消息循环,导致放入队列的WM_TIMER消息无法响应。
如果采用模态对话框,从DoModal代码中可以看出,DoModal函数内部有一个消息泵,负责在DoModal未返回前取出和响应进入消息队列的消息,通过这个泵,WM_TIMER消息正确的被处理了。调用MessageBox就可以响应的原因也是这样。
WM_CREATE是一个不进队消息,当调用CreateWindow(Ex)创建窗口时,会直接调用窗口过程处理WM_CREATE消息,而且该CreateWindow(Ex)调用直到窗口过程处理WM_CREATE返回后才返回。
CMainFrame的创建是在MFC进入消息循环前进行的,如上所述,它将立即调用CMainFrame::OnCreate,然后直到CMainFrame::OnCreate返回,MFC才从创建CMainFrame的调用中返回,然后进入消息循环。
由于你在非模态对话框显示的过程中,一直没有让CMainFrame::OnCreate返回,结果主线程不能进入消息循环,导致放入队列的WM_TIMER消息无法响应。
如果采用模态对话框,从DoModal代码中可以看出,DoModal函数内部有一个消息泵,负责在DoModal未返回前取出和响应进入消息队列的消息,通过这个泵,WM_TIMER消息正确的被处理了。调用MessageBox就可以响应的原因也是这样。
#17
我想可能的解决办法是写一个TimerProc,作为SetTimer的参数。这样WM_TIMER消息不会进入队列而是直接调用TimerProc响应。
#18
原来是这样。原因In355Hz(好象一条狗)已经讲得很清楚了,不过他提出的解决办法不一定能行。因为即使给出了一个TimerProc,也需要程序进入消息循环才可以,只是此时你不用再处理WM_TIMER消息,而是由DefWindowProc来调用你设置的回调函数TimerProc,与前面一样的原因,OnCreate返回以前WM_TIMER是不能进入到DefWindowProc中的。当然,那只是我的分析,你先试试看。
如果不行的的话,你看看这个API,也许对你有用:SetWaitableTimer。
如果不行的的话,你看看这个API,也许对你有用:SetWaitableTimer。
#19
想想还是用两个线程来实现比较好。
#20
TimerProc好像试过,不打算再试乐。
开一个线程为了splash,只有MS会这么做:)
这部分的开发期限过去了,过两天抽时间在开N个线程,嘿嘿
开一个线程为了splash,只有MS会这么做:)
这部分的开发期限过去了,过两天抽时间在开N个线程,嘿嘿
#21
原来用TimerProc也需要消息队列,我以前都没有试验过。
#1
没有自己的消息循环,恐怕不行啊
#2
用钩子吧
#3
wokao
#4
不会呀,我的非模式对话框就能响应定时器呀!请先说说您是怎么做的,为什么不能响应?
#5
你需要重载主窗口的PreMessageFilter在消息过滤时做判断是不是对话框消息
用IsDialogMessage函数。他会自动将消息给你的对话框
用IsDialogMessage函数。他会自动将消息给你的对话框
#6
同意speakboy(一个菜鸟的自白---我想变成高手!) 的见解,先说说你是怎么做的吧,很可能是其他问题导致的。
#7
我是这样做的,
见:
http://www.csdn.net/Expert/TopicView1.asp?id=947034
见:
http://www.csdn.net/Expert/TopicView1.asp?id=947034
#8
因为你是在CGradientbar中调用的SetTimer,所有windows会把所有的WM_TIMER消息都发送到CGradientbar窗口,但你把对WM_TIMER的响应放到了CStatic中,它是收不到WM_TIMER消息的。我觉得你把ON_WM_TIMER移到CGradientbar中就可以了。
#9
汗....
绝对是这个原因,CWnd::SetTimer是调用::SetTimer(hwnd,...)实现的,timer在把WM_TIMER消息送到消息队列时会用hwnd的值填充MSG结构的hwnd成员,结果DispatchMessage就把WM_TIMER发给hwnd也就是调用SetTimer的窗口的Proc了,其它的窗口收不到。
原贴竟然讨论了那么多...
绝对是这个原因,CWnd::SetTimer是调用::SetTimer(hwnd,...)实现的,timer在把WM_TIMER消息送到消息队列时会用hwnd的值填充MSG结构的hwnd成员,结果DispatchMessage就把WM_TIMER发给hwnd也就是调用SetTimer的窗口的Proc了,其它的窗口收不到。
原贴竟然讨论了那么多...
#10
to webber84(糕鱼昏):
你是如何知道我把对WM_TIMER的响应放到了CStatic中?我不是已经在CGradientbar的cpp里定义了ON_WM_TIMER吗?
BEGIN_MESSAGE_MAP(CGradientbar, CStatic)
//{{AFX_MSG_MAP(CGradientbar)
ON_WM_PAINT()
ON_WM_TIMER()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
to 汗.....
我就是在CGradientbar::Start();里调用的SetTimer(),是这个不对吗?
为什么同样的代码,如果对话框是模式的就可以,非模式的就不可以呢?
要不,谁亲自做一个可以响应对话况或使其子窗口响应各自OnTimer函数的非模式对话框?
你是如何知道我把对WM_TIMER的响应放到了CStatic中?我不是已经在CGradientbar的cpp里定义了ON_WM_TIMER吗?
BEGIN_MESSAGE_MAP(CGradientbar, CStatic)
//{{AFX_MSG_MAP(CGradientbar)
ON_WM_PAINT()
ON_WM_TIMER()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
to 汗.....
我就是在CGradientbar::Start();里调用的SetTimer(),是这个不对吗?
为什么同样的代码,如果对话框是模式的就可以,非模式的就不可以呢?
要不,谁亲自做一个可以响应对话况或使其子窗口响应各自OnTimer函数的非模式对话框?
#11
to iProgram (小癞蛤蟆):
没看清楚你的原贴,不好意思。不过CGradientbar也的确不像是个static的名字,我还以为是一个dialogbar呢。等我回学校一定要试试看。
没看清楚你的原贴,不好意思。不过CGradientbar也的确不像是个static的名字,我还以为是一个dialogbar呢。等我回学校一定要试试看。
#12
作为主对话框的一个成员,然后在主对话框中作一个onTimer,在其中调用m_child.OnTimerEx(timeid),OnTimerEx为m_child的公有成员,就可以,这样就可以了。不过,在调用之前,一定是窗口追chuangjian了
#13
to iProgram : 对不起,我没有看清就回了贴,见笑了。
这是我在一个Modeless Dialog上运行的一个Static控件,处理了WM_TIMER消息,可以运行:
class CMyStatic : public CStatic
{
public:
CMyStatic();
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMyStatic)
protected:
virtual void PreSubclassWindow();
//}}AFX_VIRTUAL
virtual ~CMyStatic() {};
protected:
UINT m_iTimer;
// Generated message map functions
//{{AFX_MSG(CMyStatic)
afx_msg void OnDestroy();
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnTimer(UINT nIDEvent);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CMyStatic::CMyStatic()
{
m_iTimer = (UINT)-1;
}
BEGIN_MESSAGE_MAP(CMyStatic, CStatic)
//{{AFX_MSG_MAP(CMyStatic)
ON_WM_DESTROY()
ON_WM_CREATE()
ON_WM_TIMER()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CMyStatic::PreSubclassWindow()
{
if (m_iTimer == (UINT)-1)
m_iTimer = SetTimer(::GetWindowLong(GetSafeHwnd(), GWL_ID), 500, NULL);
CStatic::PreSubclassWindow();
}
void CMyStatic::OnDestroy()
{
CStatic::OnDestroy();
if (m_iTimer != (UINT)-1)
{
KillTimer(m_iTimer);
m_iTimer = (UINT)-1;
}
}
int CMyStatic::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CStatic::OnCreate(lpCreateStruct) == -1)
return -1;
if (m_iTimer == (UINT)-1)
m_iTimer = SetTimer(::GetWindowLong(GetSafeHwnd(), GWL_ID), 500, NULL);
return 0;
}
void CMyStatic::OnTimer(UINT nIDEvent)
{
CString strStatic;
GetWindowText(strStatic);
TCHAR tchar = strStatic[0];
strStatic.Delete(0);
strStatic += tchar;
SetWindowText(strStatic);
CStatic::OnTimer(nIDEvent);
}
模式对话框是这样创建的:
m_pAboutDlg = new CAboutDlg;
m_pAboutDlg->Create(CAboutDlg::IDD);
m_pAboutDlg->ShowWindow(SW_SHOW);
m_pAboutDlg->UpdateWindow();
CMyStatic作为一个DDX_Control加在对话框上
DDX_Control(pDX, IDC_MYSTATIC, m_myStatic);
不知道是不是和你的情况一致。
这是我在一个Modeless Dialog上运行的一个Static控件,处理了WM_TIMER消息,可以运行:
class CMyStatic : public CStatic
{
public:
CMyStatic();
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMyStatic)
protected:
virtual void PreSubclassWindow();
//}}AFX_VIRTUAL
virtual ~CMyStatic() {};
protected:
UINT m_iTimer;
// Generated message map functions
//{{AFX_MSG(CMyStatic)
afx_msg void OnDestroy();
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnTimer(UINT nIDEvent);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CMyStatic::CMyStatic()
{
m_iTimer = (UINT)-1;
}
BEGIN_MESSAGE_MAP(CMyStatic, CStatic)
//{{AFX_MSG_MAP(CMyStatic)
ON_WM_DESTROY()
ON_WM_CREATE()
ON_WM_TIMER()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CMyStatic::PreSubclassWindow()
{
if (m_iTimer == (UINT)-1)
m_iTimer = SetTimer(::GetWindowLong(GetSafeHwnd(), GWL_ID), 500, NULL);
CStatic::PreSubclassWindow();
}
void CMyStatic::OnDestroy()
{
CStatic::OnDestroy();
if (m_iTimer != (UINT)-1)
{
KillTimer(m_iTimer);
m_iTimer = (UINT)-1;
}
}
int CMyStatic::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CStatic::OnCreate(lpCreateStruct) == -1)
return -1;
if (m_iTimer == (UINT)-1)
m_iTimer = SetTimer(::GetWindowLong(GetSafeHwnd(), GWL_ID), 500, NULL);
return 0;
}
void CMyStatic::OnTimer(UINT nIDEvent)
{
CString strStatic;
GetWindowText(strStatic);
TCHAR tchar = strStatic[0];
strStatic.Delete(0);
strStatic += tchar;
SetWindowText(strStatic);
CStatic::OnTimer(nIDEvent);
}
模式对话框是这样创建的:
m_pAboutDlg = new CAboutDlg;
m_pAboutDlg->Create(CAboutDlg::IDD);
m_pAboutDlg->ShowWindow(SW_SHOW);
m_pAboutDlg->UpdateWindow();
CMyStatic作为一个DDX_Control加在对话框上
DDX_Control(pDX, IDC_MYSTATIC, m_myStatic);
不知道是不是和你的情况一致。
#14
void CTestDlg::OnTimer(UINT nIDEvent)
{
CTime t2 = CTime::GetCurrentTime();;
m_smsg.Format("%d:%d:%d",t2.GetHour(),t2.GetMinute(),t2.GetSecond());
UpdateData(FALSE);
CDialog::OnTimer(nIDEvent);
}
int CTestDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialog::OnCreate(lpCreateStruct) == -1)
return -1;
SetTimer(1,1000,NULL);
return 0;
}
{
CTime t2 = CTime::GetCurrentTime();;
m_smsg.Format("%d:%d:%d",t2.GetHour(),t2.GetMinute(),t2.GetSecond());
UpdateData(FALSE);
CDialog::OnTimer(nIDEvent);
}
int CTestDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CDialog::OnCreate(lpCreateStruct) == -1)
return -1;
SetTimer(1,1000,NULL);
return 0;
}
#15
有了一些进展。
我要实现的效果是,类似win98启动画面那种位图滚动的效果,把这种效果加在我程序的splash中,于是我做了一个类CGradientbar实现这种滚动效果,CGradientbar中用到了定时器。
我要在CMainFrame::OnCreate中显示这个Splash,因为要在OnCreate加载很多东西,耗时15秒种,因此会在OnCreate进行中,不断把所作的事情显示在splash的一个Static中(这个一直工作正常),起初因为splash只出现在OnCreate中,我直接在OnCreate的堆栈上创建splash对话框,发现定时器无效。后来改在堆上创建(CSplashDlg* m_pSplashDlg作为类成员在.h里声明),定时器依然无效,但我在OnCreate返回之前没有删除splash对象(没有delete m_pSplashDlg;),发现CMainFrame::OnCreate返回之后定时器才开始工作。所以问题不是出在非模式对话框上,问题应该是为什么在CMainFrame::OnCreate函数开始时启动的m_pSplashDlg中的定时器直到CMainFrame::OnCreate返回后才开始工作?
相关代码:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
m_pSplash=new CSplashDlg(this);
m_pSplash->Create(IDD_DIALOG_SPLASH);
m_pSplash->SetWindowPos(&(CWnd::wndTopMost),0,0,380,280,SWP_NOMOVE|SWP_DRAWFRAME);
// m_wndBar是CGradientbar对象,CGradientbar::Start(0做一些初始工作,并启动CGradientbar的定时器
m_pSplash->m_wndBar.Start();
m_pSplash->ShowWindow(SW_SHOW);
m_pSplash->UpdateWindow();
//现在开始做耗时很长的加载工作
........................................................
//其间不断的把工作显示在m_pSplash上:
m_pSplash->GetDlgItem(IDC_STATIC_TODO)->SetWindowText("正在加载xxxxxx");
..........................................................
//delete m_pSplash; //如果此时不delete,return 0后m_pSplash->m_wndBar的定时器才开始工作,TNND
return 0;
}
我要实现的效果是,类似win98启动画面那种位图滚动的效果,把这种效果加在我程序的splash中,于是我做了一个类CGradientbar实现这种滚动效果,CGradientbar中用到了定时器。
我要在CMainFrame::OnCreate中显示这个Splash,因为要在OnCreate加载很多东西,耗时15秒种,因此会在OnCreate进行中,不断把所作的事情显示在splash的一个Static中(这个一直工作正常),起初因为splash只出现在OnCreate中,我直接在OnCreate的堆栈上创建splash对话框,发现定时器无效。后来改在堆上创建(CSplashDlg* m_pSplashDlg作为类成员在.h里声明),定时器依然无效,但我在OnCreate返回之前没有删除splash对象(没有delete m_pSplashDlg;),发现CMainFrame::OnCreate返回之后定时器才开始工作。所以问题不是出在非模式对话框上,问题应该是为什么在CMainFrame::OnCreate函数开始时启动的m_pSplashDlg中的定时器直到CMainFrame::OnCreate返回后才开始工作?
相关代码:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
m_pSplash=new CSplashDlg(this);
m_pSplash->Create(IDD_DIALOG_SPLASH);
m_pSplash->SetWindowPos(&(CWnd::wndTopMost),0,0,380,280,SWP_NOMOVE|SWP_DRAWFRAME);
// m_wndBar是CGradientbar对象,CGradientbar::Start(0做一些初始工作,并启动CGradientbar的定时器
m_pSplash->m_wndBar.Start();
m_pSplash->ShowWindow(SW_SHOW);
m_pSplash->UpdateWindow();
//现在开始做耗时很长的加载工作
........................................................
//其间不断的把工作显示在m_pSplash上:
m_pSplash->GetDlgItem(IDC_STATIC_TODO)->SetWindowText("正在加载xxxxxx");
..........................................................
//delete m_pSplash; //如果此时不delete,return 0后m_pSplash->m_wndBar的定时器才开始工作,TNND
return 0;
}
#16
对你的问题有一些理解了:
WM_CREATE是一个不进队消息,当调用CreateWindow(Ex)创建窗口时,会直接调用窗口过程处理WM_CREATE消息,而且该CreateWindow(Ex)调用直到窗口过程处理WM_CREATE返回后才返回。
CMainFrame的创建是在MFC进入消息循环前进行的,如上所述,它将立即调用CMainFrame::OnCreate,然后直到CMainFrame::OnCreate返回,MFC才从创建CMainFrame的调用中返回,然后进入消息循环。
由于你在非模态对话框显示的过程中,一直没有让CMainFrame::OnCreate返回,结果主线程不能进入消息循环,导致放入队列的WM_TIMER消息无法响应。
如果采用模态对话框,从DoModal代码中可以看出,DoModal函数内部有一个消息泵,负责在DoModal未返回前取出和响应进入消息队列的消息,通过这个泵,WM_TIMER消息正确的被处理了。调用MessageBox就可以响应的原因也是这样。
WM_CREATE是一个不进队消息,当调用CreateWindow(Ex)创建窗口时,会直接调用窗口过程处理WM_CREATE消息,而且该CreateWindow(Ex)调用直到窗口过程处理WM_CREATE返回后才返回。
CMainFrame的创建是在MFC进入消息循环前进行的,如上所述,它将立即调用CMainFrame::OnCreate,然后直到CMainFrame::OnCreate返回,MFC才从创建CMainFrame的调用中返回,然后进入消息循环。
由于你在非模态对话框显示的过程中,一直没有让CMainFrame::OnCreate返回,结果主线程不能进入消息循环,导致放入队列的WM_TIMER消息无法响应。
如果采用模态对话框,从DoModal代码中可以看出,DoModal函数内部有一个消息泵,负责在DoModal未返回前取出和响应进入消息队列的消息,通过这个泵,WM_TIMER消息正确的被处理了。调用MessageBox就可以响应的原因也是这样。
#17
我想可能的解决办法是写一个TimerProc,作为SetTimer的参数。这样WM_TIMER消息不会进入队列而是直接调用TimerProc响应。
#18
原来是这样。原因In355Hz(好象一条狗)已经讲得很清楚了,不过他提出的解决办法不一定能行。因为即使给出了一个TimerProc,也需要程序进入消息循环才可以,只是此时你不用再处理WM_TIMER消息,而是由DefWindowProc来调用你设置的回调函数TimerProc,与前面一样的原因,OnCreate返回以前WM_TIMER是不能进入到DefWindowProc中的。当然,那只是我的分析,你先试试看。
如果不行的的话,你看看这个API,也许对你有用:SetWaitableTimer。
如果不行的的话,你看看这个API,也许对你有用:SetWaitableTimer。
#19
想想还是用两个线程来实现比较好。
#20
TimerProc好像试过,不打算再试乐。
开一个线程为了splash,只有MS会这么做:)
这部分的开发期限过去了,过两天抽时间在开N个线程,嘿嘿
开一个线程为了splash,只有MS会这么做:)
这部分的开发期限过去了,过两天抽时间在开N个线程,嘿嘿
#21
原来用TimerProc也需要消息队列,我以前都没有试验过。