Home > Software design >  How to call class A method inside class B method in Python
How to call class A method inside class B method in Python

Time:02-19

I currently face a problem when I want to call a class A method inside a class B method. The code is running fine. However, the problem happen at line 73 in ImageProcessing.py where MainApplication.signup() is asking for parameter. This function is built for returning to the signup page. I am not sure if it is the right way to code like this. Please help me. I would appreciate your kindness.

*This is Display.py

import tkinter as tk
from tkinter import *
from PIL import ImageTk, Image
import os
import ImageProcessing

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

        # Resize image
        self.open_image = Image.open('images/log_icon.png')
        self.resized_image = self.open_image.resize((170, 170), Image.ANTIALIAS)
        # Define image
        self.img = ImageTk.PhotoImage(self.resized_image)
        self.bg1 = ImageTk.PhotoImage(Image.open('images/darkblue.png'))
        self.lock = ImageTk.PhotoImage(Image.open('Icon/lock.ico'))
        self.loginBtn = ImageTk.PhotoImage(Image.open('images/login-button.png'))

        # Create labels and buttons
        self.my_label = Label(master, image=self.bg1)
        self.my_label.place(x=0, y=0, relwidth=1, relheight=1)

        self.log_head = Label(master, image=self.img, bg="#1f1a30")
        self.log_head.place(x=115, y=10)

        self.lock_label = Label(master, image=self.lock, bg="#39304d")
        self.lock_label.place(x=50, y=200, height=35, width=40)

        self.username = Entry(master, font=("arial", 13), bg="#39304d", fg="white", borderwidth=0)
        self.username.place(x=90, y=200, width=250, height=35)

        self.login_btn = Button(master, image=self.loginBtn, borderwidth=0, bg="#1f1a30", activebackground="#1f1a30", command=self.login)
        self.login_btn.place(x=35, y=300)

        self.signup_label = Label(master, text="Don't have an account?", bg="#1f1a30", font=("times new roman", 10),
                             fg="white")
        self.signup_label.place(x=110, y=380)

        self.signup_btn = Button(master, text="Sign Up", borderwidth=0, bg="#1f1a30", font=("times new roman", 10, "underline"),
                             fg="#0df6e3", activebackground="#1f1a30", command=self.signup)
        self.signup_btn.place(x=240, y=380)

        self.forget_btn = Button(master, text="Forgot Your Password?", borderwidth=0, bg="#1f1a30",
                            font=("times new roman", 10),
                            fg="#0df6e3", activebackground="#1f1a30")
        self.forget_btn.place(x=132, y=410)


    def signup(self):
        def open(filename):
            os.chdir("C:\Python Projects\PyFYP")  # file path
            os.system('python '   filename)  # run the python command on cmd to execute both windows

        self.master.destroy()
        open("Registration.py")

    def login(self):
        pass

def main_login():
    App = tk.Tk()
    App.title("Login")
    App.iconbitmap('C:/Python Projects/PyFYP/Icon/snake2.ico')
    App.resizable(False, False)

    # Put TK Window screen to center
    app_width = 390
    app_height = 500

    screen_width = App.winfo_screenwidth()
    screen_height = App.winfo_screenheight()

    sys_width = (screen_width / 2) - (app_width / 2)
    sys_height = (screen_height / 2) - (app_height / 2)
    App.geometry(f'{app_width}x{app_height} {int(sys_width)} {int(sys_height)}')
    MainApplication(App)
    App.mainloop()


if __name__ == "__main__":
    main_login()

*This is ImageProcessing.py

import tkinter as tk
from tkinter import *
from tkinter import ttk, filedialog
from tkinter.filedialog import askopenfile
from PIL import ImageTk, Image
import cv2
import numpy as np
from tkinter import messagebox
import time
import Display


