Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2005.08.14;
Скачать: [xml.tar.bz2];

Вниз

Динамическая форма в библиотечном модуле   Найти похожие ветки 

 
msguns ©   (2005-07-21 13:53) [0]

В продолжение ветки
http://delphimaster.net/view/1-1121773434/

Все же я пришел к выводу, что в библиотечном модуле целесообразно объявить класс формы, которую надо создавать и показывать при обращении к соответстующим процедурам/функциям библиотечного модуля. Там же прописывать все визуальные объекты и, главное, методы и евенты контролов. В этом случае я могу обращаться из этих методов друг к другу как к методам класса.
Например, в событии OnChange эдита легко можно активировать/деактивировать соотв.кнопки, по OnClick в листбоксе запросто вызвать метод поиска записи в датасете внешнего модуля, продеклариованный и описанный в этом же классе. Кроме того, становятся отовсюду доступны переменные как самой формы, так и всех "подотчетных" и продекларированных в ней контролов.

При реализации подобных действий способом из приведенной ссылки ("надув" компиллятора по рецепту ЮЗ) чрезвычайно геморный. Текст получается громоздкий и плохочитаемый.

Подчеркну, что имеется в виду не форма типа MessageBox, а достаточно "нагруженное" окно, предназначенное для универсального поиска юзером записей в произвольных датасетах (6 контролов типа чекбокс, едит, комбобокс, листбокс, несколько кнопок, куча лабелей. И все это лежит на "наполеоне" из панелей.

Прошу высказаться за либо против принятого мною решения.
С благодарностью.


 
Stakan ©   (2005-07-21 14:41) [1]

Я уже высказывался за такой подход в той ветке.
Всё получается красиво и никаких недокументированных приёмов.


 
msguns ©   (2005-07-21 15:00) [2]

>Stakan ©   (21.07.05 14:41) [1]

Т.е. "ЗА" ?

ЗЫ. Извиняюсь, что ветка попала в "Базы". ИМХО, было бы неплохо пересадить ее в "Основную"


 
evvcom ©   (2005-07-21 15:06) [3]

Возможно, что проще действительно создать класс формы. Я прибегаю к способу [5] из той ветки действительно в крайних случаях. Например, в последнем проекте:
В конструктор динамически создаваемой формы передается массив записей с типами и свойствами создаваемых на форме контролов. Для некоторых контролов важны дополнительные параметры из "его" записи. Вот ссылку на эту запись я и передаю через параметр Data в обработчик-процедуру. Получается в процедуре все очень наглядно, так как и имена и типы такие, какие мне удобны. Можно, конечно, то же самое сделать и через метод класса, а параметр через Tag передать, хотя тоже не в каждом объекте этот Tag имеется.


 
msguns ©   (2005-07-21 16:18) [4]

Прошу сильно не смеяться, я такого не делал еще, а Тексейры под рукой нет.
Код:

unit DBServ; // Библиотечный модуль

interface

Uses Forms, Classes, Controls, StdCtrls, ComCtrls, ExtCtrls, Graphics,
    Buttons, DB, Grids, Types, DBGrids, Dialogs;

type
 TDBServ_SearchDlgForm = class(TForm)
 // Контролы, которые должны быть созданы формой
 pnUserTop: TPanel;       // Панель пользователя
  lbColumnName: TLabel;
  cmbColumnList: TComboBox;
  lbPromptEnter: TLabel;
  edSample: TEdit;
 pnSearchOptions: TPanel; // Панель опций поиска
  lbSearchMode: TLabel;
  rbtSearchImdl: TRadioButton;
  rbtSearchFirst: TRadioButton;
  rbtSearchList: TRadioButton;
  lbSearchOptions: TLabel;
  chbSearchCaseIns: TCheckBox;
  lbSearchResume: TLabel;
  spbStartSearch: TSpeedButton;
  spbCloseForm: TSpeedButton;
 pnFindResult: TPanel;    // Панель результатов спискового поиска
  lbFindResult: TLabel;
  lsbFindList: TListBox;
  pnListStatus: TPanel;
 private
 public
//   constructor Create(AOwner: TComponent);
//   procedure FormShow(Sender: TObject);
 end;
 ...

type
 procedure DBServ_SearchRecordByUserDialog(Grid: TDBGrid);
 ...

implementation
...

procedure DBServ_SearchRecordByUserDialog(Grid: TDBGrid);
begin
 with TDBServ_SearchDlgForm.Create(Application) do
   begin
    ShowMessage("Форма создана") ;
//     ShowModal;
   end;
end;


При обращении к этой процедуре дохнет с сообщением о невозможности найти файл ресурсов.

Ради Бога, побейте ногами !


 
msguns ©   (2005-07-21 16:23) [5]

Теоретически я понимаю, что дельфя пытается создать на форме контролы, свойства которых (парент, местоположение и т.д.) должны находиться в .res. Но у меня и вся фишка в том, что нет и не может быть файла ресурсов ! Закомментарив все эти контролы и оставив только саму форму, получил тот же эффект.


 
alex_***   (2005-07-21 16:29) [6]

честно говоря нет времени читать всю ветку по ссылке, но нельзя ли тогда все контролы создавать руками в runtime без файла ресурсов и руками же вешать события на них? если уж так хочется чтоб все было настраиваемое


 
evvcom ©   (2005-07-21 16:34) [7]


> При обращении к этой процедуре дохнет с сообщением о невозможности
> найти файл ресурсов.

Правильно дохнет. У тебя исходники VCL есть? Если бы туда заглянул, то увидел бы, что в TCustomForm.Create есть такое:
 if not InitInheritedComponent(Self, TForm) then
   raise EResNotFound.CreateFmt(SResNotFound, [ClassName]);
в InitInheritedComponent вызывается InternalReadComponentRes до тех пор пока не дойдет до RootAncestor = TForm.

Либо создавай форму с ресурсами, либо наследуйся от TObject, например, и заведи поле класса TForm.


 
msguns ©   (2005-07-21 16:35) [8]

>alex_***   (21.07.05 16:29) [6]

Да я так и делаю сейчас. Только вот код страшный:

procedure DBServ_SearchRecordByUserDialog(Grid: TDBGrid);
// Создание окна поискового диалога
Const
 MinHeight: integer = 320;
 MinWidth: integer = 360;
var
 i: integer;
 SearchForm: TForm;
 SamplePanel,SearchPanel,SearchOptionPanel,FindListPanel: TPanel;
 LablPromptCol,SampleLabel,OptTitle1Label,OptTitle2Label,ListTitleLabel: TLabel;
 ColumnList: TComboBox;
 ListFind: TListBox;
 ListStatus: TPanel;
 OptRadioImdl, OptRadioFirst, OptRadioList: TRadioButton;
 OptCheckCase, OptCheckPartial: TCheckBox;
 SampleEdit: TEdit;
 GridActiveCell: TRect;
 MColChange, MEditChange: TMethod;
 MRadioButtonClick: TMethod;
 //---------------------------------------------------------------
 // Обработчики событий динамически созданных визуальных контролов
 //---------------------------------------------------------------
 procedure OnChangeColumn(Self: TDBGrid; Sender: TObject);
 var
   i: integer;
 begin
   //  Определить имя поля датасета по титулу выбранной колонки
   with Self, Sender as TComboBox do
   for i := 0 to Self.Columns.Count-1 do
     if (Self.Columns[i].Field.FieldKind=fkData) and
        (Self.Columns[i].Title.Caption=Items[Itemindex]) then
       begin
        // Сделать выбранную колонку текущей в гриде
        SelectedIndex := i;
        break;
       end;
 end;
 //---------------------------------------------------------------
 procedure OnChangeSample(Self: TDBGrid; Sender: TObject);
 begin
   if TEdit(Sender).Tag>0 then exit;
   with Self do
     DBServ_LocateRecord(DataSource.DataSet,SelectedField.FieldName,TEdit(Sender).Text);
 end;
 //---------------------------------------------------------------
 procedure OnClickRadioButton(Self: TEdit; Sender: TObject);
 begin
   if TRadioButton(Sender).Caption="Немедленный поиск" then Self.Tag := 0 else Self.Tag := 1;
 end;

begin
//  with TDBServ_SearchDlgForm.Create(Application) do
//    begin
//     ShowMessage("Форма создана") ;
//     ShowModal;
//    end;
//  exit;
 MColChange.Code := @OnChangeColumn;
 MColChange.Data := Grid;
 MEditChange.Code := @OnChangeSample;
 MEditChange.Data := Grid;
 MRadioButtonClick.Code := @OnClickRadioButton;
 // ******************* СОЗДАНИЕ ВИЗУАЛЬНЫХ КОНРОЛОВ ******************
 // Получить координаты ячейки
 GridActiveCell := TDBGridCrack(Grid).CellRect(TDBGridCrack(Grid).Col,TDBGridCrack(Grid).Row);
 // Создать форму
 SearchForm := TForm.Create(Grid.Owner);
 with SearchForm do
   begin
    BorderIcons := [biSystemMenu];
    BorderStyle := bsSingle;
    Height := MinHeight;    // 200
    Width := MinWidth;      // 360
    // Позиционировать форму
    if (Grid.ClientOrigin.X+GridActiveCell.Right+MinWidth)>(TForm(Grid.Owner).Left+TForm(Grid.Owner).Width) then
       // Слева от ячейки
       Left := Grid.ClientOrigin.X+GridActiveCell.Left-MinWidth
    else
       Left := Grid.ClientOrigin.X+GridActiveCell.Right;
    Top := TForm(Grid.Owner).Top+TForm(Grid.Owner).Height div 2 - Height div 2;
    Caption := "Поиск записей по значению колонки";
   end;
 // Создать панель пользователя
 SamplePanel := TPanel.Create(SearchForm);
 with SamplePanel do
   begin
    Parent := SearchForm; Align := alTop; BevelOuter := bvLowered; Height := 48;
   end;
 LablPromptCol := TLabel.Create(SearchForm);
 with LablPromptCol do
   begin
    Caption := "Поиск по колонке ";
    Left := 4;
    Top := 6;
    Parent := SamplePanel;
   end;
 // Создать комбобокс для списка колонок
 ColumnList := TCombobox.Create(SearchForm);
 with ColumnList do
   begin
    Top := 2;
    Parent := SamplePanel;
    Left := LablPromptCol.Left+LablPromptCol.Width+4;
    Width := MinWidth-Left-10;
    Sorted := false;
    // Заполнить список названиями колонок
    for i := 0 to Grid.Columns.Count-1 do
      if Grid.Columns[i].Field.FieldKind=fkData then
        begin
         Items.Add(Grid.Columns[i].Title.Caption);
         if Grid.Columns[i].Field=Grid.SelectedField then
         ItemIndex := i;   // Текущее поле
        end;
    OnChange := TNotifyEvent(MColChange);
   end;


 
msguns ©   (2005-07-21 16:37) [9]

 // Создать надпись перед шаблоном
 SampleLabel := TLabel.Create(SearchForm);
 with SampleLabel do
   begin
    Caption := "Маска поиска "; Left := 4; Parent := SamplePanel;
   end;
 // Создать эдит для ввода шаблона поиска
 SampleEdit := TEdit.Create(SearchForm);
 with SampleEdit do
   begin
    Top := ColumnList.Top+ColumnList.Height+1;
    Left := SampleLabel.Left+SampleLabel.Width+4;
    Width := MinWidth-Left-10;
    Text := Grid.SelectedField.AsString;
    OnChange := TNotifyEvent(MEditChange);
    Parent := SamplePanel;
   end;
 MRadioButtonClick.Data := SampleEdit;
 // Выровнять метку по высоте
 SampleLabel.Top := SampleEdit.Top+3; //(ColumnList.Top-LablPromptCol.Top);
 // Создать панель поиска
 SearchPanel := TPanel.Create(SearchForm);
 with SearchPanel do
   begin
    Parent := SearchForm; Align := alClient; BevelOuter := bvLowered;
   end;
 // Создать панель опций поиска
 SearchOptionPanel := TPanel.Create(SearchForm);
 with SearchOptionPanel do
   begin
    Parent := SearchPanel; Align := alLeft; BevelOuter := bvRaised; Width := 160;
   end;
 // Создать заголовок режимов
 OptTitle1Label := TLabel.Create(SearchForm);
 with OptTitle1Label do
   begin
    Caption := "Режимы поиска"; Parent := SearchOptionPanel;
    Font.Style := [fsbold]; Height := 20; //Layout := tlBottom;
    Align := alTop; Alignment := taCenter; Layout := tlCenter;
   end;
 // Создать радиобатоны переключения режимов поиска
 OptRadioImdl := TRadioButton.Create(SearchForm);
 OptRadioFirst := TRadioButton.Create(SearchForm);
 OptRadioList := TRadioButton.Create(SearchForm);
 with OptRadioImdl do
   begin
    Caption := "Немедленный поиск"; Parent := SearchOptionPanel;
    Left := 4; Width := TPanel(Parent).Width-Left-4;
    Top := OptTitle1Label.Top+OptTitle1Label.Height+2; Checked := true;
    OnClick := TNotifyEvent(MRadioButtonClick);
   end;
 with OptRadioFirst do
   begin
    Caption := "Поиск первой похожей"; Parent := SearchOptionPanel;
    Left := OptRadioImdl.Left; Width := OptRadioImdl.Width;
    Top := OptRadioImdl.Top+OptRadioImdl.Height+2; // Checked := false;
    OnClick := TNotifyEvent(MRadioButtonClick);
   end;
 with OptRadioList do
   begin
    Caption := "Поиск всех похожих"; Parent := SearchOptionPanel;
    Left := OptRadioImdl.Left; Width := OptRadioImdl.Width;
    Top := OptRadioFirst.Top+OptRadioFirst.Height+2; // Checked := false;
    OnClick := TNotifyEvent(MRadioButtonClick);
   end;
 // Создать заголовок опций
 OptTitle2Label := TLabel.Create(SearchForm);
 with OptTitle2Label do
   begin
    Caption := "Опции поиска"; Parent := SearchOptionPanel;
    Font.Style := [fsbold];
    Left := 2; Width := TPanel(Parent).Width-4;
    Top := OptRadioList.Top+OptRadioList.Height+8;
    Alignment := taCenter;
   end;


 
msguns ©   (2005-07-21 16:38) [10]

 // Создать чекбоксы опций
 OptCheckCase := TCheckBox.Create(SearchForm);
 OptCheckPartial := TCheckBox.Create(SearchForm);
 with OptCheckCase do
   begin
    Caption := "Игнорировать регистр"; Parent := SearchOptionPanel;
    Top := OptTitle2Label.Top+OptTitle2Label.Height+2;
    Left := 6; Width := TPanel(Parent).Width-8;
    Checked := true;
   end;
 with OptCheckPartial do
   begin
    Caption := "Полное совпадение"; Parent := SearchOptionPanel;
    Top := OptCheckCase.Top+OptCheckCase.Height+2;
    Left := 6; Width := TPanel(Parent).Width-8;
    Checked := true;
   end;
 // Создать панель со списком найденных
 FindListPanel := TPanel.Create(SearchForm);
 with FindListPanel do
   begin
    Parent := SearchPanel; Align := alClient; BevelOuter := bvRaised;
   end;
 // Создать надпись
 ListTitleLabel := TLabel.Create(SearchForm);
 with ListTitleLabel do
   begin
    Caption := "Результат поиска"; Parent := FindListPanel;
    Font := OptTitle1Label.Font; Align := alTop; Height := OptTitle1Label.Height;
    Alignment := OptTitle1Label.Alignment;
    Layout := OptTitle1Label.Layout;
   end;
 // Создать панель статуса
 ListStatus := TPanel.Create(SearchForm);
 with ListStatus do
   begin
    Parent := FindListPanel; Align := alBottom;
    Height := 18; BevelOuter := bvLowered;
    Alignment := taCenter; Caption := "  Запись 2 из 9999";
   end;
 // Создать список найденных
 ListFind := TListBox.Create(SearchForm);
 with ListFind do
   begin
    Parent := FindListPanel; Align := alClient;
    Color := TPanel(Parent).Color;
   end;

 SearchForm.ShowModal;
end;

function DBServ_LocateRecord(DataSet: TDataSet; FieldName,Sample: string;
        CaseIns: boolean = true; PartKey: boolean = true): boolean;
begin
 result := DataSet.Locate(FieldName,Sample,[loCaseInsensitive,loPartialKey]);
end;


 
msguns ©   (2005-07-21 16:40) [11]

Кроме того, непонятки с тем, как мне в процедурах - обработчиках событий обращаться к другим (не Sender`у) контролам и, главное, как выполнить процедуры, определенные внутри DBServ_SearchRecordByUserDialog


 
evvcom ©   (2005-07-21 16:47) [12]


> procedure OnChangeColumn(Self: TDBGrid; Sender: TObject);
>  var
>    i: integer;
>  begin
>    //  Определить имя поля датасета по титулу выбранной
> колонки
>    with Self, Sender as TComboBox do
>    for i := 0 to Self.Columns.Count-1 do
...
> =Items[Itemindex])

Ты опять "не читатель", ты опять "писатель"? Я ж писал тебе в той еще ветке. Замени, ведь нагляднее будет так:

procedure OnChangeColumn(DBGrid: TDBGrid; ComboBox: TComboBox);
...
for i := 0 to DBGrid.Columns.Count-1 do
...
= ComboBox.Items[ComboBox.Itemindex])

и мой совет, прекращай with использовать, код с ним менее читабелен, а отладка затруднительна. Вместо with Object1.Object2.Object3 лучше завести локальную переменную и явно ей присвоить эту байду, а потом к свойствам/методам обращаться уже через нее.


 
evvcom ©   (2005-07-21 16:52) [13]

Во, напостил! Одного я не пойму, чего тебе так обычная форма с ресурсом не нравится? Политические убеждения или вера не позволяет?


 
msguns ©   (2005-07-21 17:00) [14]

>evvcom ©   (21.07.05 16:52) [13]
>Одного я не пойму, чего тебе так обычная форма с ресурсом не нравится? Политические убеждения или вера не позволяет?

Это фрагмент библиотечного модуля, содержащего универсальные фичи работы с произвольным НД. К нему я буду обращаться из конкретных приложений с помощью uses.
Какие в нем могут быть ресурсы и формы ?
Работает же OpenDialog безо всяких визуальных компонент, самодостаточно.


 
stakan ©   (2005-07-21 17:03) [15]

unit FormUnit;

interface

procedure ShowUnitForm;

implementation

uses
 Forms, StdCtrls, Dialogs, Classes, Windows;

type
 TUnitForm = class(TForm)
 private
   Button: TButton;
   procedure ButtonClick(Sender: TObject);
 public
   constructor CreateNew(AOwner: TComponent); reintroduce;
 end;

procedure ShowUnitForm;
var
 Form: TUnitForm;
begin
 Form := TUnitForm.CreateNew(Application);
 try
   Form.Button := TButton.Create(Form);
   Form.Button.Parent := Form;
   Form.Button.OnClick := Form.ButtonClick;
   Form.ShowModal;
 finally
   Form.Free;
 end;
end;

{ TUnitForm }

procedure TUnitForm.ButtonClick(Sender: TObject);
begin
 ShowMessage("Banzai");
end;

constructor TUnitForm.CreateNew(AOwner: TComponent);
var
 NonClientMetrics: TNonClientMetrics;
begin
 inherited CreateNew(AOwner);
 NonClientMetrics.cbSize := sizeof(NonClientMetrics);
 if SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, @NonClientMetrics, 0) then
   Font.Handle := CreateFontIndirect(NonClientMetrics.lfMessageFont);
end;

end.

Подсмотрено в Dialogs.pas


 
Stakan ©   (2005-07-21 17:07) [16]


>public
>    constructor CreateNew(AOwner: TComponent);
> reintroduce;

Лишнее.
Главное - это Form := TUnitForm.CreateNew(Application);


 
evvcom ©   (2005-07-22 08:23) [17]


> Какие в нем могут быть ресурсы и формы ?

Обычные. Чем тебе ресурсы-то не нравятся? Ну будет у тебя не один юнит, а dfm-ка еще с ним, чего плохого?

> Работает же OpenDialog безо всяких визуальных компонент,
> самодостаточно.

OpenDialog, насколько я помню, просто надстройка над API-шной функцией, чтобы параметры передать в стиле Delphi.



Страницы: 1 вся ветка

Форум: "Основная";
Текущий архив: 2005.08.14;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.54 MB
Время: 0.011 c
3-1120471111
Yurisimus
2005-07-04 13:58
2005.08.14
Верхний регистр в ADOQuery


3-1120721303
Lexa
2005-07-07 11:28
2005.08.14
При открытии базы *.mdb создается файл *.ldb


10-1099556750
sands
2004-11-04 11:25
2005.08.14
Callbacks & CORBA


9-1114243463
Trof
2005-04-23 12:04
2005.08.14
Стычки между ботами. Glscene


3-1120738308
st0rm
2005-07-07 16:11
2005.08.14
Клонирование связанных таблиц в Access`e!





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский