VS Code打开我们的工程文件夹:
新建一个文件:editor.py
首先既然要用到GUI,自然是要import包进来:
import sys
import os
from PySide6.QtCore import *
from PySide6.QtGui import *
from PySide6.QtWidgets import *
from ui_savemain import Ui_MainWindow
同时我们也导入自己制作的UI界面。
ui_savemain正是上一节中我们保存的py文件的名字。
那么怎么调用出来呢。
class SaveEditor(QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
if __name__ == "__main__":
app = QApplication(sys.argv)
main_window = SaveEditor()
main_window.show()
app.exec()
新建一个类,多重继承QMainWindow,Ui_MainWindow
,然后实例化这个类,直接运行我们就能看到窗体了,同时能看到我们自己放的两个按钮。
我这里是后期效果了,前期效果没有存图。先放着吧。
首先让我们来想想如何实现导入字符串的效果,把字符串输入进去很容易,但是如何把字符串正确处理并且显示图片呢?这就是整个程序第一个核心难点。
虽然鼓励大家独立思考,但是我这里直接说吧。
首先我们知道楼层信息字符串包含很多$$$$$$,那么我们首先要处理掉$,然后每个数字对应一个图块,那么我们只要建立121个(11*11)按钮,把数字放进按钮里面,显示出来,然后点击按钮,可以更改数字,然后修改完了最后再输出按钮上的数字,然后再把分隔符$填充回去就可以了。
但是按钮实在是太丑了,我们有别的东西可以利用吗,可以,就是label
,这个控件没有边框,可以显示图片,让我们的界面美观起来,但是label
有个重大的缺陷:它本身不能被单击事件响应——或者说当初GUI控件的作者就没设计这个功能,我们曲线救国,让label
能够响应单击事件:
这里的代码不要求大家理解,简单说一下就是自定义label
的信号槽,让他响应单击事件。
class MyQLabel(QLabel):
button_clicked_signal = Signal()
def __init__(self, parent=None):
super(MyQLabel, self).__init__(parent)
self.button_clicked_signal.connect(self.change_map)#绑定一个指定函数,这个是后面要做的功能,先放进来
def mouseReleaseEvent(self, QMouseEvent):
self.button_clicked_signal.emit()
这样label
也准备好了,让我们开始编写逻辑代码。
仔细想一下,程序是不是应该先把121个label
放置到窗口里,然后再绘制地图呢?
确实应该是这样,那么首先我们要确定label
的坐标,足足有121个,让我们借助range函数和for循环来计算出每个label
的坐标。
定位到主类,新建一个函数calculate_xy
:
def calculate_xy(self):
xy_offset = 52 # 定义偏移量,因为label的坐标并不是从(0,0)开始的
self.xy_list = []#用来存放坐标值
for i1 in range(11):#循环11次
for i2 in range(11):#循环11次
y = i1 * 32#每次循环x和y都将*32
x = i2 * 32#因为每个label的大小是32*32,为了不重叠,每次要偏移32个像素
xy = (x + xy_offset, y + xy_offset)#把之前的偏移量加上
self.xy_list.append(xy)#把坐标结果放到list里面
计算好之后,就应该创建label
了,新建一个函数:
def setup_label(self):
self.label_list = [] # 用于存放label控件方便查找
for index in range(121): # 循环121次
object_name = "label_" + str(index) # 设定label的objectName方便我们后期查找
map_label = MyQLabel(self) # 实例化Label类,记得用之前继承过的类
map_label.setObjectName(object_name) # 设定objectname
map_label.resize(32, 32) # 设定label大小
x = self.xy_list[index][0]
y = self.xy_list[index][1]
map_label.move(x, y) # 设定坐标
self.label_list.append(map_label) # 把label放进去
定位到我们的主类,在里面新建一个函数draw_map
def draw_map(self, floor_str: str): # 传一个参数进去,用于接受楼层信息字符串
split_floor = floor_str.split("$") # 处理掉分隔符,取出数字做成list
split_floor = split_floor[0:121] # 因为会有一个空元素,对list进行切片,去掉最后一个元素,其实直接删除也可以
for index, text in enumerate(split_floor): # 进行迭代,enumerate函数会给每个list元素编号
label_widget = self.label_list[index] # 先取到对应编号的label
image_path = os.path.join("images", text + ".png") # 提前准备好了对应数字的图片文件
if os.path.exists(image_path): # 如果图片存在
label_widget.setPixmap(QPixmap(image_path)) # 给label填充图片
else:
label_widget.setPixmap(
QPixmap("images/missing.png")
) # 填充一个miss图片进去来提醒我们这个数字图块没有图片
label_widget.setToolTip(text) # 同时设置鼠标悬浮时候的提示框文本
# 把数字放到tooltip里面方便后期存取
# text变量是每个图块的数字
这样我们绘图部分就处理好了。这样的话下一章我们来搞定输入和输出。