ilovehellworld 2024-03-04 10:34 采纳率: 62.5%
浏览 15
已结题

mfc消息自创建控件

windows10 vs2010 mfc自创建的一个支持毫秒的时间控件,在release dubug下都正常,但是在win10下,重启电脑进入桌面后马上运行里面的demo.exe就会出现问题,这个控件会跑到窗体的左上角。如果重启电脑进入桌面过一会等完全启动后,再运行这个demo.exe就正常了,非常困惑,请大家帮帮忙,谢谢!
代码如下:

TimeWnd.h

#pragma once
#include "afxwin.h"
#define WM_TIMECHNGE WM_USER+50
class CTimeWnd :
    public CWnd
{
public:
    enum Value
    {
        valHours = 0,
        valMinutes,
        valSeconds,
        valMilliseconds,
        valCount
    };
 
    DECLARE_MESSAGE_MAP()
 
    int m_nValue[valCount];
    int m_nValueMax[valCount];
    double m_dPower[valCount];
    double m_dMinTime;
    double m_dMaxTime;
private:
    CRect m_Rect[valCount];
    int m_nCurSel;
    int m_nOldSel;
    CFont *m_pFont;
    bool m_bFocus;
    CSpinButtonCtrl m_Spin;
    int m_nFirst;
 
public:
    CTimeWnd(void);
    virtual ~CTimeWnd(void);
    CString GetString(int nType);
    void SetFont(CFont *pFont, BOOL bRedraw =false);
    CFont *GetFont();    
    double GetTime();
    int GetValue(int nType);
    void SetValue(int nType, int nVal);
    void SetTime(double dTime);
    void SetRange( double dMinTime, double dMaxTime );
    void SetRangeMax( int nHour, int nMin, int nSecond, int nMilliSecond );
    void SetRangeMin( int nHour, int nMin, int nSecond, int nMilliSecond );
    virtual BOOL PreTranslateMessage(MSG *pMsg);
    virtual void PreSubclassWindow();
    afx_msg void OnPaint();
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
    afx_msg void OnKillFocus(CWnd *pNewWnd);
    afx_msg void OnDeltaposSpin1(NMHDR *pNMHDR, LRESULT *pResult);
    afx_msg void OnSize(UINT nType, int cx, int cy);
    afx_msg void OnCaptureChanged(CWnd *pWnd);
    afx_msg void OnEnable(BOOL bEnable);
private:
    bool IsCountValid(int nCount);
    void ChangeChar(UINT nChar, int refer);
    void ChangeSpin(int nDelta);
    bool VarifyRange();
    void DrawSingleString(CDC *pDC, CString &str, CRect &rc, int *pOffset = NULL, bool bSelect = false);
    int GetNumberCount(int num);
    bool IsFocus();
    void ReDraw(bool bNeedBk = true);
};


TimeWnd.cpp

#include "StdAfx.h"
#include "TimeWnd.h"
 
CTimeWnd::CTimeWnd(void)
{
    for (int i=0; i<valCount; i++)
    {
        m_nValue[i] = 0;
        m_Rect[i].SetRectEmpty();
    }
    m_nValueMax[valHours] = 24;
    m_nValueMax[valMinutes] = 60;
    m_nValueMax[valSeconds] = 60;
    m_nValueMax[valMilliseconds] = 1000;
 
    m_dPower[valHours] = 3600;
    m_dPower[valMinutes] = 60;
    m_dPower[valSeconds] = 1;
    m_dPower[valMilliseconds] = 0.001000;
    m_nFirst = 0;
            
    m_nCurSel = -1;
    m_nOldSel = 0;
    m_pFont = NULL;
    m_dMinTime = 0;
    m_dMaxTime = 90000;
    m_bFocus = false;
}
 
CTimeWnd::~CTimeWnd(void)
{
}
 
BEGIN_MESSAGE_MAP(CTimeWnd, CWnd)
 
ON_WM_PAINT()
    ON_WM_CREATE()
    ON_WM_LBUTTONDOWN()
    ON_WM_KEYDOWN()
    ON_NOTIFY(UDN_DELTAPOS, 1051, &CTimeWnd::OnDeltaposSpin1)
    ON_WM_KILLFOCUS()
    ON_WM_SIZE()
    ON_WM_CAPTURECHANGED()
    ON_WM_ENABLE()
