Dynamic Button Creation - Programmers Heaven

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories

Welcome to the new platform of Programmer's Heaven! We apologize for the inconvenience caused, if you visited us from a broken link of the previous version. The main reason to move to a new platform is to provide more effective and collaborative experience to you all. Please feel free to experience the new platform and use its exciting features. Contact us for any issue that you need to get clarified. We are more than happy to help you.

Dynamic Button Creation

cherrymcherrym Posts: 2Member
I have a dialog box which I would like to create a variable number of buttons at run time. I use the CButton class, and the Create method in it, and it returns a True (for success), but I don't see the button within the dialog box. Also, any ideas how I would handle the message map event lines, since I don't know what buttons will be on the screen until run time? Thanks...

«1

Comments

  • DB1DB1 Posts: 1,142Member
    : I have a dialog box which I would like to create a variable number of buttons at run time. I use the CButton class, and the Create method in it, and it returns a True (for success), but I don't see the button within the dialog box. Also, any ideas how I would handle the message map event lines, since I don't know what buttons will be on the screen until run time? Thanks...
    :
    :

    After you create the button you have to make it visible cButton->ShowWindow(true); The question about the message mapping I would like answered also.


    [italic][blue]To understand recursive, first you need to understand recursive[/blue][/italic]

  • stoberstober Posts: 9,765Member ✭✭✭
    [blue]You have to manually set up the message map for these OnButtonClick events. The following code allocates 10 buttons and uses the same event handler for each (see [red]RED[/red] below[/blue]

    [code]
    BEGIN_MESSAGE_MAP(CTestDlg, CDialog)
    //{{AFX_MSG_MAP(CTestDlg)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    [red] ON_CONTROL_RANGE(BN_CLICKED,100,110,OnButton1)[/red]
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()

    BOOL CTestDlg::OnInitDialog()
    {
    CDialog::OnInitDialog();

    // Add "About..." menu item to system menu.

    // IDM_ABOUTBOX must be in the system command range.
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
    CString strAboutMenu;
    strAboutMenu.LoadString(IDS_ABOUTBOX);
    if (!strAboutMenu.IsEmpty())
    {
    pSysMenu->AppendMenu(MF_SEPARATOR);
    pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
    }
    }

    // Set the icon for this dialog. The framework does this automatically
    // when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE); // Set big icon
    SetIcon(m_hIcon, FALSE); // Set small icon
    [red]
    CString str;
    int top = 10;
    int bottom = 30;
    for(int i = 0; i < 10; i++)
    {
    m_ButtonArray[i] = new CButton;
    str.Format("Button%d",i+1);
    DWORD dwStyle = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON;
    m_ButtonArray[i]->Create(str, dwStyle, CRect(10,top,100,bottom), this,100+i);
    m_ButtonArray[i]->ShowWindow(TRUE);
    top += 30;
    bottom += 30;
    }
    [/red]
    return TRUE; // return TRUE unless you set the focus to a control
    }
    [red]
    // event handle for the buttons
    void CTestDlg::OnButton1()
    {
    AfxMessageBox("OnButton1 Hit");
    }
    [/red]
    [/code]
    [code]
    class CTestDlg : public CDialog
    {
    // Construction
    public:
    CTestDlg(CWnd* pParent = NULL); // standard constructor

    // Dialog Data
    //{{AFX_DATA(CTestDlg)
    enum { IDD = IDD_TEST_DIALOG };
    CButton m_Button1;
    //}}AFX_DATA

    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CTestDlg)
    protected:
    virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
    //}}AFX_VIRTUAL

    // Implementation
    protected:
    HICON m_hIcon;
    [red] CButton* m_ButtonArray[10];[/red]

    // Generated message map functions
    //{{AFX_MSG(CTestDlg)
    virtual BOOL OnInitDialog();
    afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    virtual void OnOK();
    [red] afx_msg void OnButton1();[/red]
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
    };

    [/code]



  • DB1DB1 Posts: 1,142Member
    : [blue]You have to manually set up the message map for these OnButtonClick events. The following code allocates 10 buttons and uses the same event handler for each (see [red]RED[/red] below[/blue]

    Thats neat using the "ON_CONTROL_RANGE" message map Stober. How do you tell which button was clicked in the OnButton1() function?



    [italic][blue]To understand recursive, first you need to understand recursive[/blue][/italic]

  • stoberstober Posts: 9,765Member ✭✭✭
    [b][red]This message was edited by stober at 2004-1-14 6:54:50[/red][/b][hr]
    : : [blue]You have to manually set up the message map for these OnButtonClick events. The following code allocates 10 buttons and uses the same event handler for each (see [red]RED[/red] below[/blue]
    :
    : Thats neat using the "ON_CONTROL_RANGE" message map Stober. How do you tell which button was clicked in the OnButton1() function?
    :

    call GetFocus() to get HWND, then GetDlgCtrlID() to get the ID.


  • cherrymcherrym Posts: 2Member
    : [b][red]This message was edited by stober at 2004-1-14 6:54:50[/red][/b][hr]
    : : : [blue]You have to manually set up the message map for these OnButtonClick events. The following code allocates 10 buttons and uses the same event handler for each (see [red]RED[/red] below[/blue]
    : :
    : : Thats neat using the "ON_CONTROL_RANGE" message map Stober. How do you tell which button was clicked in the OnButton1() function?
    : :
    :
    : call GetFocus() to get HWND, then GetDlgCtrlID() to get the ID.
    :
    :
    : Thanks guys, thats what I needed to know...

  • DB1DB1 Posts: 1,142Member
    : [b][red]This message was edited by stober at 2004-1-14 6:54:50[/red][/b][hr]
    : : : [blue]You have to manually set up the message map for these OnButtonClick events. The following code allocates 10 buttons and uses the same event handler for each (see [red]RED[/red] below[/blue]
    : :
    : : Thats neat using the "ON_CONTROL_RANGE" message map Stober. How do you tell which button was clicked in the OnButton1() function?
    : :
    :
    : call GetFocus() to get HWND, then GetDlgCtrlID() to get the ID.
    :
    :
    :

    Digging through MS docs, I found an easier way...
    declare the handler like this: afx_msg void OnDoSomething( UINT nID ); then you have the ID already in the handler :)



    [italic][blue]To understand recursive, first you need to understand recursive[/blue][/italic]

  • stoberstober Posts: 9,765Member ✭✭✭
    :
    : Digging through MS docs, I found an easier way...
    : declare the handler like this: afx_msg void OnDoSomething( UINT nID ); then you have the ID already in the handler :)


    [blue]Well, not really. Two reasons(): (1) The OnButtonEvent() does not have a parameter, and (2) If you don't add that function to the message map it will never get called.

    If you have a dialog with two buttons, and use the wizard to create the event handler for each, where each button uses the same event, the results are like below, which in the original posters problem, is not what he wants[/blue]
    [code]
    BEGIN_MESSAGE_MAP(CTestDlg, CDialog)
    //{{AFX_MSG_MAP(CTestDlg)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    [red] ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
    ON_BN_CLICKED(IDC_BUTTON2, OnButton1)[/red]
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()


    // in the .h file
    // Generated message map functions
    //{{AFX_MSG(CTestDlg)
    virtual BOOL OnInitDialog();
    afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    virtual void OnOK();
    [red] afx_msg void OnButton1();[/red]
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
    [/code]
  • DB1DB1 Posts: 1,142Member
    : :
    : : Digging through MS docs, I found an easier way...
    : : declare the handler like this: afx_msg void OnDoSomething( UINT nID ); then you have the ID already in the handler :)
    :
    :
    : [blue]Well, not really. Two reasons(): (1) The OnButtonEvent() does not have a parameter, and (2) If you don't add that function to the message map it will never get called.
    :
    : If you have a dialog with two buttons, and use the wizard to create the event handler for each, where each button uses the same event, the results are like below, which in the original posters problem, is not what he wants[/blue]
    : [code]
    : BEGIN_MESSAGE_MAP(CTestDlg, CDialog)
    : //{{AFX_MSG_MAP(CTestDlg)
    : ON_WM_SYSCOMMAND()
    : ON_WM_PAINT()
    : ON_WM_QUERYDRAGICON()
    : [red] ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
    : ON_BN_CLICKED(IDC_BUTTON2, OnButton1)[/red]
    : //}}AFX_MSG_MAP
    : END_MESSAGE_MAP()
    :
    :
    : // in the .h file
    : // Generated message map functions
    : //{{AFX_MSG(CTestDlg)
    : virtual BOOL OnInitDialog();
    : afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    : afx_msg void OnPaint();
    : afx_msg HCURSOR OnQueryDragIcon();
    : virtual void OnOK();
    : [red] afx_msg void OnButton1();[/red]
    : //}}AFX_MSG
    : DECLARE_MESSAGE_MAP()
    : [/code]
    :


    My reply was in response to getting the ID of the pressed button when you use the ON_CONTROL_RANGE message map.. I've tried it and it works good. Using your previous example:
    [code]
    BEGIN_MESSAGE_MAP(CTestDlg, CDialog)
    //{{AFX_MSG_MAP(CTestDlg)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    //}}AFX_MSG_MAP
    [green] // this has to be outside the wizard created AFX_MSG_MAP (see msdn docs)[/green]
    [red]ON_CONTROL_RANGE(BN_CLICKED,100,110,OnAnyButton)[/red]
    END_MESSAGE_MAP()

    BOOL CTestDlg::OnInitDialog()
    {
    CDialog::OnInitDialog();

    // Add "About..." menu item to system menu.

    // IDM_ABOUTBOX must be in the system command range.
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);

    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
    CString strAboutMenu;
    strAboutMenu.LoadString(IDS_ABOUTBOX);
    if (!strAboutMenu.IsEmpty())
    {
    pSysMenu->AppendMenu(MF_SEPARATOR);
    pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
    }
    }

    // Set the icon for this dialog. The framework does this automatically
    // when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE); // Set big icon
    SetIcon(m_hIcon, FALSE); // Set small icon

    CString str;
    int top = 10;
    int bottom = 30;
    for(int i = 0; i < 10; i++)
    {
    m_ButtonArray[i] = new CButton;
    str.Format("Button%d",i+1);
    DWORD dwStyle = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON;
    m_ButtonArray[i]->Create(str, dwStyle, CRect(10,top,100,bottom), this,100+i);
    m_ButtonArray[i]->ShowWindow(TRUE);
    top += 30;
    bottom += 30;
    }

    return TRUE; // return TRUE unless you set the focus to a control
    }

    [red]
    // event handle for the buttons
    void CTestDlg::OnAnyButton( UINT nID )
    {
    CString s;
    s.Format("button %d was pressed", nID - 100);
    AfxMessageBox(s);
    }[/red]




    // in the header file
    // Generated message map functions
    //{{AFX_MSG(CTestDlg)
    [red]afx_msg void OnAnyButton( UINT nID );[/red]
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
    [/code]


    [italic][blue]To understand recursive, first you need to understand recursive[/blue][/italic]

  • stoberstober Posts: 9,765Member ✭✭✭
    Oh I see. Yes, I agree that is a better and easier solution.
  • Scott14468Scott14468 Posts: 1Member
    Hi all,

    Thanks for this post, it has helped bunches.

    I have just one more twist to add to the conversation. Suppose instead of creating a dialog on which to display these buttons, one wants to display them on the main form, a CFameWnd. How would this be accomplished. I've tried the outlined steps, and it works great for a dialog, but not for a main window.

    Thanks,
    Scott

«1
Sign In or Register to comment.