MFC CMainFrame切换登录登出子按钮时第二次登录后控件不更新问题
问题根因
你的代码核心问题出在logout()函数的逻辑缺失:
- 登录函数
login()切换控件前会主动销毁所有子窗口,但是登出函数logout()没有做这一步,直接在原有登出按钮的位置叠加创建了新的登录按钮。 - 第一次执行登录→登出操作后,窗口内同时存在叠放的登出按钮和登录按钮,仅后创建的登录按钮可见可点击。
- 第二次执行登录操作时,虽然销毁了所有子控件再重新创建登出按钮,但因为MFC子控件Z序、重绘机制的冲突,新创建的登出按钮无法正常接收点击消息。
另外你的代码还存在堆内存泄漏问题:每次new的CButton对象没有被主动释放,仅销毁了关联的HWND窗口句柄。
修复方案
推荐两种修复方式,优先选第一种更稳定:
方案1:预创建两个按钮,切换显示/隐藏状态(推荐)
不需要反复销毁创建控件,逻辑更简单不易出问题,修改后的核心代码如下:
#define LOGIN_BTN 1 #define LOGOUT_BTN 2 class CMainFrame: public CFrameWnd { public: CMainFrame() { Create( NULL, "Learn MFC", WS_OVERLAPPEDWINDOW, CRect(CPoint(100, 100), CSize(640, 360))); }; protected: CButton* m_pLoginBtn = nullptr; CButton* m_pLogoutBtn = nullptr; afx_msg int OnCreate(LPCREATESTRUCT); afx_msg void login(); afx_msg void logout(); DECLARE_MESSAGE_MAP() // 析构函数释放内存 virtual ~CMainFrame() { if (m_pLoginBtn) delete m_pLoginBtn; if (m_pLogoutBtn) delete m_pLogoutBtn; } }; BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) ON_WM_CREATE() ON_COMMAND(LOGIN_BTN, &CMainFrame::login) ON_COMMAND(LOGOUT_BTN, &CMainFrame::logout) END_MESSAGE_MAP() int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { // 预创建两个按钮 m_pLoginBtn = new CButton(); m_pLoginBtn->Create( "Login", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, CRect(CPoint(100, 60), CSize(150, 25)), this, LOGIN_BTN); m_pLogoutBtn = new CButton; m_pLogoutBtn->Create( "Logout", WS_CHILD | BS_PUSHBUTTON, // 默认不显示,去掉WS_VISIBLE CRect(CPoint(100, 60), CSize(150, 25)), this, LOGOUT_BTN); return 0; }; void CMainFrame::login() { std::string resServer = "token"; if(resServer == "token") { // 切换显示状态即可 m_pLoginBtn->ShowWindow(SW_HIDE); m_pLogoutBtn->ShowWindow(SW_SHOW); }; } void CMainFrame::logout() { // 直接切换显示状态 m_pLogoutBtn->ShowWindow(SW_HIDE); m_pLoginBtn->ShowWindow(SW_SHOW); }; class CApplication : public CWinApp { BOOL InitInstance() { CMainFrame* mainWnd = new CMainFrame(); m_pMainWnd = mainWnd; mainWnd->ShowWindow(SW_NORMAL); mainWnd->UpdateWindow(); return TRUE; } }; CApplication app;
方案2:修复原有销毁逻辑
如果你一定要用动态创建销毁的方式,只需要给logout()函数补上销毁旧控件的逻辑即可:
void CMainFrame::logout() { // 先销毁所有子窗口,和login函数逻辑对齐 while(GetWindow(GW_CHILD)) { CWnd* pChild = GetWindow(GW_CHILD); pChild->DestroyWindow(); // 释放C++对象内存,避免泄漏 delete pChild; } CButton* loginBtn = new CButton(); loginBtn->Create( "Login", WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, CRect(CPoint(100, 60), CSize(150, 25)), this, LOGIN_BTN); };
两种方案都可以解决第二次登录后登出按钮无法点击的问题。
内容的提问来源于stack exchange,提问作者juragan
相关产品推荐
相关产品推荐