END_MESSAGE_MAP()
 
void CTimeWnd::OnDeltaposSpin1(NMHDR *pNMHDR, LRESULT *pResult)
{
    LPNMUPDOWN pNMUpDown = reinterpret_cast<LPNMUPDOWN>(pNMHDR);
    *pResult = 0;
    SetFocus();
    ChangeSpin(pNMUpDown->iDelta*(-1));
}
 
void CTimeWnd::ChangeSpin(int nDelta)
{
    if(m_nCurSel == -1)
    {
        m_nCurSel = m_nOldSel;
    }
    if (nDelta > 0)
    {
        m_nValue[m_nCurSel] = (m_nValue[m_nCurSel]+nDelta)%m_nValueMax[m_nCurSel];
    }
    else
    {
        m_nValue[m_nCurSel] = (m_nValue[m_nCurSel]+nDelta+m_nValueMax[m_nCurSel])%m_nValueMax[m_nCurSel];
    }
    
    VarifyRange();
    ReDraw(true);
    GetParent()->PostMessage(WM_TIMECHNGE, (WPARAM)GetDlgCtrlID(), (LPARAM)GetTime());
}
 
void CTimeWnd::OnPaint()
{
    CPaintDC dc(this); // device context for painting
    CRect rcBounds;   
    GetClientRect(&rcBounds);   
    CPen penWhite;   
    penWhite.CreatePen(PS_SOLID, 1, RGB(127,157,185));   
    CPen *pOldPen = dc.SelectObject(&penWhite); 
    dc.FillSolidRect(rcBounds, RGB(255,255,255));
    dc.MoveTo(rcBounds.left, rcBounds.top);   
    dc.LineTo(rcBounds.right-1, rcBounds.top);   
    dc.LineTo(rcBounds.right-1, rcBounds.bottom-1);   
    dc.LineTo(rcBounds.left, rcBounds.bottom-1);   
    dc.LineTo(rcBounds.left, rcBounds.top);  
    CString    str = NULL;
    int xoffset = 5;
    CRect rc;
    rc.SetRectEmpty();
    for(int i=0; i<valCount; i++)
    {
        str = GetString(i);
        rc = rcBounds;
        DrawSingleString(&dc,str,rc,&xoffset,(i == m_nCurSel));
        m_Rect[i] = rc;
        switch (i)
        {
        case 0:
        case 1:
            str = _T(":");
            rc = rcBounds;
            DrawSingleString(&dc, str, rc, &xoffset);
            break;
        case 2:
            str = _T(".");
            rc = rcBounds;
            DrawSingleString(&dc, str, rc, &xoffset);
            break;
        }
    }
    dc.SelectObject(pOldPen); 
}
 
void CTimeWnd::PreSubclassWindow()
{
    CWnd::PreSubclassWindow();
}
 
int CTimeWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CWnd::OnCreate(lpCreateStruct) == -1)
        return -1;
 
    m_Spin.Create(UDS_ALIGNRIGHT|UDS_AUTOBUDDY|WS_VISIBLE, CRect(0,0,20,19), this, 1051);
    m_Spin.SetBuddy(this);
 
    return 0;
}
 
void CTimeWnd::OnLButtonDown(UINT nFlags, CPoint point)
{
    for (int i=0; i<valCount; i++)
    {
        if (m_Rect[i].PtInRect(point))
        {
            if (m_nCurSel == i)break;
            m_nFirst = 0;
            ReDraw(false);
            m_nCurSel = i;
            ReDraw(true);
            break;
        }
    }
    SetFocus();
    m_bFocus = true;
    CWnd::OnLButtonDown(nFlags, point);
}
 
void CTimeWnd::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
     if (m_nCurSel == -1)
    {
        m_nCurSel = m_nOldSel;
    }
    if ((nChar>='0') && (nChar<='9'))
    {
        ChangeChar(nChar, '0');
    }
    else if ((nChar>=VK_NUMPAD0) && (nChar<=VK_NUMPAD9))
    {
        ChangeChar(nChar, VK_NUMPAD0);
    }
    ReDraw(true);
    CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}
 
