Вы можете использовать вектор для динамического добавления / удаления кнопок.Обратите внимание, что каждому указателю new CWnd
требуется соответствующий delete
, чтобы избежать утечек ресурсов, поэтому обязательно выполняйте очистку при удалении кнопок.Для простоты вы можете поместить элементы управления для каждой строки в структуре, как показано в примере ниже.Вы также должны изменить положение элементов управления при добавлении или удалении строки.
struct control_set
{
CStatic st;
CEdit e1, e2, e3;
CButton bn;
};
std::vector<control_set*> vec;
CSettingDlg::~CSettingDlg()
{
//for(auto &e : vec) delete e; <- remove this
}
void CSettingDlg::PostNcDestroy() // <- add this
{
CDialog::PostNcDestroy();
for(auto &e : vec)
delete e;
vec.clear();
}
void CSettingDlg::AddControlSet()
{
vec.push_back(new control_set);
vec.back()->st.Create(_T("text"), WS_CHILD | WS_VISIBLE, CRect(0, 0, 0, 0), this, 0);
vec.back()->e1.Create(WS_CHILD | WS_VISIBLE | WS_BORDER, CRect(0, 0, 0, 0), this, 0);
vec.back()->e2.Create(WS_CHILD | WS_VISIBLE | WS_BORDER, CRect(0, 0, 0, 0), this, 0);
vec.back()->e3.Create(WS_CHILD | WS_VISIBLE | WS_BORDER, CRect(0, 0, 0, 0), this, 0);
vec.back()->bn.Create(_T("del"), WS_CHILD | WS_VISIBLE, CRect(0, 0, 0, 0), this, 0);
resize_controls();
}
void CSettingDlg::OnBnClickedDeleteSettingDlg(UINT id)
{
UINT row = id / 100;
//add more checks to make sure this is the ID from delete buttons
if(row < 0 || row >= vec.size()) return;
delete vec[row];
vec.erase(vec.begin() + row);
resize_controls();
}
void CSettingDlg::resize_controls()
{
CRect rc(10, 20, 10 + 50, 20 + 14);
MapDialogRect(&rc);
for(size_t i = 0; i < vec.size(); i++)
{
std::vector<CWnd*> tmp{
&vec[i]->st, &vec[i]->e1, &vec[i]->e2, &vec[i]->e3, &vec[i]->bn};
CRect r = rc;
for(size_t j = 0; j < tmp.size(); j++)
{
tmp[j]->MoveWindow(r);
tmp[j]->SetDlgCtrlID(i * 100 + j);
tmp[j]->SetFont(GetFont());
r.OffsetRect(rc.Width() + 2, 0);
}
rc.OffsetRect(0, rc.Height() + 2);
}
}
И вы хотите добавить обработчик сообщений для кнопок удаления:
ON_COMMAND_RANGE(4, 904, OnBnClickedDeleteSettingDlg)
В качестве альтернативы вы можете установить позицию для элемента управления следующим образом.Сначала поместите 5 фиктивных статических элементов управления в ресурс диалогового окна со следующими идентификаторами:
| IDC_REF_STATIC | IDC_REF_EDIT1 | IDC_REF_EDIT2 | IDC_REF_EDIT3 | IDC_REF_BUTTON |
Эти элементы управления можно скрыть.
Затем используйте координаты этих фиктивных элементов управления для позиционирования новогоуправления.Вы можете просто сместить прямоугольник, чтобы перейти к следующему ряду.
void CSettingDlg::resize_controls()
{
CWnd *st = GetDlgItem(IDC_REF_STATIC);
CWnd *e1 = GetDlgItem(IDC_REF_EDIT1);
CWnd *e2 = GetDlgItem(IDC_REF_EDIT2);
CWnd *e3 = GetDlgItem(IDC_REF_EDIT3);
CWnd *bn = GetDlgItem(IDC_REF_BUTTON);
ASSERT(st && e1 && e2 && e3 && bn);
CRect r, rc;
st->GetWindowRect(&rc);
ScreenToClient(&rc);
for(size_t i = 0; i < vec.size(); i++)
{
//reposition the static control
st->GetWindowRect(&r);
ScreenToClient(&r);
r.MoveToY(rc.top);
vec[i]->st.MoveWindow(r);
//edit1
e1->GetWindowRect(&r);
ScreenToClient(&r);
r.MoveToY(rc.top);
vec[i]->e1.MoveWindow(r);
//edit2
e2->GetWindowRect(&r);
ScreenToClient(&r);
r.MoveToY(rc.top);
vec[i]->e2.MoveWindow(r);
//edit3
e3->GetWindowRect(&r);
ScreenToClient(&r);
r.MoveToY(rc.top);
vec[i]->e3.MoveWindow(r);
//button
bn->GetWindowRect(&r);
ScreenToClient(&r);
r.MoveToY(rc.top);
vec[i]->bn.MoveWindow(r);
//move rc down by one row
rc.OffsetRect(0, rc.Height() + 2);
//Set the font for each control
//Also set id for each control, based on the row
vec[i]->st.SetDlgCtrlID(i * 100 + 1);
vec[i]->st.SetFont(GetFont());
vec[i]->e1.SetDlgCtrlID(i * 100 + 2);
vec[i]->e1.SetFont(GetFont());
vec[i]->e2.SetDlgCtrlID(i * 100 + 3);
vec[i]->e2.SetFont(GetFont());
vec[i]->e3.SetDlgCtrlID(i * 100 + 4);
vec[i]->e3.SetFont(GetFont());
vec[i]->bn.SetDlgCtrlID(i * 100 + 5);
vec[i]->bn.SetFont(GetFont());
}
}