2009-05-11 13 views
6

मैं एक सर्वर ऐप लिख रहा हूं और मैं इसे कंसोल आधारित होना चाहता हूं। मुझे उपयोगकर्ता को अलग-अलग कमांड इनपुट करने में सक्षम होने की आवश्यकता है, लेकिन साथ ही यह संभावना है कि उपयोगकर्ता लिखते समय कंसोल पर कुछ आउटपुट होगा। यह बफर को गड़बड़ कर देता है। क्या ऐसा करने का कोई साफ तरीका है?सी # एक साथ कंसोल इनपुट और आउटपुट?

धन्यवाद।

+0

मुझे किसी भी आसान तरीके से पता नहीं है, नहीं।मैंने कुछ भयानक परिपक्व उत्पादों (जीडीबी, विंडबग) को इस से परेशान नहीं किया है, हालांकि वे आम तौर पर स्क्रीन पर असीमित जानकारी को डंप नहीं करते हैं। आप किस प्रकार की बातचीत की तलाश में हैं? क्या आपने यह पता लगाया है कि कंसोल _should_ व्यवहार कैसे करते हैं? –

+0

यह वास्तव में एक जटिल अवधारणा नहीं है, मैं चाहता हूं कि उपयोगकर्ता टेक्स्ट इनपुट करने में सक्षम हो, संकेत अंतिम पंक्ति के बाद हो रहा है। यदि उपयोगकर्ता टाइपिंग करते समय कोई अन्य पंक्ति लिखी जाती है, तो इस पंक्ति के बाद प्रॉम्प्ट को फिर से खींचा जाता है। –

उत्तर

4

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

static int outCol, outRow, outHeight = 10; 

    static void Main(string[] args) 
    { 
    bool quit = false; 
    System.DateTime dt = DateTime.Now; 
    do 
    { 
     if (Console.KeyAvailable) 
     { 
      if (Console.ReadKey(false).Key == ConsoleKey.Escape) 
       quit = true; 
     } 
     System.Threading.Thread.Sleep(0); 
     if (DateTime.Now.Subtract(dt).TotalSeconds > .1) 
     { 
      dt = DateTime.Now; 
      WriteOut(dt.ToString(" ss.ff"), false); 
     }    
    } while (!quit); 
    } 

    static void WriteOut(string msg, bool appendNewLine) 
    { 
    int inCol, inRow; 
    inCol = Console.CursorLeft; 
    inRow = Console.CursorTop; 

    int outLines = getMsgRowCount(outCol, msg) + (appendNewLine?1:0); 
    int outBottom = outRow + outLines; 
    if (outBottom > outHeight) 
     outBottom = outHeight; 
    if (inRow <= outBottom) 
    { 
     int scrollCount = outBottom - inRow + 1; 
     Console.MoveBufferArea(0, inRow, Console.BufferWidth, 1, 0, inRow + scrollCount); 
     inRow += scrollCount; 
    } 
    if (outRow + outLines > outHeight) 
    { 
     int scrollCount = outRow + outLines - outHeight; 
     Console.MoveBufferArea(0, scrollCount, Console.BufferWidth, outHeight - scrollCount, 0, 0); 
     outRow -= scrollCount; 
     Console.SetCursorPosition(outCol, outRow); 
    } 
    Console.SetCursorPosition(outCol, outRow); 
    if (appendNewLine) 
     Console.WriteLine(msg); 
    else 
     Console.Write(msg); 
    outCol = Console.CursorLeft; 
    outRow = Console.CursorTop; 
    Console.SetCursorPosition(inCol, inRow); 
    } 

    static int getMsgRowCount(int startCol, string msg) 
    { 
    string[] lines = msg.Split('\n'); 
    int result = 0; 
    foreach (string line in lines) 
    { 
     result += (startCol + line.Length)/Console.BufferWidth; 
     startCol = 0; 
    } 
    return result + lines.Length - 1; 
    } 
+0

बहुत बहुत धन्यवाद, मैं इसके साथ काम करूंगा! –

0

क्या आपने OpenStandardInput पर कॉल करने, किसी भी इनपुट को पढ़ने और उसकी स्थिति को रीसेट करने का प्रयास किया है, फिर आउटपुट स्ट्रीम पर लिख रहा है। इसके बाद, आप OpenStandardInput को फिर से कॉल कर सकते हैं और डेटा को स्ट्रीम में वापस भर सकते हैं।

+0

