Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 27.08.2015, 12:03   #1
fanlis
Пользователь
 
Регистрация: 13.05.2007
Сообщений: 60
По умолчанию Ожидание вывода строки

Здравствуйте. Думал, думал, чего-то в голову ничего не приходит.
Есть моя написанная программа, в ней есть Memo, в которое по мере необходимости выводятся сообщения: sMemo1.Lines.Add('...'); Они выводятся после нажатия каких-то кнопок, после расчетов и т.д. Бывает так, что выводятся несколько сообщений подряд. Я решил немного переделать программу, чтобы сообщения выводились не в Memo, а в Label и по одному. Принцип такой: Выводится сообщение в Label. Если нужно вывести новое сообщение, то программа ждет, когда я нажму на Label и только после этого выводит следующее сообщение.

Я сделал так:
Добавил процедуры
Код:
procedure TForm1.MemoAdd(str: string);
begin
  while sLabel.Caption<>'' do Application.ProcessMessages;
  sLabel.Caption:=str;
end;

procedure TForm1.sLabelClick(Sender: TObject);
begin
  sLabel.Caption:='';
end;
Заменил все строки типа sMemo1.Lines.Add('...'); на MemoAdd('...');
При нажатии на Label он очищается и следовательно можно выводить следующее сообщение.
Т.е. получается, что когда в программе встречается команда вывода сообщения и оно не очищено, то программа "застревает" в цикле и ждет нажатия на сообщение. Программа не висит и все хорошо, но этот цикл занимает процессор и это плохо. Может можно что-то другое придумать?

Фактически, допустим есть текст:
Код:
procedure .......
begin
  MemoAdd('ляляля');
  ....
  какие-то действия
  ...
  MemoAdd('еще ляля');
  ....
  какие-то действия
  ...
  MemoAdd('ляля');
end;
На каждом MemoAdd программа должна ждать нажатия мной на Label и только после этого продолжать выполнять процедуру. Но чтобы кроме нажатия на Label, я мог делать и что-то другое, например, закрыть программу.
fanlis вне форума Ответить с цитированием
Старый 27.08.2015, 17:28   #2
DIONISKA
Форумчанин
 
Регистрация: 07.11.2011
Сообщений: 161
Подмигивание

Можно добавлять сообщения в очередь и при необходимости вытаскивать оттуда, примерно так:

Код:
uses ..., System.Generics.Collections;
...
var
  Q:tqueue<string>;

...
procedure TForm.FormCreate(Sender: TObject);
begin
  q:=tqueue<string>.create;
end;

procedure TForm.FormDestroy(Sender: TObject);
begin
  freeandnil(q);
end;

procedure TForm.MemoAdd(str: string);
begin
  q.Enqueue(str);
end;

procedure TForm.LabelClick(Sender: TObject);
begin
 if q.Count>0 then Label1.Caption:=q.Dequeue;
end;
и даже костыли не нужны
DIONISKA вне форума Ответить с цитированием
Старый 28.08.2015, 09:59   #3
fanlis
Пользователь
 
Регистрация: 13.05.2007
Сообщений: 60
По умолчанию

System.Generics.Collections - это что такое в uses?? Выдает ошибку.

и такую структуру в делфи не встречал никогда:
var
Q:tqueue<string>;
fanlis вне форума Ответить с цитированием
Старый 28.08.2015, 10:14   #4
Аватар
Старожил
 
Аватар для Аватар
 
Регистрация: 17.11.2010
Сообщений: 18,922
По умолчанию

Цитата:
Сообщение от fanlis Посмотреть сообщение
такую структуру в делфи не встречал никогда
Потому, что XE
Если бы архитекторы строили здания так, как программисты пишут программы, то первый залетевший дятел разрушил бы цивилизацию
Аватар вне форума Ответить с цитированием
Старый 28.08.2015, 10:25   #5
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,229
По умолчанию

fanlis, а Delphi у Вас какая?
Если старая (< XE ), то используйте банальный TSTringList:
объявите глобально:
Код:
var 
  TS : TStringList;
на FormCreate создавайте экземпляр класса:
Код:
procedure TForm.FormCreate(Sender: TObject);
begin
  TS:= TStringList.Create;
end;
остальное, как в примере от DIONISKA
Serge_Bliznykov вне форума Ответить с цитированием
Старый 28.08.2015, 13:00   #6
fanlis
Пользователь
 
Регистрация: 13.05.2007
Сообщений: 60
По умолчанию

Ну в общем я понял вашу идею и, в принципе, ее можно применить, хотя это не совсем то, что я хотел.

Например, выполняется процедура
Код:
procedure .......
begin
  MemoAdd('Привет');
  ....
  расчеты
  ...
  MemoAdd('В результате расчетов получилось то-то');
  ....
  какие-то действия
  ...
  MemoAdd('Если вы согласны с расчетами, нажмите Да, если нет, нажмите Нет');
  ButtonYes.Visible:=true;
  ButtonNo.Visible:=true;
end;
После ее выполнения я увижу сообщение "Привет" и две кнопки, которые я могу нажать, не зная зачем они. А остальные два сообщения будут ждать меня в очереди. Я нажимаю, допустим Да, начинаются другие расчеты и все сообщения сбиваются.
Мне бы желательно, чтобы программа останавливалась после сообщения "Привет". Потом я бы нажал на него, прочитал следующее, снова нажал и увидел бы кнопки и сообщение про эти кнопки.
Но при этом нельзя делать сообщение в виде модального окна, потому что помимо нажатия на сообщения я могу, например, сменить закладку в PageControl или закрыть вообще программу.
fanlis вне форума Ответить с цитированием
Старый 28.08.2015, 14:22   #7
evg_m
Старожил
 
