Создание пользовательского меню - Delphi

добавлено: 24 ноя 11
понравилось:0
просмотров: 6270
комментов: 1

теги:

Автор: Ramin Hashimzade

Очень часто возникает вопрос, как создать меню пользователя, если для разных пользователей нужны разные меню и разные права. В связи с этим, я решил писать эту статью в свой блог, чтобы хоть чем-то помочь людям, которые задают этот вопрос себе или на форумах.
Как мы знаем, этот вопрос возникает в основном в бизнес проектах и как всем известно, почти 99,99% бизнес проектов используют разные СУБД в качестве хранения информации. Для демонстрации решения, я взял СУБД ORACLE и платформу разработки CodeGear™ Delph 2009 Version 12.0.3420.21218 Copyright 2009 Embarcadero Technologies.
Итак, мы считаем, что базу мы создали, все финансовые таблицы есть и сейчас нужно создать системные таблицы нашего проекта для хранения разграничения меню и прав доступов пользователей. Префикс нашего проекта BusinessProject-BP.
Для пользовательского меню нужны следующие таблицы:

1) BP_USER_MENU
ИМЯ ПОЛЕ ТИП ПОЛЕКомментарий
BP_ID NUMBER уникальный идентификатор таблицы
BP_PARENT_ID NUMBER ссылка на родительский пункт меню в древовидной структуре
BP_LEVEL_ID NUMBER позиция меню в в древовидной структуре
BP_MENU_CAPTION NVARCHAR2(50) Текст меню
BP_REPORT_ID NVARCHAR2(50) уникальный идентификатор библиотеки или формы которую нужно вызывать из пункта в меню. Или строка ссылки если используется веб приложение.


2) BP_USER_GROUP
ИМЯ ПОЛЕТИП ПОЛЕКомментарий
BP_IDNUMBERуникальный идентификатор таблицы
BP_ GROUP_NAMENUMBERимя группы


3) BP_USER_GROUP_MENU
ИМЯ ПОЛЕТИП ПОЛЕКомментарий
BP_IDNUMBERуникальный идентификатор таблицы
BP _MENU_IDNUMBERидентификатор меню BP_USER_MENU-> BP_ID
BP _USER_GROUP_IDNUMBERидентификатор группы BP_USER_GROUP -> BP_ID


4) BP_USER
ИМЯ ПОЛЕТИП ПОЛЕ Комментарий
BP_IDNUMBERуникальный идентификатор таблицы
BP_NAMENUMBERимя пользователя
BP_LOGINVARCHAR2(20)логин пользователя
BP_USER_GROUP_IDNUMBERимя группы к которой подключен пользователь. BP_USER_GROUP-> BP_ID


Для теста заполняем таблицы:
1) BP_USER_MENU
BP_IDBP_PARENT_IDBP_LEVEL_IDBP_MENU_CAPTIONBP_REPORT_ID
10Главное
20Отчеты
611Склад274
711Приход275
811Расход276
922Бухгалтерия
1022Казначейство
1193Отчет об остатках279
1293Отчет о прибыли280
13103Денежные обороты281
14103Касса282
15103Тестовый отчет283


2) BP_USER_GROUP
BP_IDBP_ GROUP_NAME
1test group 1
2test group 2


3) BP_USER_GROUP_MENU
BP_IDBP_MENU_IDBP_USER_GROUP_ID
10111
10221
10361
10471
10591
106101
10712
10822
10982
110102
111112
112122
113132
114151
11592


4) BP_USER
BP_IDBP_NAMEBP_LOGINBP_USER_GROUP_ID
10RAMINRAMIN1
11TESTTEST2

Всё. Тестовые данные созданы, скрипты для таблицы сложены в архив файл (USER_MENU.rar). Так как уже все есть: база, таблицы и данные, то мы можем начать создание приложения для пользователей. Так как эта статья носит тестовый характер, интерфейс входа в приложение будет совсем простым.

Открываем DELPHI, создаем новый проект, кидаем в форму 3 TLabel, 3 TTEdit, 1 TButton, 1 TADOConnecion, 1 TADOQuery и самый главный компонент TTreeView (компонент для меню). См 1.1

1.1
Картинка с другого сайта.

Пишем наш запрос для получения меню из базы данных. Запрос я написал простым, чтобы программисты с малым опытом тоже могли разобраться в нем. Так как я все таблицы создавал в своей схеме, то обращение к таблицам через схему будет таким:

