Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Movie Search
#1
I've finished the movie search script. Still a little ruff around the edges but, works. I had trouble placing text in the textbox so I went with using a frame in the textbox. That way I could kinda order the layout a little. I welcome any input. Remember it will take a few seconds to get the results as it does a few queries. My understanding of the imdb database may search through several pages to get the information.

# Do the imports
from imdb import Cinemagoer
import tkinter as tk
from tkinter import ttk
from urllib.request import urlopen
from PIL import ImageTk, Image
import io

class Data:
    '''
    The Data class retrieves all information from user input
    Searches person and movies returns all relevant information
    '''
    def __init__(self):
        self.action = Cinemagoer()

    def search_person(self, name):
        person = self.action.search_person(name.strip())[0]
        return person.get('name'), person.personID
    
    def get_person(self, id):
        person = self.action.get_person(id)
        jobs = [job for job in person.get('filmography').keys()]
        movies = [movie for movie in person['filmography'][jobs[0]]]
        return person.get('name'), movies
    
    def search_movies(self, title):
        return self.action.search_movie(title)
    
    def get_movie(self, movie_id):
        if movie_id:
         movie = self.action.get_movie(movie_id)
         return movie
    

class Window:
    '''
    Window class is for visual and has fields and buttons
    for the Controller class to use
    '''
    def __init__(self, parent):
        parent.columnconfigure(0, weight=1)
        parent.rowconfigure(0, weight=1)
        parent.minsize(800,600)
        parent['padx'] = 5
        parent['pady'] = 3
        parent['bg'] = '#c0c0c0'
        parent.title('Movie Search')
        
        container = tk.Frame(parent, bg='#333333')
        container.grid(column=0, row=0, sticky='news')
        container.grid_columnconfigure(0, weight=3)
        container.grid_rowconfigure(3, weight=3)

        header = tk.Label(container, text='Movie Search', fg='#ffffff', bg='#333333')
        header['font'] = 'tk.HEADER 28 bold'
        header.grid(column=0, row=0, sticky='new', padx=2, pady=2)

        self.msg = tk.Label(container, text='Messages: ', bg='#555555', fg='#FFFFFF', anchor='w', padx=10)
        self.msg['font'] = 'tk.MENU 13 normal'
        self.msg.grid(column=0, row=1, sticky='new', padx=2, pady=2)

        row1 = tk.Frame(container, bg='#555555')
        row1.grid(column=0, row=2, sticky='new', padx=2, pady=2)
        for i in range(5):
            weight = 4 if i == 3 else 3
            row1.grid_columnconfigure(i, weight=weight, uniform='cols')

        row2 = tk.Frame(container, bg='#555555')
        row2.grid(column=0, row=3, sticky='news', padx=2, pady=2)
        row2.grid_columnconfigure(0, weight=3, uniform='tree')
        row2.grid_columnconfigure(2, weight=3, uniform='tree')
        row2.grid_rowconfigure(0, weight=3)

        row3 = tk.Frame(container, bg='#555555')
        row3.grid(column=0, row=4, sticky='new', padx=2, pady=2)
        row3.grid_columnconfigure(0, weight=3)

        label = tk.Label(row1, text='Search by:', bg='#555555', fg='#ffffff')
        label['font'] = 'None 12 normal'
        label.grid(column=0, row=0, sticky='new', padx=2, pady=4)

        self.options = ['Actors/Actresses', 'Movie Title']
        self.picked = tk.StringVar()
        self.picked.set(self.options[0])
        
        self.searchby = tk.OptionMenu(row1, self.picked, *self.options)
        self.searchby['font'] = 'None 10 normal'
        self.searchby.grid(column=1, row=0, sticky='new', padx=2, pady=4)
        self.searchby.config(border=0)

        label = tk.Label(row1, text='Search For:', bg='#555555', fg='#ffffff')
        label['font'] = 'None 12 normal'
        label.grid(column=2, row=0, sticky='new', padx=2, pady=4)

        self.entry = tk.Entry(row1)
        self.entry['font'] = 'None 12 normal'
        self.entry.grid(column=3, row=0, sticky='new', padx=2, pady=4)

        self.button = tk.Button(row1, text='Search')
        self.button.grid(column=4, row=0, sticky='new', padx=2)

        columns = ('Title', 'Released', 'Movie ID')
        self.left_tree = ttk.Treeview(row2, columns=columns, show='headings', selectmode='browse')
        for column in columns:
            if column == columns[0]:
                self.left_tree.column(column, minwidth=0, width=300, stretch='yes')
            else:
                self.left_tree.column(column, minwidth=0, width=100)
            self.left_tree.heading(column, text=column.title())
        self.left_tree.grid(column=0, row=0, sticky='news', padx=2)

        left_scroll = tk.Scrollbar(row2, orient='vertical', command=self.left_tree.yview)
        self.left_tree.config(yscrollcommand=left_scroll.set)
        left_scroll.grid(column=1, row=0, sticky='ns', padx=2)

        self.textbox = tk.Text(row2)
        self.textbox.grid(column=2, row=0, sticky='news', padx=2)
        self.textbox.grid_columnconfigure(0, weight=3)

        textbox_scroll = tk.Scrollbar(row2, orient='vertical', command=self.textbox.yview)
        self.textbox.config(yscrollcommand=textbox_scroll.set)
        textbox_scroll.grid(column=3, row=0, sticky='ns', padx=2)

        sig = tk.Label(row3, text='my-python.org', bg='#333333', fg='#ffffff')
        sig['font'] = 'None 10 normal'
        sig.grid(column=0, row=0, sticky='new')


class Controller:
    '''
    Controller class handles all communications between the Data and Window class
    '''
    def __init__(self, data, window):
        self.data = data
        self.window = window
        self.images = []

        # Button Commands
        self.window.button['command'] = self.search

        #Dropdown command        
        self.window.picked.trace('w', self.clear)

        # Bind treeview
        self.window.left_tree.bind('<<TreeviewSelect>>', self.details)

    def search(self):
        '''
        Search method will lookup either actor or movie depending on the
        selection in the Window class. At the momment the search only works
        for finding actors and actresses
        '''
        # Clear the views
        self.window.left_tree.delete(*self.window.left_tree.get_children())
        self.window.textbox.delete('1.0', 'end')
        try:
            self.frame.destroy()
        except AttributeError:
            pass

        # Get the param for either person search or movie search
        picked = self.window.picked.get()
        
        # Get the name of the search. person or movie
        name = self.window.entry.get().strip()

        # Set alternation colors for the treeview
        self.window.left_tree.tag_configure('oddrow', background='#ccceee')
        self.window.left_tree.tag_configure('evenrow', background='white')

        # Clear the entry field
        self.window.entry.delete(0, 'end')

        # # Person was selected for search
        
        if picked == 'Actors/Actresses':
            self.window.msg['text'] = f'Messages: Search results for {name.title()}'
            
            # Call the Data class search_person method
            person = self.data.search_person(name.strip())
            

            # Get relevant data using the person[1] which is set to the person id
            data = self.data.get_person(person[1])
            
            # Create empty list to hold the data wanted
            movie_list = []

            # Loop through the data getting relevant information
            # Also checking that there is a year for the movie release
            # This helps in not getting any movies not yet released
            for movie in data[1]:
                if movie.get('year'):
                    movie_list.append((movie.get('title'), movie.get('year'), movie.movieID))
                elif movie.get('year') == None:
                    year = self.data.get_movie(movie.movieID).get('year')
                    if year:
                        movie_list.append((movie.get('title'), year, movie.movieID))
                    else:
                        pass
            
        else:
            movies = self.data.search_movies(name.strip())
            movie_list = []
            for movie in movies:

                if movie.get('year'):
                    movie_list.append((movie.get('title'), movie.get('year'), movie.movieID))
                elif movie.get('year') == None:
                    year = self.data.get_movie(movie.movieID).get('year')
                    if year:
                        movie_list.append((movie.get('title'), year, movie.movieID))
                else:
                    pass

        movie_list.sort(key=lambda year: year[1])
        # Loop through the movie_list and insert into the treeview with alternating colors
        for index, movie in enumerate(movie_list):
            if index % 2 == 0:
                self.window.left_tree.insert('', index, values=(movie[0], movie[1], movie[2]), tags=('oddrow',))
            else:
                self.window.left_tree.insert('', index, values=(movie[0], movie[1], movie[2]), tags=('evenrow',))

        
    def details(self, id):
        item = self.window.left_tree.focus()
        try:
            id = self.window.left_tree.item(item)['values'][2]
        except IndexError:
            pass
        try:
            self.frame.destroy()
        except AttributeError:
            pass

        try:
            details = self.data.get_movie(id)
            title = details.get('title')
            cast = details.get('cast')
            year = details.get('year')
            plot = details.get('plot outline')
            cover = details.get('cover')
            rating = details.get('rating')
            air_date = details.get('original air date')

            cast_list = [c.get('name') for c in cast]
            cast = ', '.join(cast_list)

            img_url = urlopen(cover).read()
            img = Image.open(io.BytesIO(img_url))
            image = ImageTk.PhotoImage(img)

            
            self.frame = tk.Frame(self.window.textbox,bg='white')
            self.frame.grid(column=0, row=0, sticky='news')
            self.frame.grid_columnconfigure(0, weight=3)

            label = tk.Label(self.frame, text=f'Title', anchor='w',bg='white')
            label['font'] = 'tk.HEADER 10 bold'
            label.grid(column=0,row=0,sticky='new',pady=8)
            label = tk.Label(self.frame, text=f'{title}', anchor='w',bg='white')
            label.grid(column=1,row=0,sticky='new',pady=8)
            
            label = tk.Label(self.frame, text=f'Year:', anchor='w',bg='white')
            label['font'] = 'tk.HEADER 10 bold'
            label.grid(column=0, row=1, sticky='new',pady=8)
            label = tk.Label(self.frame, text=f'{year}', anchor='w',bg='white')
            label.grid(column=1, row=1, sticky='new',pady=8)

            label = tk.Label(self.frame, text=f'Air Date:', anchor='w',bg='white')
            label['font'] = 'tk.HEADER 10 bold'
            label.grid(column=0, row=2, sticky='new',pady=8)
            label = tk.Label(self.frame, text=f'{air_date}', anchor='w',bg='white')
            label.grid(column=1, row=2, sticky='new',pady=8)

            label = tk.Label(self.frame, text=f'Cover Image:', image=image, compound='bottom',anchor='w',bg='white')
            label['font'] = 'tk.HEADER 10 bold'
            label.grid(column=0, row=3, columnspan=2, sticky='new',pady=8)
            
            label = tk.Label(self.frame, text=f'Rating:', anchor='w',bg='white')
            label['font'] = 'tk.HEADER 10 bold'
            label.grid(column=0, row=4, sticky='new',pady=8)
            label = tk.Label(self.frame, text=f'{rating}', anchor='w',bg='white')
            label.grid(column=1, row=4, sticky='new',pady=8)

            label = tk.Label(self.frame, text=f'Plot:', anchor='w', wraplength=800, justify='left',bg='white')
            label['font'] = 'tk.HEADER 10 bold'
            label.grid(column=0, row=5, sticky='new',pady=8)
            label = tk.Label(self.frame, text=f'{plot}', anchor='w', wraplength=800, justify='left',bg='white')
            label.grid(column=1, row=5, sticky='new',pady=8)

            label = tk.Label(self.frame, text=f'Cast:', anchor='w', wraplength=800, justify='left',bg='white')
            label['font'] = 'tk.HEADER 10 bold'
            label.grid(column=0, row=6, sticky='new',pady=8)
            label = tk.Label(self.frame, text=f'{cast}', anchor='w', wraplength=800, justify='left',bg='white')
            label.grid(column=1, row=6, sticky='new',pady=8)
            
            self.window.textbox.delete('1.0', tk.END)
            self.window.textbox.insert('end', self.frame)
            self.images.append(image)
        except TypeError:
            pass

    def clear(self, write, index, mode):
        # Clear the treevies
        self.window.left_tree.delete(*self.window.left_tree.get_children())
        self.window.textbox.delete('1.0', 'end')
        self.window.msg['text'] = 'Messages: '
        try:
            self.frame.destroy()
        except AttributeError:
            pass

if __name__ == '__main__':
    root = tk.Tk()
    img = urlopen('https://my-python.org/images/code-forum/light/light_on.png')
    data = img.read()
    image = tk.PhotoImage(data=data)
    root.wm_iconphoto(True, image)
    controller = Controller(Data(), Window(root))
    root.mainloop()

Attached Files

Thumbnail(s)
   
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags


Reply
#2
Updated version. Still haven't worked on the messages box part. May remove. Not sure yet.

# Do the imports
from imdb import Cinemagoer
import tkinter as tk
from tkinter import ttk
from urllib.request import urlopen
from PIL import ImageTk, Image
import io

class Database:
    def __init__(self):
        self.query = Cinemagoer()

    def search_person(self, name):
        return self.query.search_person(name.strip())[0]
    
    def get_person(self, id):
        return self.query.get_person(id.strip())
    
    def search_movie(self, name):
        return self.query.search_movie(name.strip())
    
    def get_movie(self, id):
        return self.query.get_movie(id.strip())
    

class Window:
    def __init__(self, parent):
        parent.columnconfigure(0, weight=1)
        parent.rowconfigure(0, weight=1)
        parent.minsize(1204, 768)
        parent.title('Movie Search')

        # Containers
        container = tk.Frame(parent, bg='#cecece')
        container.grid(column=0, row=0, sticky='news', padx=5, pady=5)
        container.grid_columnconfigure(0, weight=3)
        container.grid_rowconfigure(3, weight=3)

        # Header
        headerframe = tk.Frame(container, bg='#333333')
        headerframe['highlightbackground'] = '#000000'
        headerframe['highlightcolor'] = '#000000'
        headerframe['highlightthickness'] = 1
        headerframe.grid(column=0, row=0, sticky='new', pady=1)
        headerframe.grid_columnconfigure(0, weight=3)

        # Messages
        msgframe = tk.Frame(container, bg='#333333')
        msgframe['highlightbackground'] = '#000000'
        msgframe['highlightcolor'] = '#000000'
        msgframe['highlightthickness'] = 1
        msgframe.grid(column=0, row=1, sticky='new', pady=1)
        msgframe.grid_columnconfigure(1, weight=3)

        # Search Fields
        searchframe = tk.Frame(container, bg='#555555')
        searchframe.grid(column=0, row=2, sticky='new')
        for i in range(5):
            weight = 4 if i == 3 else 1
            searchframe.columnconfigure(i, weight=weight, uniform='cols')

        dataframe = tk.Frame(container,bg='#555555')
        dataframe.grid(column=0, row=3, sticky='news')
        dataframe.columnconfigure(0, weight=3, uniform='data')
        dataframe.columnconfigure(1, weight=3, uniform='data')
        dataframe.rowconfigure(0, weight=3)

        leftframe = tk.Frame(dataframe, bg='#555555')
        leftframe.grid(column=0, row=0, sticky='news', padx=2)
        leftframe.grid_columnconfigure(0, weight=3)
        leftframe.grid_rowconfigure(0, weight=3)
        
        rightframe = tk.Frame(dataframe, bg='white', padx=10, pady=10)
        rightframe.grid(column=1, row=0, sticky='news')
        rightframe.grid_columnconfigure(0, weight=3)
        rightframe.grid_rowconfigure(0, weight=3)

        footerframe = tk.Frame(container)
        footerframe.grid(column=0, row=4, sticky='new')

        # Label and field widgets
        label = tk.Label(headerframe, text='Movie Search')
        label['bg'] = '#555555'
        label['fg'] = '#ffffff'
        label['font'] = (None, 28, 'bold')
        label.grid(column=0, row=0, sticky='new', ipadx=10, ipady=5)

        label = tk.Label(msgframe, text='MSG: ', bg='#555555', fg='#ffffff')
        label['font'] = (None, 12, 'bold')
        label.grid(column=0, row=0, padx=2, pady=3, ipadx=3, ipady=3)

        self.msg = tk.Label(msgframe, anchor='w', bg='#555555', fg='cyan')
        self.msg['font'] = (None, 12, 'normal')
        self.msg.grid(column=1, row=0, sticky='new', padx=2, pady=3, ipadx=3, ipady=3)

        label = tk.Label(searchframe, text='Searchby:', bg='#555555', fg='#ffffff')
        label['font'] = (None, 12, 'bold')
        label.grid(column=0, row=0, padx=2, pady=4, sticky='new')

        options = ['Person', 'Movie']
        self.term = tk.StringVar()
        self.term.set(options[0])
        option = tk.OptionMenu(searchframe, self.term, *options)
        option['font'] = (None, 10, 'normal')
        option.grid(column=1, row=0, padx=2, sticky='new')

        label = tk.Label(searchframe, text='Search for:', bg='#555555', fg='#ffffff')
        label['font'] = (None, 12, 'bold')
        label.grid(column=2, row=0, padx=4, pady=4, sticky='new')

        self.entry = tk.Entry(searchframe)
        self.entry['font'] = (None, 12, 'normal')
        self.entry.grid(column=3, row=0, padx=4, pady=4, sticky='new')

        self.button = tk.Button(searchframe, text='Search', cursor='hand2')
        self.button.grid(column=4, row=0, padx=2, sticky='new')

 
        self.tree = ttk.Treeview(leftframe, selectmode='browse', show='headings', cursor='hand2')
        self.tree.grid(column=0, row=0, sticky='news')

        tree_scrollbar = tk.Scrollbar(leftframe, orient='vertical', command=self.tree.yview)
        self.tree.configure(yscrollcommand=tree_scrollbar.set)
        tree_scrollbar.configure(bg='#444444', activebackground='#666666', cursor='hand2')
        tree_scrollbar.grid(column=1, row=0, sticky='ns', padx=4)

        self.tree2 = tk.Text(rightframe, wrap=tk.WORD)
        self.tree2['highlightthickness'] = 0
        self.tree2['borderwidth'] = 0

        self.tree2['state'] = 'disabled'
        self.tree2.grid(column=0, row=0, sticky='news')

        tree2_scrollbar = tk.Scrollbar(rightframe, orient='vertical', command=self.tree2.yview)
        self.tree2.configure(yscrollcommand=tree2_scrollbar.set)
        tree2_scrollbar.configure(bg='#444444', activebackground='#666666', cursor='hand2')
        tree2_scrollbar.grid(column=1, row=0, sticky='ns', padx=4)

        footer = tk.Label(footerframe, text='mypython.org', bg='#333333', fg='#ffffff')
        footer['font'] = (None, 12, 'italic bold')
        footer['cursor'] = 'hand2'
        footer.pack(expand=True, fill='x', pady=5, ipady=3)


