Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > [ "Начинающим" ]
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 23.09.2013, 00:54
Аватар для Uniq!
Uniq! Uniq! вне форума
Местный
 
Регистрация: 29.09.2010
Сообщения: 539
Версия Delphi: Delphi XE3
Репутация: 374
По умолчанию OnShow + ProgressBar

На форме fSynch только ProgressBar
Код:
program WorkPlace;

uses
  Vcl.Forms,
  uMain in 'uMain.pas' {fMain} ,
  uSynch in 'uSynch.pas' {fSynch};

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TfSynch, fSynch);
  Application.CreateForm(TfMain, fMain);
  Application.Run;
end.
Нужно оформить загрузку данных из БД, т.е. выполнить несколько ADOTable.Open (это уже обсудили) и ещё несколько "долгосрочных" операций загрузки данных.

Куда весь этот код обработки вписывать?
в OnShow - форма не вырисовывается, но процесс загрузки идёт. Т.е. приложение зависает, потом появляется форма со 100% ProgressBar на секунду и сразу же Главное окно программы.
Ответить с цитированием
  #2  
Старый 23.09.2013, 00:57
Аватар для PhoeniX
PhoeniX PhoeniX вне форума
Always hardcore!
 
Регистрация: 04.03.2009
Адрес: СПб
Сообщения: 3,239
Версия Delphi: GCC/FPC/FASM
Репутация: 62149
По умолчанию

TThread...
__________________
Оставайтесь хорошими людьми...
VK id2634397, ds [at] phoenix [dot] dj
Ответить с цитированием
  #3  
Старый 23.09.2013, 08:33
Аватар для NumLock
NumLock NumLock вне форума
Let Me Show You
 
Регистрация: 30.04.2010
Адрес: Северодвинск
Сообщения: 5,426
Версия Delphi: 7, XE5
Репутация: 59586
По умолчанию

так http://zalil.ru/34738901 сойдет?
__________________
Пишу программы за еду.
__________________
Ответить с цитированием
  #4  
Старый 23.09.2013, 10:54
Аватар для Mrak
Mrak Mrak вне форума
Местный
 
Регистрация: 26.01.2013
Адрес: МО
Сообщения: 438
Версия Delphi: XE2
Репутация: 17
По умолчанию

с приветственной заставкой в которой кнопка (или MainMenu) - подключиться
__________________
Я за здоровый экстрим!
Спасибо за "спасибо")
Ответить с цитированием
  #5  
Старый 23.09.2013, 11:07
Аватар для Freeman
Freeman Freeman вне форума
Местный
 
Регистрация: 05.10.2012
Адрес: Санкт-Петербург
Сообщения: 577
Версия Delphi: 6
Репутация: выкл
По умолчанию

Похоже, автор плохо усвоил предыдущий урок. Я уже начинаю разочаровываться.

В приведенном коде проекта есть две фактические ошибки:
  • Форма создаваемая первой, становится главной формой приложения. В коде главной формой становится fSynch.
  • По-прежнему делаются попытки всунуть неинтерактивный код в обработчик какого-либо события, отличного от FormCreate.

Как бы сделал я:
  • Первой и единственной создается главная форма приложения.
  • В ее обработчике OnCreate выполняются все действия по инициализации, включающие в себя ручное создание формы заставки, загрузку данных из базы и уничтожение формы заставки.
Ответить с цитированием
Этот пользователь сказал Спасибо Freeman за это полезное сообщение:
Uniq! (23.09.2013)
  #6  
Старый 23.09.2013, 11:24
Аватар для Страдалецъ
Страдалецъ Страдалецъ вне форума
Гуру
 
Регистрация: 09.03.2009
Адрес: На курорте, из окна вижу теплое Баренцево море. Бррр.
Сообщения: 4,723
Репутация: 52347
По умолчанию

