`

打造自己的天气预报之(三)——给程序加个图形用户界面(GUI)

阅读更多

经过前期的设计,我们已经可以从网上获取天气信息,并且可以使用邮件发送。今天我们要给程序增加一个界面,毕竟并不是所有人都习惯命令行操作。先给大家看一下最终效果


这是在Win7下的运行效果。我使用wxPython来实现GUI。wxPython是wxWidgets的Python实现,而wxWidgets是一个开源的跨平台的C++构架库(framework),它可以提供GUI(图形用户界面)和其它工具。

开发任一wxPython程序必须包括五个基本步骤:

1、导入必须的wxPython包

2、子类化wxPyhon应用程序类

3、定义一个应用程序的初始化方法

4、创建一个应用程序类的实例

5、进入这个应用程序的主事件循环

下面我们一步一步地来实现这个界面。

首先,我们需要导入必须的wxPython包。

import wx
 一旦这个包被导入,你就可以引用wxPython的类、函数和常量(它们以wx为前缀,如wx.Frame)。当然也可以使用from wx import *来导入具体用到的类、函数或者变量,这样使用时就不必加上wx前缀,但是这样可能导致命名空间冲突,所以不建议这样做。

通常情况下,Python中的模块导入顺序无关紧要,但是wxPython中的不同,它是一个复杂的模块,当你第一次导入wx模块时,wxPython需要对别的wxPython模块执行一些初始化工作。所以我们必须将import wx作为第一条导入名句,然后再导入其他的Python模块,其他的Python模块导入顺序可以随意。

接下来,我们要使用应用程序和框架工作。每个wxPython程序必须有一个application对象和至少一个frame对象。Application对象必须是wx.App或其子类的一个实例。

要子类化wxPython的应用程序类,也就是wx.App,代码如下:

class MyApp(wx.App):
    """应用程序类wx.App的子类"""
    def __init__(self, title, sText):    #重构构造方法,其中title、sText分别是传递给主窗口的标题参数和状态栏参数
        wx.App.__init__(self)   #调用wx.App的构造方法
        frame = MyFrame(title, sText)   #创建主窗口对象
        frame.Show(True)    #显示主窗口
 

上面的代码定义了一个名为MyApp的子类,__init__方法定义了应用程序的初始化方法,在该方法中我们调用了其父方法wx.App.__init__,然后调用MyFrame方法(后面会实现)创建了一个窗口,再调用Show方法使窗口可见。

为了使应用程序运行,我们需要创建一个应用程序实例并进入它的主事件循环,代码如下:

app = MyApp(wTitle, wTime)
app.MainLoop()
至此,上述五个基本步骤我们都已经实现了,接下来我们简单说明一下如何实现文章开头的图形用户界面,也就是实现MyFrame类。

MyFrame类是wx.Frame类的子类,创建MyFrame类时需要调用其父类的构造器wx.Frame.__init__(),wx.Frame的构造器所要求的参数如下:

wx.Frame(parent, id=-1, title=””, pos=wx.DefaultPosition,
        size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE,
        name=”frame”)

我们在别的窗口部件的构造器中将会看到类似的参数。参数的说明如下:

parent:框架的父窗口。对于顶级窗口,这个值是None。框架随其父窗口的销毁而销毁。取决于平台,框架可被限制只出现在父窗口的顶部。在多文档界面的情况下,子窗口被限制为只能在父窗口中移动和缩放。
id:关于新窗口的wxPython ID号。你可以明确地传递一个。或传递-1,这将导致wxPython自动生成一个新的ID。
title:窗口的标题。
pos:一个wx.Point对象,它指定这个新窗口的左上角在屏幕中的位置。在图形用户界面程序中,通常(0,0)是显示器的左上角。这个默认的(-1,-1)将让系统决定窗口的位置。
size:一个wx.Size对象,它指定这个窗口的初始尺寸。这个默认的(-1,-1)将让系统决定窗口的初始尺寸。
style:指定窗口的类型的常量。你可以使用或运算来组合它们。
name:框架的内在的名字。以后你可以使用它来寻找这个窗口。

除于parent参数外,其他参数都是可选的。

def __init__(self, title, sText):
        wx.Frame.__init__(self, None, -1, title=title,
                                      style=wx.DEFAULT_FRAME_STYLE ^
                                      (wx.MAXIMIZE_BOX | wx.RESIZE_BORDER))
我们这里所用的style是默认类型但是没有最大化按钮和可缩放的边框。

这个窗口创建后内容是空的,我们需要在框架中插入各种对象和控件。首先增加一个wx.Panel的实例,它是其他控件的容器。

self.panel = wx.Panel(self)

我们还需要一个状态栏来显示天气发布的时间

stBar = self.CreateStatusBar()

接下来创建窗口中的各种控件。我们的程序一共需要三种控件:wx.StaticBitmap、wx.StaticText和wx.Button分别表示静态图片控件、静态文本控件以及按钮控件。这三种控件的构造方法都比较类似:

wx.StaticBitmap(parent, id=-1, bitmap=wxNullBitmap, 
                          pos=DefaultPosition,size=DefaultSize, 
                          style=0, name=StaticBitmapNameStr)
wx.StaticText(parent, id, label, pos=wx.DefaultPosition,
                          size=wx.DefaultSize, style=0, name=”staticText”)
wx.Button(parent, id, label, pos, size=wxDefaultSize, style=0,
    			  validator=DefaultValidator, name=”button”)

其中,wx.StaticBitmap构造器中的bitmap参数是一个Bitmap对象,我们可以先从本地图片文件创建图像对象,然后再转换成Bitmap对象,再生成wx.StaticBitmap控件。

创建各种控件比较简单,但是我们不能直接把创建好的控件放置在窗口中,这样的话界面比较丑陋,因此我们需要使用布局管理器——sizer来管理我们的布局。sizer是用于自动布局一组窗口部件的算法。sizer被附加到一个容器,通常是一个框架或面板。在父容器中创建的子窗口部件必须被分别地添加到sizer。当sizer被附加到容器时,它随后就管理它所包含的孩子的布局。

使用sizer的好处是很多的。当子窗口部件的容器的尺寸改变时,sizer将自动计算它的孩子的布局并作出相应的调整。同样,如果其中的一个孩子改变了尺寸,那么sizer能够自动地刷新布局。此外,当你想要改变布局时,sizer管理起来很容易。最大的弊端是sizer的布局有一些局限性。但是,最灵活sizer——grid bag和box,能够做你要它们做的几乎任何事。

Sizer之间也可以互相嵌套,本例一共使用了3种Sizer:GridbagSizer、BoxSizer、StaticBoxSizer。整个窗口使用BoxSizer将内容分为上下两部分;上半部分使用BoxSizer再分为左右两部分,左半部分使用GridBagSizer来布局天气信息,再嵌入到一个StaticBoxSizer中,右半部分使用StaticBoxSizer放置了三个按钮;下半部分使用GridBagSizer来布局每一天的天气信息,再使用StaticBoxSizer来布局未来4天的天气信息。

完整程序如下所示,关键地方我都有注释。

#! /usr/bin/env python
#coding=utf-8
import wx
from GetWeather import WeatherInfo

#todayInfo=u"12月8日星期四 小雨转多云7℃/-1℃ 北风5-6级 img/07.gif img/01.gif".split()
#daysInfo=[todayInfo,todayInfo,todayInfo,todayInfo]
class MyApp(wx.App):
    """应用程序类wx.App的子类"""
    def __init__(self, title, sText):    #重构构造方法,其中title、sText分别是传递给主窗口的标题参数和状态栏参数
        wx.App.__init__(self)   #调用wx.App的构造方法
        frame = MyFrame(title, sText)   #创建主窗口对象
        frame.Show(True)    #显示主窗口
        
class MyFrame(wx.Frame):
    def __init__(self, title, sText):
        wx.Frame.__init__(self, None, -1, title=title, style=wx.DEFAULT_FRAME_STYLE ^ (wx.MAXIMIZE_BOX | wx.RESIZE_BORDER))
        self.panel = wx.Panel(self)
        stBar = self.CreateStatusBar()  #创建状态栏
        stBar.SetStatusText(sText)  #状态栏显示发布时间
        
        hdLeft = self.LayoutHeadLeft(todayInfo)
        hdRight = self.LayoutHeadRight()
        head = self.LayoutHead(hdLeft, hdRight)
        days = self.LayoutDaysWeather(daysInfo)
        sizer = self.LayoutPanel(head, days)
        
        self.panel.SetSizer(sizer)
        sizer.Fit(self)
        sizer.SetSizeHints(self)
        
    def LayoutHeadLeft(self, todayInfo):
        """窗口上半部分左侧布局,主要是今日天气信息。
        todayInfo=[日期,图片1,图片2,天气,风力]"""
        
        #一个静态文本控件
        tLbl = wx.StaticText(self.panel, -1, label=todayInfo[3])
        
        #从文件载入图像
        img1 = wx.Image("img/a_" + todayInfo[1], wx.BITMAP_TYPE_GIF)
        img2 = wx.Image("img/a_" + todayInfo[2], wx.BITMAP_TYPE_GIF)
        
        #转换为静态图像控件
        sb1 = wx.StaticBitmap(self.panel, -1, wx.BitmapFromImage(img1))
        sb2 = wx.StaticBitmap(self.panel, -1, wx.BitmapFromImage(img2))
        
        #使用GridBagSizer来放置两个图片和两个文本控件
        GBSizer = wx.GridBagSizer(vgap=5, hgap=5)   #Grid之间水平、竖直方向间距都是5个像素
        GBSizer.Add(sb1, pos=(0, 0), span=(1, 1), flag=0)   #天气图片1,放置在第1行第1列,占一行一列
        GBSizer.Add(sb2, pos=(0, 1), span=(1, 1), flag=0)   #天气图片2,放置在第1行第2列,占一行一列
        GBSizer.Add(tLbl, pos=(1, 0), span=(1, 2), flag=0)  #天气文字信息,放置在第2行第1列,占一行两列
                
        #再使用Static Box Sizer来放置上面的GridBagSizer
        sbox = wx.StaticBox(self.panel, -1, todayInfo[0])        
        sbsizer = wx.StaticBoxSizer(sbox, wx.VERTICAL)
        sbsizer.Add(GBSizer, 0, wx.ALL, 2)
        
        return sbsizer
    
    def LayoutHeadRight(self):
        """放置3个按钮"""
        
        #三个按钮控件
        updateBtn = wx.Button(self.panel, -1, label=u"更新")
        setupBtn = wx.Button(self.panel, -1, label=u"设置")
        sendBtn = wx.Button(self.panel, -1, label=u"发送")
        
        #使用Static Box Sizer来放置上面的GridBagSizer
        sbox = wx.StaticBox(self.panel, -1, u"个性化")        
        sbsizer = wx.StaticBoxSizer(sbox, wx.VERTICAL)
        sbsizer.Add(updateBtn, 0, wx.ALL, 2)
        sbsizer.Add(setupBtn, 0, wx.ALL, 2)
        sbsizer.Add(sendBtn, 0, wx.ALL, 2)
                
        return sbsizer
    
    def LayoutHead(self, headLeft, headRight):
        
        box = wx.BoxSizer(wx.HORIZONTAL)    #使用水平BoxSizer放置今日天气信息和3个按钮
        box.Add(headLeft, 1, flag=wx.EXPAND)
        box.Add(headRight, flag=wx.EXPAND)
        
        return box
    
    def LayoutDayWeather(self, dayInfo):
        """放置未来4天每天的天气信息"""
        #两个静态文本控件
        dLbl = wx.StaticText(self.panel, -1, label=dayInfo[0])
        tLbl = wx.StaticText(self.panel, -1, label=dayInfo[3])
        #wLbl=wx.StaticText(self.panel,-1,label=todayInfo[2])
                
        #从文件载入图像
        img1 = wx.Image("img/" + dayInfo[1], wx.BITMAP_TYPE_GIF)
        img2 = wx.Image("img/" + dayInfo[2], wx.BITMAP_TYPE_GIF)
                
        #转换为静态图像控件
        sb1 = wx.StaticBitmap(self.panel, -1, wx.BitmapFromImage(img1))
        sb2 = wx.StaticBitmap(self.panel, -1, wx.BitmapFromImage(img2))
                
        #使用GridBagSizer来放置两个图片和两个文本控件
        GBSizer = wx.GridBagSizer(vgap=5, hgap=5)
        GBSizer.Add(dLbl, pos=(0, 0), span=(1, 3), flag=0)
        GBSizer.Add(sb1, pos=(1, 0), flag=0)
        GBSizer.Add(sb2, pos=(1, 1), flag=0)
        GBSizer.Add(tLbl, pos=(1, 2), flag=0)
        
        return GBSizer
    
    def LayoutDaysWeather(self, daysInfo):
        """使用竖直方向的StaticBoxSizer放置未来4天的天气信息"""
        sbox = wx.StaticBox(self.panel, -1, u"未来4日天气")
        sbsizer = wx.StaticBoxSizer(sbox, wx.VERTICAL)
        for dayInfo in daysInfo:
            sz = self.LayoutDayWeather(dayInfo)
            sbsizer.Add(sz, flag=wx.EXPAND)
        return sbsizer
    
    def LayoutPanel(self, head, days):
        """使用竖直方向的BoxSizer放置窗口上半部分内容和下半部分内容"""
        bsizer = wx.BoxSizer(wx.VERTICAL)
        bsizer.Add(head, flag=wx.EXPAND)
        bsizer.Add(days, flag=wx.EXPAND)
        return bsizer
        
if __name__ == "__main__":
    
    #南京天气
    wInfo = WeatherInfo('http://wap.weather.com.cn/wap/weather/101190101.shtml').getWeather()
    wTitle = wInfo[0]   #南京天气预报
    wTime = wInfo[1]    #发布时间
    todayInfo = wInfo[2]    #今日天气信息
    daysInfo = wInfo[3:7]   #未来4天天气信息
    app = MyApp(wTitle, wTime)  #应用程序类的一个实例
    app.MainLoop()  #进入主循环
上述程序实现了图形用户界面,当然目前还没实现3个按钮的功能,这将在下一篇中来实现。为了将天气预报信息传递给程序界面框架,我把第一篇中抓取天气信息的程序做了一些修改,主要是增加了天气图片信息,以及将抓取到的天气信息存在一个列表里方便调用,大家可以下载附件自行查看。程序中用到的天气图标文件也在附件中。
  • 大小: 29.3 KB
9
2
分享到:
评论
6 楼 wwwww55555cs 2014-11-27  
好人一生平安
5 楼 ningxh01 2014-08-06  
写的清楚明了,不错,
4 楼 mirahs 2013-10-04  
楼主,,还有这种天气预报的例子吗,,写得太好了。。。
3 楼 mirahs 2013-10-04  
楼主,好人。。
2 楼 think3t 2011-12-18  
happygao521 写道

支持一下

3Q~
1 楼 happygao521 2011-12-18  

支持一下

相关推荐

    JAVA图形界面程序——汉诺塔演示程序代码

    在这个程序中,我们将通过Swing库构建一个图形用户界面(GUI),以直观地展示汉诺塔问题的解决过程。 #### 关键知识点 ##### 1. 汉诺塔问题 汉诺塔问题包含三个柱子(A、B、C)和不同大小的盘子,所有盘子最初都堆...

    matlab——GUI程序设计

    MATLAB 的 GUI 程序设计是指使用 MATLAB 语言设计和实现图形用户界面(Graphical User Interfaces,GUI)的过程。在这种用户界面下,用户可以通过选择各种图形对象来实现命令和控制。图形对象可以分为控件对象和用户...

    QT技术手册——基于C++图形用户界面应用程序框架

    **QT技术手册——基于C++图形用户界面应用程序框架** Qt技术是软件开发领域中的一个强大工具,尤其在创建跨平台的图形用户界面(GUI)应用方面。作为一个C++库,Qt不仅提供了丰富的API,还支持多种操作系统,如...

    图形用户界面.docx

    在本实验中,我们主要探讨了Java中的图形用户界面(GUI)开发,特别是使用Java Swing库来构建交互式的应用程序。实验旨在让学生掌握以下几个关键知识点: 1. **JFrame的使用**: JFrame是Java Swing中用于创建窗口...

    经典中的经典 c语言教程——窗口图形界面设计

    本书介绍了如何为使用C语言编写的应用程序设计一个“自带汉字环境”的窗口式图形用户界面。书中系统地介绍了VGA显示卡、鼠标、键盘和扩充存储器等设备的编程方法,并在此基础上建立了一个内含式汉字编程环境HANENV,...

    可用——matlab GUI密码登陆界面.zip

    MATLAB GUI(图形用户界面)是一种使用MATLAB编程语言创建交互式用户界面的方法。这个"可用——matlab GUI密码登陆界面.zip"文件提供了一个已经预配置好的登录界面示例,适用于那些想要在MATLAB环境中构建类似功能的...

    第14章 创建图形用户界面GUI.ppt.zip

    在本章中,我们将深入探讨如何创建图形用户界面(GUI)——这是计算机程序与用户交互的重要方式。"图形用户界面"一词指的是那些利用图标、窗口、菜单和指针等视觉元素来使用户与计算机系统进行互动的软件设计。GUI为...

    matlab GUI界面设计

    使用 GUIDE 和图形句柄创建的图形用户界面的主要区别在于,利用图形句柄创建的图形界面应用程序只有一个文件—— M 文件,而利用 GUIDE 创建的图形用户界面应用程序一般由两个文件组成,一个是应用程序文件—— M ...

    java 图形界面程序——科研申报

    在Java编程领域,图形用户界面(GUI)是创建与用户交互的应用程序的重要组成部分。本项目“java 图形界面程序——科研申报”就是这样一个基于Java Swing的GUI应用,它旨在为科研申报提供一个友好的交互平台。Java ...

    java图形用户界面

    Java图形用户界面(GUI,Graphical User Interface)是Java编程中的一个重要部分,它允许开发者创建交互式的应用程序,用户可以通过鼠标和键盘与程序进行交互。在Java中,GUI主要由AWT(Abstract Window Toolkit)和...

    MATLAB图形技术——绘图及图形用户接口

    此外,MATLAB还支持创建图形用户界面(GUI),使得用户可以更直观地操作数据和程序。本文将详细介绍MATLAB中的图形技术和GUI设计方法。 #### 二、MATLAB中的绘图基础 ##### 2.1 二维绘图 在MATLAB中,最基本的绘图...

    Matlab图形技术——绘图及图形用户接口

    "Matlab图形技术——绘图及图形用户接口"这个主题涵盖了Matlab中的两大重要功能:绘图和GUI(图形用户界面)设计。这两部分是Matlab用户进行数据分析、结果展示以及交互式应用开发的关键。 首先,我们来探讨Matlab...

    matlab GUI设计——打靶

    在MATLAB中,GUI(图形用户界面)是一种强大的工具,允许用户通过图形化的交互方式与程序进行沟通。GUI设计能够使复杂的数据处理和分析过程变得更加直观和易用。本资源包"matlab GUI设计——打靶"是针对MATLAB GUI...

    python实例61-Python制作图形用户界面(GUI)让操作可视化.rar

    Python是一种强大的编程语言,广泛应用在各种领域,包括网络爬虫、数据分析、机器学习以及我们今天要讨论的主题——图形用户界面(GUI)开发。GUI能让复杂的程序操作变得直观易用,通过按钮、菜单、对话框等可视化...

    java程序GUI设计——计算器界面

    Java Swing 是Java平台上用于构建图形用户界面(GUI)的一个组件库,它提供了丰富的控件和强大的布局管理器来创建复杂的窗口应用程序。在这个实验中,我们将通过Swing包来实现一个简单的计算器界面。 实验主要涉及...

    多视图程序——绘制图形

    在IT领域,多视图程序是一种常见的应用设计模式,尤其在图形用户界面(GUI)开发中,它允许用户从不同的角度或维度查看同一份数据。本文将深入探讨多视图的概念,以及如何利用这种技术来绘制图形。 首先,我们要...

Global site tag (gtag.js) - Google Analytics