这学期的信息论与编码的课设需要用编程语言实现霍夫曼、费诺以及香农编码,要具备在windows下的可视化操作界面,因此就选用PyQt作为开发工具,本篇博客记录一下PyQt的基础以及课设的实例
《PyQt5从入门到实践》
PyQt5官方帮助文档
QApplication
[PyQt5]点击主窗口弹出另一个窗口
【PyQt】点击一个窗口的按钮来打开另一个窗口
Python 算法(2) 哈夫曼编码 Huffman Encoding
Python实现香农编码和费诺编码
[python]Huffman Encoding哈夫曼编码

PyQt基础

PyQt就是Qt的python接口,目前主要有3个版本:PyQt3、PyQt4以及PyQt5,其中PyQt5不向下兼容PyQt4,且官方默认只提供对python3.x的支持
PyQt5的主要的类如下:
PyQt5的主要模块如下:

开发环境搭建

开发的工具如下:

  • Python
  • Pycharm
  • Packet
  • pyqt5
  • pyqt5-tools
  • pyqt5designer
  • 这里就记录一下如何在Pycharm中配置PyQt5,首先要安装需要的工具包:

    接着要配置一些工具(PyQt5创建GUI图形用户界面程序时,会生成扩展名为.ui的文件,因此需要工具将其转换为.py文件;同时还需要PyQt5的设计器):

  • 添加安装pyqt5designer模块时自动安装的designer.exe,在Working directory中输入 $ProjectFileDir$ ,表示项目文件目录
  • 添加将.ui文件转换为.py文件的转换工具,选择虚拟环境目录下的python.exe(Scripts文件夹中),然后在Arguments输入将.ui文件转换为.py文件的命令,在Working directory中输入 $FileDir$ ,表示.ui文件所在的路径

    完成配置后,在Tools->External Tools中可以看到这两个工具:

    Qt Designer

    Qt Designer是一个可视化GUI设计工具,可以在Tools中直接打开,直接显示新建窗体窗口,列举了Qt支持的几种窗口类型:

  • Dialog with Buttons Bottom:按钮在底部的对话框窗口
  • Dialog with Buttons Right:按钮在右上角的对话框窗口
  • Dialog without Buttons:没有按钮的对话框窗口
  • Main Window:一个带菜单、停靠窗口和状态栏的主窗口
  • Widget:通用窗口
  • 选择后就可以开始设计,Qt Designer的几个主要组成部分如下:

  • 窗口设计区域
  • 对象查看器
  • 属性编辑器
  • 信号/槽、动作、资源编辑器
  • 同时可以在Widget Box工具箱中选用相应的控件即可开始设计自己的GUI

  • 如果设计完成,可以在窗体->预览于选择预览方式,观察实际运行的效果
  • 可以在窗体->View Python Code中查看对应的Python代码;也可以直接在pycharm中选择保存好的.ui文件,选择Tools->External Tool->PyUIC即可
  • 生成了代码后还需要设置程序入口并显示,代码如下:

    import sys
    import coding          # coding就是通过.ui文件生成的.py文件,.ui文件的名字是什么就import什么
    from PyQt5 import QtCore, QtGui, QtWidgets
    if __name__ == '__main__':
        app = QtWidgets.QApplication(sys.argv)
        MainWindow = QtWidgets.QMainWindow()
        ui = coding.Ui_MainWindow()
        ui.setupUi(MainWindow)
        MainWindow.show()
        sys.exit(app.exec_())
    

    关于这个程序的理解:

  • sys模块提供访问由解释器使用或维护的变量的接口,并提供了一些函数和解释器进行交互,操控python运行时的环境
  • sys.argv:
  • sys.exit:
  • QtWidgets模块包含了构建界面的一系列UI元素组件
  • QApplication:对于任一使用Qt的GUI应用,只能有一个QApplication对象
  • QMainWindow:QMainWindow是Qt的顶层窗口,使用它代表创建窗体对象
  • Ui_MainWindow就是.ui文件转换为.py文件生成的类,setupUi就是对对象进行初始化设置
  • MainWindow.show()用于显示窗体
  • PyQt5窗口设计基础

    PyQt5的窗口就是向用户展示信息的可视化界面,是GUI程序的基本单元
    PyQt5窗口创建完成后,可以通过属性对窗口进行设置,这些属性可以在属性编辑器中进行设置,也可以直接通过代码来实现,其常用的属性如下:

  • 窗口的对象名称,相当于窗口的标识,是唯一的,在编写代码时,对窗口的任何设置和使用都是通过该名称进行操作的,默认名称是MainWindow,可通过objectName来进行修改
    如果需要使用python代码进行设置的话,需要使用一个函数:MainWindow.setObjectName("MainWindow")
  • 窗口的标题栏名称通过windowTitle设置,也可以直接用python中的函数:MainWindow.setWindowTitle("标题栏")
  • 窗口的大小通过geometry属性设置,也可以直接用python中的函数:MainWindow.resize(252,100)
  • 窗口的样式可以使用setWindowFlags()函数设置:setWindowFlags(Qt.WindowFlags),其中Qt.WindowFlags参数表示要设置的窗口样式
  • 对窗口样式的设置要在初始化窗体后才会起作用,即要在setupUi()函数后执行
  • 信号(signal)与槽(slot)是Qt的核心机制,也是进行PyQt5编程时对象之间通信的基础,在PyQt5中,每一个QObject对象(包括各种窗口和控件)都支持信号与槽机制,通过信号与槽的关联就可以实现对象之间的通信,当信号发射时,连接的槽函数(方法)将会自动执行,在PyQt5中,信号与槽是通过对象的signal.connect()方法进行连接

    PyQt5的窗口控件中有很多内置的信号与槽,PyQt5中使用信号与槽的主要特点如下:

  • 一个信号可以连接多个槽
  • 一个槽可以监听多个信号
  • 信号与信号之间可以互连
  • 信号与槽的连接可以跨线程
  • 信号与槽的连接方式可以是同步,也可以是异步
  • 信号的参数可以是任何的python类型
  • 接下来用一个简例通过信号与槽实现一个单击按钮关闭主窗口的效果:

  • 首先添加一个PushButton,并设置按钮的text属性为"关闭"
  • 在菜单栏中选择"编辑信号/槽",然后选中关闭按钮,按住鼠标左键拖动至窗口的空白区域
  • 松开鼠标后,会自动弹出配置连接,选中"显示从QWidget继承的信号和槽"复选框,然后在上方的信号与槽列表分别选中"clicked()"和"close()",完成信号与槽的关联
  • 使用PyUIC工具将.ui文件转换为.py文件,然后编写python显示窗口并测试
  • PyQt5的常用控件

    控件是用户可以用来输入或操作数据的对象,在PyQt5中控件的基类是QFrame类,而QFrame类继承自QWidget类,QWidget类是所有用户界面对象的基类
    Qt Designer中默认对控件进行了分组:

    文本类控件主要用来显示或者编辑文本信息

    Label:标签控件

    主要用于显示用户不能编辑的文本,标识窗体上的对象,对应PyQt5中的QLabel类(QLabel类属于QtWidgets),Label控件本质上是QLabel类的一个对象

  • 设置标签文本:在Qt Designer中的属性编辑器中设置text属性/用QLabel类的setText()方法
  • 设置标签文本的对齐方式:在Qt Designer中的属性编辑器中设置alignment属性中的Horizontal和Vertical/用QLabel类的setAlignment()方法
  • Horizontal用于设置标签文本的水平对齐方式
  • AlignLeft:左对齐
  • AlignHCenter:水平居中对齐
  • AlignRight:右对齐
  • Vertical用于设置标签文本的垂直对齐方式
  • AlignTop:顶部对齐
  • AlignVCenter:垂直居中对齐
  • AlignBottom:底部对齐
  • 设置文本换行显示:在标签宽度不足的情况下,系统会默认只显示部分文字,可以设置标签中的文本换行显示,在Qt Designer中的属性编辑器中将wordWrap属性后面的复选框选中/用QLabel类的setWordWrap方法
  • 获取标签文本:用QLabel类的text()方法
  • LineEdit:单行文本框

    LineEdit是单行文本框,该控件只能输入单行字符串,对应PyQt5中的QLineEdit类,该类的常用方法如下:

  • setText():设置文本框内容
  • text():获取文本框内容
  • setPlaceholderText():设置文本框浮现文字
  • setMaxLength():设置允许文本框内输入字符的最大长度
  • setAlignment():设置文本对齐方式
  • setReadOnly():设置文本框只读
  • setEchoMode():设置文本框显示字符的模式
  • QLineEdit.Normal:正常显示输入的字符,默认设置
  • QLineEdit.NoEcho:不显示任何输入的字符,适用于即使符合密码长度也需要保密的密码
  • QLineEdit.Password:显示与平台相关的密码掩码字符,而不是实际输入的字符
  • setValidator():设置文本框验证器
  • QIntValidator:限制输入整数
  • QDoubleValidator:限制输入小数
  • QRegExpValidator:检查输入是否符合设置的正则表达式
  • clear():清除文本框内容
  • QLineEdit类的常用信号:

  • textChanged:当更改文本框中的内容时发射该信号
  • editingFinished:当文本框中的内容编辑结束后发射该信号,以按下enter键为编辑结束标志
  • TextEdit:多行文本框

    TextEdit是多行文本框控件,主要用来显示多行的文本内容,当文本内容超出控件的显示范围时,该控件将显示垂直滚动条,该类的常用方法如下:

  • setPlainText():设置文本内容
  • toPlainText():获取文本内容
  • setTextColor():设置文本颜色
  • setWordWrapMode():设置自动换行
  • clear():清除所有内容
  • 按钮类控件

    按钮类控件主要用来执行一些命令操作

    PushButton:按钮

    PushButton允许用户通过单击来执行操作,既可以显示文本,也可以显示图像,当该控件被单击时,它看起来的状态像是被按下,然后被释放,对应PyQt5中的QPushButton类,该类的常用方法如下:

  • setText():设置按钮显示的文本
  • text():获取按钮显示的文本
  • setIcon():设置按钮上的图标,可以将参数设置为QtGui.QIcon('图标路径')
  • setIconSize():设置按钮图标的大小,参数可以设置为Qtcore.Qsize(int width, int height)
  • setEnabled():设置按钮是否可用,参数设置为False时,按钮为不可用状态
  • setShortcut():设置按钮的快捷键,参数可设置为键盘中的按键或组合键
  • PushButton按钮中最常用的信号是clicked,当按钮被单击时,会发射该信号执行相应的操作

    实例:信息论与编码课程设计

    课程设计要求

    利用编程语言实现霍夫曼、费诺、香农编码

  • 霍夫曼编码:实现任意Q符号的N重序列信源的最优R进制编码(8≤Q≤15;2≤R≤5;1≤N≤3)
  • 费诺、香农编码:实现任意Q符号的二进制编码(Q≥10)
  • 编写的程序应具备在windows下的可视化操作界面,不同的编码类型用不同的菜单加以分割
  • 对于霍夫曼编码应该具备Q、N、R的能力,而费诺、香农编码能输入Q
  • 不同编码类型应当展现编码的结果,平均码长、信息熵等性能指标
  • 首先要在Qt designer中创建几个窗口,然后要将各个按键对应显示窗口的函数,然后根据几个编码过程编写代码然后在相应的控件上显示即可,这里给出三个编码的核心代码:
    霍夫曼编码:

        def Hoffman_Coding(self):
            Q,N,R,sp = self.Read_Input()
            if Q == 0 and N == 0 and R == 0 and sp == 0:
                self.ui_error.show()
                return 0
            all_sym = self.Get_All_Symbol(Q,N,R,sp)      # all nodes
            if R == 2:
                hoffman_tree = self.Hoffman_Tree_Generate_2(Q,N,sp,all_sym)
                hoffman_code = self.Coding_2(all_sym,hoffman_tree)
                outcome = ''
                for i in range(len(all_sym)):
                    outcome = outcome + str(round(all_sym[i].P,6)) + '    ' + hoffman_code[i] + '    ' +'\n'
                # print(outcome)
                self.textEdit_2.setPlainText(outcome)
                self.Calculate_Performance_Index(N,R,sp,all_sym,hoffman_code)
            elif R == 3:
                hoffman_tree = self.Hoffman_Tree_Generate_3(Q,N,sp,all_sym)
                hoffman_code = self.Coding_3(all_sym, hoffman_tree)
                outcome = ''
                for i in range(len(all_sym)):
                    outcome = outcome + str(round(all_sym[i].P, 6)) + '    ' + hoffman_code[i] + '    ' + '\n'
                self.textEdit_2.setPlainText(outcome)
                self.Calculate_Performance_Index(N, R, sp, all_sym, hoffman_code)
            elif R == 4:
                hoffman_tree = self.Hoffman_Tree_Generate_4(Q,N,sp,all_sym)
                hoffman_code = self.Coding_4(all_sym, hoffman_tree)
                outcome = ''
                for i in range(len(all_sym)):
                    outcome = outcome + str(round(all_sym[i].P, 6)) + '    ' + hoffman_code[i] + '    ' + '\n'
                self.textEdit_2.setPlainText(outcome)
                self.Calculate_Performance_Index(N, R, sp, all_sym, hoffman_code)
            elif R == 5:
                hoffman_tree = self.Hoffman_Tree_Generate_5(Q,N,sp,all_sym)
                hoffman_code = self.Coding_5(all_sym, hoffman_tree)
                outcome = ''
                for i in range(len(all_sym)):
                    outcome = outcome + str(round(all_sym[i].P, 6)) + '    ' + hoffman_code[i] + '    ' + '\n'
                self.textEdit_2.setPlainText(outcome)
                self.Calculate_Performance_Index(N, R, sp, all_sym, hoffman_code)
        def Hoffman_Tree_Generate_2(self,Q,N,sp,all_sym):
            queue = all_sym[:]
            while len(queue) > 1:
                queue.sort(key=lambda item:item.P)
                node_child1 = queue.pop(0)
                node_child2 = queue.pop(0)
                node_father = Node_2(node_child1.P + node_child2.P)
                node_father.child1 = node_child1
                node_father.child2 = node_child2
                node_child1.father = node_father
                node_child2.father = node_father
                queue.append(node_father)
            queue[0].father = None
            return queue[0]
        def Hoffman_Tree_Generate_3(self,Q,N,sp,all_sym):
            queue = all_sym[:]
            while len(queue) > 1:
                queue.sort(key=lambda item:item.P)
                node_child1 = queue.pop(0)
                node_child2 = queue.pop(0)
                node_child3 = queue.pop(0)
                node_father = Node_3(node_child1.P + node_child2.P + node_child3.P)
                node_father.child1 = node_child1
                node_father.child2 = node_child2
                node_father.child3 = node_child3
                node_child1.father = node_father
                node_child2.father = node_father
                node_child3.father = node_father
                queue.append(node_father)
            queue[0].father = None
            return queue[0]
        def Hoffman_Tree_Generate_4(self,Q,N,sp,all_sym):
            queue = all_sym[:]
            while len(queue) > 1:
                queue.sort(key=lambda item:item.P)
                node_child1 = queue.pop(0)
                node_child2 = queue.pop(0)
                node_child3 = queue.pop(0)
                node_child4 = queue.pop(0)
                node_father = Node_4(node_child1.P + node_child2.P + node_child3.P + node_child4.P)
                node_father.child1 = node_child1
                node_father.child2 = node_child2
                node_father.child3 = node_child3
                node_father.child4 = node_child4
                node_child1.father = node_father
                node_child2.father = node_father
                node_child3.father = node_father
                node_child4.father = node_father
                queue.append(node_father)
            queue[0].father = None
            return queue[0]
        def Hoffman_Tree_Generate_5(self,Q,N,sp,all_sym):
            queue = all_sym[:]
            while len(queue) > 1:
                queue.sort(key=lambda item:item.P)
                node_child1 = queue.pop(0)
                node_child2 = queue.pop(0)
                node_child3 = queue.pop(0)
                node_child4 = queue.pop(0)
                node_child5 = queue.pop(0)
                node_father = Node_5(node_child1.P + node_child2.P + node_child3.P + node_child4.P + node_child5.P)
                node_father.child1 = node_child1
                node_father.child2 = node_child2
                node_father.child3 = node_child3
                node_father.child4 = node_child4
                node_father.child5 = node_child5
                node_child1.father = node_father
                node_child2.father = node_father
                node_child3.father = node_father
                node_child4.father = node_father
                node_child5.father = node_father
                queue.append(node_father)
            queue[0].father = None
            return queue[0]
        def Coding_2(self,all_sym,root):
            codes = ['']*len(all_sym)
            for i in range(len(all_sym)):
                node_tem = all_sym[i]
                while node_tem != root:
                    if node_tem.check_num_of_child() == 1:
                        codes[i] = '0' + codes[i]
                    else:
                        codes[i] = '1' + codes[i]
                    node_tem = node_tem.father
            print(codes)
            return codes
        def Coding_3(self, all_sym, root):
            codes = ['']*len(all_sym)
            for i in range(len(all_sym)):
                node_tem = all_sym[i]
                while node_tem != root:
                    if node_tem.check_num_of_child() == 1:
                        codes[i] = '0' + codes[i]
                    elif node_tem.check_num_of_child() == 2:
                        codes[i] = '1' + codes[i]
                    else:
                        codes[i] = '2' + codes[i]
                    node_tem = node_tem.father
            print(codes)
            return codes
        def Coding_4(self, all_sym, root):
            codes = ['']*len(all_sym)
            for i in range(len(all_sym)):
                node_tem = all_sym[i]
                while node_tem != root:
                    if node_tem.check_num_of_child() == 1:
                        codes[i] = '0' + codes[i]
                    elif node_tem.check_num_of_child() == 2:
                        codes[i] = '1' + codes[i]
                    elif node_tem.check_num_of_child() == 3:
                        codes[i] = '2' + codes[i]
                    else:
                        codes[i] = '3' + codes[i]
                    node_tem = node_tem.father
            print(codes)
            return codes
        def Coding_5(self, all_sym, root):
            codes = ['']*len(all_sym)
            for i in range(len(all_sym)):
                node_tem = all_sym[i]
                while node_tem != root:
                    if node_tem.check_num_of_child() == 1:
                        codes[i] = '0' + codes[i]
                    elif node_tem.check_num_of_child() == 2:
                        codes[i] = '1' + codes[i]
                    elif node_tem.check_num_of_child() == 3:
                        codes[i] = '2' + codes[i]
                    elif node_tem.check_num_of_child() == 4:
                        codes[i] = '3' + codes[i]
                    else:
                        codes[i] = '4' + codes[i]
                    node_tem = node_tem.father
            print(codes)
            return codes
        def Get_All_Symbol(self,Q,N,R,sp):
            all_sym = []
            symbol_sequence = []
            nodes = []
            for i in range(N):
                symbol_sequence.append(0)
            for i in range(pow(Q,N)):
                j = N-1
                P = sp[symbol_sequence[0]]
                for k in range(N):
                    if k != 0:
                        P *= sp[symbol_sequence[k]]
                if R == 2:
                    all_sym.append(Node_2(P))
                elif R == 3:
                    all_sym.append(Node_3(P))
                elif R == 4:
                    all_sym.append(Node_4(P))
                elif R == 5:
                    all_sym.append(Node_5(P))
                while symbol_sequence[j] == Q-1:
                    symbol_sequence[j] = 0
                    j -= 1
                    if j == -1:
                        # print(len(all_sym))
                        if( int((Q - R)/(R - 1))!=(Q - R)/(R - 1) ):
                            Q_expand = int((Q - R)/(R - 1)+1)*(R - 1)+R
                            for i in range(Q_expand - Q):
                                if R == 2:
                                    all_sym.append(Node_2(0))
                                elif R == 3:
                                    all_sym.append(Node_3(0))
                                elif R == 4:
                                    all_sym.append(Node_4(0))
                                elif R == 5:
                                    all_sym.append(Node_5(0))
                        return all_sym
                symbol_sequence[j] += 1
        def Read_Input(self):
            Q = int(self.lineEdit_5.text())    # num of symbol
            N = int(self.lineEdit_6.text())    # num of sequence
            R = int(self.lineEdit_7.text())    # num of radix
            text = self.textEdit.toPlainText()
            sp = self.Get_Symbol_Probability(text)  # symbol probability
            if Q<8 or Q>15 or N<1 or N>3 or R<2 or R>5 or len(sp)!=Q or sum(sp)<0.99999:
                # self.ui_error.show()
                # print(sum(sp))
                return 0,0,0,0
            else:
                # print(Q,N,R,sp)
                return Q,N,R,sp
        def Str_Find_HH(self,str):  # HH:huan hang '\n'
            n = len(str)
            pos = list()
            for i in range(n):
                if str[i] == '\n':
                    pos.append(i)
            # print(pos)
            return pos
        def Get_Symbol_Probability(self,str):
            n = len(str)
            pos = self.Str_Find_HH(str)
            sp = list()
            n_pos = len(pos)
            for i in range(n_pos):
                if i == 0:
                    sp.append(float(str[0:pos[i]]))
                else:
                    sp.append(float(str[pos[i - 1] + 1:pos[i]]))
            # print(sp)
            return sp
        def Calculate_Performance_Index(self,N,R,sp,all_sym,codes):
            HU = 0
            l_avr = 0
            for i in range(len(sp)):
                HU += -sp[i]*math.log2(sp[i])
            for i in range(len(all_sym)):
                l_avr += all_sym[i].P*len(codes[i])
            effi = HU*N/l_avr/math.log2(R)
            self.lineEdit_2.setText(str(round(HU,5)))
            self.lineEdit_3.setText(str(round(l_avr,2)))
            self.lineEdit_4.setText(str(round(effi*100,4))+'%')
    

    费诺编码:

        def Feno_Coding(self):
            Q,sp = self.Read_Input()
            if Q == 0 and sp == 0:
                self.ui_error.show()
                return
            sp_node = []
            self.feno_code = ['']*len(sp)
            sp.sort(reverse=True)
            for i in range(len(sp)):
                sp_node.append(Node(sp[i],i))
            self.Coding(sp_node)
            # print(self.feno_code)
            outcome = ''
            for i in range(len(sp)):
                outcome = outcome + str(sp[i]) + '    ' + self.feno_code[i] + '    ' + '\n'
            self.textEdit_2.setPlainText(outcome)
            self.Calculate_Performance_Index(sp,self.feno_code)
        def Coding(self,sp_node):
            if len(sp_node) == 1:
                return
            findPos = 0
            diff_c = 1
            sum1 = 0
            sum2 = 0
            left_flag = 0   # 0 means left bigger than right
            for i in range(len(sp_node)-1):
                for j in range(i+1):
                    sum1 += sp_node[j].P
                for k in range(i+1,len(sp_node)):
                    sum2 += sp_node[k].P
                if abs(sum1-sum2) < diff_c:
                    diff_c = abs(sum1-sum2)
                    if sum1 < sum2:
                        left_flag = 1
                    else:
                        left_flag = 0
                    findPos = i
                sum1 = 0
                sum2 = 0
            for i in range(len(sp_node)):
                if left_flag:
                    if i <= findPos:
                        self.feno_code[sp_node[i].pos] += '1'
                    else:
                        self.feno_code[sp_node[i].pos] += '0'
                else:
                    if i <= findPos:
                        self.feno_code[sp_node[i].pos] += '0'
                    else:
                        self.feno_code[sp_node[i].pos] += '1'
            left = []
            right = []
            for i in range(findPos+1):
                left.append(sp_node[i])
            for i in range(findPos+1,len(sp_node)):
                right.append(sp_node[i])
            self.Coding(left)
            self.Coding(right)
        def Read_Input(self):
            Q = int(self.lineEdit.text())    # num of symbol
            text = self.textEdit.toPlainText()
            sp = self.Get_Symbol_Probability(text)  # symbol probability
            if Q<10 or len(sp)!=Q or sum(sp)<0.99999:
                # self.ui_error.show()
                # print(sum(sp))
                return 0,0,0,0
            else:
                # print(Q,N,R,sp)
                return Q,sp
        def Str_Find_HH(self,str):  # HH:huan hang '\n'
            n = len(str)
            pos = list()
            for i in range(n):
                if str[i] == '\n':
                    pos.append(i)
            # print(pos)
            return pos
        def Get_Symbol_Probability(self,str):
            n = len(str)
            pos = self.Str_Find_HH(str)
            sp = list()
            n_pos = len(pos)
            for i in range(n_pos):
                if i == 0:
                    sp.append(float(str[0:pos[i]]))
                else:
                    sp.append(float(str[pos[i - 1] + 1:pos[i]]))
            # print(sp)
            return sp
        def Calculate_Performance_Index(self,sp,codes):
            HU = 0
            l_avr = 0
            for i in range(len(sp)):
                HU += -sp[i]*math.log2(sp[i])
            for i in range(len(sp)):
                l_avr += sp[i]*len(codes[i])
            effi = HU/l_avr/math.log2(2)
            self.lineEdit_2.setText(str(round(HU,5)))
            self.lineEdit_3.setText(str(round(l_avr,2)))
            self.lineEdit_4.setText(str(round(effi*100,4))+'%')
    

    香农编码:

       def Shannon_Coding(self):
            Q,sp = self.Read_Input()
            if Q == 0 and sp == 0:
                self.ui_error.show()
                return
            shannon_code = ['']*len(sp)
            sp.sort(reverse=True)
            for i in range(len(sp)):
                P_acc = 0
                code = ''
                l = int(-math.log2(sp[i])+1)
                for j in range(i):
                    P_acc += sp[j]
                while True:
                    P_acc *= 2
                    if P_acc >= 1:
                        code += '1'
                    else:
                        code += '0'
                    if len(code) == l:
                        break
                    P_acc -= int(P_acc)
                    if P_acc == 0:
                        if(len(code)<l):
                            code += '0'*(l-len(code))
                            break
                shannon_code[i] = code[:l]
            # print(shannon_code)
            outcome = ''
            for i in range(len(sp)):
                outcome = outcome + str(sp[i]) + '    ' + shannon_code[i] + '    ' + '\n'
            self.textEdit_2.setPlainText(outcome)
            self.Calculate_Performance_Index(sp,shannon_code)
        def Read_Input(self):
            Q = int(self.lineEdit.text())    # num of symbol
            text = self.textEdit.toPlainText()
            sp = self.Get_Symbol_Probability(text)  # symbol probability
            if Q<10 or len(sp)!=Q or sum(sp)<0.99999:
                # self.ui_error.show()
                # print(sum(sp))
                return 0,0,0,0
            else:
                # print(Q,N,R,sp)
                return Q,sp
        def Str_Find_HH(self,str):  # HH:huan hang '\n'
            n = len(str)
            pos = list()
            for i in range(n):
                if str[i] == '\n':
                    pos.append(i)
            # print(pos)
            return pos
        def Get_Symbol_Probability(self,str):
            n = len(str)
            pos = self.Str_Find_HH(str)
            sp = list()
            n_pos = len(pos)
            for i in range(n_pos):
                if i == 0:
                    sp.append(float(str[0:pos[i]]))
                else:
                    sp.append(float(str[pos[i - 1] + 1:pos[i]]))
            # print(sp)
            return sp
        def Calculate_Performance_Index(self,sp,codes):
            HU = 0
            l_avr = 0
            for i in range(len(sp)):
                HU += -sp[i]*math.log2(sp[i])
            for i in range(len(sp)):
                l_avr += sp[i]*len(codes[i])
            effi = HU/l_avr/math.log2(2)
            self.lineEdit_2.setText(str(round(HU,5)))
            self.lineEdit_3.setText(str(round(l_avr,2)))
            self.lineEdit_4.setText(str(round(effi*100,4))+'%')
    

    程序的入口:

    import sys
    import coding
    from PyQt5 import QtCore, QtGui, QtWidgets
    if __name__ == '__main__':
        app = QtWidgets.QApplication(sys.argv)
        MainWindow = QtWidgets.QMainWindow()
        ui = coding.Ui_MainWindow()
        ui.setupUi(MainWindow)
        MainWindow.show()
        sys.exit(app.exec_())
    

    这里还附上完整的课程设计报告可供参考: