2017-01-11 28 views
0

我遇到了一個非常大的類,我現在正在嘗試清理並拆分成子類。然而,我最大的問題atm是設置正確的初始化方法,以使函數在各個子類中可調用。 這個想法是有一個Ui_MainWindow類,它正在處理gui進程。另一個處理AT命令的TextMessage類和處理所有錯誤消息的第三個MessageBoxes類。我將如何爲setupUi函數中的所有屬性創建正確的init方法?這是我最大的問題。 非常感謝您提前。 大班會在這裏:將一個大類分成幾個子類,__init__問題

ALPHA = string.ascii_letters 

class Ui_MainWindow(object): 
    def setupUi(self, MainWindow): 
     MainWindow.setObjectName("MainWindow") 
     MainWindow.resize(503, 486) 
     self.centralWidget = QtWidgets.QWidget(MainWindow) 
     self.centralWidget.setObjectName("centralWidget") 
     self.widget = QtWidgets.QWidget(self.centralWidget) 
     self.widget.setGeometry(QtCore.QRect(10, 20, 477, 391)) 
     self.widget.setObjectName("widget") 
     self.gridLayout_2 = QtWidgets.QGridLayout(self.widget) 
     self.gridLayout_2.setContentsMargins(11, 11, 11, 11) 
     self.gridLayout_2.setSpacing(6) 
     self.gridLayout_2.setObjectName("gridLayout_2") 
     self.lineEdit_2 = QtWidgets.QLineEdit(self.widget) 
     self.lineEdit_2.setObjectName("lineEdit_2") 
     self.lineEdit_2.setDisabled(True) 
     self.gridLayout_2.addWidget(self.lineEdit_2, 0, 1, 1, 1) 
     self.gridLayout = QtWidgets.QGridLayout() 
     self.gridLayout.setContentsMargins(11, 11, 11, 11) 
     self.gridLayout.setSpacing(6) 
     self.gridLayout.setObjectName("gridLayout") 
     self.radioButton = QtWidgets.QRadioButton(self.widget) 
     self.radioButton.setChecked(True) 
     self.radioButton.setObjectName("radioButton") 
     self.gridLayout.addWidget(self.radioButton, 0, 0, 1, 1) 
     self.lineEdit = QtWidgets.QLineEdit(self.widget) 
     self.lineEdit.setObjectName("lineEdit") 
     self.gridLayout.addWidget(self.lineEdit, 0, 1, 1, 1) 
     self.radioButton_2 = QtWidgets.QRadioButton(self.widget) 
     self.radioButton_2.setObjectName("radioButton_2") 
     self.gridLayout.addWidget(self.radioButton_2, 1, 0, 1, 1) 
     self.lineEdit2 = QtWidgets.QLineEdit(self.widget) 
     self.lineEdit2.setObjectName("lineEdit2") 
     self.gridLayout.addWidget(self.lineEdit2, 1, 1, 1, 1) 
     self.pushButton = QtWidgets.QPushButton(self.widget) 
     self.pushButton.setObjectName("pushButton") 
     self.pushButton.clicked.connect(self.get_path) #connect add xls button with function get_path 
     self.gridLayout.addWidget(self.pushButton, 1, 2, 1, 1) 
     self.plainTextEdit = QtWidgets.QPlainTextEdit(self.widget) 
     self.plainTextEdit.setObjectName("plainTextEdit") 
     self.gridLayout.addWidget(self.plainTextEdit, 2, 1, 2, 1) 
     self.label = QtWidgets.QLabel(self.widget) 
     self.label.setObjectName("label") 
     self.gridLayout.addWidget(self.label, 2, 0, 1, 1) 
     self.label2 = QtWidgets.QLabel(self.centralWidget) 
     self.label2.setObjectName("label2") 
     self.gridLayout.addWidget(self.label2, 2, 2, 1, 1) 
     self.pushButton_2 = QtWidgets.QPushButton(self.widget) 
     self.pushButton_2.setObjectName("pushButton_2") 
     self.gridLayout.addWidget(self.pushButton_2, 3, 2, 1, 1) 
     self.pushButton_2.clicked.connect(self.send_sms) #send sms function 
     self.gridLayout_2.addLayout(self.gridLayout, 1, 0, 1, 2) 
     self.line = QtWidgets.QFrame(self.widget) 
     self.line.setFrameShape(QtWidgets.QFrame.HLine) 
     self.line.setFrameShadow(QtWidgets.QFrame.Sunken) 
     self.line.setObjectName("line") 
     self.gridLayout_2.addWidget(self.line, 2, 0, 1, 2) 
     self.pushButton_3 = QtWidgets.QPushButton(self.widget) 
     self.pushButton_3.setObjectName("pushButton_3") 
     self.gridLayout_2.addWidget(self.pushButton_3, 0, 0, 1, 1) 
     self.pushButton_3.clicked.connect(self.connect_phone) #connect add xls button with function get_path 
     self.plainTextEdit_2 = QtWidgets.QPlainTextEdit(self.widget) 
     self.plainTextEdit_2.setObjectName("plainTextEdit_2") 
     self.plainTextEdit_2.setDisabled(True) 
     self.gridLayout_2.addWidget(self.plainTextEdit_2, 4, 1, 2, 1) 
     self.progressBar = QtWidgets.QProgressBar(self.widget) 
     self.progressBar.setProperty("value", 0) 
     self.progressBar.setObjectName("progressBar") 
     self.gridLayout_2.addWidget(self.progressBar, 4, 0, 1, 1) 
     self.checkBox = QtWidgets.QCheckBox(self.widget) 
     self.checkBox.setObjectName("checkBox") 
     self.gridLayout_2.addWidget(self.checkBox, 5, 0, 1, 1) 
     MainWindow.setCentralWidget(self.centralWidget) 
     self.menuBar = QtWidgets.QMenuBar(MainWindow) 
     self.menuBar.setGeometry(QtCore.QRect(0, 0, 503, 27)) 
     self.menuBar.setObjectName("menuBar") 
     MainWindow.setMenuBar(self.menuBar) 
     self.mainToolBar = QtWidgets.QToolBar(MainWindow) 
     self.mainToolBar.setObjectName("mainToolBar") 
     MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.mainToolBar) 
     self.statusBar = QtWidgets.QStatusBar(MainWindow) 
     self.statusBar.setObjectName("statusBar") 
     MainWindow.setStatusBar(self.statusBar) 

     self.retranslateUi(MainWindow) 
     self.radioButton.toggled['bool'].connect(self.lineEdit.setEnabled) 
     self.radioButton.toggled['bool'].connect(self.lineEdit2.setDisabled) 
     self.radioButton_2.toggled['bool'].connect(self.lineEdit.setDisabled) 
     self.radioButton_2.toggled['bool'].connect(self.lineEdit2.setEnabled) 
     self.radioButton.toggled['bool'].connect(self.pushButton.setDisabled) 
     self.radioButton_2.toggled['bool'].connect(self.pushButton.setEnabled) 
     QtCore.QMetaObject.connectSlotsByName(MainWindow) 
     self.plainTextEdit.textChanged.connect(self.bam) 

    def bam(self): 
     _translate = QtCore.QCoreApplication.translate 
    text = self.plainTextEdit.toPlainText() 
     self.label2.setText(_translate("MainWindow", str(len(text))+"/160")) 
    if len(text) > 160: 
      root = tk.Tk() 
     root.withdraw() 
     self.plainTextEdit.setPlainText(text[:160]) 
     cursor = self.plainTextEdit.textCursor() 
     cursor.setPosition(self.plainTextEdit.document().characterCount() - 1) 
     self.plainTextEdit.setTextCursor(cursor) 
     tkMessageBox.showwarning("No Way!", "Keep it low, 160chrs max") 
     root.destroy() 
     root.mainloop() 
     return 

    def retranslateUi(self, MainWindow): 
     _translate = QtCore.QCoreApplication.translate 
     MainWindow.setWindowTitle(_translate("MainWindow", "Kotti&Co Mobilizer")) 
     self.radioButton.setText(_translate("MainWindow", "Single SMS")) 
     self.radioButton_2.setText(_translate("MainWindow", "SMS to Contacts")) 
     self.pushButton.setText(_translate("MainWindow", "Add .xls")) 
     self.label.setText(_translate("MainWindow", "Message Text")) 
     self.pushButton_2.setText(_translate("MainWindow", "Send it!")) 
     self.pushButton_3.setText(_translate("MainWindow", "Connect Phone")) 
     self.checkBox.setText(_translate("MainWindow", "Status Report")) 

    def get_path(self, MainWindow): 
     _translate = QtCore.QCoreApplication.translate 
     root = tk.Tk() 
    root.withdraw() 
    file_path = filedialog.askopenfilename(title = "Kotti Kontaktliste",filetypes = (("excel files","*.xls"),("excel files", "*.xlsx"),("csv files","*.csv"),("all files","*.*"))) 
    if not file_path: 
     return None 
    else: 
     self.lineEdit2.insert(file_path) 

    def __init__(self, recipient="+491749449785", message="TextMessage.content not set."): 
     self.recipient = recipient 
     self.content = message 

    def setRecipient(self, number): 
     self.recipient = number 

    def setContent(self, message): 
     self.content = message 

    def disconnectPhone(self): 
     self.ser.close() 

    def connect_phone(self): 
    try: 
     self.ser = serial.Serial('/dev/ttyACM0', 
        460800, 
        timeout=5, 
        xonxoff = False, 
        rtscts = False, 
        bytesize = serial.EIGHTBITS, 
        parity = serial.PARITY_NONE, 
        stopbits = serial.STOPBITS_ONE) 
      #s = input('Enter AT command --> ') 
      #print ('AT command = ' + s) 
      self.ser.write(bytes('AT+CGMI' + '\r\n')) 
      self.ser.timeout = 1 
      self.ser.write('AT+CGMM' + '\r\n') 
      self.ser.timeout = 1 
      response = self.ser.read(999) 
      print(response) 
      self.lineEdit_2.setText(response) 

    except serial.SerialException: 
     self.lineEdit_2.setText("could not connect to phone") 
     return None 

    def check_phone(self): 
     self.ser = serial.Serial('/dev/ttyACM0', 
        460800, 
        timeout=5, 
        xonxoff = False, 
        rtscts = False, 
        bytesize = serial.EIGHTBITS, 
        parity = serial.PARITY_NONE, 
        stopbits = serial.STOPBITS_ONE) 

    def sendMessage(self): 
     self.ser.write('ATZ\r') 
     time.sleep(1) 
     self.ser.write('AT+CMGF=1\r') 
     time.sleep(1) 
     self.ser.write('''AT+CMGS="''' + self.recipient + '''"\r''') 
     time.sleep(1) 
     self.ser.write(self.content + "\r") 
     time.sleep(1) 
     self.ser.write(chr(26)) 
     time.sleep(2) 

    def sms_report(self): 
     self.ser.write('AT+CMEE=2\r') 
     self.ser.timeout = 3 
     time.sleep(1) 
     self.response2 = self.ser.read(999) 
     print(self.response2) 
    self.plainTextEdit_2.setPlainText(self.lineEdit.text()+'\nmessage sent successfully'+self.response2()) 

    def send_sms(self): 
     check = self.radioButton.isChecked() 
     if check == True: #single sms use 
      if not self.lineEdit.text(): 
       root = tk.Tk() 
       root.withdraw() 
       tkMessageBox.showwarning("Phone Number Missing!", "Please enter a valid phone number") 
       root.destroy() 
       root.mainloop() 
       return 
      if not self.plainTextEdit.toPlainText(): 
       root = tk.Tk() 
       root.withdraw() 
       tkMessageBox.showwarning("Message Missing!", "Please enter a text message") 
       root.destroy() 
       root.mainloop() 
       return 
      else: 
       try: 
        sms = Ui_MainWindow(str(self.lineEdit.text()), str(self.plainTextEdit.toPlainText().encode('ISO-8859-1'))) 
        sms.check_phone() 
        sms.sendMessage() 
        repo = self.checkBox.isChecked() 
        if repo == True: 
         sms.sms_report() 

        else: 
         self.plainTextEdit_2.setPlainText(self.lineEdit.text()+'\nmessage sent successfully') 
        sms.disconnectPhone() 
       except serial.SerialException: 
        root = tk.Tk() 
        root.withdraw() 
        tkMessageBox.showwarning("NO GSM Connected!", "Plug in your mobile device") 
        root.destroy() 
        root.mainloop() 
    else: #sms to contact sheet 
     if not self.lineEdit2.text(): 
      root = tk.Tk() 
      root.withdraw() 
      tkMessageBox.showwarning("No contact sheet!", "Please add path to contact file") 
      root.destroy() 
      root.mainloop() 
      return 
     if not self.plainTextEdit.toPlainText(): 
      tkm.missing_message() 
     else: 
      try: 
       with open(str(self.lineEdit2.text().encode('utf-8'))) as f: 
       if str(self.lineEdit2.text().encode('utf-8')).endswith("csv"): #check whether the file is a .csv file or anything else 
         reader2 = csv.reader(f) 
        reader2.next() 
        linecount = len(zip(*reader2)[0]) 
        f.seek(0) 
        reader = csv.reader(f) 
        reader.next() 
        #linecount = len(open(self.lineEdit2.text()).readlines()) 
        counter = 0 
        count_all = 0 
         for i, (row) in enumerate(reader): 
         #print (row[0]) 
         if not row[0] or row[0].startswith(tuple(ALPHA)): #avoid empty lines 
          counter += 1 
           continue 
         print (row[0]) 
         sms = Ui_MainWindow("+491793288636", str(self.plainTextEdit.toPlainText().encode('utf-8'))) 
         sms.check_phone() 
         sms.sendMessage() 
         count_all +=1 
         sms.disconnectPhone() 
         self.progressBar.setValue((count_all)*(100/(linecount-counter))) 
         if count_all == linecount-counter: 
          self.plainTextEdit_2.setPlainText('list completed') 
          self.progressBar.setValue(100) 
         else: 
          self.plainTextEdit_2.setPlainText(str(count_all)+'/'+str(linecount-counter)+'\n'+str(row[0])+'\nmessage sent successfully') 
       else: #get the shit done for xls or xlsx files, converting them into data.csv 
        x = xlrd.open_workbook(self.lineEdit2.text()) #hope that works in windoofs 
        worksheet = x.sheet_by_index(0) 
        csvfile = open('data.csv', 'wb') 
         writecsv = csv.writer(csvfile, quoting=csv.QUOTE_ALL) 

         for rownum in xrange(worksheet.nrows): 
          writecsv.writerow(worksheet.row_values(rownum)) 
        csvfile.close() 
        time.sleep(2) 
        with open('data.csv', 'rb') as f: 
          reader2 = csv.reader(f) 
         reader2.next() 
         linecount = len(zip(*reader2)[0]) 
         f.seek(0) 
         reader = csv.reader(f) 
         reader.next() 
         print(linecount) 
         counter = 0 
         count_all = 0 
          for i, (row) in enumerate(reader): 
          #print (row[0]) 
          if not row[0] or row[0].startswith(tuple(ALPHA)): #avoid empty lines 
           counter += 1 
            continue 
          print (row[0]) 
          sms = TextMessage("+491793288636", str(self.plainTextEdit.toPlainText().encode('utf-8'))) 
          sms.check_phone() 
          sms.sendMessage() 
          count_all +=1 
          sms.disconnectPhone() 
          self.progressBar.setValue((count_all)*(100/(linecount-counter))) 
          if count_all == linecount-counter: 
           self.plainTextEdit_2.setPlainText('list completed') 
           self.progressBar.setValue(100) 
          else: 
           self.plainTextEdit_2.setPlainText(str(count_all)+'/'+str(linecount-counter)+'\n'+str(row[0])+'\nmessage sent successfully') 
      except serial.SerialException: 
       root = tk.Tk() 
       root.withdraw() 
       tkMessageBox.showwarning("NO GSM Connected!", "Plug in your mobile device") 
       root.destroy() 
       root.mainloop() 

