强智科技·教务网成绩爬取系列文章之wxpython·GUI简单设计Ⅱ

接下来几天的内容将分为三部分讲述frame.py、guimanager.py和main.py.

*基于wxpython.

第一部分 | 图形界面绘制与功能设计:frame.py


将要用到的库

import wx
import wx.lib.buttons as wxbutton  #wxpython中一个专门的按钮库
import _thread as thread  #多线程支持,提高成绩列表刷新速度
from operator import itemgetter  #用于列表排序时指定key

from analysis import parser_data
from orignal_data import get_code_in_file

*analysis.py和orignal_data.py是自有文件.


wxpython窗体框架的主要结构

class MyFrame(wx.Frame):

    def __init__(self, parent=None, id=-1, title='窗口标题', size=wx.DefaultSize,    
        style=wx.DEFAULT_FRAME_STYLE^(wx.MAXIMIZE_BOX|wx.RESIZE_BORDER)):
        wx.Frame.__init__(self, parent, id, title=title, size=size, style=style)
        self.InitUI()
        #self.Center()  #窗体居中

    def InitUI(self):
        pass

上面是窗体的基本框架,
可以试着运行一下下面的代码,感受一下~

import wx
class MyFrame(wx.Frame):
    def __init__(self, parent=None, id=-1, title='窗口标题', size=wx.DefaultSize,    
        style=wx.DEFAULT_FRAME_STYLE^(wx.MAXIMIZE_BOX|wx.RESIZE_BORDER)):
        wx.Frame.__init__(self, parent, id, title=title, size=size, style=style)
        self.InitUI()
        #self.Center()  #窗体居中

    def InitUI(self):
        pass

class App(wx.App):
    def OnInit(self):
        myframe =MyFrame()
        myframe.Show()
        #self.SetTopWindow(myframe)  #窗体置顶
        return True

def main():
    myapp = App()
    myapp.MainLoop()

if __name__ == '__main__':
    main()

运行结果如图所示:


我们有必要了解一下wxpython库中的几个基本组件:

1. wx.TextCtrl - 文本框控件
   - 主要参数:wx.TextCtrl(parent,id=ID_ANY,value="",pos=DefaultPosition,size=DefaultSize,style=0,validator=DefaultValidator,name=TextCtrlNameStr)

2. wx.StaticText - 静态文本
   - 主要参数:wx.StaticText(parent,id=ID_ANY,label="",pos=DefaultPosition,size=DefaultSize,style=0,name=StaticTexNameStr)
3. wx.Button or wxbutton.GenButton - 按钮控钮  https://docs.wxpython.org/wx.Button.html#wx.Button
   - 主要参数:wx.Button(parent,id=ID_ANY,label="",pos=DefaultPosition,size=DefaultSize,style=0,validator=DefaultVaidator,name=ButtonNameStr)
4. wx.Choice - 下拉可选列表(菜单)控件  https://docs.wxpython.org/wx.Choice.html#wx.Choice
   - 主要参数:wx.Choice(parent,id=ID_ANY,pos=DefaultPosition,size=DefaultSize,choices[],style=0,validator=DefaultValidator, name=ChoiceNameStr)
