class TObject
{
protected:
CString _name; //В связи с использованием MFC, тип поля _name переведён из char* в CString
public:
TObject();
TObject(CString name);
virtual ~TObject();
CString GetName();
void SetName(CString name);
virtual CString Show() = 0; //Переделан вызов метода "отобразить свойства", который теперь возвращает строку
};
TObject::TObject()
{
}
TObject::~TObject()
{
}
TObject::TObject(CString name)
{
_name = name;
}
CString TObject::GetName()
{
return _name;
}
void TObject::SetName(CString name)
{
_name = name;
}
Реализация остальных классов осталась такой же за исключением изменения возвращаемого значения методом Show() и заменой сигнатуры конструктора с параметрами, например, с Worker(char* name, int age, int workExp) на Worker(CString name, int age, int workExp).
При реализации интерфейса пришлось добавить следующую структуру:
struct ObjWithOwner
{
CString _owner; //Поле, которое обозначает, кому "подчиняется" данный объект
TObject* _obj; //Указатель на объект базового класса
int _id; //Используется для нахождения элемента в массиве через ListView
};
Реализация интерфейса программы относится к двум основным окнам:
Главное окно программы (которое создаётся и вызывается первым):
Для начала изменяется код метода OnInitDialog:
BOOL Clab51Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
……………………………………………
lst.InsertColumn(0, L"Описание", LVCFMT_LEFT, 400); // Добавление заголовков в объект ListView
lst.InsertColumn(1, L"Подчиняется", LVCFMT_LEFT, 150);
……………………………………………………………
}
void Clab51Dlg::AddObj(ObjWithOwner obj) //Метод добавления объекта в список
{
ObjWithOwner* temp = new ObjWithOwner[_itemsCount + 1]; //Создаём новый массив размером на 1 больше, чем был
for (int i = 0; i < _itemsCount; ++i) //Переписываем в него элементы из предыдущего массива
{
temp[i] = _arr[i];
temp[i]._id = i;
}
if (_arr!= NULL) delete [] _arr;
_arr = temp; //Заменяем предыдущий массив новым
++_itemsCount;
_arr[_itemsCount - 1] = obj; //И добавляем новый элемент в массив
_arr[_itemsCount - 1]._id = _itemsCount - 1;
}
void Clab51Dlg::FillList() //Метод заполнение объекта lst типа ListView
{
lst.DeleteAllItems(); //Удаляем все элементы
int pos;
CString str;
for(int i = _itemsCount - 1; i >= 0; --i)
{
pos = lst.InsertItem(0, _arr[i]._obj->Show()); //Заполняем список
lst.SetItemText(pos, 1, _arr[i]._owner);
lst.SetItemData(pos, (DWORD_PTR) _arr[i]._id); //Устанавливаем это значение чтобы найти элемент в массиве по номеру
}
}
void Clab51Dlg::OnBnClickedBtnDel() //Реакция на нажатие кнопки "Удалить"
{
POSITION pos = lst.GetFirstSelectedItemPosition(); //Находим выделенный элемент
if (pos!= NULL)
{
if(MessageBox(L"Вы действительно хотите удалить выбранную запись?", L"Информация", MB_YESNO | MB_ICONINFORMATION)!= IDYES)
{
return;
}
int i = lst.GetItemData(lst.GetNextSelectedItem(pos)); //Находим его номер в массиве
DeleteObj(i); //Удаляем
FillList(); //Заполняем список заново
}
else MessageBox(L"Сначала выберите элемент для удаления.");
}
void Clab51Dlg::DeleteObj(int idx) //Метод для удаление элемента из массива
{
ObjWithOwner* temp = new ObjWithOwner[_itemsCount - 1];
for (int i = 0; i < idx; ++i)
{
temp[i] = _arr[i];
temp[i]._id = i;
}
for (int i = idx + 1; i < _itemsCount; ++i)
{
temp[i - 1] = _arr[i];
temp[i - 1]._id = i - 1;
}
delete [] _arr;
_arr = temp;
--_itemsCount;
}
void Clab51Dlg::OnBnClickedBtnAdd() //Реакция на нажатие кнопки "Добавить"
{
CEditDlg dlg; //Создаём экземпляр объекта окна редактирования
if (dlg.DoModal() == IDOK) //Если пользователь в окне нажал кнопку "OK"
{
ObjWithOwner obj;
obj._owner = dlg._ownedByStr; //Заполняем поле "в подчинении у"
//Далее, определяя тип, выбранный в ListBox'ах создаём новый элемент
if (dlg._boxTypePersDepartString == L"Рабочий")
{
obj._obj = new Worker(dlg._name, _ttoi(dlg._age), _ttoi(dlg._workExp));
}
else if (dlg._boxTypePersDepartString == L"Служащий")
{
obj._obj = new Employee(dlg._name, _ttoi(dlg._age), _ttoi(dlg._workExp));
}
else if (dlg._boxTypePersDepartString == L"Инженер")
{
obj._obj = new Engineer(dlg._name, _ttoi(dlg._age), _ttoi(dlg._workExp));
}
if (dlg._boxTypeObjString == L"Группа") //Если был выбран тип "Группа"
{
CEditDlg* addHeadDlg = new CEditDlg(); //Вызываем окно для добавления руководителя
addHeadDlg->_staticAddHeaderStr = L"Добавление руководителя";
addHeadDlg->_ownedByStr = dlg._name;
if (addHeadDlg->DoModal()!= IDOK) return; //Если руководитель не добавлен, то и группа не создаётся
TPerson* header;
if (addHeadDlg->_boxTypePersDepartString == L"Рабочий")
{
header = new Worker(addHeadDlg->_name, _ttoi(addHeadDlg->_age), _ttoi(addHeadDlg->_workExp));
}
else if (addHeadDlg->_boxTypePersDepartString == L"Служащий")
{
header = new Employee(addHeadDlg->_name, _ttoi(addHeadDlg->_age), _ttoi(addHeadDlg->_workExp));
}
else if (addHeadDlg->_boxTypePersDepartString == L"Инженер")
{
header = new Engineer(addHeadDlg->_name, _ttoi(addHeadDlg->_age), _ttoi(addHeadDlg->_workExp));
}
if (dlg._boxTypePersDepartString == L"Цех")
{
obj._obj = new WorkShop(dlg._name, header);
}
else if (dlg._boxTypePersDepartString == L"Завод")
{
obj._obj = new Factory(dlg._name, header);
}
else if (dlg._boxTypePersDepartString == L"Филиал")
{
obj._obj = new Branch(dlg._name, header);
}
}
AddObj(obj); //Добавляем этот объект в список
FillList(); //Перезаполняем список
}
}
void Clab51Dlg::OnBnClickedBtnEdit() //Реакция на нажатие кнопки "Изменить"
{
POSITION pos = lst.GetFirstSelectedItemPosition(); //Находим позицию элемента в списке
if (pos!= NULL) //Если выделен элемент
{
int i = lst.GetItemData(lst.GetNextSelectedItem(pos)); //Находим номер элемента в массиве
CEditDlg dlg; //Создаём экземпляр объекта редактирования
dlg._name = _arr[i]._obj->GetName(); //У всех объектов есть поле _name, сразу заполняем его
dlg._ownedByStr = _arr[i]._owner; //А также поле "подчиняется"
//В зависимости от типа объекта заполняем другие данные
if (typeid(*_arr[i]._obj) == typeid(WorkShop) || typeid(*_arr[i]._obj) == typeid(Factory) || typeid(*_arr[i]._obj) == typeid(Branch))
{
if (dlg.DoModal() == IDOK) _arr[i]._obj->SetName(dlg._name);
}
else
{
if (typeid(*_arr[i]._obj) == typeid(Worker))
{
Worker* cur = (Worker*)_arr[i]._obj;
dlg._age.Format(L"%d", cur->GetAge());
dlg._workExp.Format(L"%d", cur->GetWorkExp());
if (dlg.DoModal() == IDOK)
{
cur->SetName(dlg._name);
cur->SetAge(_ttoi(dlg._age));
cur->SetWorkExp(_ttoi(dlg._workExp));
}
}
else if (typeid(*_arr[i]._obj) == typeid(Engineer))
{
Engineer* cur = (Engineer*)_arr[i]._obj;
dlg._age.Format(L"%d", cur->GetAge());
dlg._workExp.Format(L"%d", cur->GetWorkExp());
if (dlg.DoModal() == IDOK)
{
cur->SetName(dlg._name);
cur->SetAge(_ttoi(dlg._age));
cur->SetWorkExp(_ttoi(dlg._workExp));
}
}
else if (typeid(*_arr[i]._obj) == typeid(Employee))
{
Employee* cur = (Employee*)_arr[i]._obj;
dlg._age.Format(L"%d", ((Employee*)_arr[i]._obj)->GetAge());
dlg._workExp.Format(L"%d", ((Employee*)_arr[i]._obj)->GetWorkExp());
if (dlg.DoModal() == IDOK)
{
cur->SetName(dlg._name);
cur->SetAge(_ttoi(dlg._age));
cur->SetWorkExp(_ttoi(dlg._workExp));
}
}
}
FillList();
}
else MessageBox(L"Сначала выберите элемент для редактирования");
}
Интерфейс окна редактирования основывается на следующем коде:
Добавляется следующий код в метод DoDataExchange:
void CEditDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
……………………………………………
if(_boxTypeObj.GetCount() == 0) //Если в выпадающем списке нет объектов, добавляем их
{
_boxTypeObj.AddString(L"Человек");
_boxTypeObj.AddString(L"Группа");
}
if (_staticAddHeaderStr!= L"") //Если создаётся руководитель для группы
{
_boxTypeObj.SetCurSel(1); //Выделяем поле "Человек"
_boxTypeObj.EnableWindow(FALSE); //И блокируем его
_boxTypePersDepart.AddString(L"Рабочий");
_boxTypePersDepart.AddString(L"Служащий");
_boxTypePersDepart.AddString(L"Инженер");
_boxTypePersDepart.SetCurSel(0);
_ageEditControl.EnableWindow(TRUE); //Активируем поля "возраст" и "трудовой стаж"
_workExpEditControl.EnableWindow(TRUE);
_staticName = L"Имя:";
}
if (_ownedByStr!= L"") _ownedBy.EnableWindow(FALSE); //Если поле "подчиняется" уже заполнено, блокируем его
}
void CEditDlg::SelchangeComboObjtype() //Реакция на изменение выбранного элемента в выпадающем списке "Тип"
{
UpdateData(TRUE); //Заносим информацию в переменные
for (int i = 0; i <= 3; ++i) //Очищаем список подтипов
_boxTypePersDepart.DeleteString(0);
//В зависимости от выбранного типа, заполняем выпадающий список "подтип", делаем активными поля "возраст" и "трудовой стаж" и изменяем описание у поля "Имя"
if (_boxTypeObjString == L"Человек")
{
_boxTypePersDepart.AddString(L"Рабочий");
_boxTypePersDepart.AddString(L"Служащий");
_boxTypePersDepart.AddString(L"Инженер");
_boxTypePersDepart.SetCurSel(0);
_ageEditControl.EnableWindow(TRUE);
_workExpEditControl.EnableWindow(TRUE);
_staticName = L"Имя:";
UpdateData(FALSE); //Перерисовываем обновлённые данные
}
else
{
_boxTypePersDepart.AddString(L"Цех");
_boxTypePersDepart.AddString(L"Завод");
_boxTypePersDepart.AddString(L"Филиал");
_boxTypePersDepart.SetCurSel(0);
_ageEditControl.EnableWindow(FALSE);
_workExpEditControl.EnableWindow(FALSE);
_staticName = L"Название:";
UpdateData(FALSE);
}
}
void CEditDlg::OnBnClickedOk() //Реакция на нажатие кнопки "Ок"
{
//Если ничего не введено в одно из полей
if (_name == L"" || _ownedByStr == L"" || (_age == L"" && _boxTypeObjString == L"Человек") || (_workExp == L"" && _boxTypeObjString == L"Человек"))
{ //Выводим сообщение об ошибке
MessageBox(L"Введены не все данные");
return;
}
CDialogEx::OnOK();
}