Форум: "Основная";
Текущий архив: 2006.07.09;
Скачать: [xml.tar.bz2];
ВнизКак правильно реализовать эффект Найти похожие ветки [Останов/Продолжить]
← →
Schooler (2006-05-22 16:13) [0]На форме :
TreeView1 :TTreeView;
btnExecute :TButton;
btnContinue :TButton;
Прохожу по TreeView1 последовательно в цикле (кнопка btnExecute):procedure TForm1.btnExecuteClick(Sender:TObject);
begin
for i:= to to TreeView1.Items.Count-1 do
begin
if TreeView1.Items[i].HasChildren
then
begin
// Некоторые действия
// ...
// Конец Некоторые действия
// Вот здесь нужно сделать ActiveControl := btnContinue
// и приостановить выполнение Цикла:
// при нажатии btnContinue продолжить Цикл
end;
end;
end;
Как правильно такие вещи делать ? Это TThread"ы ?
← →
StriderMan © (2006-05-22 16:29) [1]можно запомнить переменную i и потом с нее продолжить...
← →
Сергей М. © (2006-05-22 16:31) [2]
> Это TThread"ы ?
Где ?
← →
Schooler (2006-05-22 16:42) [3]To StriderMan © (22.05.06 16:29) [1]
Была такая идея и у меня.
Мне, кажется, не подойдет такой вариант: т.е. я не хочу покидать тело процедуры, там ряд локальных переменных, которые я потеряю (здесь упрощенный код).
To Сергей М. © (22.05.06 16:31) [2]
Что если обработчик кнопки завернуть в метод MyThread.Execute?
> Где ?
Я что, принипиально не в том направлении иду?
← →
Сергей М. © (2006-05-22 16:45) [4]
> Schooler (22.05.06 16:42) [3]
> обработчик кнопки завернуть в метод MyThread.Execute
Зачем ?
> Я что, принипиально не в том направлении иду?
Очень на то похоже ...
← →
StriderMan © (2006-05-22 16:52) [5]
> т.е. я не хочу покидать тело процедуры
может показать модальное окошко с вопросом типа "продолжить?"
есть еще такой вариант (мне самому не нравится, но на ум пришел):
заводишь в private"е формы флаг fContinue типа boolean. он выставляется в true обработчиком кнопки btnContinue.
а далее в тело твоего цикла впихнуть код
while not fContinue do
Application.ProcessMessages;
fContinue := false;
но стоит 33 раза подумать преждем чем так делать. Ведь кроме btnContinue пользователь может нажать и другие кнопки, и что произойдет тогда, одному ежу ведомо
> там ряд локальных переменных, которые я потеряю (здесь упрощенный
> код)
можно завести под них record и поместить в Private класса формы
← →
Schooler (2006-05-22 16:52) [6]To Сергей М. © (22.05.06 16:45) [4]
1. Ваш Вариант решения?
2. И, если не сложно, почему
> Очень на то похоже ...
?
← →
Schooler (2006-05-22 16:58) [7]To StriderMan © (22.05.06 16:52) [5]
> может показать модальное окошко с вопросом типа "продолжить?
> "
В том то и дело, изначально было ShowMessage
Об этом
> btnContinue пользователь может нажать и другие кнопки
естественно, нужно позаботиться! :...
btnOther1.Enabled := false;
...
btnOtherN.Enabled := false;
...
← →
StriderMan © (2006-05-22 17:12) [8]
> естественно, нужно позаботиться! :
ну если сделать все аккуратно, то мой вариант подходит. Вообще нужно задисаблить все кроме это кнопки
но все равно как-то не очень...
о! еще мысль пришла!
завести класс типа TMyTreeProcess. в нем будут описаны все переменные из процедуры и сама процедура
и добавить методы типа .Pause и .Continue;
дальше объяснять?
← →
Сергей М. © (2006-05-23 08:04) [9]
> Schooler (22.05.06 16:52) [6]
Сначала уточни, может ли измениться содержимое списка узлов в период между паузой и возобновлением ..
← →
Schooler (2006-05-29 11:34) [10]To Сергей М. © & All
Извиняйте, был в командировке.
Вот по поводу Thread-ов:
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ComCtrls;
type
TContinueThread = class(TThread)
private
Current:integer;
FCount: integer;
procedure SetCount(const Value: integer);
public
property Count:integer read FCount write SetCount;
procedure Execute;override;
procedure WaitForContinue;
end;
TForm1 = class(TForm)
TreeView1: TTreeView;
btnExecute: TButton;
btnAbort: TButton;
procedure FormActivate(Sender: TObject);
procedure btnExecuteClick(Sender: TObject);
procedure btnAbortClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
ContinueThread:TContinueThread;
implementation
{$R *.DFM}
procedure TForm1.btnExecuteClick(Sender: TObject);
Var
k:integer;
begin
if ContinueThread = nil
then
begin
btnExecute.Caption := "Continue";
btnAbort.Enabled := true;
ContinueThread := TContinueThread.Create(TRUE);
ContinueThread.Count := TreeView1.Items.Count;
ContinueThread.Priority := tpNormal;
ContinueThread.Resume;
end
else
begin
if ContinueThread.Terminated
then
begin
Form1.btnAbort.Enabled := false;
btnExecute.Caption := "Execute";
ContinueThread.Destroy;
ContinueThread := nil;
btnAbort.Enabled := false;
TreeView1.Selected := TreeView1.Items[0];
end
else ContinueThread.Resume;
end;
end;
procedure TForm1.btnAbortClick(Sender: TObject);
begin
if ContinueThread<>nil
then
begin
btnExecute.Caption := "Execute";
ContinueThread.Destroy;
ContinueThread := nil;
btnAbort.Enabled := false;
TreeView1.Selected := TreeView1.Items[0];
end;
end;
procedure TForm1.FormActivate(Sender: TObject);
begin
TreeView1.FullExpand;
btnAbort.Enabled := false;
end;
{ TCircleThread }
procedure TContinueThread.Execute;
Var
i:integer;
begin
for i:=0 to Count-1 Do
begin
Current := i;
Synchronize(WaitForContinue);
end;
Terminate;
end;
procedure TContinueThread.WaitForContinue;
begin
if Form1.TreeView1.Items[Current].HasChildren
then
begin
Form1.TreeView1.Selected := Form1.TreeView1.Items[Current];
Form1.ActiveControl:=Form1.btnExecute;
Suspend;
end
else Resume;
end;
procedure TContinueThread.SetCount(const Value: integer);
begin
FCount := Value;
end;
end.object Form1: TForm1
Left = 178
Top = 103
Width = 456
Height = 467
Caption = "Form1"
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = "MS Sans Serif"
Font.Style = []
OldCreateOrder = False
OnActivate = FormActivate
PixelsPerInch = 96
TextHeight = 13
object TreeView1: TTreeView
Left = 0
Top = 0
Width = 448
Height = 397
Align = alTop
HideSelection = False
Indent = 19
TabOrder = 0
Items.Data = {
010000001D0000000000000000000000FFFFFFFFFFFFFFFF0000000006000000
04526F6F741D0000000000000000000000FFFFFFFFFFFFFFFF00000000030000
00044E6F6465210000000000000000000000FFFFFFFFFFFFFFFF000000000000
0000085465726D696E616C210000000000000000000000FFFFFFFFFFFFFFFF00
00000000000000085465726D696E616C210000000000000000000000FFFFFFFF
FFFFFFFF0000000000000000085465726D696E616C2100000000000000000000
00FFFFFFFFFFFFFFFF0000000000000000085465726D696E616C1D0000000000
000000000000FFFFFFFFFFFFFFFF0000000003000000044E6F64652100000000
00000000000000FFFFFFFFFFFFFFFF0000000000000000085465726D696E616C
210000000000000000000000FFFFFFFFFFFFFFFF000000000000000008546572
6D696E616C210000000000000000000000FFFFFFFFFFFFFFFF00000000000000
00085465726D696E616C210000000000000000000000FFFFFFFFFFFFFFFF0000
000000000000085465726D696E616C1D0000000000000000000000FFFFFFFFFF
FFFFFF0000000003000000044E6F6465210000000000000000000000FFFFFFFF
FFFFFFFF0000000000000000085465726D696E616C2100000000000000000000
00FFFFFFFFFFFFFFFF0000000000000000085465726D696E616C210000000000
000000000000FFFFFFFFFFFFFFFF0000000000000000085465726D696E616C21
0000000000000000000000FFFFFFFFFFFFFFFF0000000000000000085465726D
696E616C}
end
object btnExecute: TButton
Left = 6
Top = 406
Width = 75
Height = 25
Caption = "Execute"
TabOrder = 1
OnClick = btnExecuteClick
end
object btnAbort: TButton
Left = 86
Top = 406
Width = 75
Height = 25
Caption = "Abort"
TabOrder = 2
OnClick = btnAbortClick
end
end
Это на скорую руку.
> Сначала уточни, может ли измениться содержимое списка узлов
> в период между паузой и возобновлением ..
Тут дело обстоит так:
если элемент уже был посещен, то он изменятся не может (т.е. его детишки неприкосновенны). С непосещенными узлами может делаться все что угодно. Небольшая доработка кода позволит контролировать это.
← →
Сергей М. © (2006-05-29 11:47) [11]
> изменятся не может (т.е. его детишки неприкосновенны)
Смена индекса узла в списке узлов (например, при сортировке) - это тоже изменение списка.
Добавление нового узла в список узлов в промежуток между паузой и возобновлением - это тоже изменение списка.
Обе эти ситуации приведут к неработоспособности твоего алгоритма, потому что твой доп.поток не знает об этих возможных изменениях.
← →
Schooler (2006-05-29 12:51) [12]To Сергей М. ©
1. Сказано же "на скорую руку".
2.
> Смена индекса узла в списке узлов (например, при сортировке)
> - это тоже изменение списка.
В моей задаче это исключено.
3.
> Добавление нового узла в список узлов в промежуток между
> паузой и возобновлением
Уточняю: "С непосещенными узлами может делаться все что угодно. Небольшая доработка кода позволит контролировать это." Т.е. узлы у которых AbsoluteIndex>Currentprocedure TContinueThread.Execute;
Var
i:integer;
begin
for i:=0 to Count-1 Do begin
Current := i;
Synchronize(WaitForContinue);
end;
Terminate;
end;
Неужели сложно заменить цикл for на While и делать, например, после добавления/удаления узла в дерево ContinueThread.Count := TreeView1.Items.Count ?
← →
Сергей М. © (2006-05-29 13:03) [13]А зачем вообще тут доп.тред понадобился ?
Судя по коду (пусть даже и на скорую руку) не вижу в нем никакой необходимости.
К тому же suspend в осн.треде - это большая засада.
← →
Schooler (2006-05-29 13:38) [14]To Сергей М. © (29.05.06 13:03) [13]
> А зачем вообще тут доп.тред понадобился ?
См. Schooler (22.05.06 16:42) [3]
Давай свой вариант без доп.треда.
> К тому же suspend в осн.треде - это большая засада.
Что Вы называете осн.тредом?
procedure TContinueThread.WaitForContinue;
Var
MyLocalVar0,..,MyLocalVarN :AnyType;
begin
if Form1.TreeView1.Items[Current].HasChildren
then
begin
// Некоторые действия над
// MyLocalVar0,..,MyLocalVarN
// Т.е. то, что мне и требовалось: я не хочу покидать тело процедуры !!!
// Конец Некоторые действия
Form1.TreeView1.Selected := Form1.TreeView1.Items[Current];
Form1.ActiveControl:=Form1.btnExecute;
Self.Suspend; end
else Self.Resume;
end;
Где здесь засада?
← →
Сергей М. © (2006-05-29 14:01) [15]
> Где здесь засада?
> Self.Suspend; end <- здесь
> Что Вы называете осн.тредом?
Основной кодовый поток процесса.
← →
Сергей М. © (2006-05-29 14:12) [16]
> Давай свой вариант без доп.треда.
var
SuspendFlag: Boolean;
NodeFrom: Integer;
..
procedure TreeWalking(TV: TTreeView; var NodeFrom: Integer);
begin
with TTreeView do
while not SuspendFlag and (NodeFrom < Items.Count) do begin
...
Application.ProcessMessages;
Inc(NodeFrom);
end;
end;
...
procedure TMyForm.ButtonStartWalkingClick;
begin
NodeFrom := 0;
SuspendFlag := False;
TreeWalking(MyTreeView, NodeFrom);
end;
procedure TMyForm.ButtonSuspendStopWalkingClick;
begin
SuspendFlag := True;
end;
procedure TMyForm.ButtonResumeWalkingClick;
begin
SuspendFlag := False;
TreeWalking(MyTreeView, NodeFrom);
end;
← →
Schooler (2006-05-29 15:14) [17]Я так понимаю, здесь еще:
procedure TMyForm.FormCreate(Sender: TObject);
begin
Application.OnMessage := AppMessage;
end;
и
procedure TMyForm.AppMessage(var Msg: TMsg; var Handled: Boolean);
begin
SuspendFlag := not SuspendFlag;
end;
???
← →
Сергей М. © (2006-05-29 15:21) [18]
> Schooler (29.05.06 15:14) [17]
Это зачем ?
Поясни ход своих мыслей с учетом [16], если таковые имеются ..
← →
Schooler (2006-05-29 15:46) [19]
> Это зачем ?
Мне надо после каждого итема остановится, попялиться на экран, осмыслить пережитое (ну типа трассировка, что-ли), и продолжить дальше движение (ButtonResumeWalkingClick) тогда , когда я захочу. Если угодно, похоже на пошаговую отладку.
С учетом [17] Твой вариант замечательно работает, только я же говорил, что я не хочу покидать тело процедуры при остановке(паузе). В Твоем варианте (когда я жму ButtonResumeWalking) я каждый раз покидаю/вхожу тело procedure TreeWalking!!!
← →
Сергей М. © (2006-05-29 16:21) [20]
> В Твоем варианте (когда я жму ButtonResumeWalking) я каждый
> раз покидаю/вхожу тело procedure TreeWalking
И что в том страшного ?
← →
Schooler (2006-05-29 16:23) [21]Да блин для меня страшно! Там выше смотри.
Ладно, спасибо ! Извини, ухожу.
← →
Сергей М. © (2006-05-29 16:57) [22]Я та ки не понял, к чему ты упомянул доп.треды .
Всуе ?
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2006.07.09;
Скачать: [xml.tar.bz2];
Память: 0.52 MB
Время: 0.01 c