Вообще сама по себе идея как-то подсчитывать прогресс выполнения обращения к БД, неудачна. Это касается и подключения и выполнения запросов. А вот как-то информировать пользователя о каком-то процессе - это нужно. Из многих виденных мной решений, наиболее удачным оказался прогрессбар в режиме пинг/понга запущенный в отдельном потоке.
Лично я выделяю под него в статусбаре приложения пустое место и как только возникает необходимость отобразить длительный процесс у меня он отображается, крутится пока не закончится процесс и снова скрывается.
__________________
Жизнь такова какова она есть и больше никакова.
Помогаю за спасибо.
Ответить с цитированием
  #7  
Старый 23.09.2013, 12:11
Аватар для Mrak
Mrak Mrak вне форума
Местный
 
Регистрация: 26.01.2013
Адрес: МО
Сообщения: 438
Версия Delphi: XE2
Репутация: 17
По умолчанию

Код:
screen.cursor:=crHourGlass;
...
screen.cursor:=crDefault;

да и все
__________________
Я за здоровый экстрим!
Спасибо за "спасибо")
Ответить с цитированием
  #8  
Старый 23.09.2013, 13:41
Аватар для Uniq!
Uniq! Uniq! вне форума
Местный
 
Регистрация: 29.09.2010
Сообщения: 539
Версия Delphi: Delphi XE3
Репутация: 374
По умолчанию

Цитата:
Сообщение от Freeman
Похоже, автор плохо усвоил предыдущий урок. Я уже начинаю разочаровываться.

С ошибками разбирался всю ночь. По поводу MainForm выяснил.
Что касается обработки информации в OnCreate главной формы:

Есть нюанс, что при загрузке данных используются и другие формы. Например выгрузка настроек из IniFil'a в форму fSettings. Т.е. её тоже нужно создать перед тем, как в неё выгружать информацию.

Итоговый код:
Код:
program WorkPlace;

uses uMain in 'uMain.pas' {fMain}; // все unit'ы
begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TfMain, fMain);
  Application.CreateForm(TfDM, fDM);
  Application.CreateForm(TfNewTicket, fNewTicket);
  Application.CreateForm(TfCheckClient, fCheckClient);
  Application.CreateForm(TfSettings, fSettings);
  Application.CreateForm(TfTicketInfo, fTicketInfo);
  Application.CreateForm(TfNewClient, fNewClient);
  Application.CreateForm(TfReport, fReport);

  fSynch := TfSynch.Create(Application);
  fSynch.Show;
  fSynch.LoadData; // функция по примеру, который предложил NumLock
  fSynch.Free;
  Application.Run;

end.
Функция Load:
Код:
procedure TfSynch.LoadData;
var
  IniF: TIniFile;
begin
  IniF := TIniFile.Create(ExtractFilePath(Application.Exename) +
    '/Settings.ini');
  with fSettings do
  begin
    gPawnshop.Text := IniF.ReadString('General', 'Pawnshop', '');
    gNum.Text := IntToStr(StrToInt('$' + IniF.ReadString('General', 'N', '')));
    gNumM.Text := IntToStr(StrToInt('$' + IniF.ReadString('General',
      'NM', '')));
    // Connection
    sDriver.Text := IniF.ReadString('Connection', 'Driver', '');
    sServer.Text := IniF.ReadString('Connection', 'Server', '');
    sPort.Text := IniF.ReadString('Connection', 'Port', '');
    sUid.Text := IniF.ReadString('Connection', 'Uid', '');
  end;
  IniF.Free;

  fDM.GlobalConn.ConnectionString := 'Driver=' + fSettings.sDriver.Text + ';' +
    'Server=' + fSettings.sServer.Text + ';' + 'Port=' + fSettings.sPort.Text +
    ';' + 'UID=' + fSettings.sUid.Text + ';' +
    'Database=gobseck;PWD=ХАРДКОЖЕНЫЙПАРОЛЬ;';

  fSynch.pSynch.Properties.Text := 'Подключение к серверу: ' +
    fSettings.sServer.Text + '. Пожалуйста, ждите...';
  Application.ProcessMessages;
  try
    fDM.GlobalConn.Connected := true;
  except
    while fDM.GlobalConn.DataSetCount <> 0 do
      fDM.GlobalConn.DataSets[0].Connection := fDM.LocalConn;
    fDM.LocalConn.Connected := true;
  end;