मैंने अभी कोशिश की लेकिन मुझे डर है कि मुझे सच में यकीन नहीं है कि यह कैसे करें ... मैंने अभी कोशिश की और यह एक अपवाद फेंक दिया "स्ट्रीम मांग का समर्थन नहीं करता है।" –

1

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

+0

+1। वैसे भी, खराब उपयोगकर्ता कैसे अपने टाइपिंग और आउटपुट के कारण आउटपुट के बीच अंतर को बताने जा रहा है, जिसके कारण वे कुछ दबाए गए पृष्ठभूमि प्रक्रिया के कारण एंटर दबाए गए थे? – MarkJ

0

मुझे यह पूरा करने का कोई सही तरीका नहीं है, मुझे लगता है। क्या टेलनेट करता है (कम से कम आखिरी संस्करण जो मैंने उपयोग किया था) किसी इनपुट को मुद्रित नहीं किया गया था (केवल कीस्ट्रोक पढ़ें) और आउटपुट को प्रिंट करने के बाद प्रिंट करें। विकल्प किसी भी डेटा को स्टोर करना है जिसे कंसोल में कंसोल में आउटपुट करने की आवश्यकता होती है, और उपयोगकर्ता ने अपना आदेश दर्ज करने के बाद ही इसे मुद्रित किया है। (आप इसे और अधिक स्पष्ट बनाने के लिए आउटपुट को टाइमस्टैंप भी कर सकते हैं।) मैं वास्तव में यहां कोई बेहतर विकल्प नहीं देख सकता - आप अनिवार्य रूप से एक सिंक्रोनस I/O इंटरफ़ेस (यानी कमांड लाइन) का उपयोग कर समस्याओं में भागने जा रहे हैं बैकएंड में एसिंक्रोनस ऑपरेशंस।

1

यदि आप क्लाइंट/सर्वर एप्लिकेशन के रूप में सर्वर का इलाज करते हैं तो इस तरह की चीज कुछ हद तक आसान समस्या बन जाती है। सर्वर को क्लाइंट व्यवस्थापक अनुप्रयोगों के लिए "n" कनेक्शन होने दें जो कमांड भेजते हैं और आउटपुट प्राप्त करते हैं। क्लाइंट एप्लिकेशन इनपुट और आउटपुट को पूरी तरह से अलग कर सकता है, जिसमें इनपुट को संभालने के लिए एक थ्रेड होता है, और आउटपुट को संभालने के लिए एक होता है।

आउटपुट थ्रेड ब्लॉक कर सकता है अगर इनपुट थ्रेड लाइन में प्रवेश करने के बीच में है, और लाइन को या तो रद्द या प्रतिबद्ध किया गया है तो अनब्लॉक करें।

2

व्यक्तिगत रूप से मैं कामयाब करने के लिए एक सांत्वना है कि एक ही समय में दोनों इनपुट और outup संभालती ईवेंट हैंडलर्स का प्रयोग करेंगे, क्लास स्क्रीनमैनेजर या जो भी हो, उस वर्ग के अंदर एक शून्य रनप्रोग्राम() mthod जोड़ें, हैंडलर के साथ एक ईवेंट बनाएं और इनपुट कुंजी "कंसोल। रीडकी (बूल) .key" पढ़ने के लिए आवश्यक चर बनाएं।

static Consolekey newKey; 
अपने मुख्य कार्यक्रम पर

, अपने वर्ग "whatev आप इसे कहा जाता है", तो थ्रेड, कि उदाहरणों आंतरिक विधि का एक धागा बनाने का एक उदाहरण creat coreThread = नया थ्रेड (प्रतिनिधि() {myinstance.myProgramMrthod() });

थ्रेड ऊपर और चलने तक आपके मुख्य में लूप। जबकि (! थ्रेड। आईएसएलीव);

फिर मुख्य प्रोग्राम लूप बनाएं।

while (true) 
{ 
} 

फिर सुरक्षा के लिए, अपने कस्टम थ्रेड में शामिल हों, इसलिए मुख्य प्रोग्राम तब तक जारी नहीं रहेगा जब तक कि कस्टम थ्रेड बंद/डिस्पोजेड न हो जाए।

customThread.Join(); 

अब आपके पास दो धागे अलग-अलग चल रहे हैं।

अपनी कक्षा में वापस, अपनी घटना हैंडलर विधि के अंदर एक स्विच बनाएं।

switch (newkey) 
{ 
case Consolekey.enter 
Console.WriteLine("enter pressed"); 
break; 

ect, ect. 

default: 
Console.write(newkey); // writes character key that dont match above conditions to the screen. 
break; 
} 

