NASA搜索应用的创建
快速原型是一种快速创建小而实用的应用程序的方法,无需花费大量时间实现所有部件,而是在应用中自上而下依次添加。相较于创建一系列嵌套的sizer,这种方法效率更高。
首先,让我们创建一个名为nasa_search_ui.py的脚本:
这里将导入一些新包。第一个是请求包,使用方便,基于Python实现文件下载和Internet相关操作,许多开发人员认为它比Python自带的urllib更好用。不过它需要安装才能使用,同时还需要安装ObjectListView。
如下是使用pip的安装方法:
另外,需要导入urllib.parse,用于编码URL参数。最后,DownloadDialog是一个用于创建对话的类,用于NASA图像的下载。
由于在应用中将使用ObjectListView,因此需要一个类来表示该窗口部件中的对象:
Result类用于保存构成ObjectListView中每行的数据。Item参数是查询响应JSON的一部分。您可以根据需求解析相关信息。
在这种情况下,需要如下字段:
标题
图片位置
NASA内部ID
照片描述
摄影师名称
图像创建时间
缩略图URL
其中一些项并不总是包含在JSON响应中,在这些情况下,将通过get()方法返回空字符串。
下面将开始UI的实现:
MainPanel是程序的主体。这里,您可以处理一些内务工作并创建一个search_results,以便用户搜索时保存Result对象列表。您还可以设置缩略图的max_size,要使用的字体,sizer以及标准路径等。
下面将如下代码加入__init__()中:
这里,使用wx.StaticText为应用程序创建标题标签。然后,添加了wx.SearchCtrl,其与wx.TextCtrl非常类似,只不过内置了特殊的按钮。此外还将搜索按钮的单击事件(EVT_SEARCHCTRL_SEARCH_BTN)和EVT_TEXT_ENTER绑定到搜索相关的事件处理程序(on_search)。
接下来添加搜索结果部件:
这段代码设置ObjectListView的方式和我的其他一些文章中的方式非常相似。您可以通过调用SetEmptyListMsg()来自定义空消息,还可以将窗口部件绑定到EVT_LIST_ITEM_SELECTED,以便用户在选择搜索结果时执行某些操作。
下面将其余代码加入__init__()中:
最后几行代码添加了标题文本控件和图像窗口部件,这些部件将在选择结果时更新。您还可以添加下载按钮,以允许用户选择要下载图像的大小。NASA通常会提供从缩略图到原始TIFF图之间的几种不同版本的图像。
要查看的首个事件处理程序是on_download():
这里,通过调用GetSelectedObject()来获取用户的选择。如果用户未选择任何内容,则退出此方法。此外,如果用户选择了某个条目,则实例化DownloadDialog并将其展示给用户以允许他们下载某些内容。
下面将学习如何实现搜索:
这里,on_search()事件将获取用户输入的字符串或者返回一个空字符串。假设用户实际输入了要搜索的内容,则使用NASA的常规搜索查询,q并对media_type进行硬编码以实现成像。之后,将查询编码为格式正确的URL,并通过requests.get()来请求JSON响应。
接下来,将尝试循环搜索结果。请注意,如果不返回任何数据,代码将运行失败并抛出异常。如果返回数据,可以对其进行解析以获取所需信息。
您将跳过未设置标题字段的项目。否则,将创建一个Result对象并将其添加到search_results列表中。在方法结束时,需要通知UI更新搜索结果。
在使用该函数之前,需要创建on_selection():
您将再次获得所选条目,但是这次采用选择标题文本进行选择并更新标题文本控制。然后检查是否存在缩略图并更新(如果有)。如果无缩略图,则设置为空图像,因为您不希望它继续显示之前选择的图像。
下一个要创建的方法是update_image():
这里,update_image()接收URL作为其唯一的参数。它接收此URL并拆分文件名。然后通过计算机的临时目录创建一个新的下载位置。接着下载图像并检查文件是否存储正确。如果是,则使用设置的max_size加载缩略图;否则将设置为空白图像。
最后几行代码Refresh()和Layout()面板,使得部件能正确显示。
最后,您需要创建最后一个方法:
这里,将创建框架,设置标题和初始大小并添加面板,之后显示框架。
主UI的外观如下:
下面让我们一起学习如何实现下载对话框吧!
下载对话框
下载对话框将允许用户下载一个或多个图像,每张图像至少存在两个甚至五六个版本。
先看一下代码的前几行:
这里将再次导入requests并在保存图像时设置wildcard。
下面将创建__init__():
在此示例中,您将创建StandardPaths的新引用并添加wx.ListBox。列表框将包含可下载图像的变量。如果结果太多无法同时显示,它还会自动添加滚动条。通过传入selection对象调用get_image_urls以获取URL列表,然后遍历urls并提取名称中包含jpg的urls。这将导致遗漏其他图像文件类型,例如PNG或TIFF。
因此可以对此代码进行改进。过滤URL的原因在于排除非图像URL,以免给用户带来困惑。
最后还需要添加一个“保存”按钮,当然也可以添加“取消”按钮,但是由于对话框顶部已经包含退出按钮,所以没必要。
下面来了解以下get_image_urls()的作用:
当用户按下“保存”按钮时,将激活此事件处理程序。当用户尝试保存某些内容而不在列表框中选择条目时,将返回-1。如果发生此类情况,将通过MessageDialog告知用户进行选择。当用户选择某些内容时,将展示一个wx.FileDialog,允许用户选择保存文件的位置以及调用内容。
如下是save()方法:
这里,您将再次使用requests下载图像。注意,这里并未对用户是否添加扩展名做出检查,请使用右侧扩展名。如果可以的话,请自行添加。
当文件下载完成后,向用户展示一条提示信息。
如果发生异常,您也可以显示一个对话框通知用户!
对话框的样式如下:
接下来让我们添加一些新功能吧!
添加高级搜索
您可以使用几个字段来缩小查询范围。但是除非用户确实想使用这些过滤器,否则尽量不要用此来扰乱用户界面的设计。为了解决这个问题,可以添加“高级搜索”选项。
添加这个功能需要重新组织代码,因此这里将nasa_search_ui.py和download_dialog.py复制到名为version_2的新文件夹中。
接下来将nasa_search_ui.py重命名为main.py作为程序的入口。为了使程序更加模块化,可以将搜索结果提取到自己的类中,并在单独的类中进行高级搜索。这意味最终将需要三个面板:
主面板
搜索结果面板
高级搜索面板
实现后的对话框样式如下:
接下来将分别讨论这些问题。
main.py脚本
main模块是应用程序的入口,是为了启动应用程序而运行的代码。如果要将应用程序绑定到可执行文件中,也可以使用它。
如下是main模块:
这个示例导入了两个与搜索相关的面板:
AdvancedSearch
RegularSearch
它还使用pubsub订阅更新主题。
让我们探索一下__init__()中包含的其他内容:
这里,可以像之前那般为页面添加标题和搜索部件,还可以添加新的“高级搜索”按钮,并使用新的sizer来包含搜索部件和按钮。然后将sizer添加到主sizer中。
接下来让我们添加面板:
在此示例中,将实例化RegularSearch和AdvancedSearch面板。由于RegularSearch是默认值,因此在启动时隐藏了用户的AdvancedSearch。
现在更新on_search():
当用户按下“输入/返回”时将调用on_search()。如果用户在搜索框中输入搜索条件,则将构建查询,并通过pubsub发送。
当用户按下Advanced Search按钮,会发生什么呢?
当触发on_advanced_search()时,会隐藏搜索部件,常规搜索面板以及高级搜索按钮。接下来,将显示高级搜索面板并在main_sizer上调用Layout(),因此面板将会进行切换并调整以适应框架大小。
最后需要创建update_ui()方法:
当用户执行Advanced Search时,将调用update_ui()方法,此方法由pubsub调用。它会执行on_advanced_search(),取消显示高级搜索面板时隐藏的所有窗口部件,当然它也可以隐藏高级搜索面板。
框架代码与之前相同,因此这里并未展示。
下面让我们接着学习如何实现常规搜索面板吧!
英文原文:https://www.blog.pythonlibrary.org/2019/04/18/creating-a-gui-application-for-nasas-api-with-wxpython/
译者:我是昵称耶~