# 使用Python编写界面逻辑
在上一章,我们已经使用逻辑编辑器,制作了一个简单的弹出界面,用来发送title消息。
本节将会继续使用上次所制作的界面json文件,使用Python零件开发来重新实现一次功能。
在开始编写之前,我们需要找到上一章使用逻辑编辑器制作界面逻辑的时候,所编辑的项目,然后选择导出资源,找到资源包,ui文件夹中,当时所编辑的文件。
导出并保存到一个能找得到的位置,再新建一个空白附加包,将刚刚导入的界面文件导入。
导入完成之后,可以自行修改命名空间。继续新建一个界面预设,给它命名为TitleScreen
。创建完成后,勾选预加载,切换到PushScreen方式打开界面。
到这里的操作和之前使用逻辑编辑器是完全一致的。
接下来我们就可以打开PyCharm,打开这个项目的文件夹,进行代码编辑,第一次打开需要设置Sources Root
,这里不再截图展示。
找到脚本文件夹/uiScript/TitleScreen.py
,就是我们的ui逻辑文件。
默认第二行的代码是
import client.extraClientApi as clientApi
我们这里可以将其修改为
import mod.client.extraClientApi as clientApi
这样就可以正常的使用补全功能,解决自动提示的报错。
观察这个类,我们可以看到其实和逻辑编辑器中的蓝图零件,可以重写的函数基本一致,同样拥有4个函数。其中OnActivate
和OnDeactive
是只有PushScreen方式创建的界面才会被调用的函数。
使用Python代码创建的UI,有两种逻辑编写的方式。一种是像逻辑编辑器一样,在初始化时为按钮添加回调函数的绑定。还有一种是,使用数据绑定,在Json文件中提前定义好需要调用的Python文件,和代码中的函数和变量进行绑定。
# 方法一
我们首先先介绍第一种方法
那么现在我们就可以在__init__
函数中,在初始化时将一些常量定义好。比如我们需要使用到的ui控件的路径。
def __init__(self, namespace, name, param):
ScreenNode.__init__(self, namespace, name, param)
self.mMainPanel = "/main_panel"
self.mTitleText = self.mMainPanel + "/title_text"
self.mConfirmButton = self.mMainPanel + "/confirm_button"
这样就定义好了所有我们可能要用到的控件的路径,方便后面的调用。
接下来重写Create
函数,为按钮添加回调函数。
def Create(self):
"""
@description UI创建成功时调用
"""
buttonControl = self.GetBaseUIControl(self.mConfirmButton).asButton()
buttonControl.AddTouchEventParams({"isSwallow": True})
buttonControl.SetButtonTouchUpCallback(self.OnConfirmButtonClick)
def OnConfirmButtonClick(self, args):
pass
这样我们的在按钮点击后,就会触发OnConfirmButtonClick
函数
接下来我们回到预设编辑器,新建一个空零件,命名为UILogic
,并将其挂接到TitleScreen
这个界面预设下。
我们在这个零件中,监听客户端发送过来的发送Title事件。首先需要给我们的这个零件改个好记的名字,这里叫做界面服务端监听
,因为我们等会儿还需要在界面逻辑文件中,通过名字获取这个零件的示例,来给自己的服务端发送通知消息。同时在初始化服务器的时候,监听TitleEvent
事件,并发送Title指令。
代码参考如下:
@registerGenericClass("UILogicPart")
class UILogicPart(PartBase):
def __init__(self):
PartBase.__init__(self)
self.name = "界面服务端监听"
def OnRecvTitle(self, args):
self.SetCommand("/title @a title {}".format(args["text"]))
def InitServer(self):
"""
@description 服务端的零件对象初始化入口
"""
self.ListenSelfEvent("TitleEvent", self, self.OnRecvTitle)
编写完界面服务端监听
这个零件后,我们就可以回到界面逻辑的代码文件中,修改按钮回调函数。
在py文件开头处,先引入预设API
import Preset.Controller.PresetApi as presetApi
然后修改按钮回调函数,先获取TitleScreen
这个预设,再获取它的零件界面服务端监听
,随后调用NotifyToServer
函数,发送我们的事件。
发送完成后关闭这个界面。
def OnConfirmButtonClick(self, args):
text = self.GetBaseUIControl(self.mTitleText).asTextEditBox().GetEditText()
presetApi.GetPresetByName("TitleScreen").GetPartByName("界面服务端监听").NotifyToServer("TitleEvent", {"text": text})
clientApi.PopScreen()
完整代码如下:
# -*- coding: utf-8 -*-
import Preset.Controller.PresetApi as presetApi
import mod.client.extraClientApi as clientApi
ViewBinder = clientApi.GetViewBinderCls()
ViewRequest = clientApi.GetViewViewRequestCls()
ScreenNode = clientApi.GetScreenNodeCls()
class TitleScreen(ScreenNode):
def __init__(self, namespace, name, param):
ScreenNode.__init__(self, namespace, name, param)
self.mMainPanel = "/main_panel"
self.mTitleText = self.mMainPanel + "/title_text"
self.mConfirmButton = self.mMainPanel + "/confirm_button"
def Create(self):
"""
@description UI创建成功时调用
"""
buttonControl = self.GetBaseUIControl(self.mConfirmButton).asButton()
buttonControl.AddTouchEventParams({"isSwallow": True})
buttonControl.SetButtonTouchUpCallback(self.OnConfirmButtonClick)
def OnConfirmButtonClick(self, args):
text = self.GetBaseUIControl(self.mTitleText).asTextEditBox().GetEditText()
presetApi.GetPresetByName("TitleScreen").GetPartByName("界面服务端监听").NotifyToServer("TitleEvent", {"text": text})
clientApi.PopScreen()
# 方法二
接下来介绍如何通过数据绑定的方式来获取文本框的数据,绑定按钮的回调函数。
在跟着方法一的步骤操作之后,方法二的区别就主要在uiScript/TitleScreen.py
这个界面逻辑文件上。
数据绑定的官方说明文档 点我,可以配合本教程食用。
我们查阅UI说明文档,找到我们所使用的界面控件,查看他的详细Json参数。
# 按钮
我们主要看文档中的参数解释的最后几个。
可以看到$pressed_button_name
这个参数,对应了python的类名和对应的函数。button_mappings
代表了具体映射。
$pressed_button_name | fpsBattle代表编写UI逻辑的python类名,click代表按钮按下时会执行该python类的click函数。也可以使用API AddTouchEventHandler 动态注册按钮回调 |
---|---|
is_handle_button_move_event | 表示按钮是否可以响应按钮移动事件,需置true配合API AddTouchEventHandler使用 |
button_mappings | 表示按钮事件响应映射网,需置[]配合API AddTouchEventHandler使用 |
我们再打开资源包/ui/soldier_title_screen.json
这个文件,搜索common.button
,找到我们的按钮控件。
可以看到,按钮的json配置中已经存在这两个值,接下来我们按照要求修改,删除button_mappings
这个项,并修改$pressed_button_name
为%文件名.函数名
。具体的来说,就是修改为
"$pressed_button_name" : "%TitleScreen.OnConfirmButtonClick",
编辑完这个文件之后,建议不要再次用界面编辑器打开这个界面。否则有可能会被自动覆盖,覆盖后需要再次将button_mappings
删除
接下来回到TitleScreen.py
,为OnConfirmButtonClick
添加绑定,在函数的上一行,添加@ViewBinder.binding(ViewBinder.BF_ButtonClickUp)
。
同时删除按钮监听的相关函数。
def Create(self):
"""
@description UI创建成功时调用
"""
pass
@ViewBinder.binding(ViewBinder.BF_ButtonClickUp)
def OnConfirmButtonClick(self, args):
text = self.GetBaseUIControl(self.mTitleText).asTextEditBox().GetEditText()
presetApi.GetPresetByName("TitleScreen").GetPartByName("界面服务端监听").NotifyToServer("TitleEvent", {"text": text})
clientApi.PopScreen()
# 文本编辑框
接下来继续看文本编辑框的绑定。
绑定的参数主要是$text_edit_box_content_binding_name
和$text_box_name
,
我们参考文档中的注1,定义一个变量,存储文本框中的实时内容。
然后定义2个函数,一个赋值,一个返回值,并且修改按钮的回调函数,让按钮从我们定义的这个变量获取文本内容。
class TitleScreen(ScreenNode):
def __init__(self, namespace, name, param):
ScreenNode.__init__(self, namespace, name, param)
self.mText = ""
@ViewBinder.binding(ViewBinder.BF_EditChanged | ViewBinder.BF_EditFinished)
def TextBox(self, args):
self.mText = args["Text"]
return ViewRequest.Refresh
@ViewBinder.binding(ViewBinder.BF_BindString)
def ReturnTextString(self):
return self.mText
@ViewBinder.binding(ViewBinder.BF_ButtonClickUp)
def OnConfirmButtonClick(self, args):
presetApi.GetPresetByName("TitleScreen").GetPartByName("界面服务端监听").NotifyToServer("TitleEvent", {"text": self.mText})
clientApi.PopScreen()
那么不难发现,其实数据绑定,只是将一个函数,绑定一个对应的类型,并将其体现到json中。
例如ReturnTextString
就返回了一个str类型的变量,并且binding中的类型也是BF_BindString
,一个文本变量。
同样的,如果json中需要填写的是int类型的变量,我们也可以定义一个int变量,然后使用binding,绑定BF_BindInt
,然后返回这个值,并在json文件中修改对应的函数。
接下来我们再修改Json,将对应的配置和我们的类与函数匹配。
"$text_box_name" : "%TitleScreen.TextBox",
"$text_edit_box_content_binding_name" : "#TitleScreen.ReturnTextString",
上方截取了部分重要的json配置,修改完成后就应该是这样的。
截至目前就修改完成。
界面的完整代码可以在这里下载 (opens new window),其中行为包/uiScript/TitleScreen_V1.py
为方法一的代码,供大家参考。
进阶
30分钟