CString CTimeWnd::GetString(int nType)
{
    CString str = NULL;
    int nCount = 0;
    int nZero = 0;
    nCount = GetNumberCount(m_nValueMax[nType]-1);
    nZero = nCount - GetNumberCount(m_nValue[nType]) ;
    m_nValue[nType] %= m_nValueMax[nType];
    str.Format(_T("%d"), m_nValue[nType]);
    while (nZero--)
    {
        str = _T("0") + str;
    }
    return str;
}

void CTimeWnd::SetRange( double dMinTime, double dMaxTime )
{
    m_dMinTime = dMinTime;
    m_dMaxTime = dMaxTime;
    VarifyRange();
}

void CTimeWnd::SetRangeMax( int nHour, int nMin, int nSecond, int nMilliSecond )
{
    double dMaxTime = 0;
    dMaxTime += nHour * m_dPower[valHours];
    dMaxTime += nMin * m_dPower[valMinutes];
    dMaxTime += nSecond * m_dPower[valSeconds];
    dMaxTime += nMilliSecond * m_dPower[valMilliseconds];
    m_dMaxTime = dMaxTime;
    VarifyRange();
}
void CTimeWnd::SetRangeMin( int nHour, int nMin, int nSecond, int nMilliSecond )
{
    double dMinTime = 0;
    dMinTime += nHour * m_dPower[valHours];
    dMinTime += nMin * m_dPower[valMinutes];
    dMinTime += nSecond * m_dPower[valSeconds];
    dMinTime += nMilliSecond * m_dPower[valMilliseconds];
    m_dMinTime = dMinTime;
    VarifyRange();
}
bool CTimeWnd::VarifyRange()
{
    bool bRet = false;
    double dCur = GetTime();
    if(    m_dMinTime > dCur )
    {
        dCur = m_dMinTime;
        bRet = true;
    }
    if(    m_dMaxTime < dCur )
    {
        dCur = m_dMaxTime;
        bRet = true;
    }
    if(bRet)
    {
        double nTemVal = 0;
        for (int i=0; i<valCount; i++)
        {
            m_nValue[i] = (int)((dCur+0.0005 - nTemVal) / m_dPower[i]);
            nTemVal += m_nValue[i] * m_dPower[i];
            m_nValue[i] %= m_nValueMax[i]; 
        }
        CRect   rcBounds;   
        GetClientRect(&rcBounds);
        rcBounds.right -= 20;
        RedrawWindow( &rcBounds );
    }
    return bRet;
}
void CTimeWnd::DrawSingleString(CDC *pDC, CString &str, CRect &rc, int *pOffset/*= -1*/, bool bSelect/* = false*/)
{
    int nHeight = rc.Height();
    int offset = 0;
    if (pOffset == NULL)
    {
        offset = rc.left;
    }
    else
    {
        offset = *pOffset;
    }
    CFont *pOldFont = NULL;
    if (m_pFont)
    {
        pOldFont = pDC->SelectObject(m_pFont);
    }
    pDC->DrawText(str, rc, DT_CALCRECT);
    rc.MoveToXY(offset, (nHeight - rc.Height())/2);
    COLORREF clr;
    int nMode = 0;
    BOOL bEnable = IsWindowEnabled();
    if (bSelect && bEnable)
    {
        pDC->FillSolidRect(rc, RGB(49,106,197));
        clr = pDC->SetTextColor(RGB(255,255,255));
        nMode = pDC->SetBkMode(TRANSPARENT);
    }
    else
    {
        pDC->FillSolidRect(rc, RGB(255,255,255));
    }
    if (bEnable)
         pDC->DrawState(CPoint(rc.left, rc.top), CSize(rc.Width(), rc.Height()), str, DSS_NORMAL, TRUE, 0, (HBRUSH)NULL);
    else
        pDC->DrawState(CPoint(rc.left, rc.top), CSize(rc.Width(), rc.Height()), str, DSS_DISABLED, TRUE, 0, (HBRUSH)NULL);
    offset += rc.Width();
    offset = offset + 1;  // 2023.3.25 by yeyizhou
    if (bSelect)
    {
        pDC->SetTextColor(clr);
        pDC->SetBkMode(nMode);
    }
    if (pOffset) *pOffset = offset;
    if (pOldFont) pDC->SelectObject(pOldFont);
}
 
