सबसे अच्छा तरीका एक संरचना आवेदन करने के लिए?


136

निम्नलिखित मेरे ठेठ अजगर टिक्चर कार्यक्रम की समग्र संरचना है।

def funA():
    def funA1():
        def funA12():
            # stuff

    def funA2():
        # stuff

def funB():
    def funB1():
        # stuff

    def funB2():
        # stuff

def funC():
    def funC1():
        # stuff

    def funC2():
        # stuff


root = tk.Tk()

button1 = tk.Button(root, command=funA)
button1.pack()
button2 = tk.Button(root, command=funB)
button2.pack()
button3 = tk.Button(root, command=funC)
button3.pack()

funA funBऔर funCएक और लाएगा Toplevelविजेट के साथ खिड़कियों जब बटन 1, 2, 3 पर उपयोगकर्ता क्लिक करें।

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

क्या कोई विशिष्ट संरचना है जिसे हमें अच्छे अभ्यास के रूप में पालन करना चाहिए? एक अजगर कार्यक्रम लिखना शुरू करने से पहले मुझे कैसे योजना बनानी चाहिए?

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


2
यहाँ कुछ उदाहरणों के साथ, टिंकर GUI डिज़ाइन पर एक उत्कृष्ट ट्यूटोरियल है - python-textbok.readthedocs.org/en/latest/… यहाँ MVC डिज़ाइन पैटर्न के साथ एक और उदाहरण है - sukhbinder.wordpress.com/2014/12/ 25 /…
बॉन्डोलिन

12
यह प्रश्न व्यापक हो सकता है, लेकिन यह अपेक्षाकृत लोकप्रिय उत्तर के रूप में उपयोगी है और एच (लगभग सभी अन्य [tkinter] उत्तरों के सापेक्ष) है। मैं फिर से खोलने के लिए नामांकित कर रहा हूं, क्योंकि मैं देख रहा हूं कि यह खुला होने से ज्यादा उपयोगी है।
ब्रायन ओकले

जवाबों:


271

मैं एक वस्तु उन्मुख दृष्टिकोण की वकालत करता हूं। यह वह टेम्प्लेट है जिसकी मैं शुरुआत करता हूं:

# Use Tkinter for python 2, tkinter for python 3
import tkinter as tk

class MainApplication(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)
        self.parent = parent

        <create the rest of your GUI here>

if __name__ == "__main__":
    root = tk.Tk()
    MainApplication(root).pack(side="top", fill="both", expand=True)
    root.mainloop()

ध्यान देने योग्य महत्वपूर्ण बातें हैं:

  • मैं वाइल्डकार्ड आयात का उपयोग नहीं करता। मैं पैकेज को "tk" के रूप में आयात करता हूं, जिसके लिए आवश्यक है कि मैं सभी आदेशों के साथ उपसर्ग करूं tk.। यह वैश्विक नेमस्पेस प्रदूषण को रोकता है, साथ ही यह कोड को पूरी तरह से स्पष्ट कर देता है जब आप टिंकर क्लासेस, टीटीके क्लास या अपने खुद के कुछ का उपयोग कर रहे होते हैं।

  • मुख्य अनुप्रयोग एक वर्ग है । यह आपको आपके सभी कॉलबैक और निजी कार्यों के लिए एक निजी नामस्थान देता है, और आमतौर पर आपके कोड को व्यवस्थित करना आसान बनाता है। एक प्रक्रियात्मक शैली में आपको शीर्ष-डाउन को कोड करना होगा, उनका उपयोग करने से पहले कार्यों को परिभाषित करना, आदि। इस पद्धति के साथ आप तब से नहीं करते हैं जब तक कि आप वास्तव में बहुत अंतिम चरण तक मुख्य विंडो नहीं बनाते हैं। मुझे tk.Frameकेवल इसलिए विरासत से पसंद है क्योंकि मैं आमतौर पर एक फ्रेम बनाकर शुरू करता हूं, लेकिन यह आवश्यक नहीं है।

यदि आपके ऐप में अतिरिक्त टॉपवेल विंडो हैं, तो मैं उनमें से प्रत्येक को एक अलग वर्ग बनाने की सलाह देता हूं tk.Toplevel। यह आपको ऊपर बताए गए सभी समान लाभ देता है - खिड़कियां परमाणु हैं, उनके पास अपने स्वयं के नाम स्थान हैं, और कोड अच्छी तरह से व्यवस्थित है। इसके अलावा, कोड को बड़ा करने के लिए शुरू होने के बाद प्रत्येक को अपने मॉड्यूल में रखना आसान हो जाता है।

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

class Navbar(tk.Frame): ...
class Toolbar(tk.Frame): ...
class Statusbar(tk.Frame): ...
class Main(tk.Frame): ...