end;

Процедуры AfterConnect для Global И Local connection идентичны (с точностью до имён):

Код:
procedure TfDM.GlobalConnAfterConnect(Sender: TObject);
var
  i: integer;
begin
  for i := 0 to fDM.GlobalConn.DataSetCount - 1 do
  begin
    fSynch.pSynch.Properties.Text := 'Загрузка: ' +
      fDM.GlobalConn.DataSets[i].Name;
    fSynch.pSynch.Update;
    fDM.GlobalConn.DataSets[i].Open;
    fSynch.pSynch.Position := fSynch.pSynch.Position +
      100 / fDM.GlobalConn.DataSetCount;
    fSynch.pSynch.Update;
  end;
end;
Здесь много граблей. Хотелось бы исправить. Особенно "пароль",который жёстко вшит в код программы =\

Последний раз редактировалось Uniq!, 23.09.2013 в 13:45.
Ответить с цитированием
  #9  
Старый 23.09.2013, 14:30
Аватар для Bargest
Bargest Bargest вне форума
Профессионал
 
Регистрация: 19.10.2010
Адрес: Москва
Сообщения: 2,390
Версия Delphi: XE3/VS12/FASM
Репутация: 14665
По умолчанию

Цитата:
Особенно "пароль",который жёстко вшит в код программы
Ну загрузить из файла, ввести с клавиатуры или прочитать по календарю майя, после чего передать в функцию LoadData как параметр. В чем проблема? Также можно и другие параметры, например имя БД.
__________________
jmp $ ; Happy End!
The Cake Is A Lie.
Ответить с цитированием
  #10  
Старый 23.09.2013, 14:44
Аватар для Mrak
Mrak Mrak вне форума
Местный
 
Регистрация: 26.01.2013
Адрес: МО
Сообщения: 438
Версия Delphi: XE2
Репутация: 17
По умолчанию

а udl файлы не нравятся?
__________________
Я за здоровый экстрим!
Спасибо за "спасибо")
Ответить с цитированием
  #11  
Старый 23.09.2013, 16:52
Аватар для Freeman
Freeman Freeman вне форума
Местный
 
Регистрация: 05.10.2012
Адрес: Санкт-Петербург
Сообщения: 577
Версия Delphi: 6
Репутация: выкл
По умолчанию

Цитата:
Сообщение от Uniq!
Есть нюанс, что при загрузке данных используются и другие формы.
Формы должны использоваться для отображения данных, поскольку они визуальные компонеты. Исключение -- главная форма. Она запускает интерактивный процесс, поэтому ей позволено брать на себя больше. Любое другое использование форм -- быдлокод. Формы не предназначены для передачи данных.

Если речь идет про конфигурацию, нужно создать некий невизуальный класс TEnvironment, умеющий читать и сохранять себя в ini-файлы или куда нужно. Логически связанные элементы конфигурации можно оформить в подклассы, можно в записи, а можно и в свойства. Предварительно созданный и проинициализированный экземпляр TEnvironment по мере надобности передается формам и модулям данных, и они читают из него нужные настройки.

Можете закидать меня помидорами, но TDataModule я считаю быдлокодерским компонентом. В Delphi он реализован неправильно: отсутствует возможность класть созданный в проекте экземпляр DataModule на форму, как это происходит с фреймами. Модуль данных должен быть невизуальным аналогом фрейма, а не нарушением агрегации, как сейчас.

Цитата:
Сообщение от Uniq!
Процедуры AfterConnect для Global И Local connection идентичны (с точностью до имён)
Они не должны быть идентичны, это должен быть физически один и тот же обработчик. В IDE есть возможность назначить один обработчик нескольким событиям, в том числе у разных компонентов, выбирая его из выпадающего списка. Это азы.

