Esempio n. 1
0
class MainWindow:
    
    def __init__(self, master):
        self.master = master
        master.title("TK Test")
        
        self.frame = tk.Frame(master, width=500, height=400, bd=1)        
        #self.frame = tk.Frame(self.master, width = 202, height = 32, highlightbackground="black", highlightcolor="black", highlightthickness=1, bd=0)
        
        
        
        self.lblURL = tk.Label(self.frame, text = "URL", width = 6, borderwidth=2, relief="groove")
        self.lblURL.grid(row = 0, column = 0, padx = 2, pady = 2)
        
        self.txtURL = StringVar()
        self.txtURL = tk.Entry(self.frame)#, height = 1, width = 40, borderwidth=2, relief="groove")
        self.txtURL.grid(row = 0, column = 1, padx = 2, pady = 2)
        
        self.msgReqBody = tk.Text(self.frame, height = 5, width = 47, borderwidth=2, relief="groove")
        self.msgReqBody.grid(row = 1, column = 0, columnspan = 2, padx = 2, pady = 2)
        
        self.btnProcess = tk.Text(self.frame, text = Send, borderwidth=2, relief="groove")
        self.btnProcess.grid(row = 2, column = 1, padx = 2, pady = 2, sticky = "w")
        
        self.frame.pack()
nur = StringVar()
asc = StringVar()
up = StringVar()
co = StringVar()
ba = StringVar()
cl = StringVar()
con = StringVar()
mes = StringVar()
ot = StringVar()
fu = StringVar()

ttk.Label(mainframe, text="Anaesthetist").grid(column=1, row=1, sticky=W)
an = ttk.Combobox(mainframe, textvariable=an)
an['values'] = gnc.BILLING_ANAESTHETISTS
an['state'] = 'readonly'
an.grid(column=2, row=1, sticky=W)

ttk.Label(mainframe, text="Endoscopist").grid(column=1, row=2, sticky=W)
end = ttk.Combobox(mainframe, textvariable=end)
end['values'] = gnc.ENDOSCOPISTS
end['state'] = 'readonly'
end.grid(column=2, row=2, sticky=W)

ttk.Label(mainframe, text="Nurse").grid(column=1, row=3, sticky=W)
nur = ttk.Combobox(mainframe, textvariable=nur)
nur['values'] = gnc.NURSES
nur['state'] = 'readonly'
nur.grid(column=2, row=3, sticky=W)