class Controller:
    def __init__(self, window, database):
        self.window = window
        self.database = database

        # Button Commands
        self.window.button['command'] = self.search
        self.window.entry.bind('<Return>', lambda event: self.search())

        # Clear trees
        self.window.term.trace('w', self.clear)

        # Bind treeview
        self.window.tree.bind('<<TreeviewSelect>>', self.details)     

    def clear(self, write, index, mode):
        self.window.entry.delete(0, 'end')
        self.window.tree.delete(*self.window.tree.get_children())
        self.window.tree2['state'] = 'normal'
        self.window.tree2.delete('1.0', 'end')
        self.window.tree2['state'] = 'disabled'
       
    def search(self):
            name = self.window.entry.get().strip()
            self.clear(None, None, None)
            self.window.tree.tag_configure('oddrow', background='#ccceee')
            self.window.tree.tag_configure('evenrow', background='#eeefff')

            if self.window.term.get() == 'Person':
                if name:
                    person = self.database.search_person(name)
                    data = self.get_person(person.personID)
                    data.sort()

                    self.window.tree['columns'] = ['title', 'id']
                    self.window.tree.column('title', minwidth=0, stretch='yes')
                    self.window.tree.column('id', minwidth=0, width=100, stretch='no')
                    self.window.tree.heading('title', text=f'Title\'s')
                    self.window.tree.heading('id', text=f'Movie ID')
                    for index, movie in enumerate(data):
                        if index % 2 == 0:
                            self.window.tree.insert('', 'end', values=(movie[0], movie[1],), tags=('oddrow',))
                        else:
                            self.window.tree.insert('', 'end', values=(movie[0],movie[1]), tags=('evenrow',))
            
            elif self.window.term.get() == 'Movie':
                if name:
                    data = self.database.search_movie(name)
                    
                    data.sort()

                    self.window.tree['columns'] = ['title', 'id']
                    self.window.tree.column('title', minwidth=0, stretch='yes')
                    self.window.tree.column('id', minwidth=0, width=100, stretch='no')
                    self.window.tree.heading('title', text=f'Title\'s')
                    self.window.tree.heading('id', text=f'Movie ID')
                    for index, movie in enumerate(data):
                        if index % 2 == 0:
                            self.window.tree.insert('', 'end', values=(movie.get('title'), movie.movieID,), tags=('oddrow',))
                        else:
                            self.window.tree.insert('', 'end', values=(movie.get('title'), movie.movieID,), tags=('evenrow',))

    def get_person(self, personid):
        person = self.database.get_person(personid)
        jobs = [job for job in person.get('filmography')]
        movies = [movie for movie in person['filmography'][jobs[0]]]
        titles = []
        for movie in movies:
            titles.append((movie.get('title'), movie.movieID))
        return titles
    
    def search_movie(self, name):
        return self.database.search_movie(name)
    
    def get_movie(self, movieid):
        return self.database.get_movie(str(movieid))

    def details(self, event):

        try:
            item = self.window.tree.focus()
            movieid = self.window.tree.item(item)['values'][1]
            data = self.get_movie(movieid)
        except IndexError:
            pass
        else:
            title = data.get('title')
            year = data.get('production status') if 'production status' in data.keys() else data.get('year')
            cover = data.get('full-size cover url')
            cast = [name.get('name') for name in data.get('cast')]
            plot_outline = data.get('plot outline')
            aired = data.get('original air date')
            rating = data.get('rating')

            img_url = urlopen(cover).read()
            img = Image.open(io.BytesIO(img_url))
            img = img.resize((300,400))
            image = ImageTk.PhotoImage(img)

            alist = [f'Title: {title}', 'img',
                     f'\n\nYear: {year}', f'Aired: {aired}',
                     f'Rating: {rating}', f'Plot Outline:\n{plot_outline}', f'Cast:\n{", ".join(cast)}']
            self.window.tree2['state'] = 'normal'
            self.window.tree2.delete('1.0', 'end')
            for index, data in enumerate(alist):
                    if data == 'img':
                        self.window.tree2.image_create('end', image=image)
                    else:
                        self.window.tree2.insert('end', f'{data}\n\n')
            self.window.tree2['state'] = 'disabled'
            image.bk=image


