2010-03-26 3 views
6

मुझे क्वेरी निष्पादन से पहले एक पॉपअप विंडो दिखाने की आवश्यकता है, एसक्यूएल क्वेरी को निष्पादित करते समय समय समाप्त हो गया है, और क्वेरी समाप्त होने पर उस विंडो को बंद करें।लंबी SQL क्वेरी निष्पादित होने पर विलुप्त समय को कैसे दिखाया जाए?

वास्तव में मैं इस तरह कुछ करना

var 
    frm : tFrmPopupElapsed; 
    // this form has a TTimer and a TLabel to show the elapsed time 
    // but the label is not updated, I tried using update and refresh 
    // but nothing happens 
begin 
    frm := tFrmPopupElapsed.Create(nil); 
    try 
    frm.Init; // this procedure enables the timer 
    frm.Show(); 
    ExecuteMyVeryLongQuery(); 
    finally 
    frm.Close; 
    end; 
end; 

कैसे लेबल बीता हुआ समय को दिखाने के लिए है, जबकि क्वेरी निष्पादित करता है अद्यतन किया जा सकता? एक टाइमर का उपयोग करना? या धागा?

+0

क्या डेटाबेस? कम से कम एक जिसे मैं जानता हूं (डीबीआईएसएएम/एलिवेट डीबी) उनके क्वेरी घटक पर एक बहुत ही आसान ऑनप्रोशेशन इवेंट प्रदान करता है। आप अपने समय में रिपोर्ट कर सकते हैं, प्रतिशत पूर्ण, आदि –

+2

छोटे सुझाव: मैं 'frm.Init' – mjn

+2

से पहले 'try' डाल दूंगा नोट करें कि' frm.Close' को कॉल करने से फॉर्म मेमोरी लीक हो जाएगा एक 'ऑनक्लोस' हैंडलर है जो 'caFree' सेट करता है। 'Frm.Release' का उपयोग करना अधिक सुरक्षित होगा। – mghie

उत्तर

4

आपको असीमित रूप से क्वेरी चलाने की आवश्यकता है, जिससे आप इस दौरान फॉर्म को अपडेट कर सकते हैं।
धागे के साथ अपने हाथ गंदे किए बिना इसे करने का सबसे आसान तरीका एंड्रियास होउस्लाडेन के AsynCalls library का उपयोग करना है।
आप Primoz Gabrijelcic द्वारा OmniThread Library पर भी एक नज़र डाल सकते हैं।

+0

+1 विफल कर सकता है। (मैं पहले ऑम्निथ्रेड का सुझाव देने जा रहा था, और दूसरा असीमित) :) – skamradt

+0

इनमें से कोई भी संभवतः 'टीटीएचडी' वंश का उपयोग करने से बेहतर है। लेकिन एक अलग धागे में एक क्वेरी निष्पादित समस्याग्रस्त हो सकता है। मुख्य थ्रेड में समानांतर में कनेक्शन ऑब्जेक्ट्स के साथ किसी भी काम को अवरुद्ध करना जरूरी है, जब तक कि कनेक्शन ऑब्जेक्ट स्पष्ट रूप से विभिन्न धागे से समानांतर पहुंच की अनुमति न दें (संभवतः वीसीएल कक्षाओं के मामले में नहीं)। अतिरिक्त प्रतिबंध हो सकते हैं, जैसे कि उसी थ्रेड में सभी प्रश्नों को निष्पादित करना, जिसमें कनेक्शन स्थापित किया गया था। उदाहरण के लिए http://17slon.com/blogs/gabr/2009/02/building-connection-pool.html देखें। – mghie

+0

+1 धन्यवाद आपके लिए सलाह बहुत अधिक है, AsynCalls लाइब्रेरी सही काम करता है। – Salvador

0

यह प्रश्न प्रारंभिक रूप से कल्पना की तुलना में बहुत अधिक जटिल है; जो इसे एक अच्छा सवाल बनाता है।

प्रारंभ में मैंने सोचा था कि एप्लिकेशन.प्रोसेसेमेसेस सही तरीका था, हालांकि यह एक संभावित खनन क्षेत्र है जब तक कि आप सावधान न हों (धन्यवाद @skamradt इसे इंगित करने के लिए धन्यवाद)। यह एक अवरुद्ध कॉल के साथ भी मदद नहीं करता है।

