2015-12-13 5 views
5

विंडोज़ पर यह आसान है। पाइथन के साथ बस अपने प्रोग्राम को pythonw के साथ चलाएं और कोड पृष्ठभूमि में निष्पादित किया जाएगा।पायथन - मैक ओएस एक्स पर जीयूआई एप्लिकेशन से डेमॉन कैसे बनाया जाए?

तो, जो चीज़ मैं प्राप्त करना चाहता हूं उसे आसानी से व्यवस्थित किया जाता है।

मेरे पास एक ऐसा एप्लिकेशन है जो वास्तव में भूमिगत सामान करने वाली सेवा है। लेकिन इस सेवा को एक नियंत्रण कक्ष की जरूरत है।

तो, विंडोज़ पर मैं एक जीयूआई बनाने के लिए wxPython का उपयोग करता हूं, यहां तक ​​कि कुछ WX सामान भी आवश्यक सेवा प्रदान करने के लिए, और जब उपयोगकर्ता समायोजन के साथ किया जाता है तो वह मुख्य विंडो पर छुपाएं और दिखाएं (झूठा) कहलाता है।

इस प्रकार जीयूआई गायब हो जाता है और सेवा पृष्ठभूमि में अपना काम जारी रखती है। उपयोगकर्ता हमेशा एक हॉटकी का उपयोग करके इसे वापस ला सकता है।

समस्या यह है कि मैक ओएस एक्स पर यह रणनीति केवल कुछ डिग्री के लिए काम करती है।

जब wx.Frame.Show (झूठी) कहा जाता है, तो विंडो मेनू मेनू के साथ गायब हो जाती है और सेवा ठीक काम करती है, लेकिन एप्लिकेशन अभी भी वहां दिखाई देता है।

आप इस तथ्य पर ध्यान दिए बिना इस पर स्विच कर सकते हैं कि आप इसके साथ कुछ भी नहीं कर सकते हैं। यह अभी भी डॉक इत्यादि में मौजूद है।

ऐसा तब होता है जब प्रोग्राम पायथन या पायथन या जब यह Py2App के साथ बंडल किया जाता है।

कोई फर्क नहीं पड़ता कि मैं क्या करता हूं, आइकन वहां रहता है।

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

छिपाने की खिड़की स्पष्ट रूप से पर्याप्त नहीं है। कोई भी चाल जानता है?

एनबी .: मैं वास्तव में जिस तरह से ऊपर वर्णित हूं और दो अलग प्रक्रियाओं और आईपीसी के साथ गड़बड़ नहीं करना चाहता हूं।

संपादित करें:

How to hide application icon from Mac OS X dock

http://codesorcery.net/2008/02/06/feature-requests-versus-the-right-way-to-do-it

How to hide the Dock icon

पिछले लिंक इसका इस्तेमाल करने के लिए है करने के लिए उचित तरीके के अनुसार:

ज्यादा खुदाई के बाद मैं इन पाया:

[NSApp setActivationPolicy: NSApplicationActivationPolicyAccessory]; 

या

[NSApp setActivationPolicy: NSApplicationActivationPolicyProhibited]; 

तो मैं क्या चाहते हैं (क्रम अग्रभूमि करने के लिए पृष्ठभूमि से स्विच और पीछे) संभव है।

लेकिन पाइथन से इसे कैसे करें ???

स्थिरांक: एनएसपीप्लिकेशन एक्टिवेशन पॉलिसीप्रोबिटेड और एनएसएप्लिकेशन एक्टिवेशन पॉलिसी एक्सेसरी ऐपकिट में मौजूद है, लेकिन मुझे सेट एप्प्लिकेशन एक्टिवेशन पॉलिसी फ़ंक्शन कहीं भी नहीं मिल रहा है।

एनएसएपीपी() में यह नहीं है।

मुझे पता है कि, ctypes साथ ObjC dylib लोड हो रहा है NSApp को सौंपने और भेज कर यह करने का एक तरीका है "setApplicationActivationPolicy: <constant_value>" है, लेकिन मैं नहीं जानता कि कितना होगा wx.App के साथ इस गंदगी() । और यह कुछ ऐसा करने के लिए थोड़ा सा काम है जो पहले से ही उपलब्ध होना चाहिए।

मेरे अनुभव में, एनएसएपीपी() और wx.App() एक ही समय में सक्रिय एक-दूसरे को बहुत पसंद करते हैं।

