मैं कर्सर को प्रतीक्षा कर्सर में कैसे बदल सकता हूं?


263

मेरे पास एक C # एप्लिकेशन है जिसमें उपयोगकर्ता इसे लॉगिन करते हैं, और हैशिंग एल्गोरिथ्म महंगा होने के कारण, इसे करने में थोड़ा समय लगता है। मैं उपयोगकर्ता को प्रतीक्षा / व्यस्त कर्सर (आमतौर पर घंटाघर) कैसे प्रदर्शित कर सकता हूं यह बताने के लिए कि कार्यक्रम कुछ कर रहा है?

परियोजना C # में है।

जवाबों:


451

आप उपयोग कर सकते हैं Cursor.Current

// Set cursor as hourglass
Cursor.Current = Cursors.WaitCursor;

// Execute your time-intensive hashing code here...

// Set cursor as default arrow
Cursor.Current = Cursors.Default;

हालाँकि, यदि हैशिंग ऑपरेशन वास्तव में लंबा है (MSDN इसे 2-7 सेकंड से अधिक परिभाषित करता है), तो आपको संभवतः प्रगति के उपयोगकर्ता को सूचित करने के लिए कर्सर के अलावा एक दृश्य प्रतिक्रिया सूचक का उपयोग करना चाहिए। दिशानिर्देशों के अधिक गहन सेट के लिए, इस लेख को देखें

संपादित करें:
के रूप में @Am ने कहा, आप कॉल करने के लिए आवश्यकता हो सकती है Application.DoEvents();के बाद Cursor.Current = Cursors.WaitCursor;यह सुनिश्चित करें कि hourglass वास्तव में प्रदर्शित होता है।


23
यह कर्सर को बदलने के लिए आवश्यक नहीं है - यदि संदेश लूप को समय-गहन कोड के दौरान नहीं बुलाया जाएगा। इसे सक्षम करने के लिए आपको Application.DoEvents () जोड़ना होगा ; पहले कर्सर सेट के बाद।
अमीर्शक

16
आप शायद एक कोशिश करना चाहते हैं..जबकि करंट सेट करने के बाद ब्लॉक करें, तो (यह सुनिश्चित करते हुए कि करंट डिफॉल्ट पर रीसेट हो जाता है)।
ट्रूविल

7
FYI करें, मैं ऊपर काम करने के लिए मिल सकता है, लेकिन इसे बदलकर इस। इसने काम कर दिया।
हंस रुडेल जूल

4
अगर मैं Application.DoEvents () के बाद Cursor.Current = Cursors.WaitCursor का उपयोग करता था, तो घंटाघर प्रदर्शित नहीं किया गया था। हालांकि, इसने Application.DoEvents () के बिना काम किया। यकीन नहीं होता क्यों
Vbp

14
यह उपयोग करने के लिए बेहतर है Application.UseWaitCursor = trueऔरApplication.UseWaitCursor = false
जियानपिएरो

169

वास्तव में,

Cursor.Current = Cursors.WaitCursor;

अस्थायी रूप से प्रतीक्षा कर्सर सेट करता है, लेकिन यह सुनिश्चित नहीं करता है कि प्रतीक्षा कर्सर आपके ऑपरेशन के अंत तक दिखाता है। आपके प्रोग्राम के भीतर अन्य प्रोग्राम या नियंत्रण आसानी से कर्सर को डिफ़ॉल्ट तीर पर वापस सेट कर सकते हैं क्योंकि वास्तव में तब होता है जब आप माउस को स्थानांतरित करते हैं जबकि ऑपरेशन अभी भी चल रहा है।

वाट्सएप कर्सर दिखाने का एक बेहतर तरीका यह है कि UseWaitCursor प्रॉपर्टी को सही रूप में सेट करें:

form.UseWaitCursor = true;

यह प्रपत्र पर सभी नियंत्रणों के लिए प्रतीक्षा कर्सर प्रदर्शित करेगा जब तक कि आप इस संपत्ति को गलत पर सेट नहीं करते हैं। यदि आप चाहते हैं कि अनुप्रयोग स्तर पर प्रतीक्षा कर्सर दिखाया जाए जिसका आपको उपयोग करना चाहिए:

Application.UseWaitCursor = true;

जानकार अच्छा लगा। मैं WPF में ऐसा ही करने की कोशिश कर रहा था, और Cursor = Cursors.Wait और Cursor = Cursors.Arrow के साथ समाप्त हुआ । लेकिन मैं ऐप के
11