ttk.Label(mainframe, text="ASA").grid(column=1, row=4, sticky=W)
asc = ttk.Combobox(mainframe, textvariable=asc)
Esempio n. 3
0
class CourseView:
    """ Luokka, joka luo näkymän, missä käyttäjä voi lisätä uusia, hallita omia kurssejaan sekä lukea statistiikkaa suoritetusta kursseista.
        Käyttäjä voi myös poistaa tietonsa sekä kirjautua ulos.

    Attributes:
        root: UI:n juuri
        frame: Frame -olio, johon liitetään näkymän komponentteja.

        _course_info_labels = Ensin None, alustamisen jälkeen LabelFrame -olio, johon liitetään kurssien tietoja esittäviä komponenteja.
        _update_course_buttons = Ensin None, alustamisen jälkeen LabelFrame -olio, johon liitetään sovelluslogiikan mahdollistavat painikkeet.
        _course_statistics_labels = Ensin None, alustamisen jälkeen LabelFrame -olio, johon liitetään kurssien statisiikkaa esittäviä komponenteja.

        self._current_courses = Ensin None, alustamisen jälkeen Treeview -olio, jossa esitetään käyttäjän nykyisten kurssien tietoja.

        self._course_id_entry = Ensin None,alustamisen jälkeen Entry -olio, joka esittää kurssin id.
        self._course_name_entry = Ensin None, mutta alustamisen jälkeen Entry -olio, johon voidaan esittää yksittäisen kurssin nimi.
        self._course_credit_entry = Ensin " ", mutta alustamisen jälkeen Entry -olio, johon voidaan esittää kurssin opintopistemäärä.
        self._course_grade_entry = Ensin "", mutta alustamisen jälkeen Entry -olio, johon voidaan esittää kurssin arvosana.
        self._course_status_entry = Ensin None, mutta alustamisen jälkeen Entry -olio, johon voidaan esittää yksittäisen kurssin status.
        self._course_url_entry = Ensin "", mutta alustamisen jälkeen Entry -olio, johon voidaan esittää kurssiin liittyvä URL.

        self._course_status = StringVar() -olio, joka esittää kurssin statusta
        self._course_id = StringVar() -olio, joka esittää kurssin arvosanaa

        self._completed_courses_label = StringVar() -olio, esittää suoritettujen kurssien lukumäärää.
        self._completed_credits_label = StringVar() -olio, esittää suoritettujen kurssien opintopisteitä
        self._average_gpa_label = StringVar() -olio, esittää suoritettujen kurssien painoetettua keskiarvoa

        self._show_login_view = show_login_view -metodi, kutsuttaessa näyttää LoginView -näkymän

        self._user = course_service.current_user(), hakee nykyisen käyttäjän nimen kutsumalla sovelluslogiikan metodia
        self._initialize(), kutsuu luokan metodia, jolla näkymä alustetaan
        self._display_all_courses(), kutsuu luokan metodia, joka näyttää kaikki käyttäjän kurssit
        self._display_statistics(), kutsuu metodia, joka näyttää käyttäjän kurssien statistiikan

    """

    def __init__(self, root, show_login_view):
        """Luokan konstruktori. Alustaa kaikki tarvittavat muuttujat sekä oliot ja luo kurssinäkymästä vastaavan luokan.

        """

        self._root = root
        self._frame = None

        self._course_info_labels = None
        self._update_course_buttons = None
        self._course_statistics_labels = None

        self._current_courses = None

        self._course_id_entry = None
        self._course_name_entry = None
        self._course_credit_entry = " "
        self._course_grade_entry = ""
        self._course_status_entry = None
        self._course_url_entry = ""

        self._course_status = StringVar()
        self._course_id = StringVar()

        self._completed_courses_label = StringVar()
        self._completed_credits_label = StringVar()
        self._average_gpa_label = StringVar()

        self._show_login_view = show_login_view

        self._user = course_service.current_user()
        self._initialize()
        self._display_all_courses()
        self._display_statistics()

    def pack(self):
        self._frame.pack(fill=constants.BOTH, expand=True)

    def destroy(self):
        self._frame.destroy()

    def _create_new_course(self):
        """ Luo uuden kurssin kurssinäkymään hakemalla käyttäjän lisäämät syötteet ja antamalla ne parametriksi sovelluslogiikan create_new_course -metodille.
            Jos lisääminen ei onnistu annetuilla syötteillä, käyttäjä saa virhe ilmoituksen, jossa ohjataan oikean syötteen antamisessa.

        """

        course_name = self._course_name_entry.get()
        course_credit = self._course_credit_entry.get()
        course_grade = self._course_grade_entry.get()
        course_status = self._course_status.get()
        course_url = self._course_url_entry.get()
        self._course_id.set(OPTIONS[0])

        try:
            new_course = course_service.create_new_course(
                course_name, course_credit, course_grade, course_status, course_url)

            if new_course:
                self._display_all_courses()
                self._display_statistics()

        except ExistingCourseError:
            messagebox.showinfo("Course registration",
                                f"Course registration failed.\nCourse {course_name} has already been added!")

        except CourseEntryError:
            messagebox.showinfo("Course registration",
                                "Course registration failed.\nEnter both course name and credits!")

        except CourseValueError:
            messagebox.showinfo("Course registration",
                                "Course registration failed.\nEnter valid input for credits and grade!\n\nCourses marked as 'Completed' must have a valid grade!")

        except InvalidUrlError:
            messagebox.showinfo("Course registration",
                                f"Something went wrong..\nURL {course_url} is not valid.\n\nMake sure the URL is given in its complete form i.e. 'https://www.google.com'.")

    def _update_course_info(self):
        """ Päivittää valitun kurssin tiedot kutsumalla sovelluslogiikan metodia update_course_info käyttäjän antamilla syötteillä.
            Jos kurssin tietojen päivittäminen ei onnistu, käyttäjä saa virhe ilmoituksen, jossa ohjataan oikeanlaisen syötteen antamisessa.

        """
        course_name = self._course_name_entry.get()
        course_credit = self._course_credit_entry.get()
        course_grade = self._course_grade_entry.get()
        course_status = self._course_status.get()
        course_url = self._course_url_entry.get()

        course_id = self._course_id_entry.get()

        try:
            if course_service.update_course_info(course_id, course_name, course_credit, course_grade, course_status, course_url) is True:
                self._display_all_courses()
                self._display_statistics()
        except CourseUpdateError:
            messagebox.showinfo("Course registration",
                                "Course update failed.\nMake sure all inputs have correct values!")
        except InvalidUrlError:
            messagebox.showinfo("Course registration",
                                f"Something went wrong..\nURL {course_url} is not valid.\n\nMake sure the URL is given in its complete form i.e. 'https://www.google.com'.")

        except CourseValueError:
            messagebox.showinfo("Course registration",
                                "Course registration failed.\nEnter valid input for credits and grade!\n\nCourses marked as 'Completed' must have a valid grade!")

    def _remove_one_course(self):
        """ Poistaa käyttäjän valitseman kurssien näkymästä sekä tietokannasta hyödyntämällä sovelluslogiikan metodeja.
            Samalla päivitetään näkymän kurssit sekä niihin liittyvän statistiikan esittäminen.

        """
        course_name = self._course_name_entry.get()

        if course_service.remove_one_course(course_name) is True:
            self._course_id.set(OPTIONS[0])
            self._display_all_courses()
            self._display_statistics()

    def _remove_all_courses(self):
        """ Poistaa kaikki kurssit näkymästä ja tietokannasta sovelluslogiikan metodejen kautta.
            Samalla päivitetään näkymän kurssit sekä niihin liittyvän statistiikan esittäminen.

        """
        if course_service.remove_all_courses() is True:
            self._course_id.set(OPTIONS[0])
            self._display_all_courses()
            self._display_statistics()

    def callback(self, selection):
        self._course_status.set(selection)
        return selection

    def _clear_entry_input(self):
        """ Tyhjentää syötekentissä olevat tiedot.

        """

        self._course_id.set(OPTIONS[0])
        self._course_name_entry.delete(0, constants.END)
        self._course_credit_entry.delete(0, constants.END)
        self._course_grade_entry.delete(0, constants.END)
        self._course_status.set(OPTIONS[0])
        self._course_url_entry.delete(0, constants.END)

        self._course_grade_entry.insert(0, "")
        self._course_url_entry.insert(0, "")

    def _select_course(self, e):
        """ Hakee käyttäjän klikkaaman kurssin tiedot ja asettaa ne näkyville syötekenttiin.
           Syötekentät tyhjennetään ennen tätä kutsumalla _clear_entry_input -metodia.

        Args:
            e: bind -metodin mahdollistava parametrisyöte, jotta hiiren klikkaus kutsuu funktiota.
        """
        # kutsutaan kentät tyhjentävää metodia
        self._clear_entry_input()

        # haetaan valitun rivin arvot
        select = self._current_courses.focus()

        values = self._current_courses.item(select, "values")

        # sisällytetään valitun rivin arvot entry-kenttiin
        try:
            self._course_id.set(values[0])
            self._course_name_entry.insert(0, values[1])
            self._course_credit_entry.insert(0, values[2])
            self._course_grade_entry.insert(0, values[3])
            self._course_status.set(values[4])
            self._course_url_entry.insert(0, values[6])
        except Exception:
            pass

    def link_tree(self, event):
        """ Avaa näkymässä olevan linkin verkkoselaimessa, kun käyttäjä tuplaklikkaa linkkiä.

        Args:
            event: bind -metodin mahdollistava parametrisyöte, jotta hiiren tuplaklikkaus kutsuu funktiota.
        """
        select = self._current_courses.focus()
        values = self._current_courses.item(select, "values")

        try:
            url = values[6]
            webbrowser.open('{}'.format(url))
        except Exception:
            pass

    def _display_all_courses(self):
        """ Hakee kaikki käyttäjän kurssit hyödyntämällä sovelluslogiikan
            metodia ja lisää ne _current_courses -olioon.

        Returns:
            None, jos kurssien näkymän päivittäminen sovelluslogiikassa ei onnistnut
        """

        # tyhjennetään treeview ennen kurssien näyttämistä
        for course in self._current_courses.get_children():
            self._current_courses.delete(course)

        courses = course_service.display_all_courses()

        if courses is not None:
            for row in courses:
                self._current_courses.insert(parent="", index="end", text="", values=(
                    row[0], row[1], row[2], row[3], row[4], row[5], row[6]))
        return None

    def _display_statistics(self):
        """ Hakee käyttäjän suorittamien kurssien statistiikkaa ja
            asettaa ne näkyvillä niille varattuihin kenttiin

        """

        completed_courses, credit_amount, gpa = course_service.statistics()

        if completed_courses == 0:
            self._completed_courses_label["text"] = "Completed courses: - "
            self._completed_credits_label["text"] = "Completed credits: - "
            self._average_gpa_label["text"] = "Weighted GPA: - "

        else:
            self._completed_courses_label["text"] = "Completed courses: " + str(
                completed_courses)
            self._completed_credits_label["text"] = "Completed credits: " + str(
                credit_amount)
            self._average_gpa_label["text"] = "Weighted GPA: " + str(gpa)

    def _delete_user(self):
        """ Poistaa käyttäjän sekä kaikki käyttäjän kurssit.
            Metodi varmistaa ennen poistamista käyttäjältä, haluaako tämä todella poistaa tiedot.
            Jos käyttäjä vastaa myöntävästi, tiedot poistetaan, muuten sovellus jatkaa toimintaa normaalisti.

        """
        result = messagebox.askquestion(
            title="Delete User", icon="question", message="Are you sure you want to delete your account? \n\nChoosing 'Yes' will delete your account forever, there is no going back. Please be certain. \n")
        try:
            if result == "yes":
                if course_service.delete_user() is True:
                    course_service.logout_user()
                    self._show_login_view()
            else:
                pass

        except DeleteUserError:
            messagebox.showinfo("Delete user",
                                "Deleting user failed.\n")

    def _initialize_heading(self):
        """ Alustaa näkymän yläosion tekstin ja kirjautuneen käyttäjän esittämisen

        """
        # Heading label, joka kertoo mitä tällä sivulla tehdään
        heading_label = ttk.Label(
            master=self._frame, text="Add new courses and view all of your existing courses!")

        current_user_label = ttk.Label(
            master=self._frame, text=f"Logged in as: {self._user}")

        heading_label.grid(row=0, column=0, columnspan=2,
                           sticky=(constants.W), padx=5, pady=5)

        current_user_label.grid(row=1, column=0, columnspan=2,
                                sticky=(constants.W), padx=5, pady=5)

    def _initialize_treeview(self):
        """ Alustaa käyttäjän tallentamien kurssien tietojen esittämisen ja siihen liittyvän muotoilun.

        """

        # Kurssit lisätään treeview-näkymään
        self._current_courses = ttk.Treeview(master=self._frame)

        # Treeview:n muotoilua
        self._current_courses["columns"] = (
            "ID", "Course Name", "Credits", "Grade", "Status", "Owner", "URL")
        self._current_courses.column("#0", width=0, stretch=constants.NO)
        self._current_courses.column("ID", width=30, stretch=constants.NO)
        self._current_courses.column(
            "Course Name", width=50, stretch=constants.YES)
        self._current_courses.column(
            "Credits", anchor=constants.CENTER, width=30, stretch=constants.YES)
        self._current_courses.column(
            "Grade", anchor=constants.CENTER, width=10, stretch=constants.YES)
        self._current_courses.column(
            "Status", anchor=constants.CENTER, width=40, stretch=constants.YES)
        self._current_courses.column(
            "Owner", anchor=constants.CENTER, width=50, stretch=constants.YES)
        self._current_courses.column(
            "URL", anchor=constants.CENTER, minwidth=200, stretch=constants.YES)

        self._current_courses.heading("#0", text="")
        self._current_courses.heading("ID", text="ID", anchor=constants.CENTER)
        self._current_courses.heading(
            "Course Name", text="Course Name")
        self._current_courses.heading(
            "Credits", text="Credits", anchor=constants.CENTER)
        self._current_courses.heading(
            "Grade", text="Grade", anchor=constants.CENTER)
        self._current_courses.heading(
            "Status", text="Status", anchor=constants.CENTER)
        self._current_courses.heading(
            "Owner", text="Owner", anchor=constants.CENTER)
        self._current_courses.heading(
            "URL", text="URL", anchor=constants.CENTER)

        # Lisätään treeview:n kurssit grid -näkymään
        self._current_courses.grid(row=2, column=0, columnspan=4,
                                   sticky=(constants.EW), padx=5, pady=5)

    def _initialize_course_info(self):
        """ Alustaa kurssitietojen lisäämiseen liittyvät syötekentät ja otsikot

        """

        # Kurssi tietojen esittäminen LabelFrame:ssa
        self._course_info_labels = ttk.LabelFrame(
            master=self._frame, text="Course information")

        course_id_label = ttk.Label(
            master=self._course_info_labels, text="ID")
        self._course_id_entry = ttk.Entry(
            master=self._course_info_labels, state=constants.DISABLED, textvariable=self._course_id)

        course_name_label = ttk.Label(
            master=self._course_info_labels, text="Name")
        self._course_name_entry = ttk.Entry(master=self._course_info_labels)

        course_credit_label = ttk.Label(
            master=self._course_info_labels, text="Credits (0-10)")
        self._course_credit_entry = ttk.Entry(master=self._course_info_labels)

        course_grade_label = ttk.Label(
            master=self._course_info_labels, text="Grade (0-5)")
        self._course_grade_entry = ttk.Entry(master=self._course_info_labels)

        self._course_status.set(OPTIONS[0])

        course_status_label = ttk.Label(
            master=self._course_info_labels, text="Status")
        self._course_status_entry = ttk.OptionMenu(
            self._course_info_labels, self._course_status, *OPTIONS, command=self.callback)

        course_url_label = ttk.Label(
            master=self._course_info_labels, text="URL")
        self._course_url_entry = ttk.Entry(master=self._course_info_labels)

        # Course info -labels
        course_id_label.grid(row=0, column=0, padx=5, pady=2)
        course_name_label.grid(
            row=0, column=1, padx=5, pady=2)
        course_credit_label.grid(
            row=0, column=2, padx=5, pady=2)
        course_grade_label.grid(
            row=0, column=3, padx=5, pady=2)
        course_status_label.grid(
            row=0, column=4, padx=5, pady=2)
        course_url_label.grid(
            row=0, column=5, padx=5, pady=2)

        # Course info -entries
        self._course_id_entry.grid(row=1, column=0, padx=5, pady=2)
        self._course_name_entry.grid(
            row=1, column=1, sticky=(constants.W), padx=5, pady=2)
        self._course_credit_entry.grid(
            row=1, column=2, sticky=(constants.EW), padx=5, pady=2)

        self._course_grade_entry.grid(
            row=1, column=3, sticky=(constants.EW), padx=5, pady=2)
        self._course_status_entry.grid(
            row=1, column=4, sticky=(constants.EW), padx=5, pady=2)

        self._course_url_entry.grid(
            row=1, column=5, sticky=(constants.E), padx=5, pady=2)

        # Lisätään kurssitiedot grid näkymään
        self._course_info_labels.grid(row=3, column=0, columnspan=5,
                                      sticky=(constants.EW), padx=5, pady=5)

    def _initilize_buttons(self):
        """ Alustaa sovelluksen toiminnallisuuksia mahdollistavat painikkeet.

        """

        # Kurssien ja näkymän muokkamispainikkeet
        self._update_course_buttons = ttk.LabelFrame(
            master=self._frame, text="Commands")

        # Style määrittely Button-oliolle
        style = ttk.Style()
        style.configure("REDBUTTON.TButton", foreground="red")

        update_course_button = ttk.Button(
            master=self._update_course_buttons, text="Update course", command=self._update_course_info)

        create_new_course_button = ttk.Button(
            master=self._update_course_buttons, text="Add new course", command=self._create_new_course)

        remove_one_course_button = ttk.Button(
            master=self._update_course_buttons, text="Remove course", command=self._remove_one_course)

        remove_all_courses_button = ttk.Button(
            master=self._update_course_buttons, text="Remove all courses", command=self._remove_all_courses)

        clear_entry_button = ttk.Button(
            master=self._update_course_buttons, text="Clear entry inputs", command=self._clear_entry_input)

        delete_user_button = ttk.Button(
            master=self._update_course_buttons, text="Delete User", style="REDBUTTON.TButton", command=self._delete_user)

        # Takaisin Login-näkymään painike
        back_to_login_view_button = ttk.Button(
            master=self._frame, text="Back to Login", command=self._show_login_view)

        # Tietojen muokkaamisen mahdollistavat painikkeet
        update_course_button.grid(
            row=0, column=0, sticky=(constants.EW), padx=5, pady=5)

        create_new_course_button.grid(
            row=0, column=1, sticky=(constants.EW), padx=5, pady=5)

        remove_one_course_button.grid(
            row=0, column=2, sticky=(constants.EW), padx=5, pady=5)

        remove_all_courses_button.grid(
            row=0, column=3, sticky=(constants.EW), padx=5, pady=5)

        clear_entry_button.grid(
            row=0, column=4, sticky=(constants.E), padx=5, pady=5)

        delete_user_button.grid(
            row=0, column=5, sticky=(constants.E), padx=5, pady=5)

        # Uloskirjautumis painikkeen lisääminen gridiin
        back_to_login_view_button.grid(
            row=6, column=0, columnspan=1, sticky=constants.EW, padx=5, pady=5)

        # lisätään painikkeet grid -näkymään
        self._update_course_buttons.grid(row=4, column=0, columnspan=4,
                                         sticky=(constants.EW), padx=5, pady=5)

    def _initilize_statistics_info(self):
        """ Alustaa käyttäjän suorittamien kurssien statistiikkaan liittyvän esityksen.

        """

        # Statistics tietojen lisääminen
        self._course_statistics_labels = ttk.LabelFrame(
            master=self._frame, text="Course Statistics for 'Completed' courses:")

        self._completed_courses_label = ttk.Label(
            master=self._course_statistics_labels, text="Completed courses: - ", font="bold")

        self._completed_credits_label = ttk.Label(
            master=self._course_statistics_labels, text="Completed credits: - ", font="bold")

        self._average_gpa_label = ttk.Label(
            master=self._course_statistics_labels, text="Weighted GPA: - ", font="bold")

        # Course stats -labels
        self._completed_courses_label.grid(
            row=0, column=0, sticky=(constants.EW), padx=5, pady=5)

        self._completed_credits_label.grid(
            row=0, column=1, sticky=(constants.EW), padx=5, pady=5)

        self._average_gpa_label.grid(
            row=0, column=2, sticky=(constants.E), padx=5, pady=5)

        # Lisätään statistiikka grid -näkymään
        self._course_statistics_labels.grid(
            row=5, column=0, columnspan=3, sticky=(constants.EW), padx=5, pady=5)

    def _initialize(self):
        """ Luo näkymän Frame -olion ja kutsuu siihen liitettävien komponenttien luomiseen käytettävät metodit.

        """

        self._frame = ttk.Frame(master=self._root)

        self._initialize_heading()

        self._initialize_treeview()

        self._initialize_course_info()

        self._initilize_buttons()

        self._initilize_statistics_info()

        # Sarakkeet ottavat kaiken jäljelle jäävän tilan, kun ikkunan kokoa muutetaan
        # yhdessä elementtien sticky-parametrien kanssa
        self._frame.columnconfigure(1, weight=1, minsize=400)
        self._frame.columnconfigure(0, weight=1)

        self._current_courses.bind("<ButtonRelease-1>", self._select_course)
        self._current_courses.bind("<Double-1>", self.link_tree)