class ProcessImage():
    def __init__(self, master):  # parent, *args, **kwargs):
        self.master = master
        self.frame = tk.Frame(self.master)

        self.bg = ImageTk.PhotoImage(Image.open('images/neon.png'))
        self.Upload_Btn_img = ImageTk.PhotoImage(Image.open('images/upload_btn.png'))
        self.proceed_Btn_img = ImageTk.PhotoImage(Image.open('images/proceed_btn.png'))
        self.cancel_Btn_img = ImageTk.PhotoImage(Image.open('images/cancel_btn.png'))
        self.reset_Btn_img = ImageTk.PhotoImage(Image.open('images/reset_btn.png'))

        # Labels and Buttons
        self.Img_process_background = tk.Label(master, image=self.bg)
        self.Img_process_background.place(x=0, y=0, relwidth=1, relheight=1)

        # OpenCV window name
        self.windowName = "Selected Image"

        # Attributes for setting coordinates
        self.coordinate = np.zeros((3, 2), int)
        self.counter = 0
        self.file_path_name = "" # Uploaded image's file path

        # Upload Image label
        self.uploadImg_label = Label(master, text="Please upload your preference image here.", bg="#1f1a30", font=("arial", 12, "bold"), fg="white")
        self.uploadImg_label.place(x=50, y=50)
        self.uploadImg_note = Label(master, text="* Only jpg, jpeg, png, are allowed.", bg="#1f1a30", font=("arial", 8, "bold"), fg="grey")
        self.uploadImg_note.place(x=50, y=75)
        self.img_resize_note = Label(master, text="* Image will be resize to 900x500.", bg="#1f1a30",font=("arial", 8, "bold"), fg="grey")
        self.img_resize_note.place(x=50, y=100)
        self.txt_uploadImg = Entry(master, font=("arial", 10), bg="#39304d", fg="white", borderwidth=0)
        self.txt_uploadImg.place(x=50, y=125, width=350, height=20)

        # Create Buttons
        self.upload_btn = tk.Button(master, image=self.Upload_Btn_img, command=self.Browsing, borderwidth=0, bg="#1f1a30",activebackground="#1f1a30")
        self.upload_btn.place(x=170, y=175, width=120)

        self.reset_Btn = Button(master, command=self.reset_it, image=self.reset_Btn_img, borderwidth=0, bg="#1f1a30",activebackground="#1f1a30")
        self.reset_Btn.place(x=80, y=250, width=120)

        self.cancel_btn = Button(master, command=self.cancel_it, image=self.cancel_Btn_img, borderwidth=0, bg="#1f1a30",activebackground="#1f1a30")
        self.cancel_btn.place(x=260, y=250, width=120)

        self.proceed_btn = Button(master, image=self.proceed_Btn_img, borderwidth=0, bg="#1f1a30",activebackground="#1f1a30", command=self.SetCoordinates)
        self.proceed_btn.place(x=170, y=400, width=120)



    def reset_it(self):
        self.counter = 0
        self.txt_uploadImg.delete(0, "end")
        self.file_path_name = ""
        messagebox.showinfo(title="Success", message="Points have been reset")


    def cancel_it(self):
        # Initialize variables
        self.master.destroy()
        self.counter = 0
        self.file_path_name = ""
        MainApplication.signup() # Return to sign up/register page



    def SetCoordinates(self):
        try:
            self.read_img = cv2.imread(self.file_path_name) # read image
            self.resized_img = cv2.resize(self.read_img, (900,500))

            while True:
                cv2.namedWindow(self.windowName)
                cv2.imshow(self.windowName, self.resized_img)
                cv2.setMouseCallback(self.windowName, self.PassPoints)
                cv2.waitKey(1)

                if self.counter == 3:
                    time.sleep(0.5)
                    messagebox.showinfo(title="Success", message="Points were marked successfully")
                    cv2.destroyWindow(self.windowName)
                    break
        except:
            messagebox.showerror(title="Error message", message="Image not found")
            cv2.destroyWindow(self.windowName)


    def PassPoints(self, event, x, y, flags, params):
        global counter

        if event == cv2.EVENT_LBUTTONDOWN:

            self.coordinate[self.counter] = x, y
            colorsB = self.resized_img[y, x, 0]
            colorsG = self.resized_img[y, x, 1]
            colorsR = self.resized_img[y, x, 2]
            self.counter  = 1
            print("x= "   str(x)   " y= "   str(y))
            print('Red: '   str(colorsR)   ' '   'Green: '   str(colorsG)   ' '   'Blue: '   str(colorsB))



    def Browsing(self):
        img_file = filedialog.askopenfile(mode='r', filetypes=[('JPEG', '*.jpeg'), ('JPEG', '*.jpg'), ('PNG', '*.png')])
        global file_path_name

        def setImageNameInput(self, text):
            self.txt_uploadImg.delete(0, "end")
            self.txt_uploadImg.insert(0, text)

        # img_file.name: the .name used to get the file path of the uploaded image
        if img_file:
            setImageNameInput(self,img_file.name)
            self.file_path_name = img_file.name

def main_image_process():
    Imageprocess_page = tk.Tk()
    Imageprocess_page.title("Image processing")
    Imageprocess_page.iconbitmap('C:/Python Projects/PyFYP/Icon/snake2.ico')
    Imageprocess_page.resizable(False, False)

    app_width = 900
    app_height = 500

    screen_width = Imageprocess_page.winfo_screenwidth()
    screen_height = Imageprocess_page.winfo_screenheight()

    sys_width = (screen_width / 2) - (app_width / 2)
    sys_height = (screen_height / 2) - (app_height / 2)
    Imageprocess_page.geometry(f'{app_width}x{app_height} {int(sys_width)} {int(sys_height)}')
    ProcessImage(Imageprocess_page)
    Imageprocess_page.mainloop()

if __name__ == "__main__":
    main_image_process()

*This is the error TypeError: signup() missing 1 required positional argument: 'self'

CodePudding user response:

You cannot call the method, because it is not a static / class method but instead the method of an instance / object of the class MainApplication.

This means that the cancel_it method's parameter self expects an instance of the class MainApplication to function properly but by calling MainApplication.cancel_it() it receives the class instead as argument and therefore throws an exception.

You could easily call it, by passing a reference to the Mainapplication-instance to your cancel_it method.

Assuming that:

self.master

in the ProcessImage classe's __init__ method is a reference to the Main-Application instance, the solution would look like this:

  def cancel_it(self):
        # Initialize variables
        self.master.destroy()
        self.counter = 0
        self.file_path_name = ""
        self.master.signup() # Return to sign up/register page

Otherwise, the method-adjustment might look something like this:

def cancel_it(self, main_application):
    # Initialize variables
    self.master.destroy()
    self.counter = 0
    self.file_path_name = ""
    main_application.signup() # Return to sign up/register page

with main_application being the reference to the MainApplication, which would have to passed as argument. If the latter case should be true - Keep in mind that you will also have to adjust the command of the button responsible for calling the function, so that it actually passes the argument main_application.

  • Related