python3GUI--壁纸下载工具(附tk源码)

继续练习Tk,本次使用Tk制作一款壁纸下载工具,支持分类查看以及定向搜索查看壁纸,分类高达15个,让我们开始吧~


一.准备工作

python Tkinter

二.预览

1. 主界面

请添加图片描述
主界面打开后会展示十几个分类,点击分类就能进入分类

2. 壁纸检索

请添加图片描述
点击检索之后,会展示检索结果

3. 壁纸查看、下载

请添加图片描述
点击图片后会弹出新窗口,此时可以下载图片到本地

三.基本思路

在这里插入图片描述

四.源代码(Tk)

#-*-coding:utf-8-*-
import io
import re
import os
import threading
from tkinter import *
from tkinter import ttk
from PIL import Image, ImageTk
from tkinter import messagebox
from wallPaper_Spider import WallPaper_Spider



class APP:
    def __init__(self):
        self.root=Tk()
        self.root.title('WallPpaer_downloader-V1.0')
        width=720
        height=560
        left=(self.root.winfo_screenwidth()-width)/2
        top=(self.root.winfo_screenheight()-height)/2
        self.root.geometry("%dx%d+%d+%d"%(width,height,left,top))
        self.click_num=0
        self.search_page=0
        self.search_click_num=0
        self.recommand_click_num=0
        self.all_cates = WallPaper_Spider().get_cates()
        self.create_widget()
        self.set_widget()
        self.create_home_cate_page()
        self.place_widget()

        self.root.mainloop()

    def create_widget(self):
        self.note = ttk.Notebook()
        self.f1 = Frame()
        self.note.add(self.f1, text='分类')

        self.f2 = Frame()
        self.note.add(self.f2, text='检索')
        self.f2_l0 = ttk.Label(self.f2, text="关键字:",justify="center")
        self.f2_e1_var = StringVar()
        self.f2_e1 = ttk.Entry(self.f2, textvariable=self.f2_e1_var,width=45,justify="center")
        self.f2_btn1 = ttk.Button(self.f2, text='搜索', command=lambda :self.thread_it(self.do_search),width=10)

        self.m=Menu(self.root)
        self.root['menu']=self.m
        self.s1=Menu(self.m,tearoff=False)
        self.s2=Menu(self.m,tearoff=False)

    def create_home_cate_page(self):
        """
        点击分类后触发
        :return:
        """
        self.f1_btn1=ttk.Button(self.f1,text="返回分类",command=lambda :self.thread_it(self.open_home_cate_page))
        self.f1_btn2=ttk.Button(self.f1,text="上一页",command=lambda :self.thread_it(self.do_turn_up_page))
        self.f1_btn3=ttk.Button(self.f1,text="下一页",command=lambda :self.thread_it(self.do_turn_down_page))
        for i in range(15):
            exec("self.f1_l{}=ttk.Label(self.f1,background='lightblue')".format(i+1))  #exec()确实比eval强大!
            exec("self.f1_paned{}=PanedWindow(self.f1)".format(i+1))

        self.load_cates()
        for i in range(15):
            exec("self.f1_l{}.bind('<Button-1>',self.open_the_cate_window)".format(i+1))
        for i in range(5):
            exec("self.f1_l{}.place(x={},y=0)".format(i+1,i*120))
        for i in range(5):
            exec("self.f1_l{}.place(x={},y=170)".format(i+6,i*120))
        for i in range(5):
            eval("self.f1_l{}.place(x={},y=340)".format(i+11,i*120))

    def set_widget(self):
        self.note.enable_traversal()
        self.m.add_cascade(menu=self.s1,label="开始")
        self.m.add_cascade(menu=self.s2,label="关于")
        self.s1.add_command(label="打开壁纸所在文件夹",command=self.open_wallpaper_dir)
        self.s1.add_command(label="退出")
        self.s2.add_command(label="关于作者",command=lambda :messagebox.showinfo("关于作者",'作者:懷淰メ'))
        self.f2_e1.bind('<Return>',self.do_search)
        self.note.bind('<<NotebookTabChanged>>', self.get_note_curr_index)
        self.root.protocol('WM_DELETE_WINDOW',self.quit)
        self.root.bind("<Escape>",self.quit)

    def place_widget(self):
        self.note.place(x=0,y=0,width=720,height=560)
        self.f2_l0.place(x=10,y=10)
        self.f2_e1.place(x=80,y=10)
        self.f2_btn1.place(x=445,y=10)

    def open_wallpaper_dir(self):
        if self.tab_index==0:
            os.startfile(os.path.abspath('./MyWallPaper/cates'))
        elif self.tab_index==1:
            os.startfile(os.path.abspath('./MyWallPaper/search'))
        else:
            pass



    def get_note_curr_index(self,event):
        #当前切换的组件
        tab_id = self.note.select()
        #当前notebok的所在索引
        self.tab_index = self.note.index(tab_id)
        #当前tab的text
        # tab_name = self.note.tab(tab_index, "text")

    def open_home_cate_page(self):
        """
        返回分类 按钮触发事件
        :return:
        """
        self.f1_btn1.place_forget()
        self.f1_btn2.place_forget()
        self.f1_btn3.place_forget()
        self.click_num+=1#记录被单击次数
        self.create_home_cate_page()

    def load_cates(self):
        """
        启动后加载分类
        :return:
        """
        for index,cate in enumerate(self.all_cates):
            image_bytes=WallPaper_Spider().get_pic_bytes(cate['cate_cover'])
            data_stream = io.BytesIO(image_bytes)
            pil_image2 = Image.open(data_stream)
            photo = pil_image2.resize((120, 170))
            exec("self.f1_paned{}.image=ImageTk.PhotoImage(photo)".format(index+1))
            exec("self.f1_l{}.config(image=self.f1_paned{}.image)".format(index+1,index+1))
            exec("self.f1_l{}.config( compound='bottom',text='{}')".format(index+1,cate['cate_name']))#compound设置标签所在图片位置

    def open_the_cate_window(self,event):
        """
        打开分类窗口
        :param event:
        :return:
        """
        self.page_num=0
        self.f1_btn1.place(x=620,y=100)
        self.f1_btn2.place(x=620,y=180)
        self.f1_btn3.place(x=620,y=260)
        for i in range(15):#取消单击绑定事件
            exec("self.f1_l{}.unbind('<Button-1>')".format(i+1))
        widget=re.sub(r'.!frame.!label','',str(event.widget))
        index=self.get_index_by_widget(widget)
        self.cate_id=self.all_cates[index].get('cate_id')
        self.cate_infos=WallPaper_Spider().get_pics_by_cate(self.cate_id,page=1)
        for index_,cate in enumerate(self.cate_infos):
            image_bytes=WallPaper_Spider().get_pic_bytes(cate['thumb'])
            data_stream = io.BytesIO(image_bytes)
            pil_image2 = Image.open(data_stream)
            photo = pil_image2.resize((120, 170))
            exec("self.f1_paned{}.image=ImageTk.PhotoImage(photo)".format(index_+1))
            exec("self.f1_l{}.config(image=self.f1_paned{}.image,text='',compound='none')".format(index_+1,index_+1))
            if index_>13:
                break
        for i in range(15):
            exec("self.f1_l{}.bind('<Button-1>',self.do_magnify_photo)".format(i + 1))

    def change_infos(self):
        """
        加载分类图片信息更新
        :return:
        """
        for i in range(15):#取消单击绑定事件
            exec("self.f1_l{}.config(image=None)".format(i+1))
            exec("self.f1_l{}.unbind('<Button-1>')".format(i+1))
        for index,cate in enumerate(self.cate_infos):
            image_bytes=WallPaper_Spider().get_pic_bytes(cate['thumb'])
            data_stream = io.BytesIO(image_bytes)
            pil_image2 = Image.open(data_stream)
            photo = pil_image2.resize((120, 170))
            exec("self.f1_paned{}.image=ImageTk.PhotoImage(photo)".format(index+1))
            exec("self.f1_l{}.config(image=self.f1_paned{}.image,text='',compound='none')".format(index+1,index+1))
            if index>13:
                break
        for i in range(15):
            exec("self.f1_l{}.bind('<Button-1>',self.do_magnify_photo)".format(i + 1))

    def do_turn_down_page(self):
        """
        下一页
        :return:
        """
        self.page_num+=1
        if self.page_num==1:
            self.page_num+=2
        self.cate_infos=WallPaper_Spider().get_pics_by_cate(self.cate_id,self.page_num)
        self.change_infos()

    def do_turn_up_page(self):
        """
        上一页
        :return:
        """
        self.page_num-=1
        if self.page_num<0:
            messagebox.showwarning("警告",'当前已经在第一页!')
        else:
            self.cate_infos=WallPaper_Spider().get_pics_by_cate(self.cate_id,self.page_num)
            self.change_infos()

    def do_magnify_photo(self,event):
        widget=re.sub(r'.!frame.!label','',str(event.widget))
        self.cate_curr_index=self.get_index_by_widget(widget)
        self.show_magnify_photo(self.cate_curr_index,self.cate_infos,type='cates')

    def show_magnify_photo(self,index,data,type):
        """
        点击放大查看窗口
        :param event:
        :return:
        """
        maginfy_photo_link=data[index]['thumb']
        self.magnify_window=Toplevel()
        image_bytes = WallPaper_Spider().get_pic_bytes(maginfy_photo_link)
        data_stream = io.BytesIO(image_bytes)
        pil_image = Image.open(data_stream)
        w, h = pil_image.size
        screen_width=self.magnify_window.winfo_screenwidth()
        screen_height=self.magnify_window.winfo_screenheight()
        left=(screen_width-w)/2
        top=(screen_height-h)/2
        self.magnify_window.geometry('%dx%d+%d+%d'%(w+110,h,left,top))
        fname = maginfy_photo_link.split('/')[-1]
        sf = "{} ({}x{})".format(fname, w, h)
        self.magnify_window.title(sf)
        tk_image = ImageTk.PhotoImage(pil_image)
        label = Label(self.magnify_window, image=tk_image,)
        label.pack(padx=5, pady=5,side=LEFT)
        maginfy_photo_link=data[index]['img']
        dir=f'./MyWallPaper/{
      
      type}/'
        try:
            os.makedirs(dir)
        except:
            pass
        filename=dir+'{}.jpg'.format(maginfy_photo_link.split('/')[3].split('?')[0])
        download_btn=ttk.Button(self.magnify_window,text="下载",command=lambda :self.thread_it(self.do_download_pic,filename,maginfy_photo_link))
        download_btn.pack(side=LEFT)
        self.magnify_window.mainloop()

    def get_index_by_widget(self,widget)->int:
        #计算所选索引
        if self.click_num==0:
            if widget=='':
                index=0
            else:
                index=int(int(widget) - (self.click_num*15) - 1)
        else:
            index = int(int(widget) - (self.click_num*15) - 1)
        return index

    def get_index_by_search_widget(self,widget)->int:
        #计算所选索引
        if self.search_click_num==1:
            if widget=="2":
                index=0
            else:
                index=int(int(widget) - (self.search_click_num*30) - 2)
        else:
            index = int(int(widget) - (self.search_click_num*30) - 2)
        return index

    def do_download_pic(self,filename,link):
        """
        下载壁纸图片
        :param filename: 完整路径+文件名
        :param link:下载地址
        :return:
        """
        if WallPaper_Spider().download_pic(filename, link):
            messagebox.showinfo("提示",'{}下载成功!'.format(filename.split('/')[-1]))
        else:
            messagebox.showerror("错误",'图片下载失败!')
        self.magnify_window.destroy()

    def show_search_result(self):
        self.search_result = WallPaper_Spider().search_wall_paper(self.keyword,self.search_page)
        self.search_total = self.search_result[0].get('total')
        self.max_search_page=int(self.search_total/30)
        if self.search_total != 0:
            for i in range(30):
                exec("self.f2_l{}=ttk.Label(self.f2,background='lightblue',text='正在加载...')".format(i + 1))
                exec("self.f2_paned{}=PanedWindow(self.f2)".format(i + 1))
                exec("self.f2_l{}.config(image=None)".format(i + 1))
                exec("self.f2_l{}.unbind('<Button-1>')".format(i + 1))

            for index, data in enumerate(self.search_result[1]):
                image_bytes = WallPaper_Spider().get_pic_bytes(data['thumb'])
                data_stream = io.BytesIO(image_bytes)
                pil_image2 = Image.open(data_stream)
                photo = pil_image2.resize((100, 120))
                exec("self.f2_paned{}.image=ImageTk.PhotoImage(photo)".format(index + 1))
                exec("self.f2_l{}.config(image=self.f2_paned{}.image,text='',compound='none')".format(index + 1,index + 1))
                exec("self.f2_l{}.bind('<Button-1>',self.do_magnify_search_photo)".format(index + 1))

            if self.search_total < 30:
                self.f2_btn2.config(state=DISABLED)
                self.f2_btn3.config(state=DISABLED)
                for i in range(self.search_total, 30):
                    exec("self.f2_l{}.config(text='无预览',image=None)".format(i + 1, i + 1))
            else:
                self.f2_btn2.config(state=NORMAL)
                self.f2_btn3.config(state=NORMAL)
            for i in range(6):
                exec("self.f2_l{}.place(x={},y=40)".format(i + 1, i * 100))
            for i in range(6):
                exec("self.f2_l{}.place(x={},y=167)".format(i + 7, i * 100))
            for i in range(6):
                eval("self.f2_l{}.place(x={},y=294)".format(i + 13, i * 100))
            for i in range(6):
                eval("self.f2_l{}.place(x={},y=421)".format(i + 19, i * 100))
            for i in range(6):
                eval("self.f2_l{}.place(x={},y=548)".format(i + 25, i * 100))
            self.f2_btn2.place(x=620, y=180)
            self.f2_btn3.place(x=620, y=260)
        else:
            messagebox.showinfo("提示",f'很抱歉,没有检索到关于[{
      
      self.keyword}]的壁纸图片!')

    def do_magnify_search_photo(self,event):
        widget=re.sub(r'.!frame2.!label','',str(event.widget))
        self.search_curr_index=self.get_index_by_search_widget(widget)
        self.show_magnify_photo(self.search_curr_index,self.search_result[1],type='search')

    def do_search(self,*args):
        self.f2_btn2 = ttk.Button(self.f2, text='上一页', command=lambda :self.thread_it(self.do_turn_up_search_page))
        self.f2_btn3 = ttk.Button(self.f2, text='下一页', command=lambda :self.thread_it(self.do_turn_down_search_page))
        self.keyword=self.f2_e1.get()
        if self.keyword!="":
            self.search_click_num += 1
            self.thread_it(self.show_search_result())
        else:
            messagebox.showwarning("警告",'请输入关键字!')
            self.f2_e1.focus()

    def do_turn_down_search_page(self):
        """
        下一页
        :return:
        """
        if self.max_search_page<=1:
            messagebox.showwarning("警告",'当前已经在第一页!')
        else:
            self.search_page+=1
            if self.search_page==1:
                self.search_page += 1
            self.search_click_num += 1
            self.thread_it(self.show_search_result())

    def do_turn_up_search_page(self):
        """
        上一页
        :return:
        """
        if self.max_search_page<=1:
            messagebox.showwarning("警告", '当前已经在第一页!')
        else:
            self.search_page-=1
            if self.search_page<0:
                self.f2_btn2.config(state=DISABLED)
            else:
                self.search_click_num+=1
                self.thread_it(self.show_search_result())

    def quit(self,*args):
        ret=messagebox.askyesno('退出','确认要退出?')
        if ret :
            self.root.destroy()
        else:
            pass

    def thread_it(self,func,*args):
        t=threading.Thread(target=func,args=args)
        t.setDaemon(True)
        t.start()

if __name__ == '__main__':
    a=APP()

五.总结

本次使用Tk制作一款壁纸下载工具,在写代码过程中也遇到了一点问题,比如如何声明动态变量,如何将一个功能封装好,以供多次调用。
动态变量声明我参考了

Python 定义动态变量

程序打包好放在了蓝奏云,思路、代码方面有什么不足欢迎各位大佬指正、批评!

猜你喜欢

转载自blog.csdn.net/a1397852386/article/details/119713263
今日推荐