Регистрация: 20.04.2008
Сообщений: 5,526
По умолчанию

1. разбить вычисления на несколько групп (блоков/ПРОЦЕДУР)
в конце которых выводить нужное сообщение. (куда и как угодно)
2. не ждать появления сообщения, а запускать КАЖДЫЙ блок по нажатию кнопки.
либо кнопке на каждый блок(процедуру) и блокировать (enabled:=false) при запуске
либо одна кнопка, НО иметь возможность УЗНАВАТЬ какую процедуру(блок вычислений) надо выполнять.
Код:
startbutton.tag=0; 1; .... (по завершении блока вычислений)
и при запуске
Код:
case button.tag of
0: 
2:
end;
сделали что смогли и спокойно ждем что еще попросит пользователь
Цитата:
потому что помимо нажатия на сообщения я могу, например, сменить закладку в PageControl или закрыть вообще программу.
P.S. вместо кнопки можно конечно же запускать и по Label.
Код:
LableMsg.tag:=0; 1; ....
но опять же только один нужный в данный момент блок.
программа — запись алгоритма на языке понятном транслятору

Последний раз редактировалось evg_m; 28.08.2015 в 14:36.
evg_m вне форума Ответить с цитированием
Старый 28.08.2015, 15:34   #8
fanlis
Пользователь
 
Регистрация: 13.05.2007
Сообщений: 60
По умолчанию

Цитата:
Сообщение от evg_m Посмотреть сообщение
1. разбить вычисления на несколько групп (блоков/ПРОЦЕДУР)
вот как раз этого и не хотелось, точнее совсем не хотелось лазить по программе и переделывать ее. Она большая и готовая. Одно дело я автозаменой заменил sMemo1.Lines.Add на MemoAdd и дописал несколько процедур, а другое разбираться в программе и менять ее (разбивать все процедуры на блоки). Хотелось решить проблему "малой кровью".
Я так понимаю, именно того, чего я хочу, сделать невозможно, поэтому все предлагают обходные методы?
fanlis вне форума Ответить с цитированием
Старый 28.08.2015, 16:05   #9
evg_m
Старожил
 
Регистрация: 20.04.2008
Сообщений: 5,526
По умолчанию

вы хотите
ВЫПОЛНИТЬ остановку внутри процедуры без остановки.
а это невозможно.
процедуру можно остановить если
есть другая процедура которая ее может запустить снова (это будут параллельные процессы) но это опять ПЕРЕДЕЛКА. и ОПЯТЬ надо будет править ваш "большой код" чтобы он имел возможность остановки.

а разбиение делается почти(!) на автомате.
если вычисления (точнее точки вывода сообщений) образуют линейную последовательность.
Цитата:
в конце которых выводить нужное сообщение. (куда и как угодно)
1.начинаем сверху
2.находим сообщение
3.переносим все от начала до сообщения в отдельную процедуру
4.дописываем запуск данной(новой из п.2) процедуры.
5.если код исходный еще остался то п.1.
программа — запись алгоритма на языке понятном транслятору

Последний раз редактировалось evg_m; 28.08.2015 в 16:09.
evg_m вне форума Ответить с цитированием
Старый 28.08.2015, 16:19   #10
DIONISKA
Форумчанин
 
Регистрация: 07.11.2011
Сообщений: 161
По умолчанию

Цитата:
такую структуру в делфи не встречал никогда
TQueue<T> - как выше отметили это в XE и выше, для D7 вроде был аналог в модуле "Concntrls", однако там свои тонкости.
Цитата:
потом я бы нажал на него, прочитал следующее, снова нажал и увидел бы кнопки и сообщение про эти кнопки.
На мой взгляд лучше убирать кнопки типа да/нет из ui и что мешает показать MessageDlg c 2-мя кнопками? Заодно это обезопасит от несвоевременного их нажатия. Например:
Код:
if mrYes=MessageDlg('Согласны с рассчётами?',mtwarning,[mbYes, mbNo],0) then 
showmessage('Вы выбрали "да"')
   else showmessage('Вы выбрали "нет"');
Цитата:
помимо нажатия на сообщения я могу, например, сменить закладку в PageControl или закрыть вообще программу.
у pagecontrol есть событие "OnChanging"
Код:
procedure PageControlChanging(Sender: TObject;
  var AllowChange: Boolean);
где в переменной AllowChange можно запретить/разрешить смену активной страницы.
Та-же история и с закрытием формы:
Код:
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
Здесь с помощью переменной CanClose можно запретить закрытие программы, или просто выводить сообщение вроде "Расчёты не окончены, закрыть программу?"
Также чтобы пользователь не запустил расчёты повторно можно создать процедуру (раз)блокировки UI (пройтись по всем кнопкам и присвоить enabled:=false/true), также для этих целей можно пользоваться атомами или критическими секциями.

Ps: первоначально это случаем не было консольным приложением?
DIONISKA вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Нет вывода строки на экран ДЕД_МАЗАЙ Assembler - Ассемблер (FASM, MASM, WASM, NASM, GoASM, Gas, RosAsm, HLA) и не рекомендуем TASM 4 23.11.2014 19:58
с++ рекурсивная функция вывода на экран строки в обратном порядке archil Помощь студентам 1 26.05.2014 15:10
Ожидание завершения DrBAXA Общие вопросы Delphi 8 26.01.2013 21:42
мультипоточное ожидание Fun_tick C# (си шарп) 5 05.03.2012 15:00
Контроллер для вывода "бегущей строки" на светодиодные табло HellMercenariess Компьютерное железо 4 20.07.2010 03:51