Esempio n. 4
0
class Application(tk.Frame):

    def __init__(self, master=None, bg=config.background_color):
        super().__init__(master)
        self.master = master
        self.master.configure(background="#1E1E1E")
        self.pack()
        self.create_widgets()
        self.limit_check()

    def create_fonts(self):
        self.font = tkFont.Font(family=config.font, weight=config.font_weight, size=config.font_size)
        self.font_large = tkFont.Font(family=config.font, weight=config.font_weight, size=round(config.font_size * 1.5))
        self.font_small = tkFont.Font(family=config.font, weight=config.font_weight, size=round(config.font_size * .66))

    def create_variables(self):
        # Set up StringVars that will be used.
        self.ticker_value = StringVar()
        self.account_value_text = StringVar()
        self.account_value_text.set(str(account_value))
        self.last_price_value = StringVar()
        self.current_position_value = StringVar()
        self.current_position_pnl = StringVar()
        self.account_value_pnl = StringVar()
        self.limit_price = StringVar()
        self.order_type = StringVar(None, 'market')

    # Create tkinter widgets.
    def create_widgets(self):
        self.create_fonts()
        self.create_variables()

        # Global is_playing as it is used as a boolean and StringVar
        global is_playing
        is_playing = StringVar()
        is_playing.set("▶")

        # Create Ticker Label for Ticker
        self.ticker_id = tk.Label(
            self,
            textvariable=self.ticker_value,
            fg=config.color_white,
            bg=config.background_color,
            font=self.font_large
        ).grid(row=0, column=0, columnspan=4, padx=33, sticky="nsew")

        # Create a label to show the last price
        self.last_price_label = tk.Label(
            self,
            textvariable=self.last_price_value,
            bg=config.background_color,
            fg=config.color_white,
            font=self.font_large
        ).grid(row=1, column=0, columnspan=4, sticky="nsew")

        # Create a button to start the reply
        self.play_button = tk.Button(
            self,
            textvariable=is_playing,
            bg=config.button_color_light,
            fg=config.color_grey,
            borderwidth=0
        )

        self.play_button["command"] = self.play_replay
        self.play_button.grid(row=2, column=0, columnspan=2, sticky="nsew")

        # Create a button for progressing to next bar
        self.next_button = tk.Button(self, text="▮▶", bg=config.button_color_light, fg=config.color_grey, borderwidth=0)
        self.next_button["command"] = self.next_bar
        self.next_button.grid(row=2, column=2, columnspan=2, sticky="nsew")

        # Create a button for long orders
        self.long_button = tk.Button(
            self,
            text="BUY",
            font=self.font,
            bg=config.button_color,
            fg=config.color_green,
            borderwidth=0
        )
        self.long_button["command"] = self.order_buy
        self.long_button.grid(row=3, column=0, columnspan=2, sticky="nsew")

        # Create a button for short orders
        self.short_button = tk.Button(
            self,
            text="SELL",
            font=self.font,
            bg=config.button_color,
            fg=config.color_red,
            borderwidth=0
        )
        self.short_button["command"] = self.order_sell
        self.short_button.grid(row=3, column=2, columnspan=2, sticky="nsew")

        # Create radio buttons to toggle between limit orders and market orders
        self.limit_radiobutton = tk.Radiobutton(
            self,
            bg=config.background_color,
            fg=config.color_dark_grey,
            selectcolor=config.background_color,
            text="LIMIT",
            variable=self.order_type,
            value="limit"
        )
        self.limit_radiobutton.grid(row=4, column=0, columnspan=2, sticky="nsew")

        self.market_radiobutton = tk.Radiobutton(
            self,
            bg=config.background_color,
            fg=config.color_dark_grey,
            selectcolor=config.background_color,
            text="MARKET",
            variable=self.order_type,
            value="market",
        ).grid(row=4, column=2, columnspan=2, sticky="nsew")

        # Create entry box for limit orders
        self.limit_price = tk.Entry(
            self,
            borderwidth=0,
            bg=config.button_color_light,
            fg=config.color_grey)
        self.limit_price.insert(0, " ")
        self.limit_price.grid(row=5, column=0, columnspan=3, sticky="nsew", padx=5)

        self.limit_copy_button = tk.Button(
            self,
            text="LAST",
            borderwidth=0,
            bg=config.button_color,
            fg=config.color_grey,
            font=self.font_small
        )
        self.limit_copy_button["command"] = self.copy_last
        self.limit_copy_button.grid(row=5, column=3, columnspan=1, sticky="nsew")

        self.current_position_label = tk.Label(
            self,
            text="Current Position",
            anchor="w",
            bg=config.background_color,
            fg=config.color_grey, font=self.font_small
        ).grid(row=6, column=0, columnspan=4, sticky="nsew")

        self.current_position_value_label = tk.Label(
            self,
            textvariable=self.current_position_value,
            anchor="w",
            bg=config.button_color_light,
            fg=config.color_dark_grey
        ).grid(row=7, column=0, columnspan=3, sticky="nsew")

        self.current_position_pnl_label = tk.Label(
            self,
            textvariable=self.current_position_pnl,
            anchor="e",
            bg=config.button_color_light,
            fg=config.color_dark_grey
        ).grid(row=7, column=3, columnspan=1, sticky="nsew")

        self.account_value_label = tk.Label(
            self,
            text="Account value",
            anchor="w",
            bg=config.background_color,
            fg=config.color_grey,
            font=self.font_small
        ).grid(row=8, column=0, columnspan=4, sticky="nsew")

        self.account_value_value_label = tk.Label(
            self,
            textvariable=self.account_value_text,
            bg=config.button_color_light,
            fg=config.color_white,
            anchor="w"
        ).grid(row=9, column=0, columnspan=3, sticky="nsew")

        self.account_value_pnl_label = tk.Label(
            self,
            textvariable=self.account_value_pnl,
            bg=config.button_color_light,
            fg=config.color_dark_grey,
            anchor="e"
        ).grid(row=9, column=3, columnspan=1, sticky="nsew")

        self.trade_history_label = tk.Label(
            self,
            text="Trades",
            anchor="w",
            bg=config.background_color,
            fg=config.color_grey,
            font=self.font_small
        ).grid(row=10, column=0, columnspan=3, sticky="nsew")

        self.trade_history_clear = tk.Button(
            self,
            text="Clear",
            bg=config.button_color,
            fg=config.color_grey,
            font=self.font_small,
            borderwidth=0
        )
        self.trade_history_clear.grid(row=10, column=3, columnspan=1, sticky="nsew")
        self.trade_history_clear['command'] = self.clear_list

        self.trade_history_list = tk.Listbox(
            self,
            fg=config.color_grey,
            bg=config.textarea_color,
            borderwidth=0)
        self.trade_history_list.grid(row=11, column=0, columnspan=4, sticky="nsew")

    # Write Timestamp to csv file
    write([time.strftime("%Y-%m-%d %H:%M")])

    # Start of Functions
    def message_box(self):
        messagebox.showinfo('Error', 'Sorry! Limit orders are not currently implemented.\n'
                                     'You can check progress here:\n'
                                     'https://github.com/Robswc/tradingview-trainer/issues/5')
        self.order_type.set('market')

    # Generic function to show error
    def show_error(self, cause, exception, message):
        messagebox.showerror(str(cause), str(str(exception) + '\n' + message))
        driver.get("https://github.com/Robswc/tradingview-trainer/wiki/Errors")

    def clear_list(self):
        clear_csv()
        self.update_labels()

    def get_ticker(self):
        #ticker = driver.find_element_by_xpath(
        #    '/html/body/div[1]/div[1]/div[3]/div[1]/div/table/tr[1]/td[2]/div/div[3]/div[1]/span[2]/div/div[1]/div'
        #).text
        ticker = driver.find_element_by_xpath(
            '/html/body/div[1]/div[1]/div[3]/div[1]/div/table/tr[1]/td[2]/div/div[3]/div[1]/span[2]/div/div[1]'
        ).text
        ticker = str(ticker).split(' ')

        print(ticker[0])
        return str(ticker[0])

    def get_price_data(self, request):
        try:
            if request == 'o':
                return float(driver.find_element_by_xpath(
                    '/html/body/div[1]/div[1]/div[3]/div[1]/div/table/tr[1]/td[2]/div/div[3]/div[1]/div/span[1]/span[2]'
                ).text)

            if request == 'h':
                return float(driver.find_element_by_xpath(
                    '/html/body/div[1]/div[1]/div[3]/div[1]/div/table/tr[1]/td[2]/div/div[3]/div[1]/div/span[2]/span[2]'
                ).text)

            if request == 'l':
                return float(driver.find_element_by_xpath(
                    '/html/body/div[1]/div[1]/div[3]/div[1]/div/table/tr[1]/td[2]/div/div[3]/div[1]/div/span[3]/span[2]'
                ).text)

            if request == 'c':
                return float(driver.find_element_by_xpath(
                    '/html/body/div[1]/div[1]/div[3]/div[1]/div/table/tr[1]/td[2]/div/div[3]/div[1]/div/span[4]/span[2]'
                ).text)
        except:
            return 0

    def get_limit_price(self):
        self.limit_price.get()

    def get_position_pnl(self):
        if get_position()['quantity'] < 0:
            pnl_percent = ((get_position()['entry'] - self.get_last_price()) / get_position()['entry']) * 100
        if get_position()['quantity'] > 0:
            pnl_percent = ((self.get_last_price() - get_position()['entry']) / self.get_last_price()) * 100

        try:
            return round(pnl_percent, 2)
        except:
            return 0

    # Doesn't seem to work :(
    def add_marker(self):
        pass
        # actions = ActionChains(driver)
        # element = driver.find_element_by_xpath('/html/body/div[1]/div[1]/div[3]/div[1]/div/table/tr[1]')
        # element.click()
        # actions.click(element).key_down(Keys.ALT, 'v').perform()

    def update_labels(self):

        # update all labels via tk StringVar()
        self.last_price_value.set(str(self.get_last_price()))
        self.current_position_pnl.set(str(self.get_position_pnl()) + '%')
        self.account_value_pnl.set(str(round(percent_change(get_account_value(), float(config.initial_amount)), 2)) + '%')
        self.current_position_value.set(str(get_position()['quantity']) + " @ " + str(get_position()['entry']))
        self.account_value_text.set(locale.currency(get_account_value(), grouping=True))
        self.ticker_value.set(self.get_ticker())

        # Update trade history box
        self.trade_history_list.delete(0, 'end')
        for trade in read_all():
            self.trade_history_list.insert(0, trade)

    # get last price via xpath
    def get_last_price(self):
        try:
            last_price = driver.find_element_by_xpath(
                '/html/body/div[1]/div[1]/div[3]/div[1]/div/table/tr[1]/td[2]/div/div[3]/div[1]/div/span[4]/span[2]'
            ).text
            return float(last_price)
        except:
            try:
                last_price = driver.find_element_by_xpath(config.custom_xpath_last_price).text
                return float(last_price)
            except Exception as error:
                self.show_error('last_value', str(error), 'Please report error here: ')


    # function to pass buy order to order engine.
    def order_buy(self):
        oe = OrderEngine
        if self.order_type.get() == 'market':
            oe.market(OrderEngine, round(get_account_value(), 2), self.get_last_price())
        if self.order_type.get() == 'limit':
            print('LIMIT BIMIT ORDER HEHEH')
            oe.limit(OrderEngine, round(get_account_value(), 2), float(self.limit_price.get()), self.get_last_price())
        self.update_labels()

    # function to pass sell order to order engine.
    def order_sell(self):
        oe = OrderEngine
        if self.order_type.get() == 'market':
            print(type(get_account_value()), type(self.get_last_price()))
            oe.market(OrderEngine, round(get_account_value(), 2) * -1, float(self.get_last_price()))
        if self.order_type.get() == 'limit':
            oe.limit(OrderEngine, get_account_value() * -1, float(self.limit_price.get()), self.get_last_price())
        self.update_labels()

    # Check with the order engine to see if there is a limit order.
    def limit_check(self):
        oe = OrderEngine
        oe.on_tick(OrderEngine,
                   self.get_price_data('o'),
                   self.get_price_data('h'),
                   self.get_price_data('l'),
                   self.get_price_data('c')
                   )
        global is_playing
        print(str(is_playing.get()))

        if str(is_playing.get()) == "▮▮":
            print(str(is_playing.get()))
            self.after(500, self.limit_check)

    # Function to auto-fill last price into limit price.
    def copy_last(self):
        self.limit_price.delete(0, "end")
        self.limit_price.insert(0, self.last_price_value.get())

    # Click next bar w/selenium, use functions to grab values.
    def next_bar(self):
        print(self.limit_price.get())
        global is_playing
        try:
            driver.find_element_by_xpath('/html/body/div[7]/div/div[2]/div[3]/div').click()
        except:
            try:
                driver.find_element_by_xpath(config.custom_xpath_replay).click()
            except:
                self.show_error('next_bar', 'xpath error', 'Please report error here: ')

        is_playing.set("▶")
        self.limit_check()
        self.update_labels()
        print('>>')

    # Function to click the play-replay with selenium, check for limit orders.
    def play_replay(self):
        global is_playing
        self.update_labels()
        try:
            driver.find_element_by_xpath('/html/body/div[9]/div/div[2]/div[2]/div').click()
        except Exception:
            driver.find_element_by_xpath(config.custom_xpath_play_replay).click()
        print(str(is_playing.get()))
        if str(is_playing.get()) == "▶":
            is_playing.set("▮▮")
            print(str(is_playing))
            self.limit_check()
        else:
            is_playing.set("▶")
            print(str(is_playing))
Esempio n. 5
0
        pady=pady,
        sticky='n'
    )

    txt_history = Text(
        frm_R,
        font=font,
        state='normal',
        width=31,
        height=15
    )
    scrollb = Scrollbar(frm_R)
    scrollb.config(command=txt_history.yview)
    txt_history.config(yscrollcommand=scrollb.set)
    scrollb.grid(row=1, column=1, pady=pady, sticky='nsew')
    txt_history.grid(row=1, column=0, pady=pady, sticky='nsew')

    btn_clear_history = Button(
        frm_R,
        text='Clear history',
        command=lambda: txt_history.delete('1.0', END)
    )
    btn_clear_history.grid(
        row=2,
        column=0,
        columnspan=2,
        padx=padx,
        pady=pady,
        sticky='nsew'
    )
    # END: Content of the frm_R frame.