शायद हम एनएसएपीपी() उदाहरण प्राप्त कर सकते हैं कि Wx किसी भी तरह से उपयोग कर रहा है और Wx के प्रतिनिधि का उपयोग कर रहा है ???

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

तो, आदर्श रूप से, setAplicationActivationPolicy का उपयोग करना मेरा लक्ष्य है, लेकिन कैसे? (सरल और आसान और wx.App() कृपया कोई मैसअप नहीं।)

कोई विचार ???

+0

पीएस आप 'info.plist' समाधान क्यों नहीं करते? –

+0

क्योंकि इसका मतलब है कि प्रक्रिया पृष्ठभूमि में शुरू होती है और मैं जो भी जीयूआई दिखाना चाहता हूं वह ठीक रहेगा, लेकिन मैं फोकस खोने के बाद इस ऐप पर वापस नहीं जा पाऊंगा, यानी डॉक आइकन मौजूद नहीं होगा। इसे TransformProcessType() का उपयोग करके ठीक किया जा सकता है, जिसे मैं नहीं जानता कि पाइथन से फिर से कॉल कैसे करें, और जहां यह छिपा हुआ है, अगर यह बिल्कुल लागू किया गया है। लेकिन, अगर मैं ऐसा करता हूं, तो इसका मतलब यह होगा कि मुझे 2 प्रक्रियाएं होनी चाहिए। एक डिमन, जो डिमन रहता है, और एक जीयूआई, जो अनुरोध करते समय एप्लिकेशन को फिर से कॉल करता है और इसे डिमन के रूप में चलाने के लिए कहता है। – Dalen

+0

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

उत्तर

1

ठीक है लोग, बिना किसी गड़बड़ी के एक अच्छा, अच्छा और सही समाधान है।

सबसे पहले, मैं समझाना चाहता हूं कि Windows GUI प्रक्रिया पृष्ठभूमि में क्यों जाती है जब wx.Frame.Show (MyFrame, False) को कॉल किया जाता है।

विवरण पर बहुत कम स्पष्टीकरण और छोड़ना यह है कि विंडोज़ विंडो और एप्लिकेशन को एक ही चीज़ पर विचार करती है।

आईई। एमएस विंडोज़ एप्लिकेशन का मुख्य तत्व आपकी मुख्य जीयूआई विंडो है।

तो, जब यह विंडो छिपी हुई है, तो एप्लिकेशन में अब कोई GUI नहीं है और पृष्ठभूमि में चलना जारी है।

मैक ओएस एक्स एप्लिकेशन को आपके एप्लिकेशन के रूप में मानता है और आपके द्वारा चुने जाने वाले किसी भी विंडो में इसके बच्चे बोलने के लिए चुनते हैं।

यह आपको विंडोज़ पेश करने के दौरान एक एप्लिकेशन चलाने की अनुमति देता है लेकिन मेन्यू बार, जिससे आप एक ऐसी क्रिया चुन सकते हैं जो एक आवश्यक विंडो उत्पन्न करेगी।

संपादकों जहां एक से अधिक फ़ाइल एक ही बार में, अपने स्वयं के विंडो में प्रत्येक और जब आप पिछले एक बंद करते हैं, तो आप अभी भी एक नया एक खोलने के लिए या एक खाली एक बना सकते हैं, आदि आदि खोला हो सकता है के लिए बहुत आसान

इसलिए मैक ओएस एक्स एप्लिकेशन का मुख्य तत्व एप्लिकेशन ही है, और यही कारण है कि आखिरी विंडो छिपी हुई है, तर्कसंगत रूप से यह खुला रहता है। इसके मेन्यू बार को नष्ट करने से भी मदद नहीं मिलेगी। ऐप का नाम डॉक में और एप्लिकेशन स्विचर में और फोर्स क्विट में मौजूद रहेगा। आप इसे स्विच करने और कुछ भी करने में सक्षम होंगे। : डी लेकिन, सौभाग्य से, मैक हमें इसे पृष्ठभूमि में रखने के लिए फ़ंक्शन प्रदान करता है। और इस फ़ंक्शन का पहले से ही एनएसएपीपी ऑब्जेक्ट से सेट एप्प्लिकेशन एक्टिवेशन पॉलिसी() का उल्लेख किया गया है।

समस्या पाइथन के एपकिट में इसका नामकरण था, जो NSApp.setActivationPolicy_() है। मामलों को और जटिल बनाने के लिए, यह सीधे पायथन के इंटरैक्टिव खोल से उपलब्ध नहीं है लेकिन इसे कम से कम आयातित मॉड्यूल से बुलाया जाना है।

क्यों? मुझे पता नहीं है। वैसे भी यहां पृष्ठभूमि में एक एप्लिकेशन फेंकने का एक पूरा उदाहरण है जो मैक और विंडोज पर काम करेगा।

मैंने लिनक्स पर यह कोशिश नहीं की, जो एक ऐप पेश करने के मामले में मैक और विंडोज के व्यवहार को जोड़ती है, इसलिए, केवल एक खिड़की छिपाने के लिए पर्याप्त रहना होगा।

उदाहरण को और अधिक क्रॉस-प्लेटफ़ॉर्म बनाने के लिए संपादित करने के लिए स्वतंत्र महसूस करें।

उदाहरण:



""" 
This app will show you small window with the randomly generated code that will confirm that reopened window is still the same app returned from background, 
and the button allowing you to send it to background. 
After you send it to background, wait 8 seconds and application will return to foreground again. 
Too prove that the application is continuing its work in the background, the app will call wx.Bell() every second. 
You should hear the sound while app is in the foreground and when it is in background too. 

Merry Christmas and a happy New Year! 
""" 

import wx 
import random, sys 

if sys.platform=="darwin": 
    from AppKit import NSBundle, NSApp, NSAutoreleasePool, NSApplicationActivationPolicyRegular, NSApplicationActivationPolicyProhibited 

    # Use Info.plist values to know whether our process started as daemon 
    # Also, change this dict in case anyone is later checking it (e.g. some module) 
    # Note: Changing this dict doesn't change Info.plist file 
    info = NSBundle.mainBundle().infoDictionary() 

    def SendToBackground(): 
     # Change info, just in case someone checks it later 
     info["LSUIElement"] = "1" 
     NSApp.setActivationPolicy_(NSApplicationActivationPolicyProhibited) 

    def ReturnToForeground(): 
     # Change info, just in case someone checks it later 
     info["LSUIElement"] = "0" 
     NSApp.setActivationPolicy_(NSApplicationActivationPolicyRegular) 

else: 
    # Simulate Mac OS X App - Info.plist 
    info = {"LSUIElement": "0"} # Assume non background at startup 
           # If programmer chose not to display GUI at startup then she/he should change this before calling ReturnToForeground() 
           # To preserve consistency and allow correct IsDaemon() answer 
    def SendToBackground(): 
     info["LSUIElement"] = "1" 

    def ReturnToForeground(): 
     info["LSUIElement"] = "0" 

def IsDaemon(): 
    return info["LSUIElement"]=="1" 

class Interface (wx.Frame): 
    def __init__ (self): 
     wx.Frame.__init__(self, None, -1, "Test", pos=(100, 100), size=(100, 100)) 
     wx.StaticText(self, -1, "Test code: "+str(random.randint(1000, 10000)), pos=(10, 10), size=(80, 20)) 
     b = wx.Button(self, -1, "DAEMONIZE ME", size=(80, 20), pos=(10, 50)) 
     wx.EVT_BUTTON(self, b.GetId(), self.OnDaemonize) 
     self.belltimer = wx.Timer(self) 
     wx.EVT_TIMER(self, self.belltimer.GetId(), self.OnBellTimer) 
     self.belltimer.Start(1000) 
     # On Mac OS X, you wouldn't be able to quit the app without the menu bar: 
     if sys.platform=="darwin": 
      self.SetMenuBar(wx.MenuBar()) 
     self.Show() 

    def OnBellTimer (self, e): 
     wx.Bell() 

    def OnDaemonize (self, e): 
     self.Show(False) 
     SendToBackground() 
     self.timer = wx.Timer(self) 
     wx.EVT_TIMER(self, self.timer.GetId(), self.OnExorcize) 
     self.timer.Start(8000) 

    def OnExorcize (self, e): 
     self.timer.Stop() 
     ReturnToForeground() 
     self.Show() 
     self.Raise() 

app = wx.App() 
i = Interface() 
app.MainLoop() 

बेशक