if __name__ == "__main__": 
    import sys 
    app = QtWidgets.QApplication(sys.argv) 
    MainWindow = QtWidgets.QMainWindow() 
    ui = Ui_MainWindow() 
    ui.setupUi(MainWindow) 
    MainWindow.show() 
    sys.exit(app.exec_()) 

我嘗試了其他類來完成到目前爲止是這樣的:

lml = Ui_MainWindow() 

class MessageBoxes(): 

    def missing_phone_number(self): 
    root = tk.Tk() 
    root.withdraw() 
    tkMessageBox.showwarning("Phone Number Missing!", "Please enter a valid phone number") 
    root.destroy() 
    root.mainloop() 
    return 
    def missing_message(self): 
    root = tk.Tk() 
    root.withdraw() 
    tkMessageBox.showwarning("Message Missing!", "Please enter a text message") 
    root.destroy() 
    root.mainloop() 
    return 

class TextMessage(): 

    def __init__(self, recipient="+491749449785", message="TextMessage.content not set."): 
     self.recipient = recipient 
     self.content = message 

    def missing_phone_number(self): 
     tkm = MessageBoxes() 

但我總是得到問題的Ui_MainWindow類的屬性,如:AttributeError: Ui_MainWindow instance has no attribute 'lineEdit'

+1