class MainApplication(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        tk.Frame.__init__(self, parent, *args, **kwargs)
        self.statusbar = Statusbar(self, ...)
        self.toolbar = Toolbar(self, ...)
        self.navbar = Navbar(self, ...)
        self.main = Main(self, ...)

        self.statusbar.pack(side="bottom", fill="x")
        self.toolbar.pack(side="top", fill="x")
        self.navbar.pack(side="left", fill="y")
        self.main.pack(side="right", fill="both", expand=True)

चूंकि उन सभी उदाहरणों में एक आम माता-पिता का हिस्सा होता है, इसलिए माता-पिता प्रभावी रूप से मॉडल-व्यू-कंट्रोलर आर्किटेक्चर का "कंट्रोलर" हिस्सा बन जाते हैं। इसलिए, उदाहरण के लिए, मुख्य विंडो कॉल करके स्थिति पट्टी पर कुछ रख सकती है self.parent.statusbar.set("Hello, world")। यह आपको घटकों के बीच एक सरल इंटरफ़ेस को परिभाषित करने की अनुमति देता है, जिससे कपलिंग को न्यूनतम रखने में मदद मिलती है।


22
@ ब्रायन ओकले क्या आपको इंटरनेट पर कोई अच्छा नमूना कोड पता है कि मैं उनकी संरचना का अध्ययन कर सकता हूं?
क्रिस आंग

2
मैं ऑब्जेक्ट ओरिएंटेड अप्रोच दूसरा। हालाँकि, GUI को कॉल करने वाले अपने वर्ग पर विरासत का उपयोग करने से बचना मेरे अनुभव में एक अच्छा विचार है। यह आपको अधिक लचीलापन प्रदान करता है यदि दोनों टीके और फ़्रेम ऑब्जेक्ट एक वर्ग की विशेषता हैं जो किसी भी चीज़ से विरासत में नहीं मिलता है। इस तरह आप Tk और Frame वस्तुओं को अधिक आसानी से (और कम अस्पष्ट रूप से) एक्सेस कर सकते हैं, और यदि आप इसे नहीं चाहते हैं तो एक को नष्ट करना आपकी कक्षा में सब कुछ नष्ट नहीं करेगा। मैं सटीक कारण भूल गया कि यह कुछ कार्यक्रमों में महत्वपूर्ण क्यों है, लेकिन यह आपको अधिक चीजें करने की अनुमति देता है।
ब्रूट्सफोरोज़थ्रैक्स

1
बस एक क्लास होने से आपको एक निजी नाम नहीं मिलेगा? फ़्रेम को उप-वर्ग में सुधारना उस पर क्यों?
gcb

3
@gcb: हाँ, कोई भी वर्ग आपको एक निजी नामस्थान देगा। एक उप-वर्ग क्यों? मैं आम तौर पर वैसे भी एक फ्रेम बनाने जा रहा हूं, इसलिए इसे प्रबंधित करने के लिए एक कम वर्ग है (फ़्रेम का उपवर्ग, ऑब्जेक्ट से विरासत में प्राप्त एक वर्ग, एक विशेषता के रूप में एक फ्रेम के साथ)। मैंने जवाब को थोड़ा और स्पष्ट कर दिया है। प्रतिक्रिया के लिए धन्यवाद।
ब्रायन ओकले

2
@ काम: parentजब तक आप इसे बाद में उपयोग करने जा रहे हैं, तब तक किसी संदर्भ को सहेजने की आवश्यकता नहीं है । मैंने इसे सहेजा नहीं था क्योंकि मेरे उदाहरण में किसी भी कोड की आवश्यकता नहीं थी कि इसे बचाया जाए।
ब्रायन ओकले

39

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

import tkinter as tk

class Demo1:
    def __init__(self, master):
        self.master = master
        self.frame = tk.Frame(self.master)
        self.button1 = tk.Button(self.frame, text = 'New Window', width = 25, command = self.new_window)
        self.button1.pack()
        self.frame.pack()
    def new_window(self):
        self.newWindow = tk.Toplevel(self.master)
        self.app = Demo2(self.newWindow)

class Demo2:
    def __init__(self, master):
        self.master = master
        self.frame = tk.Frame(self.master)
        self.quitButton = tk.Button(self.frame, text = 'Quit', width = 25, command = self.close_windows)
        self.quitButton.pack()
        self.frame.pack()
    def close_windows(self):
        self.master.destroy()

def main(): 
    root = tk.Tk()
    app = Demo1(root)
    root.mainloop()

if __name__ == '__main__':
    main()

और देखें:

उम्मीद है की वो मदद करदे।


6

यह एक बुरा ढांचा नहीं है; यह ठीक काम करेगा। हालाँकि, आपको किसी बटन या किसी चीज़ पर क्लिक करने पर कमांड करने के लिए फ़ंक्शन में फ़ंक्शन करने होंगे

तो आप जो कर सकते हैं, उसके लिए कक्षाएं लिखें, फिर कक्षा में ऐसी विधियाँ हों जो बटन क्लिक और इस तरह के कमांड को संभालती हैं।

यहाँ एक उदाहरण है:

import tkinter as tk

class Window1:
    def __init__(self, master):
        pass
        # Create labels, entries,buttons
    def button_click(self):
        pass
        # If button is clicked, run this method and open window 2


class Window2:
    def __init__(self, master):
        #create buttons,entries,etc

    def button_method(self):
        #run this when button click to close window
        self.master.destroy()

def main(): #run mianloop 
    root = tk.Tk()
    app = Window1(root)
    root.mainloop()

if __name__ == '__main__':
    main()

आमतौर पर कई खिड़कियों के साथ tk प्रोग्राम कई बड़ी कक्षाएं होती हैं और __init__सभी प्रविष्टियों में, लेबल आदि बनाए जाते हैं और फिर प्रत्येक विधि को ईवेंट के बटन को हैंडल करना होता है

वास्तव में इसे करने का एक सही तरीका नहीं है, जो कुछ भी आपके लिए काम करता है और जब तक यह पढ़ने योग्य हो जाता है, तब तक आप इसे आसानी से समझा सकते हैं क्योंकि अगर आप आसानी से अपने कार्यक्रम की व्याख्या नहीं कर सकते हैं, तो शायद ऐसा करने का एक बेहतर तरीका है। ।

थिंकर में सोचकर देखिए


3
"थिंकर में सोचना" वैश्विक आयात की वकालत करता है, जो मुझे लगता है कि बहुत बुरी सलाह है।
ब्रायन ओकली

1
यह सच है कि मैं आपको केवल मुख्य वर्ग मेथोस संरचना के कुछ ग्लोबल्स का उपयोग करने का सुझाव नहीं देता हूं :)
सीरियल