, इस उदाहरण टर्मिनल से या CLI खिड़की के साथ शुरू किया जा सकता है। इस मामले में आपके प्रोग्राम पर टर्मिनल नियंत्रण खोला जाएगा जबकि ऐप केवल दिखाई देगा और गायब हो जाएगा।

अपने जीयूआई डेमॉन को पूरा करने के लिए, आप इसे pythonw (Windows पर) के साथ शुरू कर देना चाहिए या daemontest.pyw फ़ाइल से लॉन्च करें

और मैक पर आप का उपयोग करना चाहिए:

% nohup python daemontest.py & 

या यह बंडल py2app के साथ या पायथन लॉन्चर का उपयोग करें जो python.org पायथन संस्करण के साथ आता है टर्मिनल के बिना daemontest.py शुरू करने के लिए।

नोट: यह उदाहरण मैक ओएस एक्स पर एक ही दोष से पीड़ित है जो मेरे प्रश्न में दिए गए लिंक पर उल्लिखित है। मैं गलत फोकस करने की समस्या का संदर्भ देता हूं और मेनू बार पृष्ठभूमि से आने पर तुरंत प्रकट नहीं होता है। उपयोगकर्ता को ठीक से काम करने के लिए चारों ओर स्विच करना होगा और नए लौटे ऐप पर वापस जाना होगा। मुझे आशा है कि कोई भी इसे हल करेगा। और इसी तरह। यह काफी परेशान है।

एक और नोट: यदि आपके प्रोग्राम में थ्रेड चल रहे हैं, तो डिमोनिज़िंग और एक्सोर्सिज़िंग करते समय उन्हें रोक दें। विशेष रूप से यदि वे ऐप्पल कार्यक्रमों का उपयोग करके किसी अन्य ऐप से संचार कर रहे हैं। स्पष्ट होने के लिए, wx.Timers के बारे में कुछ भी किया जाना चाहिए। यदि आप सावधान नहीं हैं, तो प्रोग्राम समाप्त होने पर आपको गैर-मौजूदा एनएसयूयूटोरिलीपूल और/या सेगमेंटेशनफॉल्ट के आसपास समस्याएं लीक हो सकती हैं।

+0

बहुत विस्तृत और सहायक! –

-1

ठीक है। यहाँ तुम क्या करना चाहते हैं के लिए कोड है:

import AppKit 
info = AppKit.NSBundle.mainBundle().infoDictionary() 
info["LSUIElement"] = "1" 

यह मेसियर जवाब आप नहीं करना चाहते हैं, लेकिन मैं वैसे भी यह सूची जाएगा। info.plist फ़ाइल में इस कुंजी में जोड़ें:

<key>LSUIElement</key> 
<string>1</string> 

एक और अधिक daemonish समाधान लेकिन इसका मतलब यह एक जीयूआई नहीं हो सकता है, तो आप info.plist फ़ाइल के लिए इस कुंजी में जोड़ें:

<key>LSBackgroundOnly</key> 
<string>1</string> 

Source

+0

@Dalen यह काम करता है? –

+0

नहीं, ज़ाहिर है यह नहीं है! इस dict में मूल्यों को जोड़ना केवल wx.App() या किसी अन्य ऐप क्लास को प्रारंभ करने से पहले प्रभावी हो सकता है। wx.App() वहां से मूल्यों को पकड़ता है और यदि LSUIElement = 1 है, तो ऐप उपयोगकर्ता को प्रस्तुत नहीं किया जाएगा। गलत जवाब के लिए – Dalen

+0

-1। : डी! हालांकि, आप ही वह व्यक्ति हैं जिन्होंने एक देने का प्रयास किया। यहां तक ​​कि संभावना भी थी कि यह काम करेगा, अगर प्रश्न() प्रश्न में एक नियम नहीं था() लेकिन ताना-जैसी वस्तु जो गिनती में बदलाव लेती है। फिर मूल्य बदलना दिखा रहा है/छुपाएं। तो कोशिश करने के लिए तो ब्रावो। इसके अलावा, आपके जवाब ने मुझे पागल की तरह गुगलिंग के दौरान समाधान पर ठोकर खाई। मेरा जवाब देखें मैंने आपके समाधान को पूर्ण समाधान पर काम करते समय कुछ सामान कैसे करें इस बारे में एक सुझाव के रूप में भी इस्तेमाल किया। इसलिए मुझे लगता है कि आप बहुत अच्छी कमाई +50 बक्षीस। धन्यवाद! – Dalen

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