def display(self,list_): self.displayFrame.destroy() self.displayFrame=ScrollableFrame(self.frame) self.displayFrame.grid(row=3,column=0,columnspan=2,sticky="nsew",padx=10,pady=10) # print(list_) Label(self.displayFrame.frame,text='Sl. no.',relief=GROOVE).grid(row=0,column=0,sticky=E+W,padx=2) Label(self.displayFrame.frame,text='Item Name',relief=GROOVE).grid(row=0,column=1,sticky=E+W,padx=2) Label(self.displayFrame.frame,text='Location',relief=GROOVE).grid(row=0,column=2,sticky=E+W,padx=2) Label(self.displayFrame.frame,text='Quanitity',relief=GROOVE).grid(row=0,column=3,sticky=E+W,padx=2) Label(self.displayFrame.frame,text='Type',relief=GROOVE).grid(row=0,column=4,sticky=E+W,padx=2) for i in range(len(list_)): itemSerial = Label(self.displayFrame.frame, anchor=W, text=i+1) itemName = Label(self.displayFrame.frame,wraplength=400, anchor=W, text=list_[i][0]) itemLocation = Label(self.displayFrame.frame, anchor=W, text=list_[i][1]) itemQuantity= Label(self.displayFrame.frame, anchor=W, text=list_[i][2]) itemType= Label(self.displayFrame.frame, anchor=W, text=list_[i][3]) itemSerial.grid(row=i+1, column=0, sticky=W+E,padx=2,pady=1) itemName.grid(row=i+1, column=1, sticky=W+E,padx=2,pady=1) itemLocation.grid(row=i+1,column=2,sticky=W+E,padx=2,pady=1) itemQuantity.grid(row=i+1,column=3,sticky=W+E,padx=2,pady=1) itemType.grid(row=i+1,column=4,sticky=W+E,padx=2,pady=1) # studentRollAndName.bind('<Button-1>', self.bindingAction) self.displayFrame.frame.columnconfigure(1,weight=1)
def __init__(self, parentFrame, width, height): Tkinter.Frame.__init__(self, parentFrame, width=width, height=height) optionsFrame = Tkinter.Frame(self, height=50) optionsFrame.grid(column=0, row=0) # Add a drop-down box to add more searches self.addSearchWidgetFrame = Tkinter.Frame(optionsFrame) Tkinter.Label(self.addSearchWidgetFrame, text="Add search field:").grid(column=0, row=0) self.addSearchWidgetComboboxValue = Tkinter.StringVar() addSearchWidgetCombobox = ttk.Combobox( self.addSearchWidgetFrame, state='readonly', values=sorted(self.nameToType.keys()), textvariable=self.addSearchWidgetComboboxValue) addSearchWidgetCombobox.grid(column=1, row=0) self.addSearchWidgetFrame.grid(column=0, row=0, sticky=Tkinter.E) # React when an option is chosen addSearchWidgetCombobox.bind( '<<ComboboxSelected>>', lambda *args: self.addSearchWidget( self.addSearchWidgetComboboxValue.get())) self.searchParametersFrame = ScrollableFrame(self, width=width, height=height - 50) self.searchParametersFrame.grid(column=0, row=1) # Start out with the most common search fields already shown for field in ('Name', 'CMC', 'Text'): self.addSearchWidget(field, False) # Give the first widget created the focus, since that makes the most sense self.searchWidgets[0].takeFocus()
def bindingAction(self, event): popupCourse = Tk() popupCourse.eval('tk::PlaceWindow . center') popupCourse.config(bg='white') popupCourse.geometry("430x460") popupCourse.minsize(430, 460) popupCourse.maxsize(430, 460) rollAndName = event.widget.cget('text') roll = rollAndName.split(' ') popupCourse.title("Register courses for " + roll[0]) roll = roll[0] courses = StudentCourses.getcourses(roll) entryframe = Frame(popupCourse) entryframe.grid(row=0, column=0) tex = Label(entryframe, text="Enter Semester", padx=5, bg='white', pady=20) tex.grid(row=0, column=0) sem = Entry(entryframe) entryframe.configure(bg='white') sem.grid(row=0, column=1) courseframe = ScrollableFrame(popupCourse) buttons = [] Label(courseframe.frame, text="Code", padx=10, borderwidth=1, relief='solid').grid(row=0, column=0, sticky=W+E) Label(courseframe.frame, text="Course Name", anchor=W, padx=20, borderwidth=1, relief='solid').grid(row=0, column=1, sticky=W+E) Label(courseframe.frame, text="Credits", anchor=W, padx=10, borderwidth=1, relief='solid').grid(row=0, column=2, sticky=W+E) Label(courseframe.frame, text=" ", anchor=W, padx=10, borderwidth=1, relief='solid').grid(row=0, column=3, sticky=W+E) for i in range(len(courses)): Label(courseframe.frame, text=courses[i][0], padx=10).grid(row=i+1, column=0) Label(courseframe.frame, text=courses[i][1], anchor=W, padx=20).grid(row=i+1, column=1, sticky=W+E) Label(courseframe.frame, text=courses[i][3], padx=10).grid(row=i+1, column=2, sticky=W+E) buttons.append(ttk.Checkbutton(courseframe.frame, takefocus=0, var = IntVar(0))) buttons[i].grid(row=i+1, column=3, sticky=E+W) buttons[i].state(['!alternate']) courseframe.grid(row=1, column=0) submitbutton = ttk.Button(master=popupCourse, text='Submit', command= lambda : self.formsubmit(buttons, sem, courses, roll, popupCourse)) submitbutton.config(padding = [5,5,5,5]) submitbutton.grid(row=4, column=0, columnspan=1) popupCourse.columnconfigure(0, weight=1) # Serial Name of Course popupCourse.columnconfigure(1, weight=2) # Name of Course popupCourse.columnconfigure(2, weight=1) # Credits of the Course popupCourse.columnconfigure(3, weight=1)
def __init__(self,root): root.title("Department Inventory") root.geometry('800x600') root.minsize(800, 600) root.maxsize(800, 600) self.frame=Frame(root) self.frame.grid(row=0, column=0, sticky='nsew') self.itemnameLabel=Label(self.frame,text="Item Name: ",anchor=E) self.itemnameEntry=Entry(self.frame,borderwidth=0,width=27) self.itemtypeLabel=Label(self.frame,text="Type: ",anchor=E) self.combostyle=ttk.Style() self.combostyle.map('TCombobox', fieldbackground=[('readonly', 'white')]) self.combostyle.map('TCombobox', selectbackground=[('readonly', 'white')]) # self.combostyle. self.var=StringVar(self.frame) self.var.set("All") self.typeDropdown = ttk.Combobox(self.frame,foreground="black",width=27,takefocus=False,textvariable=self.var,state='readonly') self.typeDropdown['value']=('All', 'Miscellaneous', 'Computers', 'Furniture', 'Stationery') self.typeDropdown.bind("<FocusIn>", dropdown_defocus) self.submitButton=Button(self.frame,text='Search',command=lambda:self.search()) self.addButton=Button(self.frame,text='Purchase New Item',command=lambda:self.add(root)) self.displayFrame=ScrollableFrame(self.frame) self.backButton=Button(self.frame,text="Back",command=lambda: self.back(root)) self.exitButton=Button(self.frame,text="Exit",command=exit) self.itemnameLabel.grid(row=0,column=0,sticky=E+W,pady=10,padx=10) self.itemnameEntry.grid(row=0,column=1,sticky=W,pady=10) self.itemtypeLabel.grid(row=1,column=0,sticky=E+W,pady=10,padx=10) self.typeDropdown.grid(row=1,column=1,sticky=W,pady=10) self.submitButton.grid(row=2,column=0,sticky=E,pady=10,padx=10) self.addButton.grid(row=2,column=1,sticky=W,pady=10,padx=10) self.displayFrame.grid(row=3,column=0,columnspan=2,sticky="nsew",padx=10,pady=10) self.exitButton.grid(row=4,column=0,columnspan=2,sticky=W,padx=50,pady=20) self.backButton.grid(row=4,column=1,columnspan=2,sticky=E,padx=50,pady=20) for i in range(2): self.frame.columnconfigure(i,weight=1) self.frame.rowconfigure(3,weight=1)
def show_pictures(images_paths, title): win = tk.Toplevel() win.wm_title("Pictures") win.configure(bg=BACKGROUND_COLOR) win.attributes("-fullscreen", True) frame = tk.Frame(win, bg=BACKGROUND_COLOR) new_title(frame, title) frame.pack() # Menu bar menu_bar = tk.Menu(win) menu_bar.add_command(label="Close", command=win.destroy) win.configure(menu=menu_bar) # 80% of the screen's height scale = 0.8 scrollable_frame = ScrollableFrame(win, win.winfo_screenheight()*scale, IMAGE_MAX_SIZE, 3, 30, 30, BACKGROUND_COLOR) scrollable_frame.fill_data(images_paths, command_bind_on_click=show_full_picture)
def display_courses(self, root, list_): self.displayFrame.destroy() self.displayFrame = Frame(self.frame) self.displayScrollframe = ScrollableFrame(self.displayFrame) self.displayScrollframe.grid(column=0, row=0, sticky="nsew") self.displayFrame.grid(row=5, column=0, columnspan=2) self.displayScrollframe.frame.columnconfigure(1, weight=1) for i in range(len(list_)): courseserialLabel = Label(self.displayScrollframe.frame, anchor=W, text=i + 1) courserollnameLabel = Label(self.displayScrollframe.frame, anchor=W, text=list_[i][0] + ' ' + list_[i][1]) courseserialLabel.grid(row=i, column=0, sticky=W + E, padx=5) courserollnameLabel.grid(row=i, column=1, sticky=W + E)
def display(self, root, list_): self.searchResults.destroy() self.searchResults = ScrollableFrame(self.frame) self.searchResults.grid(row=5, column=0, padx=30, sticky="nsew", columnspan=2) self.searchResults.frame.columnconfigure(1, weight=1) for i in range(len(list_)): studentSerial = Label(self.searchResults.frame, anchor=W, text=i + 1) studentRollAndName = Label(self.searchResults.frame, anchor=W, text=list_[i][0] + ' ' + list_[i][1]) studentSerial.grid(row=i, column=0, sticky=W + E, padx=5) studentRollAndName.grid(row=i, column=1, sticky=W + E) studentRollAndName.bind('<Button-1>', self.bindingAction)
def __init__(self, root): self.frame = Frame(root) self.frame.grid(row=0, column=0, sticky='nsew') self.newButton = Button(self.frame, text="Add...", command=lambda: self.new(root)) self.displayAll = ScrollableFrame(self.frame) self.exitButton = Button(self.frame, text="Exit", command=exit) self.backButton = Button(self.frame, text="Back", command=lambda: self.back(root)) self.newButton.grid(row=1, column=0, padx=50, pady=50, columnspan=2) self.displayAll.grid(row=2, column=0, columnspan=2) self.exitButton.grid(row=3, column=0, padx=50, pady=50, sticky=S + W) self.backButton.grid(row=3, column=0, padx=50, pady=50, sticky=S + E) self.frame.columnconfigure(0, weight=1)
def display(self): self.displayAll.destroy() self.displayAll = ScrollableFrame(self.frame) self.displayAll.grid(row=0, column=0, padx=30, sticky=N+S+E+W) connect_, cursor_ = ES.get_student_db_ES() cursor_.execute('SELECT * FROM publications') allPublications = cursor_.fetchall() Label(self.displayAll.frame, text='Sr. No.', relief=GROOVE).grid(row=0, column=0, sticky=E+W) Label(self.displayAll.frame, text='Author', relief=GROOVE).grid(row=0, column=1, sticky=E+W) Label(self.displayAll.frame, text='Name', relief=GROOVE).grid(row=0, column=2, sticky=E+W) Label(self.displayAll.frame, text='Date', relief=GROOVE).grid(row=0, column=3, sticky=E+W) for i in range(len(allPublications)): Label(self.displayAll.frame, anchor=W, text=i+1).grid(row=i+1, column=0, sticky=E+W, padx=2, pady=2) Label(self.displayAll.frame, anchor=W, text=allPublications[i][0]).grid(row=i+1, column=1, sticky=E+W, padx=2, pady=2) publicationName = Label(self.displayAll.frame, anchor=W, text=allPublications[i][1]) publicationName.grid(row=i+1, column=2, sticky=E+W, padx=2, pady=2) Label(self.displayAll.frame, anchor=W, text=allPublications[i][2]).grid(row=i+1, column=3, sticky=E+W, padx=2, pady=2) publicationName.bind('<Button-1>', self.bindingAction) self.displayAll.frame.columnconfigure(2, weight=2) self.displayAll.frame.columnconfigure(1, weight=1)
def __init__(self, root): self.frame = Frame(root) self.frame.grid(row=0, column=0, sticky='nsew') self.nameLabel = Label(self.frame, text='Name', fg="black") self.nameEntry = Entry(self.frame, borderwidth=0) self.rollLabel = Label(self.frame, text='Roll No', fg="black") self.rollEntry = Entry(self.frame, borderwidth=0) self.searchButton = Button(self.frame, text='Search', command=lambda: self.search(root)) self.searchResults = ScrollableFrame(self.frame) self.nameLabel.grid(row=2, column=0, padx=5, pady=3) self.nameEntry.grid(row=2, column=1) self.rollLabel.grid(row=3, column=0, padx=5, pady=3) self.rollEntry.grid(row=3, column=1) self.exitButton = Button(self.frame, text="Exit", command=exit) self.backButton = Button(self.frame, text="Back", command=lambda: self.back(root)) self.searchButton.grid(row=4, column=0, columnspan=2, pady=20) self.searchResults.grid(row=5, column=0, padx=30, sticky="nsew", columnspan=2) self.exitButton.grid(row=8, column=0, padx=50, pady=50, sticky=S + W) self.backButton.grid(row=8, column=1, padx=50, pady=50, sticky=S + E) self.frame.rowconfigure(8, weight=1) self.frame.columnconfigure(0, weight=1) self.frame.columnconfigure(1, weight=1) root.mainloop()
def __init__(self, parent): self.container = tk.Frame(parent) # Create four scrollable frames and add them to the container self.SF1 = ScrollableFrame(self.container) self.SF1.grid(row=0, column=0, sticky=tk.N + tk.E + tk.S + tk.W) self.SF2 = ScrollableFrame(self.container, direction='both', scroll_sensitivity=8, bg='green', cursor='heart') self.SF2.grid(row=1, column=0, sticky=tk.N + tk.E + tk.S + tk.W) self.SF3 = ScrollableFrame(self.container, direction='vertical', bg='red', cursor='circle') self.SF3.grid(row=0, column=1, sticky=tk.N + tk.E + tk.S + tk.W) self.SF4 = ScrollableFrame(self.container, direction='horizontal', bg='blue', cursor='cross') self.SF4.grid(row=1, column=1, sticky=tk.N + tk.E + tk.S + tk.W) # Configure all rows and columns present to have the same weight (so they expand with the window) tk.Grid.columnconfigure(parent, 0, weight=1) tk.Grid.rowconfigure(parent, 0, weight=1) tk.Grid.columnconfigure(self.container, 0, weight=1) tk.Grid.columnconfigure(self.container, 1, weight=1) tk.Grid.rowconfigure(self.container, 0, weight=1) tk.Grid.rowconfigure(self.container, 1, weight=1) # Fill each frame with a grid of labels self.lots_of_labels(self.SF1.frame, 'default SF', (20, 20)) self.lots_of_labels(self.SF2.frame, 'green, fast scroll', (40, 10)) self.lots_of_labels(self.SF3.frame, 'red vertical', (20, 4)) self.lots_of_labels(self.SF4.frame, 'blue horizontal', (4, 20)) # Add the frame self.container.grid(row=0, column=0, sticky=tk.N + tk.E + tk.S + tk.W) # Add a button to demonstrate the set_direction method and direction attribute of SF tk.Button(text='change directions', font=('Times', 15, 'bold'), command=self.change_dir).grid(row=2, column=0)
class DepartmentResearch: def __init__(self, root): self.frame = Frame(root) self.frame.grid(row=0, column=0, sticky='nsew') self.newButton = Button(self.frame, text="Add...", command=lambda: self.new(root)) self.displayAll = ScrollableFrame(self.frame) self.exitButton = Button(self.frame, text="Exit", command=exit) self.backButton = Button(self.frame, text="Back", command=lambda: self.back(root)) self.newButton.grid(row=1, column=0, padx=50, pady=50, columnspan=2) self.displayAll.grid(row=2, column=0, columnspan=2) self.exitButton.grid(row=3, column=0, padx=50, pady=50, sticky=S + W) self.backButton.grid(row=3, column=0, padx=50, pady=50, sticky=S + E) self.frame.columnconfigure(0, weight=1) def bindingAction(self, event): pass def new(self, root): pass def back(self, root): self.clear() root.maxsize(1200, 900) DepartmentAcademic.DepartmentAcademic(root) def clear(self): self.frame.destroy()
def __init__(self, root): root.title('Academics - Courses') root.geometry('800x600') root.maxsize(800, 600) root.minsize(800, 600) self.frame = Frame(root) self.frame.grid(row=0, column=0, sticky='nsew') self.courseLabel = Label(self.frame, text='Course Name', fg="black") self.courseEntry = Entry(self.frame, borderwidth=0) self.submitButton = Button(self.frame, text='Search', command=lambda: self.search(root)) self.addcoursesButton = Button(self.frame, text='Add Courses', command=lambda: self.add(root)) self.displayFrame = ScrollableFrame(self.frame) self.courseLabel.grid(row=2, column=0, padx=5, pady=3) self.courseEntry.grid(row=2, column=1) self.exitButton = Button(self.frame, text="Exit", command=exit) self.backButton = Button(self.frame, text="Back", command=lambda: self.back(root)) self.submitButton.grid(row=3, column=0, columnspan=2, pady=20) self.addcoursesButton.grid(row=6, column=0, columnspan=2, pady=20) self.displayFrame.grid(row=4, column=0, columnspan=2) self.exitButton.grid(row=8, column=0, pady=10, padx=50, sticky=S + W) self.backButton.grid(row=8, column=1, pady=10, padx=50, sticky=S + E) self.frame.rowconfigure(8, weight=1) self.frame.columnconfigure(0, weight=1) self.frame.columnconfigure(1, weight=1) root.mainloop()
def __init__(self, parentFrame, width, height): Tkinter.Frame.__init__(self, parentFrame, width=width, height=height) # Show the message here instead of at the import statement, to give the Statusbar time to initialize if PILerrorMessage: GlobalValues.statusbar.addMessage(PILerrorMessage) # TODO: Maybe move the 'add card to deck/sideboard' buttons to the SearchResultsFrame? And the '+/-/x' buttons to the ChosenCardsFrame? # They kind of make more sense there, since they interact with those fields # Or maybe even move the 'add card' buttons to the ChosenCardsFrame too, since that's where they'd be added anyway # TODO: Occasional update checks to see if images got updated # This could be done by storing the version number of mtgimage.com, and when that changes, retrieve the changelog # Then, search the latest change(s) for setnames, and deleting the whole folder, forcing the images to be redownloaded # TODO: Display variation art of cards in same set # Some sets have multiple of the same card but with different art (Mostly lands, most sets have 4 different land arts per land type) # The multiverseIDs of the other cards is stored in the 'variations' set field self.cardDataFrame = ScrollableFrame(self, width=width, height=height) self.cardDataFrame.grid(column=0, row=1, columnspan=2, rowspan=2, sticky=Tkinter.N) for rowcount, field in enumerate(self.fieldOrder): displayname = self.fieldDisplayname[field] if field in self.fieldDisplayname else "{}:".format(field.capitalize()) namelabel = Tkinter.Label(self.cardDataFrame.innerFrame, text=displayname, anchor=Tkinter.NE) # Add and remove the label, so the 'sticky' part stays set #namelabel.grid(column=0, row=rowcount, sticky=Tkinter.NE) #namelabel.grid_remove() valuelabel = Tkinter.Label(self.cardDataFrame.innerFrame, text='', width=70, wraplength=375, justify=Tkinter.LEFT, anchor=Tkinter.W) self.fieldToLabel[field] = namelabel, valuelabel self.setSelectionCombobox = ttk.Combobox(self.cardDataFrame.innerFrame, state='readonly', width=50) self.setSelectionCombobox.bind('<<ComboboxSelected>>', lambda arg: self.setDisplayedSet(self.setSelectionCombobox.get())) self.setSelectionCombobox.label = Tkinter.Label(self.cardDataFrame.innerFrame, anchor=Tkinter.NE, text="Display Set:") self.cardImageLabel = Tkinter.Label(self.cardDataFrame.innerFrame) self.cardImageLabel.grid(column=0, row=100, columnspan=2, sticky=Tkinter.NW, padx=width/10)
def __init__(self, parentFrame, width, height): Tkinter.Frame.__init__(self, parentFrame, width=width, height=height) optionsFrame = Tkinter.Frame(self, height=50) optionsFrame.grid(column=0, row=0) # Add a drop-down box to add more searches self.addSearchWidgetFrame = Tkinter.Frame(optionsFrame) Tkinter.Label(self.addSearchWidgetFrame, text="Add search field:").grid(column=0, row=0) self.addSearchWidgetComboboxValue = Tkinter.StringVar() addSearchWidgetCombobox = ttk.Combobox(self.addSearchWidgetFrame, state='readonly', values=sorted(self.nameToType.keys()), textvariable=self.addSearchWidgetComboboxValue) addSearchWidgetCombobox.grid(column=1, row=0) self.addSearchWidgetFrame.grid(column=0, row=0, sticky=Tkinter.E) # React when an option is chosen addSearchWidgetCombobox.bind('<<ComboboxSelected>>', lambda *args: self.addSearchWidget(self.addSearchWidgetComboboxValue.get())) self.searchParametersFrame = ScrollableFrame(self, width=width, height=height-50) self.searchParametersFrame.grid(column=0, row=1) # Start out with the most common search fields already shown for field in ('Name', 'CMC', 'Text'): self.addSearchWidget(field, False) # Give the first widget created the focus, since that makes the most sense self.searchWidgets[0].takeFocus()
class SearchEntryFrame(Tkinter.Frame): # TODO: Group search fields for the same variable, add option to choose to OR or AND them # TODO: Allow saving of search layout, so if somebody always wants, say, 3 CMC fields, they don't have to add those each time, but just load their preset # TODO: Create a Combobox Search Widget, which gets a list of options to choose from (f.i. the Color field only has 5 options, a text search doesn't make sense) # Fields for which this makes sense: Color, Type (perhaps, build list from availabe types?), Layout, Rarity, Set?, # TODO: Think up a dictionary search widget, to search for format legalities searchWidgets = [] nameToType = {'Artist': SetStringSearchWidget, 'CMC': NumberSearchWidget, 'Colors': StringSearchWidget, 'Flavor': SetStringSearchWidget, 'Layout': StringSearchWidget, 'Loyalty': NumberSearchWidget, 'Manacost': StringSearchWidget, 'Number': SetStringSearchWidget, 'MultiverseID': SetNumberSearchWidget, 'Name': StringSearchWidget, 'Power': NumberSearchWidget, 'Rarity': SetStringSearchWidget, 'Set': SetnameSearchWidget, 'Text': StringSearchWidget, 'Toughness': NumberSearchWidget, 'Type': StringSearchWidget, 'Watermark': StringSearchWidget} updateFunctionId = None def __init__(self, parentFrame, width, height): Tkinter.Frame.__init__(self, parentFrame, width=width, height=height) optionsFrame = Tkinter.Frame(self, height=50) optionsFrame.grid(column=0, row=0) # Add a drop-down box to add more searches self.addSearchWidgetFrame = Tkinter.Frame(optionsFrame) Tkinter.Label(self.addSearchWidgetFrame, text="Add search field:").grid(column=0, row=0) self.addSearchWidgetComboboxValue = Tkinter.StringVar() addSearchWidgetCombobox = ttk.Combobox(self.addSearchWidgetFrame, state='readonly', values=sorted(self.nameToType.keys()), textvariable=self.addSearchWidgetComboboxValue) addSearchWidgetCombobox.grid(column=1, row=0) self.addSearchWidgetFrame.grid(column=0, row=0, sticky=Tkinter.E) # React when an option is chosen addSearchWidgetCombobox.bind('<<ComboboxSelected>>', lambda *args: self.addSearchWidget(self.addSearchWidgetComboboxValue.get())) self.searchParametersFrame = ScrollableFrame(self, width=width, height=height-50) self.searchParametersFrame.grid(column=0, row=1) # Start out with the most common search fields already shown for field in ('Name', 'CMC', 'Text'): self.addSearchWidget(field, False) # Give the first widget created the focus, since that makes the most sense self.searchWidgets[0].takeFocus() def addSearchWidget(self, fieldname, haveWidgetTakeFocus=True): widgetCount = len(self.searchWidgets) # Don't keep the list at the selected widget, but reset it to the top to make it ready for re-use self.addSearchWidgetComboboxValue.set('') # Create the new widget and place it widget = self.nameToType[fieldname](self, self.searchParametersFrame.innerFrame, fieldname) self.searchWidgets.append(widget) widget.grid(column=0, row=widgetCount + 1, columnspan=2, sticky=Tkinter.W) # Put the cursor in the new widget, so it can immediately be used. # Also fixes the 'ComboSelected' event firing when scrolling, spamming widgets if haveWidgetTakeFocus: widget.takeFocus() def removeWidget(self, widget): # Remove it from the list index = self.searchWidgets.index(widget) del self.searchWidgets[index] # And move all the following widgets (if any) up a row if len(self.searchWidgets) > index: for widgetIndex in xrange(index, len(self.searchWidgets)): self.searchWidgets[widgetIndex].grid_remove() self.searchWidgets[widgetIndex].grid(column=0, row=widgetIndex + 1) self.updateSearchDisplay() def updateSearchDisplay(self): GlobalValues.searchResultsFrame.clearCardlist() matchingCardnames = [] for cardname in GlobalValues.cards.keys(): addCard = True for widget in self.searchWidgets: if not widget.doesCardMatch(cardname): addCard = False break if addCard: matchingCardnames.append(cardname) GlobalValues.searchResultsFrame.addCards(matchingCardnames) def scheduleSearchDisplayUpdate(self): if self.updateFunctionId: self.after_cancel(self.updateFunctionId) self.updateFunctionId = self.after(250, self.updateSearchDisplay)
from ScrollableFrame import ScrollableFrame import tkinter as tk from tkinter import ttk root = tk.Tk() frame = ScrollableFrame(root) for i in range(50): ttk.Label(frame.scrollable_frame, text="Sample scrolling label").pack() frame.place(x=0, y=0, w=500, h=500) root.geometry("500x500") root.mainloop()
def display(self): self.displayAll.destroy() self.displayAll = ScrollableFrame(self.frame) self.displayAll.grid(row=0, column=0, padx=30, sticky=N + S + E + W) connect_, cursor_ = ES.get_student_db_ES() cursor_.execute('SELECT * FROM projects') allProjects = cursor_.fetchall() Label(self.displayAll.frame, text='Sr. No.', relief=GROOVE).grid(row=0, column=0, sticky=E + W) Label(self.displayAll.frame, text='Organisation', relief=GROOVE).grid(row=0, column=1, sticky=E + W) Label(self.displayAll.frame, text='Incharge', relief=GROOVE).grid(row=0, column=2, sticky=E + W) Label(self.displayAll.frame, text='Duration', relief=GROOVE).grid(row=0, column=3, sticky=E + W) Label(self.displayAll.frame, text='Status', relief=GROOVE).grid(row=0, column=4, sticky=E + W) Label(self.displayAll.frame, text='Name', relief=GROOVE).grid(row=0, column=5, sticky=E + W) for i in range(len(allProjects)): Label(self.displayAll.frame, anchor=W, text=i + 1).grid(row=i + 1, column=0, sticky=E + W, padx=2, pady=2) Label(self.displayAll.frame, anchor=W, text=allProjects[i][0]).grid(row=i + 1, column=1, sticky=E + W, padx=2, pady=2) Label(self.displayAll.frame, anchor=W, text=allProjects[i][1]).grid(row=i + 1, column=2, sticky=E + W, padx=2, pady=2) Label(self.displayAll.frame, anchor=W, text=allProjects[i][2]).grid(row=i + 1, column=3, sticky=E + W, padx=2, pady=2) Label(self.displayAll.frame, anchor=W, text=allProjects[i][3]).grid(row=i + 1, column=4, sticky=E + W, padx=2, pady=2) projectName = Label(self.displayAll.frame, anchor=W, text=allProjects[i][4], wraplength=300) projectName.grid(row=i + 1, column=5, sticky=W + E) projectName.bind('<Button-1>', self.bindingAction) self.displayAll.frame.columnconfigure(1, weight=1) self.displayAll.frame.columnconfigure(2, weight=1) self.displayAll.frame.columnconfigure(5, weight=3)
class DepartmentProject(DepartmentResearch.DepartmentResearch): def __init__(self, root): root.geometry('800x600') root.minsize(800, 600) root.maxsize(800, 600) root.title('UDIS-Department-Academics-Projects') super().__init__(root) self.display() root.mainloop() def display(self): self.displayAll.destroy() self.displayAll = ScrollableFrame(self.frame) self.displayAll.grid(row=0, column=0, padx=30, sticky=N + S + E + W) connect_, cursor_ = ES.get_student_db_ES() cursor_.execute('SELECT * FROM projects') allProjects = cursor_.fetchall() Label(self.displayAll.frame, text='Sr. No.', relief=GROOVE).grid(row=0, column=0, sticky=E + W) Label(self.displayAll.frame, text='Organisation', relief=GROOVE).grid(row=0, column=1, sticky=E + W) Label(self.displayAll.frame, text='Incharge', relief=GROOVE).grid(row=0, column=2, sticky=E + W) Label(self.displayAll.frame, text='Duration', relief=GROOVE).grid(row=0, column=3, sticky=E + W) Label(self.displayAll.frame, text='Status', relief=GROOVE).grid(row=0, column=4, sticky=E + W) Label(self.displayAll.frame, text='Name', relief=GROOVE).grid(row=0, column=5, sticky=E + W) for i in range(len(allProjects)): Label(self.displayAll.frame, anchor=W, text=i + 1).grid(row=i + 1, column=0, sticky=E + W, padx=2, pady=2) Label(self.displayAll.frame, anchor=W, text=allProjects[i][0]).grid(row=i + 1, column=1, sticky=E + W, padx=2, pady=2) Label(self.displayAll.frame, anchor=W, text=allProjects[i][1]).grid(row=i + 1, column=2, sticky=E + W, padx=2, pady=2) Label(self.displayAll.frame, anchor=W, text=allProjects[i][2]).grid(row=i + 1, column=3, sticky=E + W, padx=2, pady=2) Label(self.displayAll.frame, anchor=W, text=allProjects[i][3]).grid(row=i + 1, column=4, sticky=E + W, padx=2, pady=2) projectName = Label(self.displayAll.frame, anchor=W, text=allProjects[i][4], wraplength=300) projectName.grid(row=i + 1, column=5, sticky=W + E) projectName.bind('<Button-1>', self.bindingAction) self.displayAll.frame.columnconfigure(1, weight=1) self.displayAll.frame.columnconfigure(2, weight=1) self.displayAll.frame.columnconfigure(5, weight=3) def bindingAction(self, event): popupProject = Tk() popupProject.geometry('400x300') projectName = event.widget.cget('text') popupProject.title(projectName) connect_, cursor_ = ES.get_student_db_ES() cursor_.execute('SELECT * FROM projects WHERE name=(:name)', {'name': projectName}) project = cursor_.fetchone() Label(popupProject, text='Organisation').grid(row=1, column=0, sticky=W, padx=10) Label(popupProject, text='Incharge').grid(row=2, column=0, sticky=W, padx=10) Label(popupProject, text='Duration').grid(row=3, column=0, sticky=W, padx=10) Label(popupProject, text='Status').grid(row=4, column=0, sticky=W, padx=10) Label(popupProject, text='Name').grid(row=5, column=0, sticky=W, padx=10) Button(popupProject, text='Mark Project as Complete', command=lambda: self.markComplete(projectName)).grid( row=6, column=0, columnspan=2) Label(popupProject, text=project[0]).grid(row=1, column=1, sticky=W) Label(popupProject, text=project[1]).grid(row=2, column=1, sticky=W) Label(popupProject, text=project[2]).grid(row=3, column=1, sticky=W) Label(popupProject, text=project[3]).grid(row=4, column=1, sticky=W) Label(popupProject, text=project[4], anchor=W, justify='left', wraplength=250).grid(row=5, column=1, sticky=W) popupProject.columnconfigure(0, weight=1) popupProject.columnconfigure(1, weight=3) def markComplete(self, name): response = messagebox.askyesno( title='Mark Project as Complete', message='Are you sure you want to mark this Project: ' + name + ' as Complete') if response == 'no': return connect_, cursor_ = ES.get_student_db_ES() with connect_: cursor_.execute( '''UPDATE projects SET status="Completed" WHERE name=(:name)''', {'name': name}) def new(self, root): self.clear() ProjectNew.ProjectNew(root) @staticmethod def test(): print('Testing the DepartmentProject Class\n') success = 0 failure = 0 print('a. One or more fields left blank') try: ProjectNew.ProjectNew.addproject('', 'Flipkart', 'Niloy Ganguly', '2018-2023', '20000', '07/04/2021') failure += 1 print('\tFAIL') except Exception as e: # print(e) success += 1 print('\tPASS') try: ProjectNew.ProjectNew.addproject('Social Computing for E-Commerce', '', 'Niloy Ganguly', '2018-2023', '20000', '07/04/2021') failure += 1 print('\tFAIL') except Exception as e: # print(e) success += 1 print('\tPASS') try: ProjectNew.ProjectNew.addproject('Social Computing for E-Commerce', 'Flipkart', '', '2018-2023', '20000', '07/04/2021') failure += 1 print('\tFAIL') except Exception as e: # print(e) success += 1 print('\tPASS') try: ProjectNew.ProjectNew.addproject('Social Computing for E-Commerce', 'Flipkart', 'Niloy Ganguly', '', '20000', '07/04/2021') failure += 1 print('\tFAIL') except Exception as e: # print(e) success += 1 print('\tPASS') try: ProjectNew.ProjectNew.addproject('Social Computing for E-Commerce', 'Flipkart', 'Niloy Ganguly', '2018-2023', '', '07/04/2021') failure += 1 print('\tFAIL') except Exception as e: # print(e) success += 1 print('\tPASS') try: ProjectNew.ProjectNew.addproject('Social Computing for E-Commerce', 'Flipkart', 'Niloy Ganguly', '2018-2023', '20000', '') failure += 1 print('\tFAIL') except Exception as e: # print(e) success += 1 print('\tPASS') print('b. Invalid funds value') try: ProjectNew.ProjectNew.addproject('Social Computing for E-Commerce', 'Flipkart', 'Niloy Ganguly', '2018-2023', '-23000', '07/04/2021') failure += 1 print('\tFAIL') except Exception as e: # print(e) success += 1 print('\tPASS') try: ProjectNew.ProjectNew.addproject('Social Computing for E-Commerce', 'Flipkart', 'Niloy Ganguly', '2018-2023', '20 Thousand', '07/04/2021') failure += 1 print('\tFAIL') except Exception as e: # print(e) success += 1 print('\tPASS') print('c. Sufficient Balance not present in the Department Account') try: ProjectNew.ProjectNew.addproject('Social Computing for E-Commerce', 'Flipkart', 'Niloy Ganguly', '2018-2023', '20000000', '07/04/2021') failure += 1 print('\tFAIL') except Exception as e: # print(e) success += 1 print('\tPASS') print('d. Project Name already Exists') try: ProjectNew.ProjectNew.addproject( 'Unified Software-Defined Architecture for Industrial Internet of Things', 'IMPRINT-II', 'Sudip Misra', '2019-2020', '20000', '07/04/2021') failure += 1 print('\tFAIL') except Exception as e: # print(e) success += 1 print('\tPASS') print('e. Happy Path Testing') try: ProjectNew.ProjectNew.addproject('Social Computing for E-Commerce', 'Flipkart', 'Niloy Ganguly', '2018-2023', '20000', '07/04/2021') connect_, cursor_ = ES.get_student_db_ES() cursor_.execute('SELECT * FROM projects WHERE name=(:name)', {'name': 'Social Computing for E-Commerce'}) results1 = cursor_.fetchall() cursor_.execute( 'SELECT * FROM transactions WHERE organisation=(:org) AND amount=(:amt) AND date=(:date) AND purpose=(:purpose)', { 'org': 'Flipkart', 'amt': -20000, 'date': '07/04/2021', 'purpose': 'Project : Social Computing for E-Commerce' }) results2 = cursor_.fetchall() if not len(results1) == 1: print('\tFAIL') failure += 1 elif not (results1[0][0] == 'Flipkart' and results1[0][1] == 'Niloy Ganguly' and results1[0][2] == '2018-2023' and results1[0][4] == 'Social Computing for E-Commerce'): print('\tFAIL') failure += 1 elif not results2: print('\tFAIL') failure += 1 else: success += 1 print('\tPASS') except Exception as e: # print(e) failure += 1 print('\tFAIL') print(f'Test cases passed {success}/{success + failure}') print(f'Percentage = {(success / (success + failure)) * 100}')
class SearchEntryFrame(Tkinter.Frame): # TODO: Group search fields for the same variable, add option to choose to OR or AND them # TODO: Allow saving of search layout, so if somebody always wants, say, 3 CMC fields, they don't have to add those each time, but just load their preset # TODO: Create a Combobox Search Widget, which gets a list of options to choose from (f.i. the Color field only has 5 options, a text search doesn't make sense) # Fields for which this makes sense: Color, Type (perhaps, build list from availabe types?), Layout, Rarity, Set?, # TODO: Think up a dictionary search widget, to search for format legalities searchWidgets = [] nameToType = { 'Artist': SetStringSearchWidget, 'CMC': NumberSearchWidget, 'Colors': StringSearchWidget, 'Flavor': SetStringSearchWidget, 'Layout': StringSearchWidget, 'Loyalty': NumberSearchWidget, 'Manacost': StringSearchWidget, 'Number': SetStringSearchWidget, 'MultiverseID': SetNumberSearchWidget, 'Name': StringSearchWidget, 'Power': NumberSearchWidget, 'Rarity': SetStringSearchWidget, 'Set': SetnameSearchWidget, 'Text': StringSearchWidget, 'Toughness': NumberSearchWidget, 'Type': StringSearchWidget, 'Watermark': StringSearchWidget } updateFunctionId = None def __init__(self, parentFrame, width, height): Tkinter.Frame.__init__(self, parentFrame, width=width, height=height) optionsFrame = Tkinter.Frame(self, height=50) optionsFrame.grid(column=0, row=0) # Add a drop-down box to add more searches self.addSearchWidgetFrame = Tkinter.Frame(optionsFrame) Tkinter.Label(self.addSearchWidgetFrame, text="Add search field:").grid(column=0, row=0) self.addSearchWidgetComboboxValue = Tkinter.StringVar() addSearchWidgetCombobox = ttk.Combobox( self.addSearchWidgetFrame, state='readonly', values=sorted(self.nameToType.keys()), textvariable=self.addSearchWidgetComboboxValue) addSearchWidgetCombobox.grid(column=1, row=0) self.addSearchWidgetFrame.grid(column=0, row=0, sticky=Tkinter.E) # React when an option is chosen addSearchWidgetCombobox.bind( '<<ComboboxSelected>>', lambda *args: self.addSearchWidget( self.addSearchWidgetComboboxValue.get())) self.searchParametersFrame = ScrollableFrame(self, width=width, height=height - 50) self.searchParametersFrame.grid(column=0, row=1) # Start out with the most common search fields already shown for field in ('Name', 'CMC', 'Text'): self.addSearchWidget(field, False) # Give the first widget created the focus, since that makes the most sense self.searchWidgets[0].takeFocus() def addSearchWidget(self, fieldname, haveWidgetTakeFocus=True): widgetCount = len(self.searchWidgets) # Don't keep the list at the selected widget, but reset it to the top to make it ready for re-use self.addSearchWidgetComboboxValue.set('') # Create the new widget and place it widget = self.nameToType[fieldname]( self, self.searchParametersFrame.innerFrame, fieldname) self.searchWidgets.append(widget) widget.grid(column=0, row=widgetCount + 1, columnspan=2, sticky=Tkinter.W) # Put the cursor in the new widget, so it can immediately be used. # Also fixes the 'ComboSelected' event firing when scrolling, spamming widgets if haveWidgetTakeFocus: widget.takeFocus() def removeWidget(self, widget): # Remove it from the list index = self.searchWidgets.index(widget) del self.searchWidgets[index] # And move all the following widgets (if any) up a row if len(self.searchWidgets) > index: for widgetIndex in xrange(index, len(self.searchWidgets)): self.searchWidgets[widgetIndex].grid_remove() self.searchWidgets[widgetIndex].grid(column=0, row=widgetIndex + 1) self.updateSearchDisplay() def updateSearchDisplay(self): GlobalValues.searchResultsFrame.clearCardlist() matchingCardnames = [] for cardname in GlobalValues.cards.keys(): addCard = True for widget in self.searchWidgets: if not widget.doesCardMatch(cardname): addCard = False break if addCard: matchingCardnames.append(cardname) GlobalValues.searchResultsFrame.addCards(matchingCardnames) def scheduleSearchDisplayUpdate(self): if self.updateFunctionId: self.after_cancel(self.updateFunctionId) self.updateFunctionId = self.after(250, self.updateSearchDisplay)
def clickAdd(self): self.addCard() self.editCard(len(self.set) - 1) def exit(self): self.updateFile() self.deleteECS() self.addButton.delete() return len(self.set) window = tk.Tk() window.geometry("900x600") #-------------------- frame = SFrame(window) #650 frame.pack(fill="both") frame.scrollable_frame.config(width=685, height=1300) canvas = tk.Canvas(frame.scrollable_frame, width=10000, height=100000) canvas.place(x=0, y=0) # scrollbar = tk.Scrollbar(window) # scrollbar.pack(side = tk.RIGHT, fill = "y") window.minsize(700, 200) #frame.config(yscrollcommand = scrollbar.set) # frame.scrollable_frame.config(bg = "white") #----------------- # scrollbar = tk.Scrollbar(window) # scrollbar.place(relx=1, rely=0, relheight=1, anchor='ne') # # canvas = tk.Canvas(window, scrollregion = window.bbox('all'), width = 630) # canvas.place()
class CardDisplayFrame(Tkinter.Frame): fieldOrder = ('name', 'type', 'watermark', 'layout', 'manacost', 'cmc', 'layout', 'names', 'power', 'toughness', 'loyalty', 'hand', 'life', 'text', 'artist', 'rulings', 'sets', 'rarity', 'flavor') setFields = ['flavor', 'rarity'] # A list of fields that can be different for each set print of that card fieldDisplayname = {'cmc': 'CMC:', 'hand': 'Hand Mod:', 'life': 'Life Mod:', 'names': 'Other Card(s):'} fieldToLabel = {} # In this dict keys are the field name, and the corresponding value is a 2-tuple with the name label widget and value label widget # Field values from the card dataset will be fed to these functions for further parsing fieldParseCommands = {'layout': lambda self, layoutValue: None if layoutValue == 'normal' else layoutValue.capitalize(), # Hide the layout field if the card layout is normal 'names': lambda self, nameslist: u"; ".join([name for name in nameslist if name.lower() != self.currentlyDisplayedCard]), # Remove the current card from the list 'sets': lambda self, setdict: u"; ".join(setdict) + u' ({} sets)'.format(len(setdict)), # Display a list of the sets } currentlyDisplayedCard = None currentlyDisplayedSet = None displayType = None def __init__(self, parentFrame, width, height): Tkinter.Frame.__init__(self, parentFrame, width=width, height=height) # Show the message here instead of at the import statement, to give the Statusbar time to initialize if PILerrorMessage: GlobalValues.statusbar.addMessage(PILerrorMessage) # TODO: Maybe move the 'add card to deck/sideboard' buttons to the SearchResultsFrame? And the '+/-/x' buttons to the ChosenCardsFrame? # They kind of make more sense there, since they interact with those fields # Or maybe even move the 'add card' buttons to the ChosenCardsFrame too, since that's where they'd be added anyway # TODO: Occasional update checks to see if images got updated # This could be done by storing the version number of mtgimage.com, and when that changes, retrieve the changelog # Then, search the latest change(s) for setnames, and deleting the whole folder, forcing the images to be redownloaded # TODO: Display variation art of cards in same set # Some sets have multiple of the same card but with different art (Mostly lands, most sets have 4 different land arts per land type) # The multiverseIDs of the other cards is stored in the 'variations' set field self.cardDataFrame = ScrollableFrame(self, width=width, height=height) self.cardDataFrame.grid(column=0, row=1, columnspan=2, rowspan=2, sticky=Tkinter.N) for rowcount, field in enumerate(self.fieldOrder): displayname = self.fieldDisplayname[field] if field in self.fieldDisplayname else "{}:".format(field.capitalize()) namelabel = Tkinter.Label(self.cardDataFrame.innerFrame, text=displayname, anchor=Tkinter.NE) # Add and remove the label, so the 'sticky' part stays set #namelabel.grid(column=0, row=rowcount, sticky=Tkinter.NE) #namelabel.grid_remove() valuelabel = Tkinter.Label(self.cardDataFrame.innerFrame, text='', width=70, wraplength=375, justify=Tkinter.LEFT, anchor=Tkinter.W) self.fieldToLabel[field] = namelabel, valuelabel self.setSelectionCombobox = ttk.Combobox(self.cardDataFrame.innerFrame, state='readonly', width=50) self.setSelectionCombobox.bind('<<ComboboxSelected>>', lambda arg: self.setDisplayedSet(self.setSelectionCombobox.get())) self.setSelectionCombobox.label = Tkinter.Label(self.cardDataFrame.innerFrame, anchor=Tkinter.NE, text="Display Set:") self.cardImageLabel = Tkinter.Label(self.cardDataFrame.innerFrame) self.cardImageLabel.grid(column=0, row=100, columnspan=2, sticky=Tkinter.NW, padx=width/10) def toggleShowingImages(self): if GlobalValues.settings.getSetting('showImages', True): if self.currentlyDisplayedSet and self.currentlyDisplayedCard: self.retrieveAndDisplayCardImage(self.currentlyDisplayedSet, self.currentlyDisplayedCard) else: self.cardImageLabel.configure(image="") # Clear the current image def constructCardImagePath(self, setname, cardname): # First clean up the names a bit, so the OS doesn't get confused by weird characters return os.path.join(GlobalValues.mainfolder, "images", self.removeSpecialCharsFromString(setname), u"{}.jpg".format(self.removeSpecialCharsFromString(cardname))) @staticmethod def removeSpecialCharsFromString(s): # First remove some really unusual characters and characters that aren't allowed in filenames for char in ['"', ':']: s = s.replace(char, '') # Some characters don't parse well, replace them with more common equivalents s = s.replace(u'æ', 'ae').replace(u'—', '-') # Then turn accented characters in their un-accented equivalent s = unicodedata.normalize('NFKD', s).encode('ascii', 'ignore') return s def displayCard(self, cardname, setname=None): self.currentlyDisplayedCard = cardname # If no setname was provided, just pick the first one in the list of sets this card is in if not setname: setname = GlobalValues.cards[cardname]['sets'].keys()[0] self.currentlyDisplayedSet = setname cardinfo = GlobalValues.cards[cardname] for fieldcount, field in enumerate(self.fieldOrder): fieldvalue = None if field in self.setFields and field in cardinfo['sets'][setname]: fieldvalue = cardinfo['sets'][setname][field] elif field in cardinfo: fieldvalue = cardinfo[field] if fieldvalue is not None: # Field does exist! Make sure it's shown, and filled in properly self.fieldToLabel[field][0].grid(column=0, row=fieldcount, sticky=Tkinter.NE) self.fieldToLabel[field][1].grid(column=1, row=fieldcount) # If we need to parse the value in a special way, do that if field in self.fieldParseCommands: fieldvalue = self.fieldParseCommands[field](self, fieldvalue) # A fieldparse command could return None, handle that if fieldvalue: self.fieldToLabel[field][1].configure(text=fieldvalue) if fieldvalue is None: # Field doesn't exist, hide it self.fieldToLabel[field][0].grid_remove() self.fieldToLabel[field][1].grid_remove() # Update the set selector, or hide it if the card is in only one set if len(cardinfo['sets']) > 1: self.setSelectionCombobox.label.grid(column=0, row=99) self.setSelectionCombobox.configure(values=cardinfo['sets'].keys()) self.setSelectionCombobox.set(setname) self.setSelectionCombobox.grid(column=1, row=99, sticky=Tkinter.W) else: self.setSelectionCombobox.label.grid_remove() self.setSelectionCombobox.grid_remove() # If we already have the image, show it, if we should if GlobalValues.isImageLibraryLoaded and GlobalValues.settings.getSetting('showImages', True): # TODO: Show a 'loading' image, perhaps the backside of cards? # TODO: If a card is in multiple sets, and the first set doesn't have a multiverseid so we can't retrieve picture, go to next set self.cardImageLabel.configure(image="") self.retrieveAndDisplayCardImage(setname, cardname) def retrieveAndDisplayCardImage(self, setname, cardname): # If we already have the image, just draw it if os.path.exists(self.constructCardImagePath(setname, cardname)): self.drawCardImage(setname, cardname) # Otherwise, retrieve it else: self.cardImageLabel.configure(text="Downloading...") # Fetch the card image in a new thread, to not freeze the GUI cardImageDownloadThread = threading.Thread(target=self.downloadCardImage, args=(setname, cardname)) cardImageDownloadThread.start() def drawCardImage(self, setname, cardname): img = Image.open(self.constructCardImagePath(setname, cardname)) # Make sure the image isn't too wide width, height = img.size maxwidth = self.configure('width')[-1] - 20.0 if width > maxwidth: # Too large! Calculate the aspect ratio, and reduce the height as much as the width, so it doesn't get stretched ratio = width / maxwidth newheight = height / ratio print u"Image for '{}/{}' too large, changing size from {}, {} to {}, {} (ratio {})".format(setname, cardname, width, height, maxwidth, newheight, ratio) GlobalValues.statusbar.addMessage(u"Image for card '{}' is too large, shrinking to {:.0f}%".format(ratio * 100)) img = img.resize((int(maxwidth), int(round(newheight))), Image.ANTIALIAS) try: img = ImageTk.PhotoImage(img) except IOError as e: GlobalValues.statusbar.addMessage("ERROR displaying image for '{}' ({})".format(cardname, e.message)) self.cardImageLabel.configure(text='') # Delete the offending image, redownloading might fix the problem os.remove(self.constructCardImagePath(setname, cardname)) else: self.cardImageLabel.configure(text='', image=img) self.cardImageLabel.image = img # Store a reference to the Image instance, otherwise it gets garbage-collected def downloadCardImage(self, setname, cardname): # Create these variables outside the try-catch so we can always reference them in the catch cardImageUrl = '' localImageLocation = '' # These are used a few times, no need to repeat the effort fixedSetname = self.removeSpecialCharsFromString(setname) if 'multiverseid' not in GlobalValues.cards[cardname]['sets'][setname]: GlobalValues.statusbar.addMessage(u"Skipping art download for '{}' (no multiverse id)".format(cardname)) self.cardImageLabel.configure(text='') return try: # Get the first set the card is in # TODO: Allow for multiple image sources, like 'api.mtgdb.info' cardImageUrl = "http://gatherer.wizards.com/Handlers/Image.ashx?type=card&multiverseid={}".format(GlobalValues.cards[cardname]['sets'][setname]['multiverseid']) localImageLocation = self.constructCardImagePath(fixedSetname, cardname) # Make sure all the folders exist if not os.path.exists(os.path.dirname(localImageLocation)): os.makedirs(os.path.dirname(localImageLocation)) try: urllib.urlretrieve(cardImageUrl, localImageLocation) except IOError as ioe: print u"ERROR occured while trying to download the card '{}' from set '{}':".format(cardname, setname) print ioe GlobalValues.statusbar.addMessage(u"ERROR occured while downloading art for card '{}' ({})".format(cardname, ioe.message)) self.cardImageLabel.configure(text='') # Clear the 'Downloading' message return # Check if the file downloaded correctly with open(localImageLocation, 'r') as imageFile: imagefileContents = imageFile.readlines() if len(imagefileContents) == 0: # Something went wrong (The file starts with an HTML tag instead of binary data) # Show error and remove the file print u"ERROR downloading card '{}', online file not found".format(cardImageUrl) GlobalValues.statusbar.addMessage(u"Art file for '{}' failed to download properly".format(cardname)) os.remove(localImageLocation) self.cardImageLabel.configure(text='') else: # Check if the requested card should still be displayed if self.currentlyDisplayedSet == setname and self.currentlyDisplayedCard == cardname: self.drawCardImage(setname, cardname) except Exception as e: print "ERROR while fetching card image: ", e print u" Card '{}' in set '{}' ('{}')".format(cardname, setname, fixedSetname) print u" Url is '{}'; local image location is '{}'".format(cardImageUrl, localImageLocation) traceback.print_exc() GlobalValues.statusbar.addMessage(u"ERROR while fetching card image for '{}'! ({})".format(cardname, e.message)) def addCardToList(self, listname): GlobalValues.chosenCardsFrame.addCard(self.currentlyDisplayedCard, listname) # Deselect the search results list and both the deck and sideboard list, then select the one we need GlobalValues.searchResultsFrame.clearSelection() GlobalValues.chosenCardsFrame.deckTreeview.clearSelection() GlobalValues.chosenCardsFrame.sideboardTreeview.clearSelection() GlobalValues.chosenCardsFrame.selectCard(self.currentlyDisplayedCard, listname) def increaseCardCount(self, *args): GlobalValues.chosenCardsFrame.changeCardCount(self.currentlyDisplayedCard, 1, self.displayType) def decreaseCardCount(self, *args): GlobalValues.chosenCardsFrame.changeCardCount(self.currentlyDisplayedCard, -1, self.displayType) def removeCard(self, *args): GlobalValues.chosenCardsFrame.removeCard(self.currentlyDisplayedCard, self.displayType) def setDisplayedSet(self, setname): if setname != self.currentlyDisplayedSet: self.currentlyDisplayedSet = setname self.setSelectionCombobox.set(setname) self.cardDataFrame.innerFrame.focus_set() # Move the focus from the combobox to the parent frame, so scrolling doesn't change sets self.displayCard(self.currentlyDisplayedCard, setname)
class DepartmentInventory: def __init__(self,root): root.title("Department Inventory") root.geometry('800x600') root.minsize(800, 600) root.maxsize(800, 600) self.frame=Frame(root) self.frame.grid(row=0, column=0, sticky='nsew') self.itemnameLabel=Label(self.frame,text="Item Name: ",anchor=E) self.itemnameEntry=Entry(self.frame,borderwidth=0,width=27) self.itemtypeLabel=Label(self.frame,text="Type: ",anchor=E) self.combostyle=ttk.Style() self.combostyle.map('TCombobox', fieldbackground=[('readonly', 'white')]) self.combostyle.map('TCombobox', selectbackground=[('readonly', 'white')]) # self.combostyle. self.var=StringVar(self.frame) self.var.set("All") self.typeDropdown = ttk.Combobox(self.frame,foreground="black",width=27,takefocus=False,textvariable=self.var,state='readonly') self.typeDropdown['value']=('All', 'Miscellaneous', 'Computers', 'Furniture', 'Stationery') self.typeDropdown.bind("<FocusIn>", dropdown_defocus) self.submitButton=Button(self.frame,text='Search',command=lambda:self.search()) self.addButton=Button(self.frame,text='Purchase New Item',command=lambda:self.add(root)) self.displayFrame=ScrollableFrame(self.frame) self.backButton=Button(self.frame,text="Back",command=lambda: self.back(root)) self.exitButton=Button(self.frame,text="Exit",command=exit) self.itemnameLabel.grid(row=0,column=0,sticky=E+W,pady=10,padx=10) self.itemnameEntry.grid(row=0,column=1,sticky=W,pady=10) self.itemtypeLabel.grid(row=1,column=0,sticky=E+W,pady=10,padx=10) self.typeDropdown.grid(row=1,column=1,sticky=W,pady=10) self.submitButton.grid(row=2,column=0,sticky=E,pady=10,padx=10) self.addButton.grid(row=2,column=1,sticky=W,pady=10,padx=10) self.displayFrame.grid(row=3,column=0,columnspan=2,sticky="nsew",padx=10,pady=10) self.exitButton.grid(row=4,column=0,columnspan=2,sticky=W,padx=50,pady=20) self.backButton.grid(row=4,column=1,columnspan=2,sticky=E,padx=50,pady=20) for i in range(2): self.frame.columnconfigure(i,weight=1) self.frame.rowconfigure(3,weight=1) def display(self,list_): self.displayFrame.destroy() self.displayFrame=ScrollableFrame(self.frame) self.displayFrame.grid(row=3,column=0,columnspan=2,sticky="nsew",padx=10,pady=10) # print(list_) Label(self.displayFrame.frame,text='Sl. no.',relief=GROOVE).grid(row=0,column=0,sticky=E+W,padx=2) Label(self.displayFrame.frame,text='Item Name',relief=GROOVE).grid(row=0,column=1,sticky=E+W,padx=2) Label(self.displayFrame.frame,text='Location',relief=GROOVE).grid(row=0,column=2,sticky=E+W,padx=2) Label(self.displayFrame.frame,text='Quanitity',relief=GROOVE).grid(row=0,column=3,sticky=E+W,padx=2) Label(self.displayFrame.frame,text='Type',relief=GROOVE).grid(row=0,column=4,sticky=E+W,padx=2) for i in range(len(list_)): itemSerial = Label(self.displayFrame.frame, anchor=W, text=i+1) itemName = Label(self.displayFrame.frame,wraplength=400, anchor=W, text=list_[i][0]) itemLocation = Label(self.displayFrame.frame, anchor=W, text=list_[i][1]) itemQuantity= Label(self.displayFrame.frame, anchor=W, text=list_[i][2]) itemType= Label(self.displayFrame.frame, anchor=W, text=list_[i][3]) itemSerial.grid(row=i+1, column=0, sticky=W+E,padx=2,pady=1) itemName.grid(row=i+1, column=1, sticky=W+E,padx=2,pady=1) itemLocation.grid(row=i+1,column=2,sticky=W+E,padx=2,pady=1) itemQuantity.grid(row=i+1,column=3,sticky=W+E,padx=2,pady=1) itemType.grid(row=i+1,column=4,sticky=W+E,padx=2,pady=1) # studentRollAndName.bind('<Button-1>', self.bindingAction) self.displayFrame.frame.columnconfigure(1,weight=1) @staticmethod def getInventory(name_,type_): connect_, cursor_ = ES.get_student_db_ES() if name_ == "" and type_ == "All": cursor_.execute("SELECT * FROM inventory") elif name_ != "" and type_=="All": cursor_.execute("SELECT * FROM inventory WHERE item_name LIKE (:name)",{'name':'%'+name_+'%'}) elif name_ == "" and type_!="All": cursor_.execute("SELECT * FROM inventory WHERE type LIKE (:type)", {'type':'%'+type_+'%'}) else: cursor_.execute("SELECT * FROM inventory WHERE item_name LIKE (:name) AND type LIKE (:type)", {'name':'%'+name_+'%', 'type':'%'+type_+'%'}) return cursor_.fetchall() def search(self): name_ = self.itemnameEntry.get() type_ = self.typeDropdown.get() self.display(DepartmentInventory.getInventory(name_,type_)) def add(self,root): self.clear() DepartmentPurchase.DepartmentPurchase(root) def back(self,root): self.clear() DepartmentUDIS.DepartmentMainMenu(root) @staticmethod def test(): print("\nTesting the Department Purchase class") success = 0 fail = 0 print("\ta. Blank name and type all:") list_=[('Pens', 'Academic Section', 100, 'Stationery', 500), ('Computer Table', 'Software Lab', 10, 'Furniture', 100)] if DepartmentInventory.getInventory('','All')==list_: print("\tPASS") success=success+1 else: print("\tFAIL\n") fail=fail+1 print("\tb. Specific name and type all:") list_=[('Pens', 'Academic Section', 100, 'Stationery', 500)] if DepartmentInventory.getInventory('Pens','All')==list_: print("\tPASS") success=success+1 else: print("\tFAIL\n") fail=fail+1 print("\tc. No name and type specific:") list_=[('Pens', 'Academic Section', 100, 'Stationery', 500)] if DepartmentInventory.getInventory('','Stationery')==list_: print("\tPASS") success=success+1 else: print("\tFAIL\n") fail=fail+1 print("\td. Name specific and type specific:") list_=[('Computer Table', 'Software Lab', 10, 'Furniture', 100)] if DepartmentInventory.getInventory('comp','Furniture')==list_: print("\tPASS") success=success+1 else: print("\tFAIL\n") fail=fail+1 print(f'Test cases passed {success}/{success+fail}') print(f'Percentage = {(success/(success+fail))*100}') def clear(self): self.frame.destroy()
class StudentSearch: def __init__(self, root): self.frame = Frame(root) self.frame.grid(row=0, column=0, sticky='nsew') self.nameLabel = Label(self.frame, text='Name', fg="black") self.nameEntry = Entry(self.frame, borderwidth=0) self.rollLabel = Label(self.frame, text='Roll No', fg="black") self.rollEntry = Entry(self.frame, borderwidth=0) self.searchButton = Button(self.frame, text='Search', command=lambda: self.search(root)) self.searchResults = ScrollableFrame(self.frame) self.nameLabel.grid(row=2, column=0, padx=5, pady=3) self.nameEntry.grid(row=2, column=1) self.rollLabel.grid(row=3, column=0, padx=5, pady=3) self.rollEntry.grid(row=3, column=1) self.exitButton = Button(self.frame, text="Exit", command=exit) self.backButton = Button(self.frame, text="Back", command=lambda: self.back(root)) self.searchButton.grid(row=4, column=0, columnspan=2, pady=20) self.searchResults.grid(row=5, column=0, padx=30, sticky="nsew", columnspan=2) self.exitButton.grid(row=8, column=0, padx=50, pady=50, sticky=S + W) self.backButton.grid(row=8, column=1, padx=50, pady=50, sticky=S + E) self.frame.rowconfigure(8, weight=1) self.frame.columnconfigure(0, weight=1) self.frame.columnconfigure(1, weight=1) root.mainloop() def bindingAction(self, event): pass def display(self, root, list_): self.searchResults.destroy() self.searchResults = ScrollableFrame(self.frame) self.searchResults.grid(row=5, column=0, padx=30, sticky="nsew", columnspan=2) self.searchResults.frame.columnconfigure(1, weight=1) for i in range(len(list_)): studentSerial = Label(self.searchResults.frame, anchor=W, text=i + 1) studentRollAndName = Label(self.searchResults.frame, anchor=W, text=list_[i][0] + ' ' + list_[i][1]) studentSerial.grid(row=i, column=0, sticky=W + E, padx=5) studentRollAndName.grid(row=i, column=1, sticky=W + E) studentRollAndName.bind('<Button-1>', self.bindingAction) def back(self, root): pass def search(self, root): connect_, cursor_ = ES.get_student_db_ES() name_ = self.nameEntry.get() roll_no_ = self.rollEntry.get() if name_ == "" and roll_no_ == "": cursor_.execute("SELECT * FROM student") elif roll_no_ == "": cursor_.execute( "SELECT * FROM student WHERE student_name LIKE (:name)", {'name': '%' + name_ + '%'}) elif name_ == "": cursor_.execute("SELECT * FROM student WHERE roll LIKE (:roll)", {'roll': '%' + roll_no_ + '%'}) else: cursor_.execute( "SELECT * FROM student WHERE student_name LIKE (:name) AND roll LIKE (:roll)", { 'name': '%' + name_ + '%', 'roll': '%' + roll_no_ + '%' }) self.display(root, cursor_.fetchall()) def clear(self): self.frame.destroy()
class CardDisplayFrame(Tkinter.Frame): fieldOrder = ('name', 'type', 'watermark', 'layout', 'manacost', 'cmc', 'layout', 'names', 'power', 'toughness', 'loyalty', 'hand', 'life', 'text', 'artist', 'rulings', 'sets', 'rarity', 'flavor') setFields = [ 'flavor', 'rarity' ] # A list of fields that can be different for each set print of that card fieldDisplayname = { 'cmc': 'CMC:', 'hand': 'Hand Mod:', 'life': 'Life Mod:', 'names': 'Other Card(s):' } fieldToLabel = { } # In this dict keys are the field name, and the corresponding value is a 2-tuple with the name label widget and value label widget # Field values from the card dataset will be fed to these functions for further parsing fieldParseCommands = { 'layout': lambda self, layoutValue: None if layoutValue == 'normal' else layoutValue.capitalize( ), # Hide the layout field if the card layout is normal 'names': lambda self, nameslist: u"; ".join([ name for name in nameslist if name.lower() != self.currentlyDisplayedCard ]), # Remove the current card from the list 'sets': lambda self, setdict: u"; ".join(setdict) + u' ({} sets)'.format( len(setdict)), # Display a list of the sets } currentlyDisplayedCard = None currentlyDisplayedSet = None displayType = None def __init__(self, parentFrame, width, height): Tkinter.Frame.__init__(self, parentFrame, width=width, height=height) # Show the message here instead of at the import statement, to give the Statusbar time to initialize if PILerrorMessage: GlobalValues.statusbar.addMessage(PILerrorMessage) # TODO: Maybe move the 'add card to deck/sideboard' buttons to the SearchResultsFrame? And the '+/-/x' buttons to the ChosenCardsFrame? # They kind of make more sense there, since they interact with those fields # Or maybe even move the 'add card' buttons to the ChosenCardsFrame too, since that's where they'd be added anyway # TODO: Occasional update checks to see if images got updated # This could be done by storing the version number of mtgimage.com, and when that changes, retrieve the changelog # Then, search the latest change(s) for setnames, and deleting the whole folder, forcing the images to be redownloaded # TODO: Display variation art of cards in same set # Some sets have multiple of the same card but with different art (Mostly lands, most sets have 4 different land arts per land type) # The multiverseIDs of the other cards is stored in the 'variations' set field self.cardDataFrame = ScrollableFrame(self, width=width, height=height) self.cardDataFrame.grid(column=0, row=1, columnspan=2, rowspan=2, sticky=Tkinter.N) for rowcount, field in enumerate(self.fieldOrder): displayname = self.fieldDisplayname[ field] if field in self.fieldDisplayname else "{}:".format( field.capitalize()) namelabel = Tkinter.Label(self.cardDataFrame.innerFrame, text=displayname, anchor=Tkinter.NE) # Add and remove the label, so the 'sticky' part stays set #namelabel.grid(column=0, row=rowcount, sticky=Tkinter.NE) #namelabel.grid_remove() valuelabel = Tkinter.Label(self.cardDataFrame.innerFrame, text='', width=70, wraplength=375, justify=Tkinter.LEFT, anchor=Tkinter.W) self.fieldToLabel[field] = namelabel, valuelabel self.setSelectionCombobox = ttk.Combobox(self.cardDataFrame.innerFrame, state='readonly', width=50) self.setSelectionCombobox.bind( '<<ComboboxSelected>>', lambda arg: self.setDisplayedSet(self.setSelectionCombobox.get())) self.setSelectionCombobox.label = Tkinter.Label( self.cardDataFrame.innerFrame, anchor=Tkinter.NE, text="Display Set:") self.cardImageLabel = Tkinter.Label(self.cardDataFrame.innerFrame) self.cardImageLabel.grid(column=0, row=100, columnspan=2, sticky=Tkinter.NW, padx=width / 10) def toggleShowingImages(self): if GlobalValues.settings.getSetting('showImages', True): if self.currentlyDisplayedSet and self.currentlyDisplayedCard: self.retrieveAndDisplayCardImage(self.currentlyDisplayedSet, self.currentlyDisplayedCard) else: self.cardImageLabel.configure(image="") # Clear the current image def constructCardImagePath(self, setname, cardname): # First clean up the names a bit, so the OS doesn't get confused by weird characters return os.path.join( GlobalValues.mainfolder, "images", self.removeSpecialCharsFromString(setname), u"{}.jpg".format(self.removeSpecialCharsFromString(cardname))) @staticmethod def removeSpecialCharsFromString(s): # First remove some really unusual characters and characters that aren't allowed in filenames for char in ['"', ':']: s = s.replace(char, '') # Some characters don't parse well, replace them with more common equivalents s = s.replace(u'æ', 'ae').replace(u'—', '-') # Then turn accented characters in their un-accented equivalent s = unicodedata.normalize('NFKD', s).encode('ascii', 'ignore') return s def displayCard(self, cardname, setname=None): self.currentlyDisplayedCard = cardname # If no setname was provided, just pick the first one in the list of sets this card is in if not setname: setname = GlobalValues.cards[cardname]['sets'].keys()[0] self.currentlyDisplayedSet = setname cardinfo = GlobalValues.cards[cardname] for fieldcount, field in enumerate(self.fieldOrder): fieldvalue = None if field in self.setFields and field in cardinfo['sets'][setname]: fieldvalue = cardinfo['sets'][setname][field] elif field in cardinfo: fieldvalue = cardinfo[field] if fieldvalue is not None: # Field does exist! Make sure it's shown, and filled in properly self.fieldToLabel[field][0].grid(column=0, row=fieldcount, sticky=Tkinter.NE) self.fieldToLabel[field][1].grid(column=1, row=fieldcount) # If we need to parse the value in a special way, do that if field in self.fieldParseCommands: fieldvalue = self.fieldParseCommands[field](self, fieldvalue) # A fieldparse command could return None, handle that if fieldvalue: self.fieldToLabel[field][1].configure(text=fieldvalue) if fieldvalue is None: # Field doesn't exist, hide it self.fieldToLabel[field][0].grid_remove() self.fieldToLabel[field][1].grid_remove() # Update the set selector, or hide it if the card is in only one set if len(cardinfo['sets']) > 1: self.setSelectionCombobox.label.grid(column=0, row=99) self.setSelectionCombobox.configure(values=cardinfo['sets'].keys()) self.setSelectionCombobox.set(setname) self.setSelectionCombobox.grid(column=1, row=99, sticky=Tkinter.W) else: self.setSelectionCombobox.label.grid_remove() self.setSelectionCombobox.grid_remove() # If we already have the image, show it, if we should if GlobalValues.isImageLibraryLoaded and GlobalValues.settings.getSetting( 'showImages', True): # TODO: Show a 'loading' image, perhaps the backside of cards? # TODO: If a card is in multiple sets, and the first set doesn't have a multiverseid so we can't retrieve picture, go to next set self.cardImageLabel.configure(image="") self.retrieveAndDisplayCardImage(setname, cardname) def retrieveAndDisplayCardImage(self, setname, cardname): # If we already have the image, just draw it if os.path.exists(self.constructCardImagePath(setname, cardname)): self.drawCardImage(setname, cardname) # Otherwise, retrieve it else: self.cardImageLabel.configure(text="Downloading...") # Fetch the card image in a new thread, to not freeze the GUI cardImageDownloadThread = threading.Thread( target=self.downloadCardImage, args=(setname, cardname)) cardImageDownloadThread.start() def drawCardImage(self, setname, cardname): img = Image.open(self.constructCardImagePath(setname, cardname)) # Make sure the image isn't too wide width, height = img.size maxwidth = self.configure('width')[-1] - 20.0 if width > maxwidth: # Too large! Calculate the aspect ratio, and reduce the height as much as the width, so it doesn't get stretched ratio = width / maxwidth newheight = height / ratio print u"Image for '{}/{}' too large, changing size from {}, {} to {}, {} (ratio {})".format( setname, cardname, width, height, maxwidth, newheight, ratio) GlobalValues.statusbar.addMessage( u"Image for card '{}' is too large, shrinking to {:.0f}%". format(ratio * 100)) img = img.resize((int(maxwidth), int(round(newheight))), Image.ANTIALIAS) try: img = ImageTk.PhotoImage(img) except IOError as e: GlobalValues.statusbar.addMessage( "ERROR displaying image for '{}' ({})".format( cardname, e.message)) self.cardImageLabel.configure(text='') # Delete the offending image, redownloading might fix the problem os.remove(self.constructCardImagePath(setname, cardname)) else: self.cardImageLabel.configure(text='', image=img) self.cardImageLabel.image = img # Store a reference to the Image instance, otherwise it gets garbage-collected def downloadCardImage(self, setname, cardname): # Create these variables outside the try-catch so we can always reference them in the catch cardImageUrl = '' localImageLocation = '' # These are used a few times, no need to repeat the effort fixedSetname = self.removeSpecialCharsFromString(setname) if 'multiverseid' not in GlobalValues.cards[cardname]['sets'][setname]: GlobalValues.statusbar.addMessage( u"Skipping art download for '{}' (no multiverse id)".format( cardname)) self.cardImageLabel.configure(text='') return try: # Get the first set the card is in # TODO: Allow for multiple image sources, like 'api.mtgdb.info' cardImageUrl = "http://gatherer.wizards.com/Handlers/Image.ashx?type=card&multiverseid={}".format( GlobalValues.cards[cardname]['sets'][setname]['multiverseid']) localImageLocation = self.constructCardImagePath( fixedSetname, cardname) # Make sure all the folders exist if not os.path.exists(os.path.dirname(localImageLocation)): os.makedirs(os.path.dirname(localImageLocation)) try: urllib.urlretrieve(cardImageUrl, localImageLocation) except IOError as ioe: print u"ERROR occured while trying to download the card '{}' from set '{}':".format( cardname, setname) print ioe GlobalValues.statusbar.addMessage( u"ERROR occured while downloading art for card '{}' ({})". format(cardname, ioe.message)) self.cardImageLabel.configure( text='') # Clear the 'Downloading' message return # Check if the file downloaded correctly with open(localImageLocation, 'r') as imageFile: imagefileContents = imageFile.readlines() if len(imagefileContents) == 0: # Something went wrong (The file starts with an HTML tag instead of binary data) # Show error and remove the file print u"ERROR downloading card '{}', online file not found".format( cardImageUrl) GlobalValues.statusbar.addMessage( u"Art file for '{}' failed to download properly".format( cardname)) os.remove(localImageLocation) self.cardImageLabel.configure(text='') else: # Check if the requested card should still be displayed if self.currentlyDisplayedSet == setname and self.currentlyDisplayedCard == cardname: self.drawCardImage(setname, cardname) except Exception as e: print "ERROR while fetching card image: ", e print u" Card '{}' in set '{}' ('{}')".format( cardname, setname, fixedSetname) print u" Url is '{}'; local image location is '{}'".format( cardImageUrl, localImageLocation) traceback.print_exc() GlobalValues.statusbar.addMessage( u"ERROR while fetching card image for '{}'! ({})".format( cardname, e.message)) def addCardToList(self, listname): GlobalValues.chosenCardsFrame.addCard(self.currentlyDisplayedCard, listname) # Deselect the search results list and both the deck and sideboard list, then select the one we need GlobalValues.searchResultsFrame.clearSelection() GlobalValues.chosenCardsFrame.deckTreeview.clearSelection() GlobalValues.chosenCardsFrame.sideboardTreeview.clearSelection() GlobalValues.chosenCardsFrame.selectCard(self.currentlyDisplayedCard, listname) def increaseCardCount(self, *args): GlobalValues.chosenCardsFrame.changeCardCount( self.currentlyDisplayedCard, 1, self.displayType) def decreaseCardCount(self, *args): GlobalValues.chosenCardsFrame.changeCardCount( self.currentlyDisplayedCard, -1, self.displayType) def removeCard(self, *args): GlobalValues.chosenCardsFrame.removeCard(self.currentlyDisplayedCard, self.displayType) def setDisplayedSet(self, setname): if setname != self.currentlyDisplayedSet: self.currentlyDisplayedSet = setname self.setSelectionCombobox.set(setname) self.cardDataFrame.innerFrame.focus_set( ) # Move the focus from the combobox to the parent frame, so scrolling doesn't change sets self.displayCard(self.currentlyDisplayedCard, setname)
def __init__(self, parentFrame, width, height): Tkinter.Frame.__init__(self, parentFrame, width=width, height=height) # Show the message here instead of at the import statement, to give the Statusbar time to initialize if PILerrorMessage: GlobalValues.statusbar.addMessage(PILerrorMessage) # TODO: Maybe move the 'add card to deck/sideboard' buttons to the SearchResultsFrame? And the '+/-/x' buttons to the ChosenCardsFrame? # They kind of make more sense there, since they interact with those fields # Or maybe even move the 'add card' buttons to the ChosenCardsFrame too, since that's where they'd be added anyway # TODO: Occasional update checks to see if images got updated # This could be done by storing the version number of mtgimage.com, and when that changes, retrieve the changelog # Then, search the latest change(s) for setnames, and deleting the whole folder, forcing the images to be redownloaded # TODO: Display variation art of cards in same set # Some sets have multiple of the same card but with different art (Mostly lands, most sets have 4 different land arts per land type) # The multiverseIDs of the other cards is stored in the 'variations' set field self.cardDataFrame = ScrollableFrame(self, width=width, height=height) self.cardDataFrame.grid(column=0, row=1, columnspan=2, rowspan=2, sticky=Tkinter.N) for rowcount, field in enumerate(self.fieldOrder): displayname = self.fieldDisplayname[ field] if field in self.fieldDisplayname else "{}:".format( field.capitalize()) namelabel = Tkinter.Label(self.cardDataFrame.innerFrame, text=displayname, anchor=Tkinter.NE) # Add and remove the label, so the 'sticky' part stays set #namelabel.grid(column=0, row=rowcount, sticky=Tkinter.NE) #namelabel.grid_remove() valuelabel = Tkinter.Label(self.cardDataFrame.innerFrame, text='', width=70, wraplength=375, justify=Tkinter.LEFT, anchor=Tkinter.W) self.fieldToLabel[field] = namelabel, valuelabel self.setSelectionCombobox = ttk.Combobox(self.cardDataFrame.innerFrame, state='readonly', width=50) self.setSelectionCombobox.bind( '<<ComboboxSelected>>', lambda arg: self.setDisplayedSet(self.setSelectionCombobox.get())) self.setSelectionCombobox.label = Tkinter.Label( self.cardDataFrame.innerFrame, anchor=Tkinter.NE, text="Display Set:") self.cardImageLabel = Tkinter.Label(self.cardDataFrame.innerFrame) self.cardImageLabel.grid(column=0, row=100, columnspan=2, sticky=Tkinter.NW, padx=width / 10)
class DepartmentCourses: def __init__(self, root): root.title('Academics - Courses') root.geometry('800x600') root.maxsize(800, 600) root.minsize(800, 600) self.frame = Frame(root) self.frame.grid(row=0, column=0, sticky='nsew') self.courseLabel = Label(self.frame, text='Course Name', fg="black") self.courseEntry = Entry(self.frame, borderwidth=0) self.submitButton = Button(self.frame, text='Search', command=lambda: self.search(root)) self.addcoursesButton = Button(self.frame, text='Add Courses', command=lambda: self.add(root)) self.displayFrame = ScrollableFrame(self.frame) self.courseLabel.grid(row=2, column=0, padx=5, pady=3) self.courseEntry.grid(row=2, column=1) self.exitButton = Button(self.frame, text="Exit", command=exit) self.backButton = Button(self.frame, text="Back", command=lambda: self.back(root)) self.submitButton.grid(row=3, column=0, columnspan=2, pady=20) self.addcoursesButton.grid(row=6, column=0, columnspan=2, pady=20) self.displayFrame.grid(row=4, column=0, columnspan=2) self.exitButton.grid(row=8, column=0, pady=10, padx=50, sticky=S + W) self.backButton.grid(row=8, column=1, pady=10, padx=50, sticky=S + E) self.frame.rowconfigure(8, weight=1) self.frame.columnconfigure(0, weight=1) self.frame.columnconfigure(1, weight=1) root.mainloop() def display_courses(self, root, list_): self.displayFrame.destroy() self.displayFrame = Frame(self.frame) self.displayScrollframe = ScrollableFrame(self.displayFrame) self.displayScrollframe.grid(column=0, row=0, sticky="nsew") self.displayFrame.grid(row=5, column=0, columnspan=2) self.displayScrollframe.frame.columnconfigure(1, weight=1) for i in range(len(list_)): courseserialLabel = Label(self.displayScrollframe.frame, anchor=W, text=i + 1) courserollnameLabel = Label(self.displayScrollframe.frame, anchor=W, text=list_[i][0] + ' ' + list_[i][1]) courseserialLabel.grid(row=i, column=0, sticky=W + E, padx=5) courserollnameLabel.grid(row=i, column=1, sticky=W + E) # studentname_Label_DepartmentCourses.bind('<Button-1>', self.viewstudentname_popup_Command_DepartmentCourses) def back(self, root): self.clear() root.maxsize(800, 600) DepartmentAcademic.DepartmentAcademic(root) def search(self, root): coursename_ = self.courseEntry.get() self.display_courses(root, DepartmentCourses.searchcourse(coursename_)) @staticmethod def searchcourse(coursename_): connect_, cursor_ = ES.get_student_db_ES() cursor_.execute( "SELECT * FROM all_courses WHERE course_name LIKE (:coursename)", {'coursename': '%' + coursename_ + '%'}) return cursor_.fetchall() def clear(self): self.frame.destroy() def add(self, root): self.clear() CoursesNew.CoursesNew(root) @staticmethod def test(): connect_, cursor_ = ES.get_student_db_ES() print('Testing the DepartmentCourses Class\n') success = 0 fail = 0 print('a. Course Code already present') try: CoursesNew.CoursesNew.addcourse( 'CS20006', 'Software Engineering Lab', 'Abir Das, Sourangshu Bhattacharya', '2') fail += 1 print('\tFAIL') except Exception as e: # print(e) success += 1 print('\tPASS') print('b. Credits entered is not a number') try: CoursesNew.CoursesNew.addcourse( 'CS29006', 'Software Engineering Lab', 'Abir Das, Sourangshu Bhattacharya', 'II') fail += 1 print('\tFAIL') except Exception as e: # print(e) success += 1 print('\tPASS') print('c. Credits is not in the appropriate range of {1, 2, 3, 4, 5}') try: CoursesNew.CoursesNew.addcourse( 'CS29006', 'Software Engineering Lab', 'Abir Das, Sourangshu Bhattacharya', '-2') fail += 1 print('\tFAIL') except Exception as e: # print(e) success += 1 print('\tPASS') try: CoursesNew.CoursesNew.addcourse( 'CS29006', 'Software Engineering Lab', 'Abir Das, Sourangshu Bhattacharya', '8') fail += 1 print('\tFAIL') except Exception as e: # print(e) success += 1 print('\tPASS') print('d. One or more fields left blank') try: CoursesNew.CoursesNew.addcourse( '', 'Software Engineering Lab', 'Abir Das, Sourangshu Bhattacharya', '2') fail += 1 print('\tFAIL') except Exception as e: # print(e) success += 1 print('\tPASS') try: CoursesNew.CoursesNew.addcourse( 'CS29006', '', 'Abir Das, Sourangshu Bhattacharya', '2') fail += 1 print('\tFAIL') except Exception as e: # print(e) success += 1 print('\tPASS') try: CoursesNew.CoursesNew.addcourse('CS29006', 'Software Engineering Lab', '', '2') fail += 1 print('\tFAIL') except Exception as e: # print(e) success += 1 print('\tPASS') try: CoursesNew.CoursesNew.addcourse( 'CS29006', 'Software Engineering Lab', 'Abir Das, Sourangshu Bhattacharya', '') fail += 1 print('\tFAIL') except Exception as e: # print(e) success += 1 print('\tPASS') print('e. Happy Path Testing') try: CoursesNew.CoursesNew.addcourse( 'CS29006', 'Software Engineering Lab', 'Abir Das, Sourangshu Bhattacharya', '2') cursor_.execute('SELECT * FROM all_courses WHERE sub_code=(:code)', {'code': 'CS29006'}) results = cursor_.fetchall() if not len(results) == 1: # print('More than one result returned') print('\tFAIL') fail += 1 elif not (results[0][0] == 'CS29006' and results[0][1] == 'Software Engineering Lab' and results[0][2] == 'Abir Das, Sourangshu Bhattacharya' and results[0][3] == 2): # print('Data entered doesn\'t match') print('\tFAIL') fail += 1 else: print('\tPASS') success += 1 except Exception as e: # print(e) fail += 1 print('\tFAIL') try: CoursesNew.CoursesNew.addcourse( 'CS29002', 'Switching Circuits Lab', 'Chittaranjan Mandal, Pabitra Mitra', '2') cursor_.execute('SELECT * FROM all_courses WHERE sub_code=(:code)', {'code': 'CS29002'}) results = cursor_.fetchall() if not len(results) == 1: # print('More than one result returned') print('\tFAIL') fail += 1 elif not (results[0][0] == 'CS29002' and results[0][1] == 'Switching Circuits Lab' and results[0][2] == 'Chittaranjan Mandal, Pabitra Mitra' and results[0][3] == 2): # print('Data entered doesn\'t match') print('\tFAIL') fail += 1 else: print('\tPASS') success += 1 except Exception as e: # print(e) fail += 1 print('\tFAIL') try: CoursesNew.CoursesNew.addcourse('CS29003', 'Algorithms Lab', 'Animesh Mukherjee, Pawan Goyal', '2') cursor_.execute('SELECT * FROM all_courses WHERE sub_code=(:code)', {'code': 'CS29003'}) results = cursor_.fetchall() if not len(results) == 1: # print('More than one result returned') print('\tFAIL') fail += 1 elif not (results[0][0] == 'CS29003' and results[0][1] == 'Algorithms Lab' and results[0][2] == 'Animesh Mukherjee, Pawan Goyal' and results[0][3] == 2): # print('Data entered doesn\'t match') print('\tFAIL') fail += 1 else: print('\tPASS') success += 1 except Exception as e: # print(e) fail += 1 print('\tFAIL') try: CoursesNew.CoursesNew.addcourse('CS39003', 'Compilers Lab', 'Partha Pratim Das', '2') cursor_.execute('SELECT * FROM all_courses WHERE sub_code=(:code)', {'code': 'CS39003'}) results = cursor_.fetchall() if not len(results) == 1: # print('More than one result returned') print('\tFAIL') fail += 1 elif not (results[0][0] == 'CS39003' and results[0][1] == 'Compilers Lab' and results[0][2] == 'Partha Pratim Das' and results[0][3] == 2): # print('Data entered doesn\'t match') print('\tFAIL') fail += 1 else: print('\tPASS') success += 1 except Exception as e: # print(e) fail += 1 print('\tFAIL') print('f. Searching Courses with empty keyword') expected = [ ('CS31003', 'Compilers', 'Partha Pratim Das', 3), ('CS31005', 'Algorithms II', 'Abhijit Das', 4), ('CS21004', 'FLAT', 'Abhijit Das', 4), ('CS21002', 'SCLD', 'Chittaranjan Mandal', 4), ('CS20006', 'Software Engineering', 'Partha Pratim Das', 3), ('CS21003', 'Algorithms I', 'Pawan Goyal', 4), ('CS21001', 'Discrete Structures', 'Aritra Hazra', 4), ('CS10001', 'PDS', 'Sudeshna Sarkar', 3), ('CS29006', 'Software Engineering Lab', 'Abir Das, Sourangshu Bhattacharya', 2), ('CS29002', 'Switching Circuits Lab', 'Chittaranjan Mandal, Pabitra Mitra', 2), ('CS29003', 'Algorithms Lab', 'Animesh Mukherjee, Pawan Goyal', 2), ('CS39003', 'Compilers Lab', 'Partha Pratim Das', 2) ] result = DepartmentCourses.searchcourse('') if expected == result: success += 1 print('\tPASS') else: fail += 1 print('\tFAIL') print('g. Searching Courses with Keyword "Lab"') expected = [('CS29006', 'Software Engineering Lab', 'Abir Das, Sourangshu Bhattacharya', 2), ('CS29002', 'Switching Circuits Lab', 'Chittaranjan Mandal, Pabitra Mitra', 2), ('CS29003', 'Algorithms Lab', 'Animesh Mukherjee, Pawan Goyal', 2), ('CS39003', 'Compilers Lab', 'Partha Pratim Das', 2)] if expected == DepartmentCourses.searchcourse('Lab'): success += 1 print('\tPASS') else: fail += 1 print('\tFAIL') print('h. Searching Courses with Keyword "Software"') expected = [('CS20006', 'Software Engineering', 'Partha Pratim Das', 3), ('CS29006', 'Software Engineering Lab', 'Abir Das, Sourangshu Bhattacharya', 2)] if expected == DepartmentCourses.searchcourse('Software'): success += 1 print('\tPASS') else: fail += 1 print('\tFAIL') print(f'Test cases passed {success}/{success + fail}') print(f'Percentage = {(success / (success + fail)) * 100}')
class MainGUI: def __init__(self, parent): self.container = tk.Frame(parent) # Create four scrollable frames and add them to the container self.SF1 = ScrollableFrame(self.container) self.SF1.grid(row=0, column=0, sticky=tk.N + tk.E + tk.S + tk.W) self.SF2 = ScrollableFrame(self.container, direction='both', scroll_sensitivity=8, bg='green', cursor='heart') self.SF2.grid(row=1, column=0, sticky=tk.N + tk.E + tk.S + tk.W) self.SF3 = ScrollableFrame(self.container, direction='vertical', bg='red', cursor='circle') self.SF3.grid(row=0, column=1, sticky=tk.N + tk.E + tk.S + tk.W) self.SF4 = ScrollableFrame(self.container, direction='horizontal', bg='blue', cursor='cross') self.SF4.grid(row=1, column=1, sticky=tk.N + tk.E + tk.S + tk.W) # Configure all rows and columns present to have the same weight (so they expand with the window) tk.Grid.columnconfigure(parent, 0, weight=1) tk.Grid.rowconfigure(parent, 0, weight=1) tk.Grid.columnconfigure(self.container, 0, weight=1) tk.Grid.columnconfigure(self.container, 1, weight=1) tk.Grid.rowconfigure(self.container, 0, weight=1) tk.Grid.rowconfigure(self.container, 1, weight=1) # Fill each frame with a grid of labels self.lots_of_labels(self.SF1.frame, 'default SF', (20, 20)) self.lots_of_labels(self.SF2.frame, 'green, fast scroll', (40, 10)) self.lots_of_labels(self.SF3.frame, 'red vertical', (20, 4)) self.lots_of_labels(self.SF4.frame, 'blue horizontal', (4, 20)) # Add the frame self.container.grid(row=0, column=0, sticky=tk.N + tk.E + tk.S + tk.W) # Add a button to demonstrate the set_direction method and direction attribute of SF tk.Button(text='change directions', font=('Times', 15, 'bold'), command=self.change_dir).grid(row=2, column=0) # Rotate through all the possibilities of scroll direction setups def change_dir(self): if self.SF2.direction == 'both': self.SF2.set_direction('horizontal') elif self.SF2.direction == 'horizontal': self.SF2.set_direction('vertical') elif self.SF2.direction == 'vertical': self.SF2.set_direction('both') # Populates a frame with a grid of labes of given text and same bg as frame def lots_of_labels(self, parent, text, dim): for row in range(dim[0]): for col in range(dim[1]): tk.Grid.columnconfigure(parent, col, weight=1) tk.Grid.rowconfigure(parent, row, weight=1) tk.Label(parent, fg='black', text=text, bg=parent.cget('bg')).grid(row=row, column=col)
class DepartmentPublication(DepartmentResearch.DepartmentResearch): def __init__(self, root): root.geometry('800x600') root.minsize(800, 600) root.maxsize(800, 600) root.title('UDIS-Department-Academics-Publications') super().__init__(root) self.display() root.mainloop() def display(self): self.displayAll.destroy() self.displayAll = ScrollableFrame(self.frame) self.displayAll.grid(row=0, column=0, padx=30, sticky=N+S+E+W) connect_, cursor_ = ES.get_student_db_ES() cursor_.execute('SELECT * FROM publications') allPublications = cursor_.fetchall() Label(self.displayAll.frame, text='Sr. No.', relief=GROOVE).grid(row=0, column=0, sticky=E+W) Label(self.displayAll.frame, text='Author', relief=GROOVE).grid(row=0, column=1, sticky=E+W) Label(self.displayAll.frame, text='Name', relief=GROOVE).grid(row=0, column=2, sticky=E+W) Label(self.displayAll.frame, text='Date', relief=GROOVE).grid(row=0, column=3, sticky=E+W) for i in range(len(allPublications)): Label(self.displayAll.frame, anchor=W, text=i+1).grid(row=i+1, column=0, sticky=E+W, padx=2, pady=2) Label(self.displayAll.frame, anchor=W, text=allPublications[i][0]).grid(row=i+1, column=1, sticky=E+W, padx=2, pady=2) publicationName = Label(self.displayAll.frame, anchor=W, text=allPublications[i][1]) publicationName.grid(row=i+1, column=2, sticky=E+W, padx=2, pady=2) Label(self.displayAll.frame, anchor=W, text=allPublications[i][2]).grid(row=i+1, column=3, sticky=E+W, padx=2, pady=2) publicationName.bind('<Button-1>', self.bindingAction) self.displayAll.frame.columnconfigure(2, weight=2) self.displayAll.frame.columnconfigure(1, weight=1) def bindingAction(self, event): popupPublication = Tk() popupPublication.geometry('400x300') publicationName = event.widget.cget('text') popupPublication.title(publicationName) connect_, cursor_ = ES.get_student_db_ES() cursor_.execute('SELECT * FROM publications WHERE pub_name=(:name)', {'name':publicationName}) publication = cursor_.fetchone() Label(popupPublication, text='Author').grid(row=1, column=0, sticky=W, padx=10) Label(popupPublication, text='Name').grid(row=2, column=0, sticky=W, padx=10) Label(popupPublication, text='Date').grid(row=3, column=0, sticky=W, padx=10) Label(popupPublication, text=publication[0]).grid(row=1, column=1, sticky=W) Label(popupPublication, text=publication[1]).grid(row=2, column=1, sticky=W) Label(popupPublication, text=publication[2]).grid(row=3, column=1, sticky=W) def new(self, root): self.clear() PublicationNew.PublicationNew(root) @staticmethod def test(): connect_, cursor_ = ES.get_student_db_ES() print('Testing the DepartmentPublication Class\n') success = 0 fail = 0 print('a. Some fields are left empty') try : PublicationNew.PublicationNew.addpublication('Heuristic search through islands', 'Partha Pratim Chakraborty', '') fail+=1 print('\tFAIL') except Exception: print('\tPASS') success+=1 try : PublicationNew.PublicationNew.addpublication('', 'Partha Pratim Chakraborty', '2009') fail+=1 print('\tFAIL') except Exception: print('\tPASS') success+=1 print('b. Publication already exists') try : PublicationNew.PublicationNew.addpublication('Automatic Detection of Human Fall', 'C. Mandal', '2007') fail+=1 print('\tFAIL') except Exception: print('\tPASS') success+=1 print('c. Happy path test') try : PublicationNew.PublicationNew.addpublication('Heuristic search through islands', 'Partha Pratim Chakraborty', '2009') cursor_.execute('SELECT * FROM publications WHERE pub_name=(:name)', {'name': 'Heuristic search through islands'}) results = cursor_.fetchall() if not len(results) == 1: print('\tFAIL') fail+=1 elif not (results[0][0] == 'Partha Pratim Chakraborty' and results[0][1] == 'Heuristic search through islands' and results[0][2] == '2009'): print('\tFAIL') fail+=1 else: print('\tPASS') success+=1 except Exception as e: print("\tFAIL") fail+=1 print(f'Test cases passed {success}/{success + fail}') print(f'Percentage = {(success / (success + fail)) * 100}')
def viewPerformance(self, roll_no, popupStudent, student): popupStudent.destroy() backlogsDict, semDict = self.fetchPerformance(roll_no) viewWindow = Tk() viewWindow.title(student[0]) viewWindow.maxsize(700, 550) viewWindow.minsize(690, 500) viewWindow.title(student[0]) connect_, cursor_ = ES.get_student_db_ES() perfView = ScrollableFrame(viewWindow) perfView.grid(row=1, column=0, sticky="nsew") detailsFrame = Frame(perfView.frame) detailsFrame.grid(row=0, column=0, sticky=E + W) Label(detailsFrame, text='Name: ' + student[1], anchor=W, relief=GROOVE).grid(row=0, column=0, columnspan=2, sticky=W + E) Label(detailsFrame, text='Roll no.: ' + student[0], anchor=W, relief=GROOVE).grid(row=1, column=0, sticky=W + E) Label(detailsFrame, text='Degree: ' + student[3], anchor=W, relief=GROOVE).grid(row=1, column=1, sticky=W + E) detailsFrame.columnconfigure(0, weight=3) detailsFrame.columnconfigure(1, weight=2) backlogsFrame = Frame(perfView.frame) backlogsFrame.grid(row=1, column=0, sticky=E + W, pady=10) Label(backlogsFrame, text="Backlogs", anchor=W, relief=GROOVE).grid(row=0, column=0, columnspan=4, sticky=E + W) if len(backlogsDict) != 0: Label(backlogsFrame, text="Course Code", relief=GROOVE, width=12).grid(row=1, column=0, sticky=E + W) Label(backlogsFrame, text="Course Name", relief=GROOVE).grid(row=1, column=1, sticky=E + W) Label(backlogsFrame, text="Credits", relief=GROOVE, width=12).grid(row=1, column=2, sticky=E + W) Label(backlogsFrame, text="Most Recent semester taken in", relief=GROOVE).grid(row=1, column=3, sticky=E + W) ind = 0 for i in backlogsDict: cursor_.execute( 'SELECT course_name,credits FROM all_courses WHERE sub_code=(:code)', {'code': i}) info = cursor_.fetchone() Label(backlogsFrame, text=str(i), relief=FLAT).grid(row=2 + ind, column=0, sticky=E + W) Label(backlogsFrame, text=str(info[0]), relief=FLAT).grid(row=2 + ind, column=1, sticky=E + W) Label(backlogsFrame, text=str(info[1]), relief=FLAT).grid(row=2 + ind, column=2, sticky=E + W) Label(backlogsFrame, text=str(backlogsDict[i]), relief=FLAT).grid(row=2 + ind, column=3, sticky=E + W) ind = ind + 1 backlogsFrame.columnconfigure(3, weight=1) else: Label(backlogsFrame, text="None", anchor=W, relief=GROOVE).grid(row=1, column=0, columnspan=4, sticky=E + W) backlogsFrame.columnconfigure(1, weight=1) ind = 3 for i in semDict: self.semPerformance(perfView, ind, i, semDict[i]) ind = ind + 1 self.ongoingSemester(student[0], perfView, ind) perfView.frame.columnconfigure(0, weight=1) viewWindow.rowconfigure(1, weight=1) viewWindow.columnconfigure(0, weight=1) Button(viewWindow, text="Save as PDF", command=lambda: self.savePDF(perfView)).grid(row=2, column=0)