I'm trying to create an hierarchic window that contains 3 views using CMDIChildWnd, 2 CSplitterWnd's and 3 CFormView's:
A form view that contains a static control
A form to display the main window that I use to view a PDF document
A side panel for some actions related to the main view
The main splitter (containing the MainView and TaskPane) is initialized with 1 row and 2 columns.
The second splitter contains 2 rows and 1 column, containing the Tabs and the main splitter.
This image describes how it should be built:
My problem is that the MainView has no focus and therefore, the tool bar buttons are not enabled for zooming, saving as, etc...
When I'm not using the Banner Splitter, it works fine.
I tried the setActivePane() setFocus() setActiveWindow()
Here is how I create it in the CChildFrame::OnCreateClient()
if (m_BannerSplitter->CreateStatic(this, 2, 1))
{
m_BannerSplitter->CreateView(0,
0,
RUNTIME_CLASS(CBannerView),
CSize(r.Width(),28),
pContext);
m_splitter->CreateStatic(m_BannerSplitter,
1,
2,
WS_CHILD | WS_VISIBLE | WM_SHOWWINDOW,
m_BannerSplitter->IdFromRowCol(1,0));
}
else
{
m_splitter->CreateStatic(this, 1, 2);
}
m_splitter->CreateView(0,
0,
RUNTIME_CLASS(CMainView),
CSize(r.Width()-m_splitter->m_iRightTabFullWidth-14,1),
pContext);
m_splitter->CreateView(0,
1,
RUNTIME_CLASS(CTasksView),
CSize(m_splitter->m_iRightTabFullWidth, 1),
pContext);
m_splitter->SetColumnInfo(1,
m_splitter->m_iRightTabFullWidth,
m_splitter->m_iRightTabFullWidth);
The problem is that the command routing always checks the active view followed by the document.
If all commands should be handled by the appropriate view, no matter what view has the focus just implement your own command routing.
So overwrite CMainFrame::OnCmdMsg.
BOOL CMainFrame::OnCmdMsg(UINT nID,int nCode,void* pExtra,AFX_CMDHANDLERINFO* pHandlerInfo)
{
// Do the standard routing (View, Frame, Application)
if (__super::OnCmdMsg(nID,nCode,pExtra,pHandlerInfo))
return TRUE;
// If not handled ask all other views to handle the command
return m_pBannerView->OnCmdMsg(nID,nCode,pExtra,pHandlerInfo) ||
m_pMainView->OnCmdMsg(nID,nCode,pExtra,pHandlerInfo) ||
m_pTaskView->OnCmdMsg(nID,nCode,pExtra,pHandlerInfo);
}
My code will just offer every command to every available view after it was not handled by the normal routing.
I have found the solution and it was pretty simply.
The object contains the splitters is a CMDIChildWnd that has SetActiveView(CView * view) function.
So I tried to get the view using:
CView *mainView = (CView *)m_splitter->GetDlgItem(m_splitter->IdFromRowCol(0, 0));
and than used from the CChildFrame::OnCreateClient() event
SetActiveView(mainView);
Related
In this instance I am not "stuck" but looking for some 'guidance' on how to perform a GUI layout mechanism that makes sense and easy to construct. I am using a TreeControl that visually "matches" Winamp's options/preferences dialog for all the settings and program options.
TO BE CLEAR: This is not something I've ever attempted and looking for user input to help me get across the finish line.
I have 6 items in the 'tree' (the 'parent') and 5 'subitems'. I have it fully constructed and I can get the data from whatever node is selected (which I'll post below images).
I am using a "do.Modal dialog" and, when I click on the tree node, I want the right side of the dialog to update to the needed controls for that node function. The execution of controls through "show" and "hide" to me seems pretty easy. The issue I have is the how to do the visual "static" controls in the resource editor when each "node paged" controls may or may not sit on top of each other visually during design time. During run time, when each node is selected on the nodes controls will be active but during design time, I may have controls sitting on top of each other and will be a logistical nightmare trying to sort out their positions etc.
How do I resolve that aspect of building it? I think of it as a select: 'node' show: 'option page controls' so I get the logic; I'm just wondering if I should have separate "popup" pages and call those … or deal with the controls directly. Does that makes sense?
I've done some searching on how to do this, but the examples are all over the place and I figured asking here makes the most sense. I'm sure there are multiple ways to do this, I'm just looking for the shortest path and easiest to maintain and possibly expand on the options in the future.
The examples of the dialog and the source code I'm using:
Here is the initialization code:
BOOL CSettingsDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
HTREEITEM hParent, hToolbars, hColorScheme, hTabStyles, hPowerUser,
hResetApp;
//HTREEITEM hCompany, hLevel, hLevelNext; // Used in core example, not needed here
hParent = m_TreeCtrl.InsertItem((L"Preferences"), TVI_ROOT);
hToolbars = m_TreeCtrl.InsertItem((L"Toolbars"), hParent);
hColorScheme = m_TreeCtrl.InsertItem((L"Color Scheme"), hParent);
hTabStyles = m_TreeCtrl.InsertItem((L"Tab Styles"), hParent);
hPowerUser = m_TreeCtrl.InsertItem((L"Power User"), hParent);
hResetApp= m_TreeCtrl.InsertItem((L"Reset All Options"), hParent);
m_TreeCtrl.Expand(hParent, TVE_EXPAND);
m_TreeCtrl.SelectItem(hParent);
GetDlgItem(IDC_SETTINGS_CAPTION)->SetWindowText(_T("Preferences Settings"));
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
Here is the dialog framework that I'm starting from scratch with just to arrive here:
void CSettingsDlg::OnTvnSelchangedTree1(NMHDR *pNMHDR, LRESULT *pResult)
{
//LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
//SetDlgItemInt(IDC_TXT_TREE1, m_TreeCtrl.GetItemData(pNMTreeView->itemNew.hItem));
//*pResult = 0;
HTREEITEM sel = m_TreeCtrl.GetSelectedItem();
CPoint point;
CString str;
GetCursorPos(&point);
m_TreeCtrl.ScreenToClient(&point);
UINT flags = 0;
HTREEITEM hitItem = m_TreeCtrl.HitTest(point, &flags);
if (hitItem && sel != hitItem)
{
sel = hitItem;
m_TreeCtrl.SelectItem(sel);
str = m_TreeCtrl.GetItemText(sel);
//MessageBox((LPCTSTR)str); // Just to verify.
}
if (str == "Preferences")
{
this->SetWindowText(_T("Preferences Settings"));
GetDlgItem(IDC_SETTINGS_CAPTION)->SetWindowText(_T("Preferences Settings"));
}
if (str == "Toolbars")
{
this->SetWindowText(_T("Toolbars Settings"));
GetDlgItem(IDC_SETTINGS_CAPTION)->SetWindowText(_T("Toolbars Settings"));
}
if (str == "Color Scheme")
{
this->SetWindowText(_T("Color Scheme"));
GetDlgItem(IDC_SETTINGS_CAPTION)->SetWindowText(_T("Color Scheme Settings"));
}
if (str == "Tab Styles")
{
this->SetWindowText(_T("Tab Styles Settings"));
GetDlgItem(IDC_SETTINGS_CAPTION)->SetWindowText(_T("Tab Styles Settings"));
}
if (str == "Power User")
{
this->SetWindowText(_T("Power User Settings"));
GetDlgItem(IDC_SETTINGS_CAPTION)->SetWindowText(_T("Power User Settings"));
}
if (str == "Reset All Options")
{
this->SetWindowText(_T("Reset All Settings"));
GetDlgItem(IDC_SETTINGS_CAPTION)->SetWindowText(_T("Reset All Settings"));
}
*pResult = 0;
}
So as shown, you can see that I have the ability to change the static caption to the "active" page node that is selected from the tree. I'm looking to solve the best way to handle the GUI elements that will go on the right side....
Some controls for example will be:
Color scheme Node: 5 check boxes for theme changing
Toolbars Node: Radio button for Docked or Floating
Power User Node: Checkbox to disable user warning within program operation
Tab Styles Node: Radio buttons to select flat, 3d, whatever.
and when the user "selects" whatever it writes it to the registry and then I call the function to read the data blah blah blah...
So that is where I'm at. Does anyone have any suggestions on a course of action, so I don't paint myself into a corner?
Although I can't actually speak for how the authors of the "Winamp" software implemented their UI, I would suggest that you consider using a property sheet for your case, where each set of controls can be implemented as separate property pages, each of which will be defined (both in the resource script and in the C++ code) in ways very similar to individual modal dialog boxes.
The 'classic' property sheet has a horizontal row of tabs (normally, at the top of the sheet) to select each page, as shown in the sample below. Indeed, some sources/platforms refer to a property sheet as a "tabbed dialog".
However, the new(ish) CMFCPropertySheet class allows you to replace that tab control with one of several other options, which will show as separate 'panes' (on the left-hand side of the sheet). To use one of these alternative styles, call the SetLook() member function in your constructor override with the CMFCPropertySheet::PropSheetLook_Tree enum value. The example shown in the link is not exactly what you have shown in your question, but the CMFCPropertySheet and CMFCPropertyPage classes allow many, many customizations to their appearance and style.
I have never actually used the PropSheetLook_Tree style, but the image below shows "one I made earlier" with the PropSheetLook_OutlookBar style.
I have an MFC program written that reads files, stores the data, and draws it as text on the client view.
I want to make a menu button View->Split that splits the client area into two, separately scrolling views displaying the same data.
I saw some things about CWndSplitter online and read through some documentation but none of it has proved to be useful because they talk about using OnCreate and deleting the default view to get it to work. This is not an option. I want to keep the default view, but split it in two if the user clicks the button.
I've currently created a CWndSplitter member variable and defined a menu button event handler in my SDI-1View.cpp. When called, it does absolutely nothing but cause the screen to flicker and a second click crashes the program.
void CSDI1View::OnViewSplit32778()
{
// TODO: Add your command handler code here
/*
int rows = 2;
int columns = 1;
if (!m_wndSplitter.CreateStatic(this, rows, columns))
return;
if (!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CSDI1View), CSize(100, 100), NULL) ||
(!m_wndSplitter.CreateView(1, 0, RUNTIME_CLASS(CSDI1View), CSize(100, 100), NULL)))
{
m_wndSplitter.DestroyWindow();
return;
}
*/
}
Can anyone tell me what the normal approach to splitting a client view in half is? I just want to integrate that into an event handler.
Any help would be greatly appreciated.
Thanks.
--------------------------------EDIT----------------------------------
I now have the following code in my Split button event handler, thanks to the outline provided by xMRi, but it is still not working properly...
void CMainFrame::OnViewSplit()
{
// TODO: Add your command handler code here
//calculate client size
CRect cr;
GetClientRect(&cr);
if (!m_mainSplitter.CreateStatic(this, 2, 1))
{
MessageBox(_T("Error setting up splitter frames! (CreateStatic)"),
_T("Init Error!"), MB_OK | MB_ICONERROR);
return;
}
// Set the parent of the splitter window to the current view
CSDI1View * view = CSDI1View::GetView();
m_mainSplitter.SetParent(this);
view->SetParent(&m_mainSplitter);
// Create a CCreateContext
CCreateContext cc;
CRuntimeClass* prt = RUNTIME_CLASS(CSDI1View);
cc.m_pNewViewClass = prt;
cc.m_pCurrentDoc = view->GetDocument();
cc.m_pNewDocTemplate = NULL;
cc.m_pLastView = NULL;
cc.m_pCurrentFrame = this;
if (!m_mainSplitter.CreateView(0, 0,
cc.m_pNewViewClass,
CSize(cr.Width(), cr.Height()/2), &cc))
{
MessageBox(_T("Error setting up splitter frames! (CreateView 1)"),
_T("Init Error!"), MB_OK | MB_ICONERROR);
return;
}
if (!m_mainSplitter.CreateView(1, 0,
cc.m_pNewViewClass,
CSize(cr.Width(), cr.Height()/2), &cc))
{
MessageBox(_T("Error setting up splitter frames! (CreateView 2)"),
_T("Init Error!"), MB_OK | MB_ICONERROR);
return;
}
m_bInitSplitter = TRUE;
}
Upon clicking the view->split button, I get a "Debug Assertion Error" popup and the first call to CreateView returns FALSE, displaying my messagebox: "Error setting up splitter frames! (CreateView 1)"
A static splitter is for a static split--i.e., a window that's always split. You usually use it when you want to have a different view in each pane of the split (e.g. display a column of numbers in one pane, and a graph in the other pane).
For a situation like yours that you want to be able to have the window, then later split it and have two essentially identical views, you (at least normally) want to use a dynamic splitter.
At least normally, you create the splitter when you create the view. That will create a window that has a handle at the top, right-hand corner that the user pulls down to split the view:
To split the window, the user pulls down on the handle:
When the split is where they want it, they release the mouse button, and the view splits into two separately scrollable sections:
Since you didn't specify whether you wanted vertical or horizontal splitting, I set this one up to allow either or both:
The code for this looks something like this:
BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT, CCreateContext* pContext) {
return my_splitter.Create(this,
2, 2, // 2 rows, 2 columns
CSize(20, 20), // minimum pane size
pContext);
}
where my_splitter is defined something like this:
CSplitterWnd my_splitter;
If you want to use a splitter window on demand, you need to change the parent of the current view.
So the steps are:
create a simple SDI application
On demand create a splitter window
Use SetParent to the current view and set it as a parent in the splitter window.
Create another window in the second splitter.
And the way back.
Use SetParent and attach the normal view back to the main frame.
Destroy the splitter
There are active samples how to switch a view in a current document (MSDN). It helps you how IDs must be replaced and changed.
I am making MDI application , and without using splitter my document has multiple views. Now i want to change the document view from the MainFrame of an application...
here it is what i am doing , i have outlookbar with some menu buttons, when user will click those buttons then i will show CFormView inside the document as a child instead of popup dialog. Now i dont know how to change the view from MainFrame where the menu handler has been written.
Kindly suggest any tip if you know any...there are more than 5 different views and 4 of them are CFormView.
MainFrame ->MenuhandlerFunction (Menu Clicks)
MenuHandlerFunction -> Open New Document with New View Based on CFormView
(total 5 different CFormView and their handlers inside MainFrame Written)
I'm not very sure how you select which view to display, but here is some code to iterate through the views of the current document in your MainFrame:
EDIT: modified code for MDI
CMDIChildWnd *pChild = (CMDIChildWnd*)GetActiveFrame(); // EDIT: added line
CDocument *pDoc = pChild->GetActiveDocument(); // EDIT: added pChild->
POSITION pos = pDoc->GetFirstViewPosition();
while (pos != NULL)
{ CView* pView = GetNextView(pos);
// if this is the view you want to activate
// pChild->SetActiveView(pView); // EDIT: added pChild->
}
I create a MFC MDI application, and want to split a window into two parts at a time dynamically by right click and choosing a "AddSplitWnd" pop menu item. I try to use CSplitterWnd::CreateStatic to implement it, once the window is split, it need to create a new view, but I want to use the previous view instead, so does anyone know how to implement it. Thank you.
Here is a code snippet to exchange views in a splitter in a SDI environment. This should be adaptable to work in MDI as well.
CView* CDoc::SwitchToView(CView* pNewView)
{
CFrameWndEx* pMainWnd = (CFrameWndEx*)AfxGetMainWnd();
CView* pOldActiveView;
pOldActiveView = pMainWnd->GetActiveView();
CSplitterWnd* pSplitter = (CSplitterWnd *)pOldActiveView->GetParent();
// in this case Pane 0,0 is exchanged
pOldActiveView = (CView*) pSplitter->GetPane(0,0);
// set flag so that document will not be deleted when view is destroyed
m_bAutoDelete = FALSE;
// Dettach existing view
RemoveView(pOldActiveView);
// set flag back to default
m_bAutoDelete = TRUE;
// Set the child window ID of the active view to the ID of the corresponding
// pane. Set the child ID of the previously active view to some other ID.
::SetWindowLong(pOldActiveView->m_hWnd, GWL_ID, 0);
::SetWindowLong(pNewView->m_hWnd, GWL_ID, pSplitter->IdFromRowCol(0,0));
// Show the newly active view and hide the inactive view.
pNewView->ShowWindow(SW_SHOW);
pOldActiveView->ShowWindow(SW_HIDE);
// Attach new view
AddView(pNewView);
// Set active
pSplitter->GetParentFrame()->SetActiveView(pNewView);
pSplitter->RecalcLayout();
return pOldActiveView;
}
HTH
We have a series of dialogs in our application for which the dialog template defines 4 buttons along the bottom of the screen. However (depending which version of our hardware the application is running on) we sometimes create 2 additional buttons and then line up the 6 buttons (4 from the template, 2 created by calling CButton::Create()) along the bottom.
The problem I have is that usually the user can move the focus between these buttons using the left / right arrow keys (there is no mouse or touchscreen, just a restricted keyboard). This follows the control TAB-order as you would expect for the 4 buttons from the template. However the 2 dynamically create controls appear to be inserted at the beginning of the TAB-order, and that means (because they are put at the right-hand side of the screen) that they are in the "wrong" order as far as the cursor keys goes. In other words, when the focus gets to the left-hand button (TAB order 1) pressing the left arrow jumps the focus to the button on the right-hand side, which is just plain confusing...
There appears to be some link between Z-order (which I can affect with SetWindowPos()) and TAB-order but it does not seem to be a simple 1-to-1: by changing the Z-order I can move the sequence around so that the buttons are completely in the wrong order, so I can change the Z-order, but I can't work out how to get them in the right order.
Can anyone give a concise explanation of how TAB-order works, and how to control the sequencing of controls at runtime?
Edit:
kol suggested below using SetWindowPos() to set the Z-order. This I had tried before but it does not let the cursor keys control the focus as expected.
However, by rigging this up so I can use TAB (as a test -- this isn't practical for the end-user solution) I find that kol's solution does resolve the TAB-order. The problem I have is that this is not the same as the order used by the cursor keys!
So, revised question: how can I specify the order in which left / right cursor keys move focus between controls?
Solution:
With assistance from kol and MarkRansom's input, I have got this working now.
I used SetWindowPos() as suggested by kol to put my new buttons after the existing buttons in the TAB order, and then (as Mark suggested) made the first button WS_GROUP | WS_TABSTOP but cleared those flags from the other buttons.
However this was not enough to solve the problem, with the 2 new buttons still appearing to come before the first rather than after the second when using arrow keys (not TAB) to move around.
I looked at my dialog template, and it was like this:
IDD_QUERY DIALOG 0, 0, 156, 34
STYLE DS_SETFONT | WS_POPUP | WS_CAPTION
FONT 8, "MS Sans Serif"
BEGIN
PUSHBUTTON "+++Skey1+++",IDC_SKEY_1,1,21,36,12
PUSHBUTTON "+++Skey2+++",IDC_SKEY_2,40,21,37,12
PUSHBUTTON "+++Skey3+++",IDC_SKEY_3,79,21,36,12
PUSHBUTTON "+++Skey4+++",IDC_SKEY_4,118,21,36,12
LTEXT "Static",IDC_QUERY_MSG,2,1,153,15
END
So the static IDC_QUERY_MSG, which is used to display information to the user, was coming after the 4th button in the template. To resolve the problem, I moved IDC_QUERY_MSG before the first button (IDC_SKEY_1): this means the 6 buttons are not split up by a static inbetween, and has solved the problem.
Thanks to everyone for their assistance!
Use the SetWindowPos member of your buttons. Calling it on button A and setting its first parameter to button B, puts button A after button B in the TAB order. If you want to set the order of two controls, you have to know the controls before and after them in the TAB order - this example shows how to do this (its not MFC but pure WinAPI, but it's easy to understand).
== UPDATE ==
I created a dialog template with four buttons at the bottom and an editbox at the top, with TAB order button1 -> button2 -> button3 -> button4 -> editbox -> button1 -> ... In OnInitDialog, I added two additional buttons at runtime, and inserted them into the existing TAB order between button4 and editbox using SetWindowPos and GetNextWindow. Pressing TAB repeatedly shows that the TAB order is correct: button1 -> button2 -> button3 -> button4 -> button5 -> button6 -> editbox -> button1 -> ...
class CTestDlg : public CDialogEx
{
public:
CTestDlg() : CDialogEx(CTestDlg::IDD) {}
enum { IDD = IDD_TESTDIALOG };
protected:
CButton button5;
CButton button6;
virtual BOOL OnInitDialog();
};
BOOL CTestDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
CButton* button4 = (CButton*)GetDlgItem(IDBUTTON4);
CWnd* next = button4->GetNextWindow(GW_HWNDNEXT);
button5.Create("Button5", WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_PUSHBUTTON, CRect(340, 172, 415, 195), this, 1005);
button5.SetWindowPos(button4, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
button6.Create("Button6", WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_PUSHBUTTON, CRect(422, 172, 497, 195), this, 1006);
button6.SetWindowPos(&button5, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
if (next != NULL)
next->SetWindowPos(&button6, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE);
return TRUE;
}
void CDynamicMfcButtonTestApp::OnTestRun()
{
CTestDlg testDlg;
testDlg.DoModal();
}
== UPDATE2 ==
The order of controls can be set using SetWindowPos and GetNextWindow, as above. The "tab order" and the "arrow order" can be set by setting the WS_TABSTOP and WS_GROUP styles of the controls:
The WS_TABSTOP style specifies the controls to which the user can
move by pressing the TAB key or SHIFT+TAB keys.
The WS_GROUP style
marks the beginning of a group of controls. If a control in the group
has the input focus when the user begins pressing direction keys, the
focus remains in the group. In general, the first control in a group
must have the WS_GROUP style and all other controls in the group must
not have this style. All controls in the group must be
contiguous—that is, they must have been created consecutively with no
intervening controls.
More details can be found on MSDN, here.
Try this:
Create a vector of dlg ids and populate it in the order you want the tab order to be:
typedef std::vector<int> TABLIST;
TABLIST lst;
lst.push_back( IDC_CONTROL1 );
lst.push_back( IDC_CONTROL2 );
lst.push_back( IDC_CONTROL3 );
Then call the setTabOrder method with the list:
void setTabOrder( TABLIST * plstTabs)
{
// Iterate through the list and put each item at the top of the tab order.
// Remember to do this backwards so the last item is actually the first item
// in the tab order
HDWP hDefer = BeginDeferWindowPos( (int)plstTabs->size() );
for ( TABLIST::reverse_iterator itTab = plstTabs->rbegin(); itTab != plstTabs->rend(); ++itTab )
{
DeferWindowPos( hDefer, GetDlgItem( *itTab )->m_hWnd, HWND_TOP, 0,0,0,0,
SWP_NOSIZE | SWP_NOMOVE | SWP_NOREPOSITION );
}
EndDeferWindowPos( hDefer );
}
Modified version of #snowduded's code that makes sure the WS_TABSTOP style is in also.
// Build your order in a vector.
std::vector<WORD> vCtrlIds;
vCtrlIds.push_back(IDC_CONTROL1);
vCtrlIds.push_back(IDC_CONTROL2);
vCtrlIds.push_back(IDC_CONTROL3);
// ... keep doing it!
// Iterate through the list and put each item at the top of the tab order.
// Remember to do this backwards so the last item is actually the first item
// in the tab order.
HDWP vDefer = BeginDeferWindowPos(vCtrlIds.size());
for(auto vCtrlId(vCtrlIds.rbegin()); vCtrlId != vCtrlIds.rend(); ++vCtrlId){
HWND vCtrl(GetDlgItem(*vCtrlId)); // Grab the handle.
SetWindowLongPtr(vCtrl, GWL_STYLE, // Make sure we have WS_TABSTOP.
GetWindowLongPtr(vCtrl, GWL_STYLE) | WS_TABSTOP);
DeferWindowPos(vDefer, vCtrl, HWND_TOP, 0, 0, 0, 0, // Reorder.
SWP_NOSIZE | SWP_NOMOVE | SWP_NOREPOSITION );
}
EndDeferWindowPos(vDefer);
Props to #snowdude for an excellent reusable solution.
If you are talking about a tab order of different controls over a dialog:
Try this
Open the dlg in resource and press Ctrl+D
Now you can set order by selecting controls one after another.
You can't change the tab order in runtime. What you can do is to put these two buttons in your dialog resource (with the right tab order), and make them invisible. Then you show/arrange the buttons as soon as you need them.