2
अनुप्रयोग के तहत UseWaitCursor नहीं मिल सका!
चंद्र एस्के

मैंने पाया कि फॉर्म सेट करते समय। UseWaitCursor = ऑपरेशन के अंत में गलत है, यह वास्तव में कर्सर को तब तक रीसेट नहीं करता है जब तक आप मूव या क्लिक नहीं करते। OTOH, form.Cursor में यह समस्या नहीं है। मुझे Cursor.Current काम करने के लिए नहीं मिला।
स्टीवर्ट

39

पिछले पर बिल्डिंग, मेरा पसंदीदा दृष्टिकोण (चूंकि यह अक्सर निष्पादित कार्रवाई है) एक कैरीसमैटिक हेल्पर क्लास में प्रतीक्षा कर्सर कोड को लपेटने के लिए है, इसलिए इसका उपयोग करके उपयोग किया जा सकता है () (कोड की एक पंक्ति), वैकल्पिक पैरामीटर लें, चलाएं भीतर कोड, फिर साफ करें (कर्सर को पुनर्स्थापित करें)।

public class CursorWait : IDisposable
{
    public CursorWait(bool appStarting = false, bool applicationCursor = false)
    {
        // Wait
        Cursor.Current = appStarting ? Cursors.AppStarting : Cursors.WaitCursor;
        if (applicationCursor) Application.UseWaitCursor = true;
    }

    public void Dispose()
    {
        // Reset
        Cursor.Current = Cursors.Default;
        Application.UseWaitCursor = false;
    }
}

उपयोग:

using (new CursorWait())
{
    // Perform some code that shows cursor
}

द्वारा प्रेरित: codeproject.com/Articles/6287/WaitCursor-hack-use-use
torno

नहीं देखा था, लेकिन हाँ समान दृष्टिकोण। वह वर्तमान कर्सर का बैकअप लेता है और फिर उसे पुनर्स्थापित करता है, जो कि यदि आप भारी कर्सर को बदल रहे हैं तो उपयोगी हो सकता है।
mhapps

27

Form या Window स्तर पर UseWaitCursor का उपयोग करना अधिक आसान है। एक विशिष्ट उपयोग का मामला नीचे जैसा दिख सकता है:

    private void button1_Click(object sender, EventArgs e)
    {

        try
        {
            this.Enabled = false;//optional, better target a panel or specific controls
            this.UseWaitCursor = true;//from the Form/Window instance
            Application.DoEvents();//messages pumped to update controls
            //execute a lengthy blocking operation here, 
            //bla bla ....
        }
        finally
        {
            this.Enabled = true;//optional
            this.UseWaitCursor = false;
        }
    }

बेहतर यूआई अनुभव के लिए आपको एक अलग धागे से एसिंक्रोनसी का उपयोग करना चाहिए।


2
यह ACCEPTED उत्तर होना चाहिए। यह केवल एक ही है जो प्रयास का उपयोग करता है।
जॉन हेनकेल

1
मेरा उत्थान है, मैं अपने कार्यान्वयन में आखिरकार कोशिश कर रहा था
जैक

19

मेरा दृष्टिकोण एक पृष्ठभूमि कार्यकर्ता में सभी गणना करना होगा।

फिर कर्सर को इस तरह बदलें:

this.Cursor = Cursors.Wait;

और थ्रेड के फिनिश इवेंट में कर्सर को रीस्टोर करें:

this.Cursor = Cursors.Default;

ध्यान दें, यह विशिष्ट नियंत्रणों के लिए भी किया जा सकता है, इसलिए कर्सर केवल तभी होगा जब माउस उनके ऊपर होगा।


@ मालफिस्ट: अच्छा तरीका :), तो आपको बस इतना करना है कि अंतिम ईवेंट में रिस्टोर करें, और अपना काम करें।
अमीरखां

4

ठीक है, इसलिए मैंने एक स्थिर एसिंक्रोनस विधि बनाई। उस नियंत्रण को निष्क्रिय कर दिया जो कार्रवाई शुरू करता है और एप्लिकेशन कर्सर को बदलता है। यह कार्य को एक कार्य के रूप में चलाता है और समाप्त होने का इंतजार करता है। प्रतीक्षा करते समय कॉल करने वाले पर नियंत्रण रखें। तो अनुप्रयोग संवेदनशील रहता है, भले ही व्यस्त आइकन घूमता है।