Другой явный образчик быдлокода -- обращение из события к самому себе через внешнюю переменную. Грубо говоря, в коде нужно везде поубирать обращения к fDM к чертовой матери.

Цитата:
Сообщение от Uniq!
Функция Load:
Тут тоже все поставлено с ног на голову. Не формы управляют процессом, а процесс управляет формами. Форма-заставка -- всего лишь бессловесная табличка, в ней не место коду загрузки данных.

Цитата:
Сообщение от Mrak
а udl файлы не нравятся?
Возможно, это будет решением. Тогда в настройках можно задавать имя UDL-файла.

Последний раз редактировалось Freeman, 23.09.2013 в 16:55.
Ответить с цитированием
  #12  
Старый 23.09.2013, 22:16
Аватар для Uniq!
Uniq! Uniq! вне форума
Местный
 
Регистрация: 29.09.2010
Сообщения: 539
Версия Delphi: Delphi XE3
Репутация: 374
По умолчанию

Нужны хорошие книжки. Я осилил около десятка за 10 лет. И кучу интернет ресурсов. О том, что такое Sender узнал только сегодня.

Что касается AfterConnect:
Код:
procedure TfDM.DoAfterConnect(Sender: TObject);
var
  i: integer;
  Connection: TADOConnection;
begin
  Connection := (Sender as TADOConnection);
  for i := 0 to Connection.DataSetCount - 1 do
  begin
    fSynch.pSynch.Properties.Text := 'Загрузка: ' + GlobalConn.DataSets[i].Name;
    fSynch.pSynch.Update;
    Connection.DataSets[i].Open;
    fSynch.pSynch.Position := fSynch.pSynch.Position + 100 / Connection.DataSetCount;
    fSynch.pSynch.Update;
  end;
end;

Это типа класс. Сейчас ещё пару вёдер критики бы, было бы замечательно.
Код:
unit uEnvironment;

interface

uses IniFiles;

type
  TEnvironment = Class(TIniFile)
  private
    function GetNum: string;
    function GetNumM: string;
    function GetPawnshop: string;
    procedure SetNum(const Value: string);
    procedure SetNumM(const Value: string);
    procedure SetPawnshop(const Value: string);
  public
    property Pawnshop: string read GetPawnshop write SetPawnshop;
    property Num: string read GetNum write SetNum;
    property NumM: string read GetNumM write SetNumM;
    constructor Create(FilePath: string);
  end;

var
  Environment: TEnvironment;

implementation

{ TEnvironment }

constructor TEnvironment.Create(FilePath: string);
begin

end;

function TEnvironment.GetPawnshop: string;
begin
  Environment.ReadString('General', 'Pawnshop', '');
end;

function TEnvironment.GetNum: string;
begin
  Environment.ReadString('General', 'Num', '');
end;

function TEnvironment.GetNumM: string;
begin
  Environment.ReadString('General', 'NumM', '');
end;

procedure TEnvironment.SetPawnshop(const Value: string);
begin
  Environment.WriteString('General', 'Pawnshop', Value);
end;

procedure TEnvironment.SetNum(const Value: string);
begin
  Environment.WriteString('General', 'Num', Value);
end;

procedure TEnvironment.SetNumM(const Value: string);
begin
  Environment.WriteString('General', 'NumM', Value);
end;

{$R *.dfm}

end.

Я так понимаю экземпляр этого класса должен быть доступен из всех форм (хотя чутьё подсказывает, что не из форм, а из процесса(сов)).
Если отказываться от fDM (никогда, кстати не использовал, прочитал в книге, что на нём удобно держать тьму этих компонентов), то как тогда быть? Держать их на главной форме?
Я уже думаю создать методичку для самого себя. Чтоб по полочкам всё разложить.

Последний раз редактировалось Uniq!, 24.09.2013 в 02:27.
Ответить с цитированием
  #13  
Старый 23.09.2013, 23:55
Аватар для Freeman
Freeman Freeman вне форума
Местный
 
Регистрация: 05.10.2012
Адрес: Санкт-Петербург
Сообщения: 577
Версия Delphi: 6
Репутация: выкл
По умолчанию