स्टिक एलियोर लॉजिक इनके साथ कि आप कुंजी को कैसे संभालना चाहते हैं। How to use multiple modifier keys in C# कुछ मदद की हो सकती है।

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

while (true) 
{ 
newKey = Console.ReadKey(true).Key; 
if (newKey != oldKey) 
{ 
KeyChange.Invoke(); 
} 
} 

इस पाश भंडार किसी भी कुंजी दबाया और फिर अगर थेरेस एक नई कुंजी, सही आग अगर घटना को देखने के लिए जाँच करता है।

अब आपके पास जो कुछ दिख रहा है उसका मूल है, एक स्ट्रिंग जो एक नई कुंजी के लिए पूछताछ करता है, जबकि मुख्य लूप जो भी टेक्स्ट प्रदर्शित करना चाहते हैं उसे प्रदर्शित करने के लिए स्वतंत्र है।

इसके साथ दो फिक्स करने योग्य बग जो मैं सोच सकता हूं, स्विच के अंदर एक "डिफ़ॉल्ट" कैप्स या तारों में कंसोल पर प्रिंट करेगा। और दूसरा कंसोल में जोड़ा गया कोई भी पाठ कर्सर बिंदु पर जोड़ा जाता है, इसलिए यह उस पाठ में जोड़ता है जिसमें उपयोगकर्ता के पास इनपुट होता है।

मैं कभी भी ऐसा करूंगा, क्योंकि मैंने इसे अभी बनाया है, आपको कंसोल में टेक्स्ट को कैसे प्रबंधित करना है। फिर एक घटना का उपयोग कर im। मैं पूरे तरीकों और कार्यों का उपयोग कर सकता हूं लेकिन घटनाओं में कार्यक्रम में लचीलापन बढ़ता है, मुझे लगता है।

ठीक है इसलिए हम कंसोल में टेक्स्ट जोड़ने में सक्षम होना चाहते हैं, इसके बिना हम जो इनपुट दर्ज करते हैं उसे परेशान किए बिना। नीचे इनपुट रखना;

एक नया प्रतिनिधि बनाएं जिसमें एक स्ट्रिंग तर्क, शून्य प्रतिनिधि myDelegate (स्ट्रिंग Arg) के साथ हस्ताक्षर है। फिर इस प्रतिनिधि के साथ एक कार्यक्रम बनाएं, इसे नई लाइन, न्यूइनपूट, व्हाटिव को कॉल करें।

ईवेंट हैंडलर एक स्ट्रिंग तर्क लेगा (कंसोल अपडेट टेक्स्ट को दोबारा डालने वाला: जो आप इनपुट इनपुट के ऊपर कंसोल में डालना चाहते हैं) यह उस पाठ को ले जाएगा जो उपयोगकर्ता कंसोल में प्रवेश कर रहा है, उसे स्टोर करें, फिर कंसोल पर पैरामीटर स्ट्रिंग को मुद्रित करें, फिर नीचे दिए गए उपयोगकर्ताओं के इनपुट को प्रिंट करें।

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

स्ट्रिंग "इनपुट" या जो कुछ भी कॉल करें।

कुंजीपटल ईवेंट हैंडल के डिफ़ॉल्ट क्षेत्र में इनपुट + = newkey जोड़ें।

Consolekey.enter अनुभाग कंसोल लेखन इनपुट में इनपुट = string.empty या string = ""।

ईवेंट हैंडलर में कुछ तर्क जोड़ें।

public void OnInsert(string Argument) 
     { 
      Console.CursorTop -= 1; 

    // moves the cursor to far left so new input overwrites the old. 



    // if arg string is longer, then print arg string then print input // string. 

      if (Argument.Length > input.Length) 
      { 
       Console.WriteLine(Argument); 
       Console.WriteLine(input); 
      } 
      else 
      { 

    // if the users input if longer than the argument text then print 
    // out the argument text, then print white spaces to overwrite the 
    // remaining input characters still displayed on screen. 


       for (int i = 0; i < input.Length;i++) 
       { 
        if (i < Argument.Length) 
        { 
         Console.Write(Argument[i]); 
        } 
        else 
        { 
         Console.Write(' '); 
        } 
       } 
       Console.Write(Environment.NewLine); 
       Console.WriteLine(input); 
      } 
     } 

hope this helps some of you, its not perfect, a quick put together test that works enough to be built on. 
+1

oldKey एक const = 0 है; – Gorlykio

संबंधित मुद्दे