void CTimeWnd::OnKillFocus(CWnd *pNewWnd)
{
    CWnd::OnKillFocus(pNewWnd);
    ReDraw(false);
    m_nOldSel = m_nCurSel;
    m_nCurSel = -1;
    m_bFocus = false; 
}
 
void CTimeWnd::ReDraw(bool bNeedBk/*= true*/)
{
    if (m_nCurSel == -1)
    {
        return;
    }
    CDC *pDC = GetDC();
    CString str = GetString(m_nCurSel);
    CRect   rcBounds;   
    GetClientRect(&rcBounds);   
    rcBounds.left = m_Rect[m_nCurSel].left;
    rcBounds.right = m_Rect[m_nCurSel].right;
    DrawSingleString(pDC, str, rcBounds, NULL, bNeedBk);
    ReleaseDC(pDC);
}
 
void CTimeWnd::SetFont(CFont *pFont, BOOL bRedraw/*=false*/)
{
    m_pFont = pFont;
    if (bRedraw)
    {
        Invalidate();
    }
}
 
CFont *CTimeWnd::GetFont()
{
    return m_pFont;
}
 
void CTimeWnd::ChangeChar(UINT nChar, int refer)
{
    if (!IsCountValid(m_nCurSel)) return;
    int iCharValue = nChar - refer;
    int iTemVal = m_nValue[m_nCurSel] * 10 + iCharValue;
    //m_nValue[m_nCurSel] = (iTemVal >= m_nValueMax[m_nCurSel]) ? iCharValue : iTemVal;
    m_nValue[m_nCurSel] = (m_nFirst<=0) ? iCharValue : (iTemVal%m_nValueMax[m_nCurSel]);
    if(m_nCurSel==3)
    {
        if(++m_nFirst>2 )
            m_nFirst = 0;
    }
    else
        m_nFirst = !m_nFirst;
    VarifyRange();
    GetParent()->PostMessage(WM_TIMECHNGE, (WPARAM)GetDlgCtrlID(), (LPARAM)GetTime());
}
 
 
BOOL CTimeWnd::PreTranslateMessage(MSG *pMsg)
{
    if (pMsg->message == WM_KEYDOWN)
    {
        if (pMsg->wParam == VK_UP)
        {
            ChangeSpin(1);
            return true;
        }
        if (pMsg->wParam == VK_DOWN)
        {
            ChangeSpin(-1);
            return true;
        }
        if (pMsg->wParam == VK_LEFT)
        {
            ReDraw(false);
            m_nCurSel = (m_nCurSel + valCount - 1) % valCount;
            ReDraw(true);
            return true;
        }
        if (pMsg->wParam == VK_RIGHT)
        {
            ReDraw(false);
            m_nCurSel = (m_nCurSel + 1) % valCount;
            ReDraw(true);
            return true;
        }
        if (pMsg->wParam == VK_END)
        {        
            m_nValue[m_nCurSel] = m_nValueMax[m_nCurSel];
        }
        if (pMsg->wParam == VK_HOME)
        {
            m_nValue[m_nCurSel] = 0;
        }
    }
    return CWnd::PreTranslateMessage(pMsg);
}
 
double CTimeWnd::GetTime()
{
    double dTime = 0;
    for (int i=0; i<valCount; i++)
    {
        dTime += m_nValue[i] * m_dPower[i];
    }
    return dTime;
}
 
int CTimeWnd::GetValue(int nType)
{
    if (!IsCountValid(nType)) 
        return 0;
    else 
        return m_nValue[nType];
}
 
void CTimeWnd::SetValue(int nType, int nVal)
{
    if ((!IsCountValid(nType)) || nVal<0) return;
    else m_nValue[nType] = nVal % m_nValueMax[nType];
    
    VarifyRange();
}
 