2

OOP दृष्टिकोण frameहोना चाहिए और उदाहरण चर के बजाय एक वर्ग चर होना चाहिए ।

from Tkinter import *
class App:
  def __init__(self, master):
    frame = Frame(master)
    frame.pack()
    self.button = Button(frame, 
                         text="QUIT", fg="red",
                         command=frame.quit)
    self.button.pack(side=LEFT)
    self.slogan = Button(frame,
                         text="Hello",
                         command=self.write_slogan)
    self.slogan.pack(side=LEFT)
  def write_slogan(self):
    print "Tkinter is easy to use!"

root = Tk()
app = App(root)
root.mainloop()

यहाँ छवि विवरण दर्ज करें

संदर्भ: http://www.python-course.eu/tkinter_buttons.php


2
आप केवल TKinterपायथन 2 का उपयोग कर सकते हैं । मैं tkinterपायथन 3. के लिए उपयोग करने की सलाह दूंगा। मैं एक main()फ़ंक्शन के तहत कोड की अंतिम तीन पंक्तियों को भी रखूंगा और कार्यक्रम के अंत में कॉल करूंगा । मैं निश्चित रूप से इसका उपयोग from module_name import *करने से बचूंगा क्योंकि यह वैश्विक नाम स्थान को प्रदूषित करता है और पठनीयता को कम कर सकता है।
Zac

1
कैसे आप के बीच का अंतर बता सकते हैं button1 = tk.Button(root, command=funA)और button1 = ttk.Button(root, command=funA)अगर tkinterविस्तार मॉड्यूल भी आयात किया जा रहा था? *वाक्य रचना के साथ , कोड की दोनों पंक्तियाँ प्रतीत होंगी button1 = Button(root, command=funA)। मैं उस सिंटैक्स का उपयोग करने की अनुशंसा नहीं करूंगा।
ज़ैक

0

कक्षा का उपयोग करके अपने एप्लिकेशन को व्यवस्थित करना आपके और अन्य लोगों के लिए आसान होता है जो आपके साथ समस्याओं को डीबग करने और ऐप को आसानी से सुधारने का काम करते हैं।

आप अपने आवेदन को इस तरह आसानी से व्यवस्थित कर सकते हैं:

class hello(Tk):
    def __init__(self):
        super(hello, self).__init__()
        self.btn = Button(text = "Click me", command=close)
        self.btn.pack()
    def close():
        self.destroy()

app = hello()
app.mainloop()

-2

संभवतः यह जानने का सबसे अच्छा तरीका है कि अन्य लोगों के कोड को पढ़कर अपने कार्यक्रम को कैसे तैयार किया जाए, खासकर अगर यह एक बड़ा कार्यक्रम है जिसमें कई लोगों ने योगदान दिया है। कई परियोजनाओं के कोड को देखने के बाद, आपको यह विचार करना चाहिए कि सर्वसम्मति की शैली क्या होनी चाहिए।

