使用fbs打包pyqt5本人亲自尝试过的_no module named 'fbs_runtime-程序员宅基地

技术标签: 笔记  

首先安装python3.6 安装教略 新建个文件夹(testfbs) 进入 testfbs目录下 在testfbs下打开控制台 创建python虚拟环境命令如下:

python -m venv venv
进入环境目录 命令如下:

cd venv/scripts/

在此环境激活环境命令如下:

activate.bat

activate python36

venv/scripts/在目录下执行安装fbs

pip install fbs -i https://pypi.doubanio.com/simple

接着new一个新窗口在testfbs目录下

执行下面命令创建项目(为什么这样因为你要使用虚拟环境中的fbs)

D:\testfbs\venv\Scripts\fbs startproject

执行命令之后就会出现输入项目名字之类的 填写后项目就算创建成功了

接着就是打开D:\testfbs\src\main\python目录

这个下会有一个main.py

下面是一个我打包2048的一个例子代码

#!/usr/bin/env python
# -*- coding: utf-8 -*-


from fbs_runtime.application_context.PyQt5 import ApplicationContext
from PyQt5.QtWidgets import QMainWindow, QApplication, QMessageBox
from PyQt5.QtGui import QPainter, QColor, QFont, QPen
from PyQt5.QtCore import Qt, QRect
import sys
import os
import copy
import random
class GameForm(QMainWindow):
    def __init__(self, parent=None):
        super(GameForm, self).__init__(parent)
        self.initUi()
        # 定义各数字的背景颜色
        self.colors = {
    0: (204, 192, 179), 2: (238, 228, 218), 4: (237, 224, 200),
                       8: (242, 177, 121), 16: (245, 149, 99), 32: (246, 124, 95),
                       64: (246, 94, 59), 128: (237, 207, 114), 256: (237, 207, 114),
                       512: (237, 207, 114), 1024: (237, 207, 114), 2048: (237, 207, 114),
                       4096: (237, 207, 114), 8192: (237, 207, 114), 16384: (237, 207, 114),
                       32768: (237, 207, 114), 65536: (237, 207, 114), 131072: (237, 207, 114),
                       262144: (237, 207, 114), 524288: (237, 207, 114), 1048576: (237, 207, 114)}
        self.initGameData()
        self.chiese_grid = ["","相遇", "初识", "爱慕", "暧昧", "试探", "表白", "尴尬", "牵手", "热恋", "分手", "", "", "", "", "", "", "", ]
        self.chiese_grid1 = ["","北齐", "北周", "北魏", "隋朝", "唐朝", "宋朝", "明朝", "清朝", "民国", "中国", "", "", "", "", "", "", "", ]
        self.chiese_grid2 = ["","相遇", "初识", "爱慕", "暧昧", "试探", "表白", "尴尬", "牵手", "热恋", "分手", "", "", "", "", "", "", "", ]


    def is2powern(self, s):
        if s==0:
            return 0
        elif s==1:
            return 1

        for i in range(1,100):
            if 2**i==s:
                return i
    def initUi(self):
        self.setWindowTitle("2048")
        self.resize(505, 720)
        self.setFixedSize(self.width(), self.height())
        self.initGameOpt()

    def initGameOpt(self):
        ''' 初始化游戏配置 '''
        self.lbFont = QFont('SimSun', 12)  # label字体
        self.lgFont = QFont('SimSun', 50)  # Logo字体
        self.nmFont = QFont('SimSun', 36)  # 面板数字字体

    def initGameData(self):
        ''' 初始化游戏数字 '''
        self.data = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
        count = 0
        while count < 2:
            row = random.randint(0, len(self.data) - 1)
            col = random.randint(0, len(self.data[0]) - 1)
            if self.data[row][col] != 0:
                continue
            self.data[row][col] = 2 if random.randint(0, 1) else 4
            count += 1

        self.curScore = 0
        self.bstScore = 0
        # 载入最高得分
        if os.path.exists("bestscore.ini"):
            with open("bestscore.ini", "r") as f:
                self.bstScore = int(f.read())

    def paintEvent(self, e):
        ''' 重写绘图事件 '''
        qp = QPainter()
        qp.begin(self)
        self.drawGameGraph(qp)
        qp.end()

    def keyPressEvent(self, e):
        keyCode = e.key()
        ret = False
        if keyCode == Qt.Key_Left:
            ret = self.move("Left")
        elif keyCode == Qt.Key_Right:
            ret = self.move("Right")
        elif keyCode == Qt.Key_Up:
            ret = self.move("Up")
        elif keyCode == Qt.Key_Down:
            ret = self.move("Down")
        else:
            pass

        if ret:
            self.repaint()

    def closeEvent(self, e):
        # 保存最高得分
        with open("bestscore.ini", "w") as f:
            f.write(str(self.bstScore))

    def drawGameGraph(self, qp):
        ''' 绘制游戏图形 '''
        self.drawLog(qp)
        self.drawLabel(qp)
        self.drawScore(qp)
        self.drawBg(qp)
        self.drawTiles(qp)

    def drawScore(self, qp):
        ''' 绘制得分 '''
        qp.setFont(self.lbFont)
        fontsize = self.lbFont.pointSize()
        scoreLabelSize = len(u"SCORE") * fontsize
        bestLabelSize = len(u"BEST") * fontsize
        curScoreBoardMinW = 15 * 2 + scoreLabelSize  # SCORE栏的最小宽度
        bstScoreBoardMinW = 15 * 2 + bestLabelSize  # BEST栏的最小宽度
        curScoreSize = len(str(self.curScore)) * fontsize
        bstScoreSize = len(str(self.bstScore)) * fontsize
        curScoreBoardNedW = 10 + curScoreSize
        bstScoreBoardNedW = 10 + bstScoreSize
        curScoreBoardW = max(curScoreBoardMinW, curScoreBoardNedW)
        bstScoreBoardW = max(bstScoreBoardMinW, bstScoreBoardNedW)
        qp.setBrush(QColor(187, 173, 160))
        qp.setPen(QColor(187, 173, 160))
        qp.drawRect(505 - 15 - bstScoreBoardW, 40, bstScoreBoardW, 50)
        qp.drawRect(505 - 15 - bstScoreBoardW - 5 - curScoreBoardW, 40, curScoreBoardW, 50)

        bstLabelRect = QRect(505 - 15 - bstScoreBoardW, 40, bstScoreBoardW, 25)
        bstScoreRect = QRect(505 - 15 - bstScoreBoardW, 65, bstScoreBoardW, 25)
        scoerLabelRect = QRect(505 - 15 - bstScoreBoardW - 5 - curScoreBoardW, 40, curScoreBoardW, 25)
        curScoreRect = QRect(505 - 15 - bstScoreBoardW - 5 - curScoreBoardW, 65, curScoreBoardW, 25)

        qp.setPen(QColor(238, 228, 218))
        qp.drawText(bstLabelRect, Qt.AlignCenter, u"BEST")
        qp.drawText(scoerLabelRect, Qt.AlignCenter, u"SCORE")

        qp.setPen(QColor(255, 255, 255))
        qp.drawText(bstScoreRect, Qt.AlignCenter, str(self.bstScore))
        qp.drawText(curScoreRect, Qt.AlignCenter, str(self.curScore))

    def drawBg(self, qp):
        ''' 绘制背景图 '''
        col = QColor(187, 173, 160)
        qp.setPen(col)

        qp.setBrush(QColor(187, 173, 160))
        qp.drawRect(15, 150, 475, 475)  # 绘制游戏区域

    def drawLog(self, qp):
        ''' 绘制Logo '''
        pen = QPen(QColor(255, 93, 29), 15)
        qp.setFont(self.lgFont)
        qp.setPen(pen)
        qp.drawText(QRect(10, 0, 150, 130), Qt.AlignCenter, "2048")

    def drawLabel(self, qp):
        ''' 绘制所有标签信息 '''
        qp.setFont(self.lbFont)
        qp.setPen(QColor(119, 110, 101))
        qp.drawText(15, 134, u"合并相同数字,得到2048吧!")
        qp.drawText(15, 660, u"怎么玩:")
        qp.drawText(45, 680, u"用-> <- 上下左右箭头按键来移动方块.")
        qp.drawText(45, 700, u"当两个相同数字的方块碰到一起时,会合成一个!")

    def drawTiles(self, qp):
        ''' 绘制数字背景 '''
        qp.setFont(self.nmFont)
        for row in range(4):
            for col in range(4):
                value = self.data[row][col]
                color = self.colors[value]

                qp.setPen(QColor(*color))
                qp.setBrush(QColor(*color))
                qp.drawRect(30 + col * 115, 165 + row * 115, 100, 100)  # 绘制数字的背景小方块
                size = self.nmFont.pointSize() * len(str(value))  # 获取当前字体下显示数字的长度
                # 根据尺寸调整字体大小
                while size > 100 - 15 * 2:
                    self.nmFont = QFont('SimSun', self.nmFont.pointSize() * 4 // 5)
                    qp.setFont(self.nmFont)
                    size = self.nmFont.pointSize() * len(str(value))  # 获取当前字体下显示数字的长度
                print("[%d][%d]: value[%d] weight: %d" % (row, col, value, size))

                # 显示非0数字
                if value == 2 or value == 4:
                    qp.setPen(QColor(119, 110, 101))  # 设置2和4数字的前景色
                else:
                    qp.setPen(QColor(255, 255, 255))  # 设置其他数字的前景色
                if value != 0:
                    rect = QRect(30 + col * 115, 165 + row * 115, 100, 100)
                    # 这里可以将其改为中文

                    # qp.drawText(rect, Qt.AlignCenter, str(value))
                    print(value)
                    qp.drawText(rect, Qt.AlignCenter, self.chiese_grid1[self.is2powern(value)])

    def putTile(self):
        ''' 找到一个空位置(数值为0),并随机填充2或4 '''
        available = []
        for row in range(len(self.data)):
            for col in range(len(self.data[0])):
                if self.data[row][col] == 0:
                    available.append((row, col))
        if available:
            row, col = available[random.randint(0, len(available) - 1)]
            self.data[row][col] = 2 if random.randint(0, 1) else 4
            return True
        return False

    def merge(self, row):
        ''' 合并一行或一列 '''
        pair = False
        newRow = []
        for i in range(len(row)):
            if pair:
                newRow.append(2 * row[i])
                self.curScore += 2 * row[i]
                pair = False
            else:
                # 可以和
                if i + 1 < len(row) and row[i] == row[i + 1]:
                    pair = True
                else:
                    # 不可以和
                    newRow.append(row[i])
        return newRow

    def slideUpDown(self, isUp):
        ''' 上下方向移动数字方格 '''
        numRows = len(self.data)
        numCols = len(self.data[0])
        oldData = copy.deepcopy(self.data)

        for col in range(numCols):
            cvl = []
            for row in range(numRows):
                if self.data[row][col] != 0:
                    cvl.append(self.data[row][col])  # 将列里面的非0元素提取出来

            if len(cvl) >= 2:
                # 看看能不能合并
                cvl = self.merge(cvl)  # 合并相同数字

            # 根据移动方向填充0
            for i in range(numRows - len(cvl)):
                if isUp:
                    cvl.append(0)
                else:
                    cvl.insert(0, 0)

            print("row=%d" % row)
            row = 0
            for row in range(numRows):
                self.data[row][col] = cvl[row]

        return oldData != self.data  # 返回数据是否发生了变化

    def slideLeftRight(self, isLeft):
        ''' 左右方向移动数字方格 '''
        numRows = len(self.data)
        numCols = len(self.data[0])
        oldData = copy.deepcopy(self.data)

        for row in range(numRows):
            rvl = []
            for col in range(numCols):
                if self.data[row][col] != 0:
                    rvl.append(self.data[row][col])

            if len(rvl) >= 2:
                rvl = self.merge(rvl)

            for i in range(numCols - len(rvl)):
                if isLeft:
                    rvl.append(0)
                else:
                    rvl.insert(0, 0)

            col = 0
            for col in range(numCols):
                self.data[row][col] = rvl[col]

        return oldData != self.data

    def move(self, direction):
        ''' 移动数字方格 '''
        isMove = False
        if direction == "Up":
            isMove = self.slideUpDown(True)
        elif direction == "Down":
            isMove = self.slideUpDown(False)
        elif direction == "Left":
            isMove = self.slideLeftRight(True)
        elif direction == "Right":
            isMove = self.slideLeftRight(False)
        else:
            pass

        if not isMove:
            return False

        self.putTile()  # 新增一个数字
        if self.curScore > self.bstScore:
            self.bstScore = self.curScore

        if self.isGameOver():
            button = QMessageBox.warning(self, "Warning", u"游戏结束,是否重新开始?",
                                         QMessageBox.Ok | QMessageBox.No,
                                         QMessageBox.Ok)

            if button == QMessageBox.Ok:
                self.initGameOpt()
                bstScore = self.bstScore
                self.initGameData()
                self.bstScore = bstScore
                return True
            else:
                return False
        else:
            return True

    def isGameOver(self):
        ''' 判断游戏是否无法继续 '''
        copyData = copy.deepcopy(self.data)  # 先暂存数据值
        curScore = self.curScore

        flag = False
        if not self.slideUpDown(True) and not self.slideUpDown(False) and \
                not self.slideLeftRight(True) and not self.slideLeftRight(False):
            flag = True  # 全部方向都不能再移动
        self.curScore = curScore
        if not flag:
            self.data = copyData  # 仍可以移动,则恢复原来数据
        return flag


if __name__ == '__main__':
    appctxt = ApplicationContext()  # 1. Instantiate ApplicationContext
    app = QApplication(sys.argv)
    form = GameForm()
    form.show()
    exit_code = appctxt.app.exec_()  # 2. Invoke appctxt.app.exec_()
    sys.exit(exit_code)

其实main.py中的代码是一个最小的打包例子重点就是这几句

from fbs_runtime.application_context.PyQt5 import ApplicationContext
if __name__ == '__main__':
    appctxt = ApplicationContext()  # 1. Instantiate ApplicationContext
    app = QApplication(sys.argv)

    # 下这两句是调用你自己的程序其他不变
    form = GameForm()
    form.show()
    # 上这两句是调用你自己的程序其他不变
    exit_code = appctxt.app.exec_()  # 2. Invoke appctxt.app.exec_()
    sys.exit(exit_code)

当前目录下还有一个图标,你可以直接将自己的图标命名为这个官方给的图标是一样的这样就可以了

还有就会说资源路径问题(比如你写的是src/test.jpg)那么就这样写

import os
basepath=os.path.split(os.path.abspath(__file__))[0]
path=os.path.join(basepath,"src/test.jpg")

接着就执行 执行一定会报错 哪里错改哪里最常现的就是缺少包

D:\testfbs\venv\Scripts\fbs run

那么就使用如下操作安装你的包 继续run 直到跑起来

D:\testfbs\venv\Scripts\pip install PyQt5-sip -i https://pypi.doubanio.com/simple
D:\testfbs\venv\Scripts\pip install PyQt5 -i https://pypi.doubanio.com/simple

代码跑成功后
直接执行下面命令
D:\testfbs\venv\Scripts\fbs freeze

执行后你会在testfbs目录下看到target文件夹 在这个文件夹中会两个文件夹一个是PyInstaller和另一个也就是你之前填写的项目名字假如你起名wei wei目录下就会有一个可执行文件好那么在打开执行文件之前 你要将资源(src)整个文件夹直接粘到此目录下 如果不出意外你的软件就打包成功了 你可以直接将target这个文件分享给任何人当然要是同一平台的

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_32759777/article/details/109598619

智能推荐

hdu 1229 还是A+B(水)-程序员宅基地

文章浏览阅读122次。还是A+BTime Limit: 2000/1000 MS (Java/Others)Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 24568Accepted Submission(s): 11729Problem Description读入两个小于10000的正整数A和B,计算A+B。...

http客户端Feign——日志配置_feign 日志设置-程序员宅基地

文章浏览阅读419次。HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息。FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。BASIC:仅记录请求的方法,URL以及响应状态码和执行时间。NONE:不记录任何日志信息,这是默认值。配置Feign日志有两种方式;方式二:java代码实现。注解中声明则代表某服务。方式一:配置文件方式。_feign 日志设置

[转载]将容器管理的持久性 Bean 用于面向服务的体系结构-程序员宅基地

文章浏览阅读155次。将容器管理的持久性 Bean 用于面向服务的体系结构本文将介绍如何使用 IBM WebSphere Process Server 对容器管理的持久性 (CMP) Bean的连接和持久性逻辑加以控制,使其可以存储在非关系数据库..._javax.ejb.objectnotfoundexception: no such entity!

基础java练习题(递归)_java 递归例题-程序员宅基地

文章浏览阅读1.5k次。基础java练习题一、递归实现跳台阶从第一级跳到第n级,有多少种跳法一次可跳一级,也可跳两级。还能跳三级import java.math.BigDecimal;import java.util.Scanner;public class Main{ public static void main(String[]args){ Scanner reader=new Scanner(System.in); while(reader.hasNext()){ _java 递归例题

面向对象程序设计(荣誉)实验一 String_对存储在string数组内的所有以字符‘a’开始并以字符‘e’结尾的单词做加密处理。-程序员宅基地

文章浏览阅读1.5k次,点赞6次,收藏6次。目录1.串应用- 计算一个串的最长的真前后缀题目描述输入输出样例输入样例输出题解2.字符串替换(string)题目描述输入输出样例输入样例输出题解3.可重叠子串 (Ver. I)题目描述输入输出样例输入样例输出题解4.字符串操作(string)题目描述输入输出样例输入样例输出题解1.串应用- 计算一个串的最长的真前后缀题目描述给定一个串,如ABCDAB,则ABCDAB的真前缀有:{ A, AB,ABC, ABCD, ABCDA }ABCDAB的真后缀有:{ B, AB,DAB, CDAB, BCDAB_对存储在string数组内的所有以字符‘a’开始并以字符‘e’结尾的单词做加密处理。

算法设计与问题求解/西安交通大学本科课程MOOC/C_算法设计与问题求解西安交通大学-程序员宅基地

文章浏览阅读68次。西安交通大学/算法设计与问题求解/树与二叉树/MOOC_算法设计与问题求解西安交通大学

随便推点

[Vue warn]: Computed property “totalPrice“ was assigned to but it has no setter._computed property "totalprice" was assigned to but-程序员宅基地

文章浏览阅读1.6k次。问题:在Vue项目中出现如下错误提示:[Vue warn]: Computed property "totalPrice" was assigned to but it has no setter. (found in <Anonymous>)代码:<input v-model="totalPrice"/>原因:v-model命令,因Vue 的双向数据绑定原理 , 会自动操作 totalPrice, 对其进行set 操作而 totalPrice 作为计..._computed property "totalprice" was assigned to but it has no setter.

basic1003-我要通过!13行搞定:也许是全网最奇葩解法_basic 1003 case 1-程序员宅基地

文章浏览阅读60次。十分暴力而简洁的解决方式:读取P和T的位置并自动生成唯一正确答案,将题给测点与之对比,不一样就给我爬!_basic 1003 case 1

服务器浏览war文件,详解将Web项目War包部署到Tomcat服务器基本步骤-程序员宅基地

文章浏览阅读422次。原标题:详解将Web项目War包部署到Tomcat服务器基本步骤详解将Web项目War包部署到Tomcat服务器基本步骤1 War包War包一般是在进行Web开发时,通常是一个网站Project下的所有源码的集合,里面包含前台HTML/CSS/JS的代码,也包含Java的代码。当开发人员在自己的开发机器上调试所有代码并通过后,为了交给测试人员测试和未来进行产品发布,都需要将开发人员的源码打包成Wa..._/opt/bosssoft/war/medical-web.war/web-inf/web.xml of module medical-web.war.

python组成三位无重复数字_python组合无重复三位数的实例-程序员宅基地

文章浏览阅读3k次,点赞3次,收藏13次。# -*- coding: utf-8 -*-# 简述:这里有四个数字,分别是:1、2、3、4#提问:能组成多少个互不相同且无重复数字的三位数?各是多少?def f(n):list=[]count=0for i in range(1,n+1):for j in range(1, n+1):for k in range(1, n+1):if i!=j and j!=k and i!=k:list.a..._python求从0到9任意组合成三位数数字不能重复并输出

ElementUl中的el-table怎样吧0和1改变为男和女_elementui table 性别-程序员宅基地

文章浏览阅读1k次,点赞3次,收藏2次。<el-table-column prop="studentSex" label="性别" :formatter="sex"></el-table-column>然后就在vue的methods中写方法就OK了methods: { sex(row,index){ if(row.studentSex == 1){ return '男'; }else{ return '女'; }..._elementui table 性别

java文件操作之移动文件到指定的目录_java中怎么将pro.txt移动到design_mode_code根目录下-程序员宅基地

文章浏览阅读1.1k次。java文件操作之移动文件到指定的目录_java中怎么将pro.txt移动到design_mode_code根目录下

推荐文章

热门文章

相关标签