|
[ DjGoran @ 31.08.2007. 10:17 ] @
| Učim delphi par dana. Napravio sam program koji poziva TQuery svakih 0.2 sekunde, i na osnovu rezultata radi ono što treba.
Medjutim, kada se program startuje, svakih 0.2 sekunde mi se pojavljuje na kratko peščani sat umesto strelice, i to je vrlo iritantno. Znači, peščani sat mi se pojavljuje 4-5 puta u jednoj sekundi.
Kako to da sprečim? |
[ savkic @ 31.08.2007. 11:27 ] @
> Učim delphi par dana. Napravio sam program koji poziva TQuery svakih 0.2 sekunde, i na osnovu rezultata radi ono što treba.
> Medjutim, kada se program startuje, svakih 0.2 sekunde mi se pojavljuje na kratko peščani sat umesto strelice, i to je vrlo iritantno.
Peščanik je indikator da se nešto radi, to je default ponašanje za izvršavanje SQL upita. Možeš pokušati da u OnBeforeOpen ili sličnom eventu kveri komponente staviš Application.MainForm.Cursor := crDefault; Inače, razmisli o drugačijem pristupu, aktiviranje kverija na 200ms nije idealno rešenje.
[ DjGoran @ 31.08.2007. 12:12 ] @
Probao sam, nema promena, i dalje se pojavljuje taj peščani sat.
Valjda postoji neki način da mu se to zabrani, globalno, za ceo program/formu, bilo šta...
Inače, bazu moram da prozivam često jer program prati promenu u bazi i reaguje kada se pojavi podatak koji odgovara SQL upitu. SQL upit je jednostavan:
Code:
SELECT * FROM nekatabela WHERE kontrolnopolje=0;
Čim se pojavi zapis koji ima tu vrednost, onda program uzme ID tog zapisa, odradi šta treba sa ostalim poljima, i uradi update zapisa:
Code:
UPDATE nekatabela SET kontrolnopolje=1 WHERE id=OnajOdMalopre;
SQL upiti nisu teški (kao što se vidi) pa mislim da tu neće biti nikakvih problema. Ako ima neki drugi način da se odradi to isto a bez stalnog proveravanja baze, rado bih ga primenio.
[ savkic @ 31.08.2007. 15:04 ] @
> Probao sam, nema promena, i dalje se pojavljuje taj peščani sat.
Koje komponente koristiš i koja baza je u pitanju?
[ DjGoran @ 31.08.2007. 18:40 ] @
TQuery, TDataSource, TDatabase, ODBC, MySQL
[ savkic @ 31.08.2007. 21:33 ] @
> Query, TDataSource, TDatabase, ODBC, MySQL
Nemam takvu kombinaciju pa ne mogu probati, koliko vidim kada se koristi paradox nema te pojave. Moguće je da se kursor setuje iz VCLa ali i iz ODBC sloja.
Savetujem ti da uključiš Use debug DCUs, postaviš brejpkointe u TWinControl.WMSetCursor, TControl.SetCursor i TScreen.SetCursor i posmatraš u kom trenutku se dešava promena kursora i odakle, pa javi nalaze ako ne uspeš sam.
[ DjGoran @ 31.08.2007. 22:28 ] @
Malo sam se igrao debagovanjem, i našao sam gde se strelica pretvara u peščani sat. Komanda:
CloseCursor
Code:
procedure TDataSet.SetActive(Value: Boolean);
begin
if (csReading in ComponentState) then
begin
FStreamedActive := Value;
end
else
if Active <> Value then
begin
if Value then
begin
DoBeforeOpen;
try
OpenCursor;
finally
if State <> dsOpening then
OpenCursorComplete;
end;
end else
begin
if not (csDestroying in ComponentState) then DoBeforeClose;
SetState(dsInactive);
CloseCursor;
if not (csDestroying in ComponentState) then DoAfterClose;
end;
end;
end;
[ DjGoran @ 31.08.2007. 23:19 ] @
Kopao sam još dublje, i evo skoro sve funkcije redom kojim se otvaraju, sve dok se pokazivač ne promeni u peščani sat.
Code:
procedure TDBDataSet.CloseCursor;
begin
inherited CloseCursor;
SetDBFlag(dbfOpened, False); <<<<OVA<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
end;
function TQuery.SetDBFlag(Flag: Integer; Value: Boolean): Boolean;
var
NewConnection: Boolean;
begin
if Value then
begin
NewConnection := DBFlags = [];
Result := inherited SetDBFlag(Flag, Value);
if not (csReading in ComponentState) and NewConnection then
FLocal := not Database.IsSQLBased;
end
else begin
if DBFlags - [Flag] = [] then SetPrepared(False); <<<<OVA<<<<<<<<<<<<<<<<<<
Result := inherited SetDBFlag(Flag, Value);
end;
end;
procedure TQuery.SetPrepared(Value: Boolean);
begin
if Handle <> nil then DatabaseError(SDataSetOpen, Self);
if Value <> Prepared then
begin
if Value then
begin
FRowsAffected := -1;
FCheckRowsAffected := True;
if Length(Text) > 1 then PrepareSQL(PChar(Text))
else DatabaseError(SEmptySQLStatement, Self);
end
else
begin
if FCheckRowsAffected then
FRowsAffected := RowsAffected;
FreeStatement;
end;
FPrepared := Value;
end;
end;
procedure TQuery.FreeStatement;
var
Result: DbiResult;
begin
if StmtHandle <> nil then
begin
Result := DbiQFree(FStmtHandle);
if not (csDestroying in ComponentState) then
Check(Result);
end;
end;
function BdeCallBack(CallType: CBType; Data: Longint;
CBInfo: Pointer): CBRType; stdcall;
begin
if (Data <> 0) then
Result := TBDECallback(Data).Invoke(CallType, CBInfo) else
Result := cbrUSEDEF;
end;
function TBDECallback.Invoke(CallType: CBType; CBInfo: Pointer): CBRType;
begin
if CallType = FCBType then
Result := FCallbackEvent(CBInfo) else
Result := cbrUSEDEF;
if Assigned(FOldCBFunc)
then Result := FOldCBFunc(CallType, FOldCBData, CBInfo);
end;
function TSession.ServerCallBack(CBInfo: Pointer): CBRType;
begin
Result := cbrUSEDEF;
if (GetCurrentThreadID <> MainThreadID) then Exit;
if (FCBSCType = cbscSQL) then
begin
if TimerID = 0 then
TimerID := SetTimer(0, 0, SQLDelay, @TimerCallBack);
if Assigned(DBScreen) and (DBScreen.Cursor <> dcrSQLWait) then
DBScreen.Cursor := dcrSQLWait; <<<<OVA<<<<<<<<<<<<<<<<<<<<<<
StartTime := GetTickCount;
end;
end;
procedure TVCLScreenApplication.SetCursor(Cursor: TDBScreenCursor);
begin
case Cursor of
dcrDefault: Forms.Screen.Cursor := crDefault;
dcrHourGlass: Forms.Screen.Cursor := crHourGlass;
dcrSQLWait: Forms.Screen.Cursor := crSQLWait; <<<<OVA<<<<<<<<<<<<<<<<<<<<<
end;
end;
procedure TScreen.SetCursor(Value: TCursor);
var
P: TPoint;
Handle: HWND;
Code: Longint;
begin
if Value <> Cursor then
begin
FCursor := Value;
if Value = crDefault then
begin
{ Reset the cursor to the default by sending a WM_SETCURSOR to the
window under the cursor }
GetCursorPos(P);
Handle := WindowFromPoint(P);
if (Handle <> 0) and
(GetWindowThreadProcessId(Handle, nil) = GetCurrentThreadId) then
begin
Code := SendMessage(Handle, WM_NCHITTEST, 0, LongInt(PointToSmallPoint(P)));
SendMessage(Handle, WM_SETCURSOR, Handle, MakeLong(Code, WM_MOUSEMOVE));
Exit;
end;
end;
Windows.SetCursor(Cursors[Value]); <<<<<<OVA<<<<<<<<<<<<<<<
end;
Inc(FCursorCount); <<<<<<<<<<<OVDE JE VEC PESCANI SAT<<<<<<<<<<<<<<
end;
function TScreen.GetCursors(Index: Integer): HCURSOR;
var
P: PCursorRec;
begin
Result := 0;
if Index <> crNone then
begin
P := FCursorList;
while (P <> nil) and (P^.Index <> Index) do P := P^.Next;
if P = nil then Result := FDefaultCursor else Result := P^.Handle;
end;
end;
function SetCursor; external user32 name 'SetCursor'; <<<<<<<OVO MENJA<<<<<<<<<
E, sada, kako ja da sredim to (po mogućnosti regularno, bez prljavih trikova) da se taj pokazivač ne menja u peščani sat?
[ savkic @ 01.09.2007. 00:31 ] @
> E, sada, kako ja da sredim to (po mogućnosti regularno, bez prljavih trikova) da se taj pokazivač ne menja u peščani sat?
Najbolje je da izvršavanje upita prebaciš u poseban thread.
Alternativa je da probaš: DB.DBScreen := nil; Ali mi deluje da će to izazvati AV, tako da je bolje da napraviš nešto slično poput TVCLScreenApplication, ali bez kursora i da njega podesiš za DBScreen.
[ DjGoran @ 01.09.2007. 07:29 ] @
Ja sam pre nekoliko dana počeo da učim Delfi, pa .... ako možeš ... prevedi to na neki razumljiv jezik :-) ništa nisam shvatio.
[ savkic @ 01.09.2007. 09:51 ] @
Za threadove pogledaj u Delphi helpu pod multi-threaded applications, takođe imaš i neke primere u Delphi demo diru.
DB.DBScren := nil; To verovatno ti nije problem da napišeš (recimo negde pre slanja prvog upita)i posmatraš šta se dešava sa programamom, pretpostavljam da će doći do AV (Access Violation). Ako to ne uspe onda ideš i praviš TVCLScreenApplication look-a-like klasu (bez promene kursora) i nju koristiš namesto DB.DBScreen. Pogledaj detaljno postojeći delphi kod i vidi gde se sve ta klasa koristi i kakav je odnos sa DBScreen.
[ DjGoran @ 01.09.2007. 09:51 ] @
Našao sam rešenje
na Internetu :-)
( http://www.programmersheaven.c...64/ReadMessage.aspx?S=B20000):
Code:
procedure TForm1.FormCreate(Sender: TObject);
begin
Screen.cursors[crSQLWait] := Screen.Cursors[crDefault];
end;
[ _deran_ @ 01.09.2007. 19:56 ] @
Citat: Ako ima neki drugi način da se odradi to isto a bez stalnog proveravanja baze, rado bih ga primenio.
Cini mi se da MySQL od verzije 5 podrzava trigger-e, pa mozes to njima odraditi bez stalnog upita baze.
[ DjGoran @ 01.09.2007. 22:25 ] @
Okidači se valjda koriste samo unutar baze, odnosno samo odradjuju neke unapred definisane radnje, a ne mogu obavestiti moj program o tome da su nastupile promene u bazi. Znači da moj program onda ne bi imao nikakvu informaciju ako je nastao trigger event, pa bi opet morao da proziva bazu s vremena na vreme, što na kraju ispada isto.
Ako grešim, obavestite me :-)
[ _deran_ @ 01.09.2007. 23:32 ] @
Sta ako ti baza naraste toliko da ti izvrsavanje traje > 0.2 s ?
Mozda bi mogao da napravis UDF koji ces pozvati kroz trigger i da on na neki nacin obavesti tvoj program... To jos nisam probao, samo glasno razmisljam :)
[ priki @ 01.09.2007. 23:32 ] @
jedna stvarčica kod MySql-a
ove komponente kod rada sa bazama podataka
zaboravi TQuery, TDatabase,
ako već koristiš MySql, probaj ovo, jako dobro, veoma brzo i free rešenje
http://zeos.firmos.at/portal.php
inače, kao što je @savkic rekao, nije ti baš pametno da
aplikacija radi upit tako često, pogotovo ne koristeci "select * "
pozdrav
[ DjGoran @ 02.09.2007. 08:01 ] @
Citat: _deran_: Sta ako ti baza naraste toliko da ti izvrsavanje traje > 0.2 s ?
Pošto sam problem sa peščanim satom rešio, da nastavimo diskusiju u drugoj temi ( http://www.elitesecurity.org/p1688980) gde je objašnjen i odgovor na ovo pitanje :-)
Copyright (C) 2001-2025 by www.elitesecurity.org. All rights reserved.
|