if __name__ == '__main__':
    root = tk.Tk()
    controller = Controller(Window(root), Database())
    img = urlopen('https://my-python.org/images/png/ratt.png')
    data = img.read()
    image = tk.PhotoImage(data=data)
    root.wm_iconphoto(True, image)
    root.mainloop()
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags


Reply
#3
A PyQt6 version. (Still needs tweaks)

from PyQt6.QtWidgets import(QApplication, QMainWindow, QWidget,QGridLayout,
                            QComboBox, QLineEdit, QPushButton,QListWidget,
                            QScrollArea, QLabel, QHBoxLayout, QFrame)
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QPixmap, QImage, QIcon
from PyQt6 import sip
from imdb import Cinemagoer
import requests
import sys


class Data:
    def __init__(self):
        self.action = Cinemagoer()

    def search_person(self, name):
        return self.action.search_person(name.strip())
     
    def get_person(self, id):
        return self.action.get_person(id)
     
    def search_movie(self, name):
        return self.action.search_movie(name)
     
    def get_movie(self, movieid):
        return self.action.get_movie(movieid)


class Window(QMainWindow):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Get screen size and set minimum size
        app = QApplication.instance()
        screen = app.primaryScreen()
        screensize = screen.geometry()
        width = screensize.width()
        height = screensize.height()
        self.setMinimumSize(width//2, height//2+20)

        # Set taskbar icon
        img_url = 'https://my-python.org/images/python-forum/on.png'
        image = QImage()
        image.loadFromData(requests.get(img_url).content)
        self.setWindowIcon(QIcon(QPixmap(image)))

        # Setup the main container
        container = QGridLayout()
        widget = QWidget()
        widget.setLayout(container)
        self.setCentralWidget(widget)
        self.show()        

        # Create the header
        header = QLabel('Movie Finder')
        header.setAlignment(Qt.AlignmentFlag.AlignCenter)
        header.setStyleSheet('''font-size: 40px; font-weight: bold; color:white;
                             background-color: #333333; padding: 10 0 10px 0;''')
        
        # Add to main container
        container.addWidget(header, 0,0,1,5,Qt.AlignmentFlag.AlignTop)
        container.setRowStretch(0,0)

        # Set a common style for field headers
        common = 'font-weight: bold; padding:0 16px 0 16px;'

        # Set header label
        label = QLabel('Search By:')
        label.setStyleSheet(common)
        container.addWidget(label, 1,0,1,1,Qt.AlignmentFlag.AlignTop)

        # Create combobox
        self.forwhat = QComboBox()
        self.forwhat.addItems(['Person', 'Movie'])
        container.addWidget(self.forwhat, 1,1,1,1,Qt.AlignmentFlag.AlignTop)

        # Create header label
        label = QLabel('Search For:')
        label.setStyleSheet(common)
        container.addWidget(label, 1,2,1,1,Qt.AlignmentFlag.AlignTop)

        # Create enty field
        self.term = QLineEdit()
        self.term.setPlaceholderText('Search for a person\'s name')
        container.addWidget(self.term, 1,3,1,1,Qt.AlignmentFlag.AlignTop)

        # Create button
        self.button = QPushButton('Search')
        self.button.setCursor(Qt.CursorShape(13))
        container.addWidget(self.button, 1,4,1,1,Qt.AlignmentFlag.AlignTop)
        container.setRowStretch(1, 0)

        # Create hbox container
        hbox = QHBoxLayout()
        container.addLayout(hbox, 2, 0, 1,5, Qt.AlignmentFlag.AlignTop)
        
        # Create listbox to hold list of movies
        self.listbox = QListWidget()
        self.listbox.setSpacing(5)
        hbox.addWidget(self.listbox)

        # Create a frame spacer, Data will be added to a grid in the controller class
        self.frame = QFrame()
        self.frame.setFrameStyle(6)
        self.frame.setStyleSheet('background-color: white;')
        self.scrollbar = QScrollArea(widget)
        self.scrollbar.setWidget(self.frame)
        self.scrollbar.setWidgetResizable(True)
        hbox.addWidget(self.scrollbar)
        hbox.setStretch(0,1)
        hbox.setStretch(1,1)

        # Create a footer
        label = QLabel('my-python.org')
        label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        label.setStyleSheet('''font-size: 14; background-color: #333333; 
                            color: #ffffff; padding: 8px; font-style: italic;''')
        container.addWidget(label, 3,0,1,5, Qt.AlignmentFlag.AlignTop)
        

class Controller:
    def __init__(self, data, window):
        self.data = data
        self.window = window

        # Button commands
        self.window.button.clicked.connect(self.search)
 
        # Place holder text
        self.window.forwhat.currentTextChanged.connect(self.whatchange)
 
        # Detect if the return key was pressed
        self.window.term.returnPressed.connect(self.search)
 
        # List item was clicked
        self.window.listbox.itemClicked.connect(self.getmovie)

    def search(self):
        ''' Method for doing searches - Search depends on forwhat dropdown value'''
        # Get search term
        term = self.window.term.text().strip()
        reset_slider = self.window.listbox.verticalScrollBar()
        reset_slider.setValue(0)


        # Create empty list to hold movie titles
        titles = []

        # Check if the search field is empty. If not do search
        if term:
            # Clear all fields
            self.clear(self.window.frame.layout())

            # Setup a layout to hold the data
            self.layout = QGridLayout()
            self.window.frame.setLayout(self.layout)

            # Are we searching for a person or movie
            forwhat = self.window.forwhat.currentText()

            ''' We are searching for a person. Get the persons id, then get person data. '''
            if forwhat == 'Person':
                personid = self.data.search_person(term)[0].personID
                person = self.data.get_person(personid)
 
                # Get the jobs the person has worked on from filmography
                jobs = [job for job in person.get('filmography')]

                # We want movies the person acted in 
                movies = [movie for movie in person['filmography'][jobs[0]]]

            # A movie title was entered for the forwhat variable
            elif forwhat == 'Movie':
                movies = self.data.search_movie(term)

            # Get all the movies from the search and append to the empty list.
            # Also getting the movie id to later use for getting the movie details.
            # Right now just using movie title to search and get id to get details.
            for movie in movies:
                    titles.append((movie.get('title'), movie.movieID))

            # Add movies to the listbox for display
            for title in titles:
                self.window.listbox.addItem(title[0])
                
        else:
            return False

    def display(self, movie):
        ''' The display method take the data passed and breaks it down into parts we want.
            Currently, all we want is title, year, cover image, rating, plot, and cast.
        '''
        title = movie.get('title')
        year = movie.get('production status') if 'production status' in movie.keys() else movie.get('year')
        cover = movie.get('full-size cover url')
        rating = movie.get('rating')
        plot = movie.get('plot outline')
        cast = [name.get('name') for name in movie.get('cast')]

        # Reset slider position to 0
        reset_slider = self.window.scrollbar.verticalScrollBar()
        reset_slider.setValue(0)

        # Start adding data to our layout for display
        header = QLabel(title)
        header.setAlignment(Qt.AlignmentFlag.AlignCenter)
        header.setStyleSheet('''background-color: #555555; color: #ffffff;
                             font-size: 20px; font-weight: bold; padding: 8px 0 8px 0;''')
        self.layout.addWidget(header, 0, 0,1,4, Qt.AlignmentFlag.AlignTop)
        self.layout.setRowStretch(0, 0)

        # Check if there is a cover photo. If there is retrieve and resize
        # and attach toa label for display
        if cover is not None:
            image = QImage()
            image.loadFromData(requests.get(cover).content)
            label = QLabel()
            label.setFixedSize(300,300)
            pixmap = QPixmap(image)
            label.setPixmap(pixmap.scaled(300,300))

        # Else there was not a cover image. Create a label to show instead
        else:
            label = QLabel('No image available')
            label.setFrameStyle(6)
            label.setFixedSize(300,300)
            label.setAlignment(Qt.AlignmentFlag.AlignCenter)
            label.setStyleSheet('background-color: #F2F3F5;')

        # Add the label to our layout
        self.layout.addWidget(label, 1,0,3,1, Qt.AlignmentFlag.AlignTop)
        self.layout.setRowStretch(1, 0)

        # The spacer is used to keep everything pushed up
        # using rowstretch
        spacer = QFrame()
        self.layout.addWidget(spacer, 5,0,1,1)
        self.layout.setRowStretch(5, 1)

        # Put other stats to the right of the image
        label = QLabel('Released:')
        label.setStyleSheet('font-weight: bold;')
        self.layout.addWidget(label, 1,1,1,1, Qt.AlignmentFlag.AlignTop)
        self.layout.addWidget(QLabel(str(year)), 1,2,1,1, Qt.AlignmentFlag.AlignTop)
        self.layout.addWidget(spacer, 1,3,2,1)
        self.layout.setColumnStretch(0,0)
        self.layout.setColumnStretch(1,0)
        self.layout.setColumnStretch(2,0)
        self.layout.setColumnStretch(3,1)

        label = QLabel('Rating:')
        label.setStyleSheet('font-weight: bold;')
        self.layout.addWidget(label, 2,1,1,1, Qt.AlignmentFlag.AlignTop)
        self.layout.addWidget(QLabel(str(rating)), 2,2,1,1, Qt.AlignmentFlag.AlignTop)
        self.layout.addWidget(spacer, 3,1,1,1)
        self.layout.setRowStretch(0,0)
        self.layout.setRowStretch(1,0)
        self.layout.setRowStretch(3,1)

        label = QLabel('Plot Outline:')
        label.setStyleSheet('font-weight: bold;')
        self.layout.addWidget(label, 4,0,1,4, Qt.AlignmentFlag.AlignTop)
        plot_label = QLabel(plot)
        plot_label.setWordWrap(True)
        self.layout.addWidget(plot_label, 5,0,1,4, Qt.AlignmentFlag.AlignTop)

        self.layout.setRowStretch(4, 0)
        self.layout.setRowStretch(5, 0)

        label = QLabel('Cast:')
        label.setStyleSheet('font-weight: bold;')
        self.layout.addWidget(label, 6,0,1,4, Qt.AlignmentFlag.AlignTop)
        cast_label = QLabel(', '.join(cast))
        cast_label.setWordWrap(True)
        self.layout.addWidget(cast_label, 7,0,1,4, Qt.AlignmentFlag.AlignTop)

        self.layout.addWidget(spacer, 8,0,1,1)
        self.layout.setRowStretch(6, 0)
        self.layout.setRowStretch(7, 0)
        self.layout.setRowStretch(8, 2)      

    def getmovie(self, movie):
        ''' Method for getting movie data. '''
        movieid = self.data.search_movie(movie.text())[0].movieID
        title = self.data.get_movie(movieid)
        self.display(title)

    def clear(self, layout=None):
        ''' method for clearing fields, list and frames '''
        self.window.term.clear()
        self.window.listbox.clear()
        if layout is not None:
            while layout.count():
                item = layout.takeAt(0)
                widget = item.widget()
                if widget is not None:
                    widget.deleteLater()
                else:
                    self.deleteLayout(item.layout())
            sip.delete(layout)
        
    def whatchange(self):
        ''' Method changes the placeholder in the entry field '''
        self.clear(self.window.frame.layout())
        if self.window.forwhat.currentText() == 'Person':
            self.window.term.setPlaceholderText('Search for a person\'s name')
        elif self.window.forwhat.currentText() == 'Movie':
            self.window.term.setPlaceholderText('Search for a movie title')


if __name__ == '__main__':
    app = QApplication([])
    controller = Controller(Data(), Window())
    sys.exit(app.exec())
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags


Reply
#4
Good job
Reply
#5
(Sep-07-2023, 04:36 AM)menator01 Wrote: I've finished the movie search script. Still a little ruff around the edges but, works. I had trouble placing text in the textbox so I went with using a frame in the textbox. That way I could kinda order the layout a little. I welcome any input. Remember it will take a few seconds to get the results as it does a few queries. My understanding of the IMDb database may search through several pages to get the information.

Great job on completing the movie search script! Using a frame in the textbox for layout sounds like a smart workaround. Excited to see your progress and any future refinements.
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020