I'm trying to close all the forms that related to client once he disconnected form the server
This action will be on the server side.
I have ( the known for me at run time ) partial unique caption for each client for example
Form caption 1:
ServiceA - ClientABC
Form caption 2:
ServiceB - ClientABC
What i already know is the - ClientABC part only.
So when the client ClientABC disconnected form my server i want to close all the related opened form in the server side.
procedure TIdServer.ClientRemove(const AContext: TIdContext);
var
sTitle: string;
function CloseChildForm(Wnd: HWND; Param: LPARAM): BOOL; stdcall;
begin
if Pos(sTitle, _GetWindowTitle(Wnd)) <> 0 then
PostMessage(Wnd, WM_CLOSE, 0, 0);
Result := True;
end;
begin
sTitle := TMyContext(AContext).Uniquename {ClientABC}
if Assigned(FListView) then begin
TThread.Queue(nil,
procedure
var
i: Integer;
begin
EnumWindows(#CloseChildForm, 0);
.......
end;
end
);
end;
end;
My problem is the string sTitle inside the CloseChildForm function always empty.
I call ClientRemove on the IdServerDisconnect procedure
procedure TIdServer.IdServerDisconnect(AContext: TIdContext);
begin
TMyContext(AContext).Queue.Clear;
........
ClientRemove(AContext);
end;
Can anyone tell me what wrong please ?
There are quite a few things wrong here:
You must not use a nested function as your callback. That is not allowed by the language and your code only compiles because the RTL declaration of EnumWindows uses an untyped pointer for the callback parameter.
Asynchronous execution with TThread.Queue means that the enclosing stack frame can be finished before the call to EnumWindows completes.
You are in danger of closing windows that do not belong in your process.
Were I faced with this problem I would solve it using Screen.Forms[]. Something like this:
for i := Screen.FormCount-1 downto 0 do
if CaptionMatches(Screen.Forms[i]) then
Screen.Forms[i].Close;
This is just an outline. I'm sure you can understand the concept. The key point is not to use EnumWindows and instead use the VCL's own mechanism to enumerate your forms.
Related
I got some problems with the TImage component of loading bitmap from stream. When i call that my image loading like that.
Normal Window
Fullscreen Window
Okay, but when i build my codes on VCL Application mode its working good.
procedure SaveToStream(Stream: TStream; Bitm: TBitmap);
var
Surface: TBitmapSurface;
begin
Surface:= TBitmapSurface.Create;
try
Surface.Assign(Bitm);
TBitmapCodecManager.SaveToStream(Stream, Surface, '.bmp');
finally
Surface.Free;
end;
end;
Calling like that,
B := TBitmap.Create;
BS:= TMemoryStream.Create;
try
B := ParseData((FData)); // my image data is converting from TByteArray to Bitmap now. Its
working no problem.
SaveToStream(BS, B);
FrmScreenViewer.ImgScreen.Bitmap.LoadFromStream(BS);
//FrmScreenViewer.ImgScreen.Bitmap:= B; //I tryed without SaveToStream method but same
result.
finally
B.Free;
BS.Free;
end;
Are there some limitations on the FMX side? Why isn't working?
ParseData Function (I used RTC Framework and some variables are customizable like RTCByteArray)
function ParseData(Data: RtcByteArray): TBitmap;
var
B: TBitmap;
M: TRtcByteArrayStream;
begin
B := TBitmap.Create;
M := TRtcByteArrayStream.Create(Data);
try
B.LoadFromStream(M);
Result := B;
finally
M.Free;
end;
end;
ERROR at line 8: PL/SQL: Statement ignored
CREATE OR REPLACE PROCEDURE POS(A IN NUMBER,M IN NUMBER,TOTAL OUT NUMBER)
AS
BEGIN
TOTAL:=0;
WHILE A>0 LOOP
M:=MOD(A,10);
TOTAL:=TOTAL+M;
A:=(A/10);//statement ignored error
END LOOP;
DBMS_OUTPUT.PUT_LINE(TOTAL);
END;
DECLARE
X NUMBER;
Y NUMBER:=5;
Z NUMBER;
BEGIN
POA(X,Y,Z);
END;
OK, I've had a look at your procedure and tried to resolve the issues you are having with it.
You haven't explained much (or indeed anything) about what you are trying to achieve which makes it really difficult to get you an answer.
People on here really want to help but you have to at least give us the tools with witch to provide that help.
Anyhow, with a host of assumptions, here is my version of your procedure with the following assumptions:
Your procedure is names POS (you name it POS in the procedure definition but then try to execute it as POA).
Your main issue was trying to assign a new value to input parameter "a" within the loop. As it is an input parameter it is immutable and you cannot assign new values to it. I have got round this by declaring a local variable "v_iter" and assigning that the value of "a" and then using it to control the loop.
I have added an "exception" section to handle any unexpected errors and output that error via DBMS_OUTPUT. You might want to make this more robust.
You do not test to check if the input parameter "a" is null or a valid number (i.e. not negative), you might want to do this to make your procedure more robust.
Here is the changed code:
CREATE OR REPLACE
PROCEDURE POS (
a IN NUMBER,
m IN NUMBER,
total OUT NUMBER
)
AS
— Declare variables
v_iter NUMBER := a;
BEGIN
— Initialise total
total := 0;
— Loop through “v_iter”
WHILE v_iter > 0
LOOP
m := MOD(v_iter,10);
total := total + m;
v_iter := (v_iter/10);
END LOOP;
DBMS_OUTPUT.put_line(total);
EXCEPTION
WHEN others
THEN
— Output and raise an error;
DBMS_OUTPUT.put_line(sqlerrm);
RAISE;
END POS;
/
To call it:
DECLARE
X NUMBER;
Y NUMBER:=5;
Z NUMBER;
BEGIN
POS(X,Y,Z);
END;
/
Hope it helps.
I'm Trying to do, in delphi, that when you press a button, I display a drop-down panel with options like this:
Does anyone know how to make this effect with VCL?
Now I have a form with 2 panels, the main is always showing and has a side button, and when I press the button the side panel is shown, but I would like to make the effect.
Thank you
I dont know your application in detail, with the transparency and other things. However, I think you will have to animate your panels/windows in some sort of loop on your own. I dont know of any VCL function for that.
Here is an example which animates a Window (its quick and dirty though):
Code:
procedure TForm1.Button1Click(Sender: TObject);
var
I, X: Integer;
begin
Form2.Width := 1;
Form2.Height := Form1.Height;
Form2.Left := Form1.Left + Form1.Width;
Form2.Top := Form1.Top;
Form2.Show;
Timer1.Enabled := true;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
if I < 500 then
begin
I := I + 1;
Form2.Width := I;
end
else
begin
Timer1.Enabled := false;
end;
end;
Not perfect, but hopefully good enough to give you an idea.
Andy
you can use TJvRollOut from Jedi JVCL.
It acts like a panel which colapse and expand. Also you can take a look at Delphi: sliding (animated) panel and
Hide, Slide And Fade Away Controls On A Delphi Form
Finally, I managed to make the effect. I put a panel and I have added a picture. then I used animatedwindows in buton click process.
procedure TFTelefonoSIP.Button1Click(Sender: TObject);
begin
if GDPanelLlamadasHidden = False then
begin
AnimateWindow(Panel1.Handle, 200, AW_SLIDE or AW_HOR_POSITIVE or AW_HIDE);
GDPanelLlamadasHidden := True;
end
else
begin
AnimateWindow(Panel1.Handle, 200, AW_SLIDE or AW_HOR_NEGATIVE or AW_ACTIVATE);
GDPanelLlamadasHidden := False;
end;
end;
But the effect is not quite what I wanted, sometimes the image shows a flash, not very aesthetic.
you should enable the "Double Buffered" property at the application form's... this should prevent the flashing..
1.The particles seems to have an excess y-direction movement, but i didn't add a background gravity for them.
2.The particles seems to move too fast when they're getting closer and closer, (because I don't know how to handle the issue of collision?)
I calculate the location by adding the corresponding force it experienced , how can i know if they collided with other? for example:
stage 1
particle1 [1,1]
particle2 [1,9]
stage 2
particle1 [9,9]
particle2 [1,9]
If I plot a graph of the path belonging to each particle, I can see if the graph of paths intercept with other, but the path intercept doesn't 100% means they'll collide, as they can have different speed.
I've tried to debug but just cannot find out where is going wrong.
in version 0 they tend to fail down (not my wish)
in version 1 they tend to fail to the right (i swap the x y) (simplified version)
here is the url of the bin and source (in pascal): stack_exchange_particle_gravity_collision.zip
here is the source code of version 0 in case you do not want to download the zip:
program ParticlesV0;
uses
graph;
const
pi=3.14159265358979;
n=500;
defaultSpeed=1;
defaultRadius=2;
defaultDensity=1e4;
energyLoss=0.50;
dotStyle=1;
backGroundLevel=0;
type
ParticleType=record
x,y,dr,dd,dx,dy,dfr,dfd:real;
color:word;
radius,mass:real;
end;
var
gd,gm:smallint;
PathToDriver:string;
l:longint;
particle:array[1..n]of ParticleType;
////////////////////////////////////////////////////////////////
procedure backGround(i:smallint);
var
y:smallint;
s,t:string;
w,ori:word;
begin
ori:=GetColor;
SetColor(10);
while i>0 do begin
for y:=0 to (GetMaxY div 10) do begin
s:='';
for w:=0 to 255 do begin
str(random(10),t);
s:=s+t;
end;
OutTextXY(5,y*10,s);
end;
dec(i);
end;
SetColor(ori);
end;
procedure line(x1,y1,x2,y2:smallint);
var
x,y:smallint;
begin
x:=getx;
y:=gety;
moveto(x1,y1);
lineto(x2,y2);
moveto(x,y);
end;
function rx(x:real):real;
begin
rx:=x+(GetMaxX div 2);
end;
function ry(y:real):real;
begin
ry:=y+(GetMaxY div 2);
end;
function s(r:real):smallint;
begin
s:=round(r);
end;
function distance(p1,p2:ParticleType):real;
var
x,y:real;
begin
x:=p1.x-p2.x;
y:=p1.y-p2.y;
distance:=sqrt(x*x+y*y);
end;
function degree(p1,p2:ParticleType):real;
var
x,y,d:real;
begin
x:=p2.x-p1.x;
y:=p2.y-p1.y;
if x0 then d:=arctan(y/x)
else if (yGetMaxX) then begin
dx:=-dx;
x:=GetMaxX-(x-GetMaxX);
end;
if (xGetMaxY) then begin
dy:=-dy;
y:=GetMaxY-(y-GetMaxY);
end;
if (y0) then begin
tfr:=G*p.mass*particle[l].mass/sqr(r);
tfd:=degree(p,particle[l]);
tdx:=tfr*cos(tfd);
tdy:=tfr*sin(tfd);
dx:=dx+tdx;
dy:=dy+tdy;
// tdx:=
end;
p.dx:=p.dx+dx;
p.dy:=p.dy+dy;
end;
end;
//++++++++++++++++++++++++++++++//
////////////////////////////////////////////////////////////////
begin
gd:=detect; { highest possible resolution }
gm:=0; { not needed, auto detection }
PathToDriver:=' '; { path to BGI fonts, drivers aren't needed }
InitGraph(gd,gm,PathToDriver);
if (GraphResult=grok) then begin
writeln('gd ',gd);
writeln('GetMaxX ',GetMaxX);
writeln('GetMaxY ',GetMaxY);
writeln('GetMaxColor ',GetMaxColor);
backGround(backGroundLevel);
line(0, 0, GetMaxX, GetMaxY);
SetFillStyle(HatchFill,13);
FillEllipse(s(rx(0)),s(ry(0)),10,10);
for l:=1 to n do initp(particle[l]);
repeat
for l:=1 to n do begin
calp(particle[l]);
movep(particle[l]);
end;
until false;
readln;
CloseGraph; { restores the old graphics mode }
end else writeln('Graphic not supported.');
readln;
end.
sorry for the poor formatting
If you want to remove a particle when it get too close, this line should do the job:
procedure calp(var p:ParticleType);
...
e:=*put a number here witch scales with mass or something esle, you can even use defaultradius constant*;
if (r>e) then begin
...
else mass:=0 <- this now means it won't pull others particles, and won't be pulled either, ideally now you need to check everywhere for 0-os, alternatively
you can place the particle randomly on the screen again, but it can cause some funny stuff, becouse of leftover vectors.
Now I build a template for our invoice printer.
But I do really not know, why it crashes without any error.
My goal is to separate the String ItemName at the ';' and print each part into a new line to a Memo1.
procedure DetailBeforeGenerate;
var
s1: String;
s2: String;
wordcount: Integer;
notelength: Integer;
begin
s1 := plPrintInvLine['ItemName'];
notelength := Length(s1);
while notelength > 0 do
begin
notelength := Length(s1);
wordcount := Pos(';' , s1);
s2 := Copy(s1, 0, wordcount-1);
Memo1.Lines.Add(s2);
Delete(s1, 0, wordcount);
end;
end;
See comments below regarding accessing index[0] in a string and thanks to David Heffernen and Ken White. BUT:
Looks like you've got an infinite loop in your code:
notelength := Length(s1);
while notelength > 0 do
begin
notelength := Length(s1);
wordcount := Pos(';' , s1);
s2 := Copy(s1, 0, wordcount-1);
Memo1.Lines.Add(s2);
Delete(s1, 0, wordcount);
end;
Delete(s1, 0, wordcount); Has no effect! Try it in Delphi debugger. Result? notelength is never decremented so you'll loop forever. ' Delete(s1, 0, wordcount);' does not blow up but neither does it delete. Use Delete(s1,1, wordcount) instead.
Index[0] in Delphi strings does not contain your character data - it's 'not accessible' according to the compiler, if you try compiling myString[0];
Also: the way your code is written, you MUST terminate with ';' or a string such as this:
s1 := 'mikey;was;here;a'; will loop infinitely on the last string after ';' ('a')
I also use ReportBuilder templates, etc: In Delphi itself you will not be able to compile MyString[0], but the copy and delete methods are protected from this error, (as David explained) however it appears from what I saw in the debugger that 'Delete(s1, 0, wordcount)' will not throw an exception but fails to delete. So I would not expect RBuilder to be any better, and perhaps worse - copy() may also be failing on string[0] in RAP.
RAP is NOT Delphi - it is a Runtime scripting environment that runs in your template, based on Object Pascal, but it does not support everything, and you cannot always expect it to behave exactly like Delphi.
BTW - ReportBuilder is now up to version 14.0X - if possible you should upgrade - there have been a lot of improvements in the RAP environment. In a later version your code might work OK or you'll get back an error message from RAP.
Also: If you want to debug in RAP it's not so easy. But to give you a clue as to where the error might be occurring, put a text label on your report and after each line of your code add
mylabel.caption:='statementxxx ran';
or
mylabel.caption:= myVariable.value;
Etc. That will give you a little ad hoc tracer - maybe show you where/why you failed, etc.
For all searching people: I found the solution with the excellent help of this community!
The working code looks like this:
procedure DetailBeforeGenerate;
var
S1: String;
S2: String;
wordcount: Integer;
notelength: Integer;
begin
S1 := plPrintInvLine['ArtName'];
notelength := Length(S1);
while (notelength > 0) do
begin
wordcount := Pos(';',S1);
S2 := Copy(S1, 1, wordcount-1);
if ( Pos(' ',S2) = 1 ) then Delete(S2, 1, 1);
Memo1.Lines.Add(S2);
Delete(S1, 1, wordcount);
notelength := notelength - wordcount;
end;
end;