5. wx.ListCtrl - 列表控件  https://docs.wxpython.org/wx.ListCtrl.html#wx.ListCtrl
   - 主要参数:wx.ListCtrl(parent,id=ID_ANY,pos=DefaultPosition,size=DefaultSize,style=LC_ICON,validator=DefaultValidator, name=ListCtrlNameStr)
        - 该类支持以下样式(主要用到wx.LC_REPORT):
          *   `wx.LC_LIST`:多列列表视图,带有可选的小图标。列是自动计算的,即您不设置列,如 `LC_REPORT`。换句话说,与[ wx.ListBox](https://docs.wxpython.org/wx.ListBox.html#wx-listbox)不同,列表包装 。
          *   `wx.LC_REPORT`:**单列或多列报表视图,带有可选标头。**
          *   `wx.LC_VIRTUAL`:应用程序按需提供项目文本。可能只能用于 `LC_REPORT`。
          *   `wx.LC_ICON`:大图标视图,带有可选标签。
          *   `wx.LC_SMALL_ICON`:小图标视图,带有可选标签。
          *   `wx.LC_ALIGN_TOP`:图标对齐顶部。Win32默认,仅限Win32。
          *   `wx.LC_ALIGN_LEFT`:图标左对齐。
          *   `wx.LC_AUTOARRANGE`:图标安排自己。仅限Win32。
          *   `wx.LC_EDIT_LABELS`:标签可编辑:编辑开始时将通知应用程序。
          *   `wx.LC_NO_HEADER`:报告模式下没有标题。
          *   `wx.LC_SINGLE_SEL`:单选(默认为多个)。
          *   `wx.LC_SORT_ASCENDING`:按升序排序。(你仍然必须提供比较回调[`wx.ListCtrl.SortItems`](https://docs.wxpython.org/wx.ListCtrl.html#wx.ListCtrl.SortItems "wx.ListCtrl.SortItems")。)
          *   `wx.LC_SORT_DESCENDING`:按降序排序。(你仍然必须提供比较回调[`wx.ListCtrl.SortItems`](https://docs.wxpython.org/wx.ListCtrl.html#wx.ListCtrl.SortItems "wx.ListCtrl.SortItems")。)
          *   `wx.LC_HRULES`:在报告模式下在行之间绘制浅水平规则。**报告模式下使用增加美观度。**
          *   `wx.LC_VRULES`:在报告模式下在列之间绘制明亮的垂直规则。**报告模式下使用增加美观度。**

6. wx.BoxSizer - 对控件进行排版  https://docs.wxpython.org/wx.BoxSizer.html#wx.BoxSizer
   - 主要参数:wx.BoxSizer(orient=HORIZONTAL)  #可能的结构
7. wx.Icon - 程序图标控件
   - 主要参数:wx.Icon(name, type=BITMAP_TYPE_ANY, desiredWidth=-1, desiredHeight=-1)

以及几个基本方法(基于wx.Frame类可使用的方法):

1. self.Center() - 窗体居中
2. self.SetIcon(icon) - 设置程序图标
3. self.listctrl.InsertColumn (col, heading, format=LIST_FORMAT_LEFT, width=LIST_AUTOSIZE) - 插入头部标签到列表
    -功能解释:
 **For report view mode (only)**, inserts a column.
Insert a new column in the list control in report view mode at the given position specifying its most common attributes.
Notice that to set the image for the column you need to use Insert(long, ListItem&) overload and specify LIST_MASK_IMAGE in the item mask.

    - 参数解释: 
**col (long)** – The index where the column should be inserted. Valid indices are from 0 up to GetColumnCount inclusive and the latter can be used to append the new column after the last existing one.
**heading (string)** – The string specifying the column heading.
**format (int)(( – The flags specifying the control heading text alignment.
**width (int)** – If positive, the width of the column in pixels. Otherwise it can be LIST_AUTOSIZE to choose the default size for the column or LIST_AUTOSIZE_USEHEADER to fit the column width to heading or to extend to fill all the remaining space for the last column. Notice that in case of LIST_AUTOSIZE fixed width is used as there are no items in this column to use for determining its best size yet. If you want to fit the column to its contents, use SetColumnWidth after adding the items with values in this column.

4. self.listctrl.SetItem(index(行, self.listctrl.InsertItem()[object]),column(列, int),label(要插入的数据, string),imageId = -1) - 设置特定列项的字符串
4. self.object.SetForegroundColour('#888888') - 设置对象的背景文本颜色(RGB格式的颜色)
5. self.choice_obj.SetSelection(0) - 设置下拉列表的先选项
6. self.choice_obj.SetString(0, 'title') - 设置下拉列表某选项的标签
7. boxsizer.Add() - 添加控件到boxsizer
    - 主要参数: Add(window(控件), proportion(比例)=0, flag=0, border(间隔)=0, userData=None)
*一种主流方法,可查阅:https://www.yiibai.com/wxpython/wx_boxsizer.html。
    - 功能解释:Appends a child to the sizer.
[wx.Sizer](https://docs.wxpython.org/wx.Sizer.html#wx-sizer) itself is an abstract class, but the parameters are equivalent in the derived classes that you will instantiate to use it so they are described here.

      - 参数解释:
        * **window** ([*wx.Window*](https://docs.wxpython.org/wx.Window.html#wx.Window "wx.Window")) – The window to be added to the sizer. Its initial size (either set explicitly by the user or calculated internally when using DefaultSize) is interpreted as the minimal and in many cases also the initial size.
        *   **proportion** (*int*) – Although the meaning of this parameter is undefined in [wx.Sizer](https://docs.wxpython.org/wx.Sizer.html#wx-sizer), it is used in [wx.BoxSizer](https://docs.wxpython.org/wx.BoxSizer.html#wx-boxsizer) to indicate if a child of a sizer can change its size in the main orientation of the [wx.BoxSizer](https://docs.wxpython.org/wx.BoxSizer.html#wx-boxsizer) - where 0 stands for not changeable and a value of more than zero is interpreted relative to the value of other children of the same [wx.BoxSizer](https://docs.wxpython.org/wx.BoxSizer.html#wx-boxsizer). For example, you might have a horizontal [wx.BoxSizer](https://docs.wxpython.org/wx.BoxSizer.html#wx-boxsizer) with three children, two of which are supposed to change their size with the sizer. Then the two stretchable windows would get a value of 1 each to make them grow and shrink equally with the sizer’s horizontal dimension.
        *   **flag** (*int*) – OR-combination of flags affecting sizer’s behaviour. See [Sizer flags list](https://docs.wxpython.org/wx.Sizer.html#wx-sizer) for details.
        *   **border** (*int*) – Determines the border width, if the flag parameter is set to include any border flag.
        *   **userData** (*PyUserData*) – Allows an extra object to be attached to the sizer item, for use in derived classes when sizing information is more complex than the proportion and flag will allow for.

       - 关于**flag**的参数可选项
            - **对齐标志**
wx.ALIGN_TOP
wx.ALIGN_BOTTOM
wx.ALIGN_LEFT
wx.ALIGN_RIGHT
wx.ALIGN_CENTER_VERTICAL
wx.ALIGN_CENTER_HORIZONTAL
            - **边界标志**
wx.TOP
wx.BOTTOM
wx.LEFT
wx.RIGHT
wx.ALL
            - **行为标志**和说明   
wx.EXPAND
项目将扩大,以填补提供给它的空间(wx.GROW是一样的)
wx.SHAPED
与EXPAND相似,但保持了项目的高宽比
wx.FIXED_MINSIZE
不允许该项目变得比其最初的最小尺寸更小
wx.RESERVE_SPACE_EVEN_IF_ HIDDEN
不允许测量器(sizer)回收项目空间,当它被隐藏时
8. self.panel.SetSizerAndFit(boxsizer) - 应用boxsizer中的设置
9. self.listctrl.ClearAll() - 清空列表内容

具体各方法的参数详情请查阅wxpython库官方文档:https://docs.wxpython.org/


下面介绍教务网查成绩小工具的主要功能及其代码实现:

  1. 点击获取\刷新验证码的按钮,刷新显示验证码。
   def image_show(self):
        '验证码显示'
        image = wx.Image('code.jpg', wx.BITMAP_TYPE_JPEG)
        temp = image.ConvertToBitmap()
        self.bmp = wx.StaticBitmap(parent=self.panel, bitmap=temp, pos=(420,40))

   def Fresh_Code(self, event):
        '刷新验证码'
        self.cookies = get_code_in_file()
        self.image_show()
  1. 点击查询成绩按钮,按之前文本框输入的登录信息以及下拉菜单的所选项模拟登陆教务网,爬取数据然后显示成绩(分级显示)。
    def OnRefresh(self,event):
        '多线程刷新列表'
        try:
            self.get_data()
        except:
            print("用户未登录,成绩无法获取!")
        if self.data:
            thread.start_new_thread(self.SetData,(0, ))
        else:
            self.OnClick()
            
    def get_data(self):
        '获取成绩数据'
        index = self.listbox.GetSelection()
        temp = [self.text.GetValue(), self.text1.GetValue(), self.list1[index]]
        verifycode_ = self.code_text.GetValue()
        self.data = parser_data(verifycode_, self.cookies, temp[0], temp[1], temp[-1])
        if self.data == []:
            self.OnClick()

    def SetData(self, pos):
        '将数据插入到列表,不同成绩段显示不同颜色'
        self.list.ClearAll()
        self.CreateHeader()
        for each in self.data:
            pos = self.list.InsertItem(pos+1,each[0])
            for i in range(1,11):
                self.list.SetItem(pos,i,each[i])
            grade = each[4]
            try:
                if int(grade) < 60:
                    self.list.SetItemBackgroundColour(pos, (255, 0, 0))  #挂科显示为红色
                elif int(grade) <= 61:
                    self.list.SetItemBackgroundColour(pos, (255, 99, 71))  #60到61为浅红
                elif int(grade) <= 74:
                    self.list.SetItemBackgroundColour(pos, (238, 221, 130))  #62到74为黄
                elif int(grade) <= 84:
                    self.list.SetItemBackgroundColour(pos, (152, 251, 152))  #75到84为浅绿
                elif int(grade) <= 100:
                    self.list.SetItemBackgroundColour(pos, (124, 252, 0))  #85到100为绿
            except:
                pass
                
            if grade == '不及格':
                self.list.SetItemBackgroundColour(pos, (255, 0, 0))  #挂科显示为红色
            elif grade == '及格' and each[3] != '军事技能训练':
                self.list.SetItemBackgroundColour(pos, (255, 99, 71))  #及格为浅红
            elif grade == '中':
                self.list.SetItemBackgroundColour(pos, (238, 221, 130))  #中为黄
            elif grade == '良' or each[3] == '军事技能训练':
                self.list.SetItemBackgroundColour(pos, (152, 251, 152))  #良为浅绿,军训特殊,大部分为及格,显示为浅绿
            elif grade == '优':
                self.list.SetItemBackgroundColour(pos, (124, 252, 0))  #优为绿
  1. 点击列表中的任一头部标签,按此标签对列表进行排序。
    def sort_by_column(self, listevent):
        '按指定标签正序排序列表'
        num = listevent.GetColumn()
        #with open('data.json', 'w') as f:
        #    f.write(json.dumps(self.data, ensure_ascii=False, indent=4, sort_keys=False))
        self.data = sorted(self.data, key=itemgetter(num))
        self.SetData(pos=0)
        
    def sort_by_column_reversed(self, listevent):
        '按指定标签逆序排序列表'
        num = listevent.GetColumn()
        self.data = sorted(self.data, key=itemgetter(num), reverse=True)
        self.SetData(pos=0)
  1. 出错时跳出Tips窗体,点击帮助按钮跳出Hlep窗体。
    def OnClick(self):
        '切换到窗体TipsFrame'
        self.UpdateUI(1)

    def OnClick_Help(self, event):
        '切换到窗体HelpFrame'
        self.UpdateUI(2)

请看frame.py的全部Codes.

import wx
import wx.lib.buttons as wxbutton
import _thread as thread
from operator import itemgetter

from analysis import parser_data
from orignal_data import get_code_in_file

class MainFrame(wx.Frame):
    
    def __init__(
            self, parent=None, id=-1, title='HNUST教务网成绩查询小工具  by:王S  公众号:胜言  来关注 一起学习吧 ~',size=wx.DefaultSize,
            style=wx.DEFAULT_FRAME_STYLE^(wx.MAXIMIZE_BOX|wx.RESIZE_BORDER), UpdateUI=None
    ):
        wx.Frame.__init__(self, parent, id, title=title, size=size, style=style)
        
        self.data = []  #数据初始化
        self.UpdateUI = UpdateUI
        self.InitUI()  #绘制UI界面
        self.Center()
        
    def InitUI(self):
        #绘制面板
        self.panel = wx.Panel(self)
        #软件图标
        self.Software_Icon()
        #文本控件集
        self.Textctrl()
        #成绩列表框
        self.Grades_List()
        #按钮集
        self.Buttons()
        #控件容器
        self.Boxsizer()
        #程序事件处理
        self.Event_deal()
        
    def Software_Icon(self):
        '设置图标'
        icon = wx.Icon('hnust(black).ico', wx.BITMAP_TYPE_ICO)
        self.SetIcon(icon)   
        
    def Choice_Listbox(self):
        '选择框控件初始化'
        self.list1 = ['', '2018-2019-1', '2017-2018-2', '2017-2018-1', '2016-2017-2','2016-2017-1', '2016-2015-2', '2016-2015-1', '2015-2014-2', '2015-2014-1']  #可选项
        self.listbox = wx.Choice(self.panel, -1, choices=self.list1)
        self.listbox.SetSelection(0)  #初选项
        self.listbox.SetString(0, '全部成绩')  #给指定项设置标签
    
    def Comment(self):  #注释静态文本
        #self.s_text = wx.StaticText(self.panel, label='*输入学号后按回车也\n 可以获取验证码哦~')
        #self.s_text1 = wx.StaticText(self.panel, label='*教务网密码输入框')
        #self.s_text2 = wx.StaticText(self.panel, label='*选择空白为查询全部成绩', pos=(250,38))
        #self.s_text3 = wx.StaticText(self.panel, label='*刷新验证码の基础招式', pos=(380,43))
        pass
        
    def Textctrl(self):
        '文本控件初始化'
        #学号输入框
        self.text = wx.TextCtrl(self.panel,value='请输入学号...', style=wx.TE_PROCESS_ENTER)
        self.text.SetForegroundColour('#888888')
        #密码输入框
        self.text1 = wx.TextCtrl(self.panel,value='password', style=wx.TE_PASSWORD)
        self.text1.SetForegroundColour('#888888')
        #学段选择框
        self.Choice_Listbox()
        #self.text2 = wx.TextCtrl(self.panel, value='2017-2018-2')
        #self.text2.SetForegroundColour('#888888')
        #注释提示
        self.Comment()
        #验证码输入框
        self.code_text = wx.TextCtrl(self.panel,value='请输入验证码...', style=wx.TE_PROCESS_ENTER)
        self.code_text.SetForegroundColour('#888888')
        
    def Grades_List(self):
        '列表控件初始化'
        self.list = wx.ListCtrl(self.panel, id=-1, pos=(10,75), size=(989,500), style=wx.LC_REPORT)  # , size=(895,500), 
        self.CreateHeader()  #创建列表标签
        self.list.InsertItem(0, "请填充信息.")  #初始化列表内容为‘请填充信息.’  
        
    def CreateHeader(self):
        '列表标签设定'
        self.list.InsertColumn(0, "学号", format=wx.LIST_FORMAT_LEFT, width=80)
        self.list.InsertColumn(1, "姓名", format=wx.LIST_FORMAT_CENTER, width=50)
        self.list.InsertColumn(2, "开课学期", format=wx.LIST_FORMAT_CENTER, width=100)
        self.list.InsertColumn(3, "课程名称", format=wx.LIST_FORMAT_LEFT, width=230)
        self.list.InsertColumn(4, "总成绩", format=wx.LIST_FORMAT_CENTER, width=50)
        self.list.InsertColumn(5, "课程性质", format=wx.LIST_FORMAT_CENTER, width=100)
        self.list.InsertColumn(6, "课程类别", format=wx.LIST_FORMAT_CENTER, width=75)
        self.list.InsertColumn(7, "学时", format=wx.LIST_FORMAT_CENTER, width=50)
        self.list.InsertColumn(8, "学分", format=wx.LIST_FORMAT_CENTER, width=50)
        self.list.InsertColumn(9, "考试性质", format=wx.LIST_FORMAT_CENTER, width=75)
        self.list.InsertColumn(10, "补重学期", format=wx.LIST_FORMAT_CENTER, width=100)
     
    def Buttons(self):
        '按钮控件初始化'
        self.button = wxbutton.GenButton(self.panel, -1, '查询成绩')
        self.code_button = wxbutton.GenButton(self.panel, -1, '获取/刷新验证码')
        self.help_button = wxbutton.GenButton(self.panel, -1, '帮助')
        
    def Boxsizer(self):
        '容器设定'
        box = wx.BoxSizer(wx.HORIZONTAL) #放置水平的box sizer
        box.Add(self.text, 0, wx.ALL, 10) #水平方向伸展时不改变尺寸
        box.Add(self.text1, 0, wx.ALL, 10)
        #box.Add(self.text2, 0, wx.ALL, 10)
        box.Add(self.code_button, 0, wx.ALL, 10)
        box.Add(self.code_text, 0, wx.ALL, 10)
        box.Add(self.listbox, 0, wx.ALL, 10)
        box.Add(self.button, 0, wx.ALL, 10)
        box.Add(self.help_button, 0, wx.ALL, 10)
        self.panel.SetSizerAndFit(box)
        
    def Event_deal(self):
        '程序事件处理'
        self.Bind(wx.EVT_BUTTON, self.Fresh_Code, self.code_button)
        self.Bind(wx.EVT_TEXT_ENTER, self.Fresh_Code, self.text)
        self.Bind(wx.EVT_BUTTON, self.OnRefresh, self.button)
        self.Bind(wx.EVT_TEXT_ENTER, self.OnRefresh, self.code_text)
        self.Bind(wx.EVT_TEXT, self.modify_colour, self.text)
        self.Bind(wx.EVT_TEXT, self.modify_colour, self.text1)
        #self.Bind(wx.EVT_TEXT, self.modify_colour, self.text2)
        self.Bind(wx.EVT_TEXT, self.modify_colour, self.code_text)
        self.Bind(wx.EVT_BUTTON, self.OnClick_Help, self.help_button)
        self.Bind(wx.EVT_LIST_COL_CLICK, self.sort_by_column, self.list)  #左键单击某列标题,正序重排列表
        self.Bind(wx.EVT_LIST_COL_RIGHT_CLICK, self.sort_by_column_reversed, self.list)  #右键单击某列标题,逆序重排列表
    
    def modify_colour(self, event):
        '文本框有输入时改变其文本颜色'
        event.GetEventObject().SetForegroundColour('#2F4F4F')
        
    def Fresh_Code(self, event):
        '刷新验证码'
        self.cookies = get_code_in_file()
        self.image_show()
        #self.bmp.SetBitmap(wx.Bitmap(wx.Image('code.jpg', wx.BITMAP_TYPE_JPEG)))

    def image_show(self):
        '验证码显示'
        image = wx.Image('code.jpg', wx.BITMAP_TYPE_JPEG)
        temp = image.ConvertToBitmap()
        #size = temp.GetWidth(), temp.GetHeight()
        self.bmp = wx.StaticBitmap(parent=self.panel, bitmap=temp, pos=(420,40))

    def OnRefresh(self,event):
        '多线程刷新列表'
        try:
            self.get_data()
        except:
            print("用户未登录,成绩无法获取!")
        if self.data:
            thread.start_new_thread(self.SetData,(0, ))
        else:
            self.OnClick()
            
    def get_data(self):
        '获取成绩数据'
        index = self.listbox.GetSelection()
        temp = [self.text.GetValue(), self.text1.GetValue(), self.list1[index]]
        verifycode_ = self.code_text.GetValue()
        self.data = parser_data(verifycode_, self.cookies, temp[0], temp[1], temp[-1])
        if self.data == []:
            self.OnClick()

    def SetData(self, pos):
        '将数据插入到列表,不同成绩段显示不同颜色'
        self.list.ClearAll()
        self.CreateHeader()
        for each in self.data:
            pos = self.list.InsertItem(pos+1,each[0])
            for i in range(1,11):
                self.list.SetItem(pos,i,each[i])
            grade = each[4]
            try:
                if int(grade) < 60:
                    self.list.SetItemBackgroundColour(pos, (255, 0, 0))  #挂科显示为红色
                elif int(grade) <= 61:
                    self.list.SetItemBackgroundColour(pos, (255, 99, 71))  #60到61为浅红
                elif int(grade) <= 74:
                    self.list.SetItemBackgroundColour(pos, (238, 221, 130))  #62到74为黄
                elif int(grade) <= 84:
                    self.list.SetItemBackgroundColour(pos, (152, 251, 152))  #75到84为浅绿
                elif int(grade) <= 100:
                    self.list.SetItemBackgroundColour(pos, (124, 252, 0))  #85到100为绿
            except:
                pass
                
            if grade == '不及格':
                self.list.SetItemBackgroundColour(pos, (255, 0, 0))  #挂科显示为红色
            elif grade == '及格' and each[3] != '军事技能训练':
                self.list.SetItemBackgroundColour(pos, (255, 99, 71))  #及格为浅红
            elif grade == '中':
                self.list.SetItemBackgroundColour(pos, (238, 221, 130))  #中为黄
            elif grade == '良' or each[3] == '军事技能训练':
                self.list.SetItemBackgroundColour(pos, (152, 251, 152))  #良为浅绿,军训特殊,大部分为及格,显示为浅绿
            elif grade == '优':
                self.list.SetItemBackgroundColour(pos, (124, 252, 0))  #优为绿
            
    def sort_by_column(self, listevent):
        '按指定标签正序排序列表'
        num = listevent.GetColumn()
        #with open('data.json', 'w') as f:
        #    f.write(json.dumps(self.data, ensure_ascii=False, indent=4, sort_keys=False))
        self.data = sorted(self.data, key=itemgetter(num))
        self.SetData(pos=0)
        
    def sort_by_column_reversed(self, listevent):
        '按指定标签逆序排序列表'
        num = listevent.GetColumn()
        self.data = sorted(self.data, key=itemgetter(num), reverse=True)
        self.SetData(pos=0)

    def OnClick(self):
        '切换到窗体TipsFrame'
        self.UpdateUI(1)

    def OnClick_Help(self, event):
        '切换到窗体HelpFrame'
        self.UpdateUI(2)
    

class TipsFrame(wx.Frame):
    
    def __init__(
        self, parent=None, id=0, title='来自王Sの温馨提示~', pos=wx.DefaultPosition,size=wx.DefaultSize, 
        style=wx.DEFAULT_FRAME_STYLE^(wx.MAXIMIZE_BOX|wx.MINIMIZE_BOX|wx.RESIZE_BORDER), UpdateUI=None
    ):
        wx.Frame.__init__(self, parent, id,title=title, size=size, pos=pos, style=style)
        
        self.UpdateUI = UpdateUI
        self.InitUI() # 绘制UI界面
        self.Center()
        
    def InitUI(self):
        #绘制面板
        panel = wx.Panel(self)
        #图标设定
        self.Software_Icon()
        #图片插入
        image = wx.Image('hnust(black).ico', wx.BITMAP_TYPE_ICO)
        temp = image.ConvertToBitmap()
        #size = temp.GetWidth(), temp.GetHeight()
        self.bmp = wx.StaticBitmap(parent=panel, bitmap=temp)
        #静态文本
        self.text = wx.StaticText(panel, label='--请检查你输入的学号、密码或验证码是否正确\n--学号输入完成记得按回车键\n--请核对你所查询的学段\n--或者刷新验证码试试吧~', pos=(10,10))
        self.text.SetForegroundColour('#FF4500')
        #确定按钮
        button = wxbutton.GenButton(panel, 0, '好的~')
        #控件排版
        box = wx.BoxSizer(wx.VERTICAL)
        box.Add(self.bmp, 0, wx.CENTER, 50)
        box.Add(self.text, 0, wx.CENTER, 50)
        box.Add(button, 0, wx.CENTER, 50)
        panel.SetSizerAndFit(box)
        #事件处理
        self.Bind(wx.EVT_BUTTON, self.OnClick, button)
        
    def Software_Icon(self):
        icon = wx.Icon('hnust(black).ico', wx.BITMAP_TYPE_ICO)
        self.SetIcon(icon)

    def OnClick(self,event):
        '关闭该窗口'
        self.Close()

        
class HelpFrame(wx.Frame):
    def __init__(
        self, parent=None, id=1, title='帮助信息', pos=wx.DefaultPosition,size=wx.DefaultSize,
        style=wx.DEFAULT_FRAME_STYLE^(wx.MAXIMIZE_BOX|wx.MINIMIZE_BOX|wx.RESIZE_BORDER), UpdateUI=None
    ):
        wx.Frame.__init__(self,parent, id, title, size=size, pos=pos, style=style)
        
        self.UpdateUI = UpdateUI
        self.InitUI()
        self.Center()
        
    def InitUI(self):
        panel = wx.Panel(self)

        self.Software_Icon()
        
        image = wx.Image('hnust(black).ico', wx.BITMAP_TYPE_ICO)
        temp = image.ConvertToBitmap()
        #size = temp.GetWidth(), temp.GetHeight()
        self.bmp = wx.StaticBitmap(parent=panel, bitmap=temp)
        
        self.text = wx.StaticText(panel, label='四步走:\n  ①输入学号按回车获取验证码\n  ②第二框输入教务网密码\n  ⑤输入验证码按回车或点击"查询成绩"即可\n', pos=(10,10))
        self.text.SetForegroundColour('#FF4500')

        button = wxbutton.GenButton(panel, 1, 'Get!')
        
        box = wx.BoxSizer(wx.VERTICAL)
        box.Add(self.bmp, 0, wx.CENTER, 50)
        box.Add(self.text, 0, wx.CENTER, 50)
        box.Add(button, 0, wx.CENTER, 50)
        panel.SetSizerAndFit(box)
        
        self.Bind(wx.EVT_BUTTON, self.OnClick, button)

    def Software_Icon(self):
        icon = wx.Icon('hnust(black).ico', wx.BITMAP_TYPE_ICO)
        self.SetIcon(icon)
        
    def OnClick(self, event):
        '关闭该窗口'
        self.Close()

这些Codes真是按照下面的思维导图所写得的,也完全符合开头所述的Frame基本结构。
主要运用的就是我上面写的那几个基本控件还有方法。
功能设计在代码中亦有介绍,敬请查看。

思维导图
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容