TK GUI设计问题和对象没有属性“ tk”?

时间:2018-09-10 23:14:07

标签: python user-interface tkinter

下面是我当前拥有的代码。我是新手程序员,正在编写一个小程序,该程序将自动进行一些引物设计工作流程(生物学家/生物信息学家代表)。

我现在遇到的问题是,我对OOP与TKinter的工作方式缺乏了解。我已经阅读了许多stackoverflow帖子,还观看了youtube视频,并阅读了试图解释它的指南,但我仍然有些茫然。我目前的理解是,每个窗口应该是自己的对象,其上方的窗口为其父对象。我试图用我的程序做到这一点。 当前,我有两个类,AUTOPRIMER和BlastAPI。 AUTOPRIMER是主窗口。我在该窗口中创建了一个按钮,单击该按钮应会打开一个新窗口。据我了解,我为该窗口创建了一个名为BlastAPI的新对象,该对象处理程序的特定要求。我看到许多指南建议将父对象放在新对象的init中,但是从父对象到主对象再到args *,kwargs **,我看到了太多的初始化变化。什么时候合适?另外,当前堆栈跟踪会提供此反馈,因为它甚至无法正确编译。

Traceback (most recent call last):
  File "/Users/Thunderpurtz/Desktop/CGIStuff/AUTOPRIMER/autoprimercode/test1.py", line 201, in <module>
    autoprimer = AUTOPRIMER(root)
  File "/Users/Thunderpurtz/Desktop/CGIStuff/AUTOPRIMER/autoprimercode/test1.py", line 105, in __init__
    self.blast = BlastAPI(self)
  File "/Users/Thunderpurtz/Desktop/CGIStuff/AUTOPRIMER/autoprimercode/test1.py", line 150, in __init__
    eValueSetting = Entry(parent)
  File "/anaconda3/lib/python3.6/tkinter/__init__.py", line 2673, in __init__
    Widget.__init__(self, master, 'entry', cnf, kw)
  File "/anaconda3/lib/python3.6/tkinter/__init__.py", line 2289, in __init__
    BaseWidget._setup(self, master, cnf)
  File "/anaconda3/lib/python3.6/tkinter/__init__.py", line 2259, in _setup
    self.tk = master.tk
AttributeError: 'AUTOPRIMER' object has no attribute 'tk'
[Finished in 0.289s]

从根本上讲,我认为我对gui编程的理解并不扎实,因此,如果有人可以提供一些很好的见解,那么。如果这个问题有点笼统,我将很乐意在评论中阐明。

import subprocess
from tkinter import *
from tkinter.filedialog import *
import tkinter.messagebox

class AUTOPRIMER:

    def __init__(self, master):
    #some functions, their content is removed as i do not believe they are relevant
        def button1():
            pass
        def button2():
            pass
        def button3():
      pass
        def getPrimers():
      pass
        def PrimerParser():
            pass
        def poolPrimers():
            pass

        self.master = master
        self.input = ""
        self.output = ""
        self.param = ""
        self.inputbool = False
        self.outputbool = False
        self.parambool = False
        self.p3filestring = '-p3_settings_file='
        self.blast = BlastAPI(self)
        master.title("Complete Genomics Inc.")

        ########## WIDGETS ##########
        entry_1 = Entry(master) #input
        entry_2 = Entry(master) #output
        entry_3 = Entry(master) #parameters

        label_1 = Label(master, text="AUTOPRIMER")
        button_1 = Button(master, text="Input Filepath: ", command=button1)
        button_2 = Button(master, text="Output Filepath: ", command=button2)
        button_3 = Button(master, text="Parameters Filepath: ", command=button3)
        button_get = Button(master, text="Get Primers", command=getPrimers)
        button_parse = Button(master, text="Parse Primers", command = PrimerParser)
        button_pool = Button(master, text="Pool Primers", command=poolPrimers)
        button_blast = Button(master, text="Blast Primers", command=self.blast)
        button_quit = Button(master, text="Quit", command=master.destroy)

        ########## LAYOUT ##########
        label_1.grid(row=0, columnspan=4) #grid doesnt take left right, it takes NSEW directions
        button_1.grid(row=1, sticky=E, padx=1, pady=1)
        button_2.grid(row=2, sticky=E, padx=1, pady=1)
        button_3.grid(row=3, sticky=E, padx=1, pady=1)
        button_get.grid(row=4)
        button_parse.grid(row=4, sticky=W, column=1)
        button_pool.grid(row=4, sticky=W, column=2)
        button_blast.grid(row=4, sticky=W, column=3)
        button_quit.grid(row=4, sticky=W, column=4)

        entry_1.grid(row=1, column=1, sticky=W, padx=1, pady=1)
        entry_2.grid(row=2, column=1, sticky=W, padx=1, pady=1)
        entry_3.grid(row=3, column=1, sticky=W, padx=1, pady=1)