पायथन, एक भाषा के रूप में, इसमें विशेष है कि कुछ मजबूत दिशानिर्देश हैं कि आपको अपने कोड को कैसे प्रारूपित करना चाहिए। पहला तथाकथित "ज़ेन ऑफ़ पायथन" है:

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

अधिक व्यावहारिक स्तर पर, PEP8 है , जो पायथन के लिए स्टाइल गाइड है।

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


12
-1 पायथन के ज़ेन का उपयोग करने के लिए। हालांकि यह सब अच्छी सलाह है, यह सीधे उस प्रश्न को संबोधित नहीं करता है जो पूछा गया था। अंतिम पैराग्राफ को बाहर निकालें और यह उत्तर इस साइट पर लगभग हर अजगर प्रश्न पर लागू हो सकता है। यह अच्छी, सकारात्मक सलाह है, लेकिन यह सवाल का जवाब नहीं देती है।
ब्रायन ओकले

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

1
मैं यहां इस विशिष्ट प्रश्न के उत्तर की तलाश में आया था। यहां तक ​​कि एक खुले अंत प्रश्न के लिए, मैं इस प्रतिक्रिया के साथ कुछ भी नहीं कर सकता। -1 मुझ से भी।
जोनाथन

कोई रास्ता नहीं, सवाल एक टिक्कर ऐप को तैयार करने के बारे में है , स्टाइल / कोडिंग / ज़ेन दिशानिर्देशों के बारे में कुछ भी नहीं है। @Arbiter के उद्धरण के रूप में आसान "हालांकि एक सीधा जवाब नहीं है", इसलिए, यह एक जवाब नहीं है। यह "शायद हाँ और शायद नहीं" की तरह है, ज़ेन प्रीपेड के साथ।
m3nda

-7

मैं व्यक्तिगत रूप से ऑब्जेक्ट ओरिएंटेड दृष्टिकोण का उपयोग नहीं करता हूं, ज्यादातर क्योंकि यह ए) केवल रास्ते में मिलता है; बी) आप एक मॉड्यूल के रूप में पुन: उपयोग नहीं करेंगे।

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

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


4
आप जो कहते हैं, वह सच नहीं है। मैंने tk- आधारित अनुप्रयोगों के hudreds लिखे हैं, दोनों व्यक्तिगत और वाणिज्यिक, और लगभग कभी भी थ्रेड्स का उपयोग नहीं करना पड़ा है। थ्रेड्स में अपना स्थान है, लेकिन यह केवल सच नहीं है कि आपको टेंकर प्रोग्राम लिखते समय उनका उपयोग करना होगा । यदि आपके पास लंबे समय तक चलने वाले कार्य हैं, तो आपको थ्रेड्स या मल्टीप्रोसेसिंग की आवश्यकता हो सकती है, लेकिन कई, कई प्रकार के प्रोग्राम हैं जिन्हें आप लिख सकते हैं कि थ्रेड्स की आवश्यकता नहीं है।
ब्रायन ओकले

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

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

2
@ erm3nda: "नेटवर्क से जुड़ा हर ऐप या IO राइटिंग थ्रेड्स या सबप्रोसेस का उपयोग करके बहुत तेज़ होगा" - यह केवल सच नहीं है। थ्रेडिंग आपके कार्यक्रम को तेजी से जरूरी नहीं बनाएगी, और कुछ मामलों में यह धीमी बना देगी। जीयूआई प्रोग्रामिंग में, थ्रेड्स का उपयोग करने का मुख्य कारण कुछ कोड को चलाने में सक्षम होना है जो अन्यथा जीयूआई को अवरुद्ध करेगा।
ब्रायन ओकले

2
@ erm3nda: नहीं, मैं कर रहा हूँ नहीं कह धागे की आवश्यकता नहीं है सब पर । उन्हें निश्चित रूप से बहुत सारी चीजों के लिए (अच्छी तरह से, थ्रेड्स या मल्टीप्रोसेसिंग) की आवश्यकता होती है। यह सिर्फ इतना है कि जीयूआई अनुप्रयोगों का एक बहुत बड़ा वर्ग है जहां टिंकर उपयुक्त है लेकिन जहां थ्रेड्स की आवश्यकता नहीं है। और हाँ, "इंस्टॉलर, नोटपैड, और अन्य आसान उपकरण" उस श्रेणी में आते हैं। शब्द, एक्सेल, फोटोशॉप इत्यादि जैसी चीजों की तुलना में दुनिया इन "आसान साधनों" से अधिक बनी है, याद रखें कि यहां संदर्भ सन्दर्भहीन है । आमतौर पर टिंकर का उपयोग बहुत बड़े, जटिल अनुप्रयोगों के लिए नहीं किया जाता है।
ब्रायन ओकले
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.