劃分一類成子類是不常見的在面向對象編程中創建派生類的原因 - 通常是爲了專門化基類 - 所以很難提供建議。 – martineau

+0

您的代碼中的縮進是否與您在此處提供的縮進相同?看起來你可能已經犯了一個複製錯誤。如果是這樣,你的縮進是錯誤的。您在成員被分配之前呼叫成員,所以他們不會存在。 – JackCC

+0

你現在在TextMessage類中的意思是?或者一般? – fahrradlaus

回答

0

你必須建立你的分類 - letś稱他們爲「混搭類」,他們共同工作的方式。

在Python中,使用內置的super很容易實現。 您必須編寫__init__方法(如果它們存在於所有類中,則可能有其他方法)採用任意keywoard參數,使用它們使用的參數,並使用super調用其他類__init__。如果所有mixin都這樣做(並且你沒有方法或者attribut namign衝突),那麼你可以用任意數量的os混合構建任意大的類。

class Base(object): 
    pass 

class M1(Base): 
    """ Methods responsible for foo-things""" 
    def __init__(self, **kwargs): 
      self.foo_param1 = kwargs.pop("foo_param1") 
      self.foo_param2 = kwargs.pop("foo_param2") 
      super(M1, self).__init__(**kwargs) 

    # define specific foo methods here: 

# repeat for other mixins: 

    class M2(Base): 
     ... 

    class M3(base): 
     ... 

# declare your main class: 

class UI_Main(M1, M2, M3, ...): 
    def __init__(self, **kwargs): 
      super(Ui_Main, self).__init__(**kwargs) 

(你真的應該使用Python3.x,在這種情況下,鬱可強制使用super().__init__(**kwargs),wihtout硬編碼當前的類名。)