class BlastAPI:
    #class that does blast alignment on primers
    from Bio.Blast import NCBIWWW
    from Bio.Blast import NCBIXML
    def __init__(self, parent):
        self.parent = parent
        super(BlastAPI, self).__init__() #saw this on another stackoverflow don't truly understand what it means

        eValueSetting = Entry(parent)
        closeButton = Button(parent, text="Close", command=self.destroy)
        inputButton = Button(parent, text="Input file", command=doNothing)
        entryField = Entry(parent)

        #layout
        self.title('Complete Genomics Inc.')

        def blastPrimers():
            filename = askopenfilename()
            with open(filename) as file:
                string = file.read()

            fasta = fasta_string

            result_handle = NCBIWW.qblast("blastn", "nt", fasta)

            with open("my_blast.xml", "w") as out_handle:
                out_handle.write(result_handle.read())
            result_handle.close()

            result_handle = open('my_blast.xml')
            blast_record = NCBIXML.parse(result_handle)
            evalue = 1 #add make it a GUI alterable value blastPrimers
            item = next(blast_record)
            E_VALUE_THRESH = eValueSetting
            while True:
                with open('BlastResults.txt', w) as blast:
                    try:
                        for alignment in item.alignments:
                             for hsp in alignment.hsps:
                                 if hsp.expect < E_VALUE_THRESH: #use this to determine if the result will be applicable / HAVE USER SET / default value?
                                     blast.write("****Alignment****")
                                     blast.write("sequence:", alignment.title)
                                     blast.write("length:", alignment.length)
                                     blast.write("e value:", hsp.expect)
                                     blast.write(hsp.query[0:75] + "...")
                                     blast.write(hsp.match[0:75] + "...")
                                     blast.write(hsp.sbjct[0:75] + "...")
                        item = next(blast_record)
                    except StopIteration:
                        print("Done!")
                        break

root = Tk()
autoprimer = AUTOPRIMER(root)
root.mainloop()

谢谢大家。

1 个答案:

答案 0 :(得分:0)

好,所以这里有很多工作要做。我想这些丢失的部分是您的主要代码的一部分,但是如果没有它们,就无法测试您的代码。我将尽我所能,并设置您的类以从需要的tkinter对象继承。通过您的BlastAPI类中的按钮命令判断,我假设该类应为Toplevel()窗口。

我已经对您的代码进行了一些更改,而没有Bio.Blast,我已经更改了一些我认为您可能需要做的事情。

import subprocess
import tkinter as tk # import tkinter as tk is good for compatibility and maintainability. Don't use *
from tkinter.filedialog import *
import tkinter.messagebox
from Bio.Blast import NCBIWWW
from Bio.Blast import NCBIXML