SELECT USER_MENU.BP_ID,
       USER_MENU.BP_PARENT_ID,
       USER_MENU.BP_LEVEL_ID,
       USER_MENU.BP_MENU_CAPTION,
       USER_MENU.BP_REPORT_ID
 FROM RAMIN.BP_USER t1  
  
 JOIN RAMIN.BP_USER_GROUP_MENU T
 ON T1.BP_USER_GROUP_ID = T.BP_USER_GROUP_ID
  
 JOIN RAMIN.BP_USER_MENU USER_MENU
 ON USER_MENU.BP_ID = T.BP_MENU_ID

 WHERE (T1.BP_LOGIN = 'ЛОГИН ПОЛЬЗОВАТЕЛЯ ВХОДЯЩЕГО В СИСТЕМУ')
 ORDER BY USER_MENU.BP_LEVEL_ID, USER_MENU.BP_ID

Если посмотреть на сам проект, то запрос можно найти на компоненте "TADOQuery1", в свойстве "SQL". Начинаем реализовать вход в систему.

При нажатии кнопки CONNECT, которая лежит в нашей форме, пользователь должен коннектится к базе и мы должны считать его меню и показать его. Код для кнопки тоже очень простой и понятливый:

// Функция для нахождение узла в древовидной структуре меню
function TForm1.FindIndexItem(Item: Integer): TTreeNode;
var
  i: Integer;
begin
  Result := nil;
  for i:=0 to TreeView1.Items.Count-1 do  
   if TreeView1.Items[i].StateIndex=Item then
    begin
     Result:=TreeView1.Items[i];
     break;
    end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Pnode: TTreeNode;
  Cnode: TTreeNode;
  Fnode: TTreeNode;
Begin
  //подключение к базе данных
  try
   ADOConnection1.ConnectionString := 'Provider=OraOLEDB.Oracle.1;Password='+EditPAROL.Text+';Persist Security Info=True;User ID='+EditLOGIN.Text+';Data Source='+EditDB.Text;
   ADOConnection1.Connected;
  except
     on E: Exception do
     begin
       Application.MessageBox(pchar(e.Message),'error',MB_ICONERROR);
       Exit;
     end;
  end;
  
  // получение ответа запроса
   ADOQuery1.Close;
      ADOQuery1.Parameters.ParamByName('login').Value := EditLOGIN.Text;
   ADOQuery1.Open;

  // --- обработка МЕНЮ пользователя ---
   TreeView1.Items.Clear;
   ADOQuery1.First;
   while not ADOQuery1.Eof do
    begin
 	    // если Меню родительское
     if ADOQuery1.FieldByName('bp_parent_id').IsNull then
     begin
        FNode := FindIndexItem(ADOQuery1.FieldByName('bp_parent_id').AsInteger);
        Pnode := TreeView1.Items.AddChildFirst(FNode, '');
        Pnode.Text := ADOQuery1.FieldByName('bp_menu_caption').AsString;
        Pnode.StateIndex := ADOQuery1.FieldByName('bp_id').AsInteger;
     end else
    // иначе
     begin
         FNode := FindIndexItem(ADOQuery1.FieldByName('bp_parent_id').AsInteger);
         Cnode := TreeView1.Items.AddChild(FNode,'');
         Cnode.Text := ADOQuery1.FieldByName('bp_menu_caption').AsString;
         Cnode.StateIndex := ADOQuery1.FieldByName('bp_id').AsInteger;
     end;
     ADOQuery1.Next;
   end;
   //  -------------------------------------------
   end;


Запускаем и проверяем см. 1.2.

1.2
Картинка с другого сайта.

Картинка с другого сайта.

USER_MENU.rar

Сейчас , нам нужна обработка кликов меню. Это так же просто. Добавляем на форму еще один TADOQuery . Напишем запрос, где в параметр ID передаем StateIndex что бы получить строку меню из базы.

select t.bp_menu_caption from BP_USER_MENU t
where t.bp_id = :id



...
  private
     a,b : integer;
...
//обрабатываем MouseDown, что б взять точки клика....
procedure TForm1.TreeView1MouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  a := x;
  b := y;
end;

// и сам клик...
procedure TForm1.TreeView1DblClick(Sender: TObject);
var
  node: TTreeNode;
begin  
  node := TreeView1.GetNodeAt(a, b);
  if (assigned(node)) and (node.HasChildren = false) then
  begin
    ADOQuery2.Close;
      ADOQuery2.Parameters.ParamByName('id').Value := node.StateIndex;
    ADOQuery2.Open;
    ShowMessage('Clicked-'+ADOQuery2.FieldByName('bp_menu_caption').AsString);
  end;
end;


В принципе всё. В след раз я выложу это же решение на платформе Visual Studio, языке C#

---
Ramin Hashimzade

Комментарии




Необходимо войти на сайт, чтобы оставлять комментарии