void CTimeWnd::SetTime(double dTime)
{
    double nTemVal = 0;
    for (int i=0; i<valCount; i++)
    {
        m_nValue[i] = (int)((dTime+0.0005 - nTemVal) / m_dPower[i]);
        nTemVal += m_nValue[i] * m_dPower[i];
        m_nValue[i] %= m_nValueMax[i]; 
    }
    VarifyRange();
}
 
bool CTimeWnd::IsFocus()
{
    return m_bFocus;
}
 
void CTimeWnd::OnSize(UINT nType, int cx, int cy)
{
    CWnd::OnSize(nType, cx, cy);
    m_Spin.MoveWindow(cx-19, 1, 18, cy-2);
}
 
void CTimeWnd::OnCaptureChanged(CWnd *pWnd)
{
    CWnd::OnCaptureChanged(pWnd);
}
 
void CTimeWnd::OnEnable(BOOL bEnable)
{
    CWnd::OnEnable(bEnable);
    Invalidate();
    m_Spin.EnableWindow(bEnable);
}
 
int CTimeWnd::GetNumberCount(int num)
{
    int i = 0;
    if (num == 0)
    {
        return 1;
    }
    while (num)
    {
        num /= 10;    
        i++;
    };
    return i;
}
 
bool CTimeWnd::IsCountValid(int nCount)
{
    if ((nCount>=0) && (nCount<valCount))
    {
        return true;
    }
    return false;
}


OnInitDialog()


    CRect rt(0,0,120,25);  
    if( !m_wndTime_StartPoint.Create( _T("Static"),_T(""),WS_CHILD|WS_VISIBLE|SS_NOTIFY,rt,this,1981) )
        MessageBox(_T("Error"));
    m_wndTime_StartPoint.MoveWindow(100,100,120,25);
  • 写回答

18条回答 默认 最新

  • 专家-郭老师 Java领域新星创作者 2024-03-04 10:35
    关注

    🌈🌈🌈参考通义千问和郭老师的小迷弟雅思莫了-编写提供🌈🌈🌈
    您可以参考如下,如果回答的不正确,及时评论区回复我,我会根据你错误描述追加回复,直到您满意为止。

    你的代码中的移动窗口函数 MoveWindow(100,100,120,25); 被直接放在创建窗口后面。考虑在系统启动初期,系统服务可能还没有完全启动,一些系统调用可能无法按照预期工作,所以可能是MoveWindow函数在系统刚启动时没有正常工作。
    如果在创建窗口后立即移动窗口,可能存在窗口还未完全创建完就调用了MoveWindow的情况。你可以试着在创建窗口和移动窗口之间添加一些延时,例如:

    if( !m_wndTime_StartPoint.Create( _T("Static"),_T(""),WS_CHILD|WS_VISIBLE|SS_NOTIFY,rt,this,1981) )
        MessageBox(_T("Error"));
    
    // 添加延时
    Sleep(500);   // 延迟500毫秒,可以根据实际情况调整
    
    m_wndTime_StartPoint.MoveWindow(100,100,120,25);
    
    
    

    另外,如果存在依赖某些系统服务的可能,可以考虑将启动这个demo.exe的操作延迟一段时间,使得在系统服务启动完全后再运行。
    以上是两个可能的解决办法,更好的策略可能需要你对问题的复现环境和复现步骤有更深入的了解和调试。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(17条)

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 3月5日
  • 已采纳回答 3月5日
  • 创建了问题 3月4日

悬赏问题

  • ¥15 Vue3 大型图片数据拖动排序
  • ¥15 划分vlan后不通了
  • ¥15 GDI处理通道视频时总是带有白色锯齿
  • ¥20 用雷电模拟器安装百达屋apk一直闪退
  • ¥15 算能科技20240506咨询(拒绝大模型回答)
  • ¥15 自适应 AR 模型 参数估计Matlab程序
  • ¥100 角动量包络面如何用MATLAB绘制
  • ¥15 merge函数占用内存过大
  • ¥15 使用EMD去噪处理RML2016数据集时候的原理
  • ¥15 神经网络预测均方误差很小 但是图像上看着差别太大