class AutoPrimer(tk.Tk): # Class names should normally use the CapWords convention.
    def __init__(self):
        #initialization
        tk.Tk.__init__(self)
        self.title("Complete Genomics Inc.")
        self.input = ""
        self.output = ""
        self.param = ""
        self.inputbool = False
        self.outputbool = False
        self.parambool = False
        self.p3filestring = '-p3_settings_file='


        self.entry_input = tk.Entry(self)
        self.entry_output = tk.Entry(self)
        self.entry_parameters = tk.Entry(self)
        self.entry_input.grid(row=1, column=1, padx=1, pady=1, sticky="w")
        self.entry_output.grid(row=2, column=1, padx=1, pady=1, sticky="w")
        self.entry_parameters.grid(row=3, column=1, padx=1, pady=1, sticky="w")

        self.label1 = tk.Label(self, text="AUTOPRIMER").grid(row=0, columnspan=4)
        tk.Button(self, text="Input Filepath: ", command=lambda: self.button1).grid(row=1, padx=1, pady=1, sticky="e")
        tk.Button(self, text="Output Filepath: ", command=lambda: self.button2).grid(row=2, padx=1, pady=1, sticky="e")
        tk.Button(self, text="Parameters Filepath: ", command=lambda: self.button3).grid(row=3, padx=1, pady=1, sticky="e")
        tk.Button(self, text="Get Primers",).grid(row=4)
        tk.Button(self, text="Parse Primers",).grid(row=4, column=1, sticky="w")
        tk.Button(self, text="Pool Primers",).grid(row=4, column=2, sticky="w")
        tk.Button(self, text="Blast Primers", command=lambda: BlastAPI(self)).grid(row=4, column=3, sticky="w")
        tk.Button(self, text="Quit", command=self.destroy).grid(row=4, column=4, sticky="w")

        #CLASS METHODS
        #Series of buttons methods that take in the filepath and displays it in the text widget to the user

    def button1(self):
        self.entry_input.delete(0,END)
        ifp = askopenfilename()
        self.setInput(ifp)
        self.entry_input.insert(0, ifp)
        self.setInputBool(True)
    def button2(self):
        self.entry_output.delete(0,END)
        ofp = asksavefilename()
        self.setOutput(ofp)
        self.entry_output.insert(0, ofp)
        self.setOutputBool(True)
    def button3(self):
        self.entry_parameters.delete(0,END)
        pfp = askopenfilename()
        self.entry_parameters.insert(0, pfp)
        self.setParameterBool(True)

    #Methods that rely on class attributes after using above buttons to set
    def get_primers(self):
        pass
    def primer_parser(self):
        pass
    def pool_primers(self):
        pass

    #Setters and Getters
    def setInput(self, value):
        self.input = value
    def setOutput(self, value):
        self.output = value
    def setParam(self, value):
        self.param = value
    def setInputBool(self, value):
        self.inputbool = value
    def setOutputBool(self, value):
        self.outputbool = value
    def setParameterBool(self, value):
        self.parambool = value




class BlastAPI(tk.Toplevel):
    def __init__(self, parent):
        tk.Toplevel.__init__(self, parent)
        self.title('Complete Genomics Inc.')
        self.e_value_thresh = ""

        self.e_value_setting = tk.Entry(self)
        self.e_value_setting.pack() # Used pack here for quick testing. You will need to work on geometry yourself.
        tk.Button(self, text="Close", command=self.destroy).pack()
        tk.Button(self, text="Input file").pack()
        self.entry_field = tk.Entry(self)
        self.entry_field.pack()


    def blast_primers(self): # Nothing is calling this function in your example.
        filename = askopenfilename()
        with open(filename) as file:
            string = file.read() # string is not being used here.

        fasta = string # No such var name in code.
        result_handle = NCBIWWW.qblast("blastn", "nt", fasta) # This had a typo NCBIWW instead of NCBIWWW.

        with open("my_blast.xml", "w") as out_handle:
            out_handle.write(result_handle.read())
        result_handle.close()

        result_handle = open('my_blast.xml')
        self.blast_record = NCBIXML.parse(result_handle)
        evalue = 1 # Is not being used here.
        self.item = next(self.blast_record)
        self.e_value_thresh = self.e_value_setting.get()
        self.blast_write_loop()


    def blast_write_loop(self):
        # I don't really like while loops and they have problems in event based GUI's.
        # I don't think a while loop is needed here anyway.
        with open('BlastResults.txt', 'w') as blast:
            try:
                for alignment in self.item.alignments:
                    for hsp in alignment.hsps:
                        if hsp.expect < self.e_value_thresh:
                            blast.write("****Alignment****")
                            blast.write("sequence:", alignment.title)
                            blast.write("length:", alignment.length)
                            blast.write("e value:", hsp.expect)
                            blast.write(hsp.query[0:75] + "...")
                            blast.write(hsp.match[0:75] + "...")
                            blast.write(hsp.sbjct[0:75] + "...")
                self.item = next(self.blast_record)
            except StopIteration:
                print("Done!")


autoprimer = AutoPrimer()
autoprimer.mainloop()