1

I want to click a button and shown it "pressed" until a timer has terminated.

The problem I have is, wenn I use CButton::SetState(TRUE) the function OnBnClickedButton1() is called always twice and even worse it is called again when I press a another button in the dialog or hide the dialog window.

(Update: I have now tested the same code at home under VS6 with WindowsXP, it works fine as expected. At work (VS2010 with Window 10) this code does not work.)

Header file

class CTestDialog : public CDialog
{
    CButton btnButton1;

    enum {eTimerCoolingId = 123};
    BOOL m_bCooling;
    DWORD m_dwStartTick;
    ...
}

CPP file

...
DDX_Control(pDX, IDC_BUTTON1, m_btnButton1);

void CTestDialog::OnBnClickedButton1()
{
    m_bCooling = !m_bCooling;
    m_btnButton1.SetState(m_bCooling);
    m_dwStartTick = GetTickCount();

    if (m_bCooling)
        SetTimer(eTimerCoolingId,100,NULL);
    else
        KillTimer(eTimerCoolingId);
}

void CTestDlg::OnTimer(UINT nIDEvent) 
{
    int nCoolTime = 5;  // [sec]
    CString str;

    switch(nIDEvent)
    {
    case eTimerCoolingId:

        int nElapsedTime = (GetTickCount() - m_dwStartTick) / 1000;
        if (nElapsedTime > nCoolTime)
        {
            KillTimer(eTimerCoolingId);
            m_bCooling = false;
            m_btnButton1.SetState(FALSE);
            str.Format("Cooler On");
        }
        else
        {
            str.Format("Cooling.. %d [sec]", (nCoolTime - nElapsedTime));
        }
    }

   m_btnButton1.SetWindowText(str);
   CDialog::OnTimer(nIDEvent);
}
Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
Tom Tom
  • 1,127
  • 11
  • 25
  • Are btnStartTimer and OnBnClickedButton1 for the same button or different buttons? – Werner Henze Apr 20 '16 at 07:52
  • Show the button as disabled rather. – acraig5075 Apr 20 '16 at 07:52
  • What is the ID of the button? Are you using the same ID twice? Are you calling OnBnClickedButton1 also for other Messages (see message map)? You can set a breakpoint in OnBnClickedButton1 and check the call stack every time the breakpoint is hit to see who is calling the function and what the message was. – Werner Henze Apr 20 '16 at 07:59
  • - Yes, btnStartTimer and OnBnClickedButton1 is for the same button. - Suggestion as Disabled button is not an option, because I want stop the timer if I press the same button again. – Tom Tom Apr 20 '16 at 08:17
  • @Michael You can genarate a simple Dialog based using the MFC Application Wizard and add a simple button. OnBnClickedButton1() will always called twice when the associate m_btnButton1 is set with SetState(TRUE). – Tom Tom Apr 20 '16 at 09:20
  • @TomTom you should make that clear in your question. Please update your question. – Jabberwocky Apr 20 '16 at 10:02
  • @TomTom I could not reproduce the problem. We need more information. Maybe your message map is messed up or there is some other error in the code you didn't show. Without more information the question cannot be answered. – Jabberwocky Apr 20 '16 at 10:07
  • If your intent is to manage the rendering of the button, why are you not using an owner drawn button that uses the timer to render the state of the button? At the end of the timer, you can invalidate the button and release the "pressed" state. – rrirower Apr 20 '16 at 14:35
  • @Michael Walz. Add a break point in OnBnClickedBtn1() and run it under debugger and tell me if it's called twice. – Tom Tom Apr 21 '16 at 08:31
  • 1
    @TomTom What I could reproduce is following: when I comment out the call to `SetState` in `OnBnClickedButton1` everything works as expected. When I leave the call to `SetState`, it first works, but when I click on another unrelated button (such as "Cancel") while the countdown is running, `OnBnClickedButton1` gets called immediately even before the mouse button is released. So there is obviously something fishy going on with `SetState`. My suggestion: simply don't use `SetState`. This test has been done on Windows 7. – Jabberwocky Apr 21 '16 at 09:11
  • @Michael Walz. Yes it's hopeless, SetStafe(TRUE) is very fishy. And probably not indended for push like buttons. MSDN says only: "Sets whether a button control is highlighted or not." – Tom Tom Apr 21 '16 at 10:31

1 Answers1

0

It's hopeless. SetState(TRUE) is very fishy and probably not indended for push like buttons. MSDN says:

"Set whether a button control is higilighted or not".

I have tried it with different buttons (Nornal-, Radio-, CheckBox-, MFCButton). For all of this buttons: SetState is forcing the message handler to be called again. (Don't know why!?)

I use now a Check-Box Button and set the push-like style. And call CButton::SetCheck() instead of SetState().

Tom Tom
  • 1,127
  • 11
  • 25