async public static void LengthyOperation(Control control, Action action)
{
    try
    {
        control.Enabled = false;
        Application.UseWaitCursor = true;
        Task doWork = new Task(() => action(), TaskCreationOptions.LongRunning);
        Log.Info("Task Start");
        doWork.Start();
        Log.Info("Before Await");
        await doWork;
        Log.Info("After await");
    }
    finally
    {
        Log.Info("Finally");
        Application.UseWaitCursor = false;
        control.Enabled = true;
    }

यहाँ कोड मुख्य रूप है

    private void btnSleep_Click(object sender, EventArgs e)
    {
        var control = sender as Control;
        if (control != null)
        {
            Log.Info("Launching lengthy operation...");
            CursorWait.LengthyOperation(control, () => DummyAction());
            Log.Info("...Lengthy operation launched.");
        }

    }

    private void DummyAction()
    {
        try
        {
            var _log = NLog.LogManager.GetLogger("TmpLogger");
            _log.Info("Action - Sleep");
            TimeSpan sleep = new TimeSpan(0, 0, 16);
            Thread.Sleep(sleep);
            _log.Info("Action - Wakeup");
        }
        finally
        {
        }
    }

मुझे डमी एक्शन (मैं Nlog का उपयोग कर रहा हूं) के लिए एक अलग लकड़हारे का उपयोग करना पड़ा और मेरा मुख्य लकड़हारा UI (एक समृद्ध पाठ बॉक्स) को लिख रहा है। मैं व्यस्त कर्सर को केवल तब प्राप्त नहीं कर पा रहा था जब किसी विशेष कंटेनर को फ़ॉर्म पर दिखाया गया था (लेकिन मैंने बहुत कोशिश नहीं की थी।) सभी नियंत्रणों में एक UseWaitCursor संपत्ति है, लेकिन यह नियंत्रण पर कोई प्रभाव नहीं दिखता है। मैंने कोशिश की (हो सकता है क्योंकि वे शीर्ष पर नहीं थे?)

यहां मुख्य लॉग है, जो उस क्रम में होने वाली चीजों को दिखाता है जिसकी हम उम्मीद करते हैं:

16:51:33.1064 Launching lengthy operation...
16:51:33.1215 Task Start
16:51:33.1215 Before Await
16:51:33.1215 ...Lengthy operation launched.
16:51:49.1276 After await
16:51:49.1537 Finally

2

नीचे दी गई कक्षा के साथ आप डोनट के सुझाव को "अपवाद सुरक्षित" बना सकते हैं।

using (new CursorHandler())
{
    // Execute your time-intensive hashing code here...
}

वर्ग CursorHandler

public class CursorHandler
    : IDisposable
{
    public CursorHandler(Cursor cursor = null)
    {
        _saved = Cursor.Current;
        Cursor.Current = cursor ?? Cursors.WaitCursor;
    }

    public void Dispose()
    {
        if (_saved != null)
        {
            Cursor.Current = _saved;
            _saved = null;
        }
    }

    private Cursor _saved;
}

2

ओके, अन्य लोगों का दृष्टिकोण बहुत स्पष्ट है, लेकिन मैं कुछ जोड़ना चाहूंगा, जैसा कि निम्नलिखित है:

Cursor tempCursor = Cursor.Current;

Cursor.Current = Cursors.WaitCursor;

//do Time-consuming Operations         

Cursor.Current = tempCursor;

2

विंडोज फॉर्म के लिए यूआई-कंट्रोल का एक वैकल्पिक अक्षम होना बहुत उपयोगी हो सकता है। तो मेरा सुझाव इस तरह दिखता है:

public class AppWaitCursor : IDisposable
{
    private readonly Control _eventControl;

    public AppWaitCursor(object eventSender = null)
    {
         _eventControl = eventSender as Control;
        if (_eventControl != null)
            _eventControl.Enabled = false;

        Application.UseWaitCursor = true;
        Application.DoEvents();
    }

    public void Dispose()
    {
        if (_eventControl != null)
            _eventControl.Enabled = true;

        Cursor.Current = Cursors.Default;
        Application.UseWaitCursor = false;
    }
}

उपयोग:

private void UiControl_Click(object sender, EventArgs e)
{
    using (new AppWaitCursor(sender))
    {
        LongRunningCall();
    }
}

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.