Цитата:
Сообщение от Uniq!
Что касается AfterConnect:
Советую еще раз подумать над кодом AfterConnect. Прямое управление компонентами чужой формы противоречит инкапсуляции. Перечитай, что я писал про заставки. У формы заставки должны быть методы, принимающие входные параметры и делающие всю работу внутри себя.

Цитата:
Сообщение от Uniq!
Я так понимаю экземпляр этого класса должен быть доступен из всех форм
Я нигде не писал "должен быть доступен". Класс классу волк, а нужные данные передаются из метода в метод параметром.

Возможно, мои слова про удаление обращений к fDM не совсем понятны. Имел в виду, что нужно удалить все точечные обращения к экземпляру fDM из кода самого fDM, чтобы он обращался к своим компонентам через Self.

Слова про избавление от модуля данных можно пропустить мимо ушей. Delphi же не переделаешь. Фреймы в проекте не используются?
Ответить с цитированием
  #14  
Старый 24.09.2013, 03:02
Аватар для Uniq!
Uniq! Uniq! вне форума
Местный
 
Регистрация: 29.09.2010
Сообщения: 539
Версия Delphi: Delphi XE3
Репутация: 374
По умолчанию

Памятка:
1) Создал Главную форму (на ней ADOConnection и все ADOTable)
2) Создал Splash-форму (исключил её из автосоздаваемых)
3) Обработчики ниже.

В итоге, с учётом всего сказанного Freeman'ом по теме передачи данных из формы в форму и взаимодействия элементов получил:
Код:
procedure TfMain.FormCreate(Sender: TObject);
var
  i: integer;
begin
  fSplash := TfSplash.Create(Application);
  fSplash.Show;
  fSplash.Update;
  for i := 0 to Connection.DataSetCount - 1 do
    Connection.DataSets[i].Open;
  fSplash.Free;
end;
Назначенная единственная DSBeforeOpen ко всем ADOTable
Код:
procedure TfMain.DSBeforeOpen(DataSet: TDataSet);
begin
  if fSplash <> nil then
    fSplash.ShowProgressFor(DataSet.Name);
end;
Сама публичная fSplash.ShowProgressFor(DataSet.Name):
Код:
procedure TfSplash.ShowProgressFor(const LoadingItem: string);
begin
  if LoadingItem <> '' then
    ProgressText.Caption := Format('Загрузка %s...', [LoadingItem])
  else
    ProgressText.Caption := '';
  ProgressText.Update;
end;
Проблема с интерактивным и не интерактивным взаимодействием решена, по-моему, верно.

Последний раз редактировалось Uniq!, 24.09.2013 в 03:05.
Ответить с цитированием
  #15  
Старый 24.09.2013, 08:44
Аватар для Freeman
Freeman Freeman вне форума
Местный
 
Регистрация: 05.10.2012
Адрес: Санкт-Петербург
Сообщения: 577
Версия Delphi: 6
Репутация: выкл
По умолчанию

Цитата:
Сообщение от Uniq!
Код:
procedure TfMain.FormCreate(Sender: TObject);
var
  i: integer;
begin
  fSplash := TfSplash.Create(Application);
  fSplash.Show;
  fSplash.Update;
  for i := 0 to Connection.DataSetCount - 1 do
    Connection.DataSets[i].Open;
  fSplash.Free;
end;
Тут как бы сам собой напрашивается try-finally, вдруг при подключении к базе исключение произойдет?
Код:
procedure TfMain.FormCreate(Sender: TObject);
var
  i: integer;
begin
  fSplash := TfSplash.Create(Application);
  try
    fSplash.Show;
    fSplash.Update;
    for i := 0 to Connection.DataSetCount - 1 do
      Connection.DataSets[i].Open;
  finally
    fSplash.Free;
  end;
end;
Нужно завести себе хорошую привычку всегда заключать в try-finally работу с динамически созданным локальным объектом.
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 17:13.


 

Сайт

Форум

FAQ

Соглашения

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2025