एक पृष्ठभूमि थ्रेड की आवश्यकता निम्नानुसार है: ( त्रुटियों को इंगित करने के लिए धन्यवाद @mghie अब हल हो गए हैं)। डेटाबेस थ्रेड को अलग-अलग धागे में कॉल करने के साथ अभी भी समस्याएं हो सकती हैं - इसलिए पृष्ठभूमि थ्रेड को इस ऑपरेशन के लिए अपना डेटाबेस कनेक्शन होना चाहिए (यदि व्यावहारिक हो)।

नीचे दिए गए उदाहरण में मैंने विशेष रूप से प्रगति विंडो बनाने और नष्ट करने के लिए कोड नहीं दिखाया है क्योंकि यह कोड को और भी लंबा कर देगा, और यह करना आसान है।

सबसे पहले पृष्ठभूमि धागा प्रश्न पर कार्रवाई करने:

तो हम दो वस्तुओं ऐसा करने की जरूरत है।

unit BackgroundProcess; 

{$mode objfpc}{$H+} 

interface 

uses 
    Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs, windows; 

const 
    WM_MY_BACKGROUNDNOTIFY = WM_USER + 555; { change this } 
    NOTIFY_BEGIN = 22; 
    NOTIFY_END = 33; 

type 
    TBackgroundQueryThread = class(TThread) 
    private 
    hwndnotify : HWND; 
    protected 
    procedure Execute; override; 
    public 
    constructor Create(owner: TForm); 
    end; 


implementation 

constructor TBackgroundQueryThread.Create(owner: TForm) ; 
begin 
    inherited Create(False); 
    hwndnotify := owner.Handle; 
    FreeOnTerminate := true; 
    resume; 
end; 

procedure TBackgroundQueryThread.Execute; 
begin 
    PostMessage(hwndnotify, WM_MY_BACKGROUNDNOTIFY, NOTIFY_BEGIN, 0); 
    Sleep(2000); (* Query goes here. *) 
    PostMessage(hwndnotify, WM_MY_BACKGROUNDNOTIFY, NOTIFY_END, 0); 
end; 

end.   

रूप है कि क्वेरी का आह्वान:

unit mainform; 

interface 

uses 
    Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs, 
    StdCtrls, ExtCtrls, windows, BackgroundProcess; 

type 
    TForm1 = class(TForm) 
    private 
    frm : tFrmPopupElapsed; 
    { private declarations } 
    procedure OnMyBackgrounNotify(var Msg: TMessage); message WM_MY_BACKGROUNDNOTIFY; 
    public 
    { public declarations } 
    end; 

var 
    Form1: TForm1; 

implementation 


procedure TForm1.OnMyBackgrounNotify(var Msg: TMessage); 
begin 
    if (msg.WParam = NOTIFY_BEGIN) THEN 
    BEGIN 
    if (frm = nil) THEN 
    BEGIN 
     frm := tFrmPopupElapsed.Create(nil); 
     frm.Init; // this procedure enables the timer 
     frm.Show(); 
    END; 
    END; 

    if (msg.WParam = NOTIFY_END) THEN 
    BEGIN 
    if (frm <> nil) THEN 
    BEGIN 
     frm.Close; 
    END; 
    END; 

end; 

end. 
+2

एप्लिकेशन का उपयोग करने के बारे में बहुत सावधान रहें। प्रोसेस मैसेज, क्योंकि यदि आप सावधान नहीं हैं, तो इसे आसानी से अन्य समस्याओं का कारण बन सकता है, और आम तौर पर अंतिम चीज़ के रूप में माना जाना चाहिए जो आप करना चाहते हैं, पहले नहीं। एक और समाधान की तलाश करें, जैसे पृष्ठभूमि थ्रेड, पहले। – skamradt

+1

आप सही हैं - अब मैं याद दिलाता हूं कि जब तक आप सावधान न हों तब तक आप भयानक पुनर्वित्त की समस्याओं में शामिल हो सकते हैं। तो सही दृष्टिकोण सिर्फ एक धागा और एक ttimer है - अद्यतन के लिए पृष्ठभूमि धागा रखते हुए। –

+0

-1 पृष्ठभूमि थ्रेड से वीसीएल कोड को कॉल करने के लिए, और घटकों के तरीकों को कॉल करने के लिए जो पहले से ही मुक्त हो सकते हैं। – mghie

1

अगर आप यूजर इंटरफेस क्वेरी निष्पादन के दौरान संवेदनशील होना चाहता हूँ तुम एक पृष्ठभूमि सूत्र में क्वेरी चलाने के लिए की आवश्यकता होगी। अगर क्वेरी रद्दीकरण का समर्थन करती है, तो आप एक रद्द बटन भी जोड़ सकते हैं। मेरा मानना ​​है कि केवल एडीओ प्रश्न इसका समर्थन करते हैं।