实现一个用PyQt写的格式化一个文本的小工具

一款使用Python和PyQt开发的文本处理工具,旨在快速在大量文本行的前后或中间插入特定字符,提升文本编辑效率。

1 本工具使用python的PyQt编写的,第一次尝试,所以暂时将代码和界面写到一起,后期应该会分开。

2 实现的功能是  例如  AA  BB  要在这两个字符前后,中间,添加特定的字符,如果只有一行,还是手动比较快,但是行数过多之后就比较麻烦了,因此编写此工具作为第一版。

import sys

from PyQt5.QtCore import Qt, pyqtSignal
from PyQt5.QtGui import QIcon, QTextCursor
from PyQt5.QtWidgets import (QMainWindow, QApplication, QAction, qApp, QHBoxLayout, QVBoxLayout, QPushButton,
                             QFrame, QTextEdit, QFileDialog, QSplitter, QWidget, QDesktopWidget, QCheckBox, QMessageBox,
                             QScrollArea, QLabel, QLineEdit, QGridLayout)


class NeLa2(QMainWindow):
    textsignal = pyqtSignal(str)  # 信号定义为类属性

    def __init__(self):
        super().__init__()

        self.v_splitter = QSplitter(Qt.Vertical)
        self.h_splitter = QSplitter(Qt.Horizontal)
        self.buttom = QFrame(self)
        self.all_box = QHBoxLayout(self)  # 总体布局
        self.topright = QFrame(self)  # 右边控件
        self.topleft = QFrame(self)  # 左边控件

        self.frm = QFrame(self)  # 程序的总体面板
        self.lbl = QLabel()  # 底部显示面板

        self.s = SecondWindow()  # 子面板
        self.textsignal.connect(self.s.showSelect)  # 连接信号和槽函数
        self.initUI()

    def initUI(self):
        global text_edit
        text_edit = QTextEdit()  # 文本框

        self.initMenu()  # 初始化菜单栏
        self.initLayout()  # 初始化布局

        self.lbl.setFrameShape(QLabel.StyledPanel)
        self.lbl.setFixedSize(835, 30)

        buttom_hbox = QHBoxLayout(self)  # 下,底部显示面板布局
        buttom_hbox.addWidget(self.lbl)
        self.buttom.setLayout(buttom_hbox)

    # 初始化布局
    def initLayout(self):

        self.topleft = QFrame(self)
        self.topleft.setFrameShape(QFrame.StyledPanel)

        self.topright = QFrame(self)
        self.topright.setFrameShape(QFrame.StyledPanel)

        self.buttom.setFrameShape(QFrame.StyledPanel)

        self.h_splitter.addWidget(self.topleft)
        self.h_splitter.addWidget(self.topright)

        self.v_splitter.addWidget(self.h_splitter)
        self.v_splitter.addWidget(self.buttom)

        self.all_box.addWidget(self.v_splitter)

        self.topright.setGeometry(0, 20, 800, 780)  # 顶部右边,使得左边范围变小
        self.h_splitter.setGeometry(0, 20, 700, 600)  # 是的下边范围变小
        self.frm.setGeometry(0, 20, 880, 760)
        self.frm.setLayout(self.all_box)

        # self.setGeometry(500, 200, 880, 780)  # 距左,距上,宽,高
        self.setFixedSize(880, 780)
        self.show()
        self.center()

    # 初始化菜单栏
    def initMenu(self):
        self.statusBar()

        # 退出菜单
        exitAction = QAction(QIcon('../img/exit.jpg'), 'Exit', self)
        exitAction.setShortcut('Ctrl+Q')  # 快捷键
        exitAction.setStatusTip('Exit Tools')
        exitAction.triggered.connect(qApp.quit)

        # 打开文件菜单
        open_file = QAction(QIcon('../img/exit.jpg'), 'Open...', self)
        open_file.setShortcut('Ctrl+O')
        open_file.setStatusTip('Open New File')
        open_file.triggered.connect(self.show_dialog)

        # 编辑菜单
        editAction = QAction(QIcon('../img/exit.jpg'), 'Edit', self)
        editAction.setShortcut('Ctrl+E')  # 快捷键
        editAction.setStatusTip('Edit Tools')
        editAction.triggered.connect(self.editDialog)
        # 设置菜单
        menubar = self.menuBar()
        filemenu = menubar.addMenu('&File')
        filemenu.addAction(exitAction)
        filemenu.addAction(open_file)

        editmenu = menubar.addMenu('&Edit')
        editmenu.addAction(editAction)
        self.setWindowTitle('Main ')

    # 显示到中间
    def center(self):
        # screen = QDesktopWidget().screenGeometry()
        # size = self.geometry()
        # self.move((screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2)

        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.x(), qr.y())

    # 编辑控件
    def editDialog(self):

        btnJSP = QPushButton(self)
        btnJava = QPushButton(self)
        btnJava.clicked.connect(self.showText)

        btnJava.setText('Java')
        btnJSP.setText('Jsp')

        vbox = QVBoxLayout(self)
        vbox.addWidget(btnJava)
        vbox.addWidget(btnJSP)
        vbox.addStretch(1)

        lhbox = QHBoxLayout(self)
        lhbox.addStretch(1)  # 延伸因子,均分布局
        lhbox.addLayout(vbox)

        rhbox = QHBoxLayout(self)
        rhbox.addWidget(text_edit)

        text_edit.selectionChanged.connect(self.selectLines)  # 连接文本选中事件

        self.topleft.setLayout(lhbox)  # 添加按钮控件
        self.topright.setLayout(rhbox)  # 添加编辑文本控件

    # open file
    def show_dialog(self):
        fname = QFileDialog.getOpenFileName(self, 'Open File', '/home')

        if fname[0]:
            f = open(fname[0], 'r')

            with f:
                data = f.read()
                text_edit.setText(data)

    # 获取内容显示到子窗口
    def showText(self):
        content = text_edit.toPlainText()
        self.sendEditText(content)
        self.s.click()

    def sendEditText(self, content):
        self.textsignal.emit(content)  # 发送信号

    # 选中行
    def selectLines(self):
        # print('文本信息')
        # print(text_edit.toPlainText())

        try:
            cursor = text_edit.textCursor()
            col_num = '列位置:{}'.format(QTextCursor.columnNumber(cursor))
            block_num = 'row:{}'.format(QTextCursor.blockNumber(cursor) + 1)
            start = '光标是否在开始位置:{}'.format(QTextCursor.atStart(cursor))
            end = '光标是否在结束位置:{}'.format(QTextCursor.atEnd(cursor))
            sel_str = str(QTextCursor.selection(cursor).toPlainText())
            nsel_str = '选择的文本:{}'.format(QTextCursor.selectedText(cursor))

            if sel_str != '':
                nexline = str(sel_str.count('\n')) + ' line break'
                l = len(sel_str)
                if l == 1:
                    len_str = '1 char'
                elif l > 1:
                    len_str = str(len(sel_str)) + 'chars'
                self.lbl.setText(col_num + '   ' + block_num + '   ' + len_str + '   ' + nexline)

            # print(col_num)
            # print(block_num)
            # print(start)
            # print(end)
            # print(sel_str)  # 带有格式的文本
            # print(nsel_str)  # 不带有格式的文本
            # print(sel_str.count('\n'))  # 几个换行

        except Exception as e:
            print(e)

    # 重新显示
    def reShowText(self):
        if len(l) == 0:
            return
        try:
            text_edit.clear()
            for x in l:
                text_edit.append(x)
        except Exception as e:
            print(e)


class SecondWindow(QWidget):
    listsignal = pyqtSignal(list)  # 信号定义为类属性

    def __init__(self):
        super().__init__()
        self.label = QLabel()
        self.top = QFrame(self)
        self.buttom = QFrame(self)
        self.top_edit = QTextEdit()
        self.scroll = QScrollArea()

        self.vehbox = QVBoxLayout()

        self.listsignal.connect(NeLa2.reShowText)  # 连接信号和槽函数
        self.initUI()

    def initUI(self):
        # 功能按钮
        selectAllButton = QPushButton('Select All')
        selectAllButton.clicked.connect(self.selectAll)
        deselectAllButton = QPushButton('Deselect All')
        deselectAllButton.clicked.connect(self.deselectAll)

        AnalysisButton = QPushButton('Analysis')
        AnalysisButton.clicked.connect(self.analyText)

        # 分析后显示控件
        global anaLabel  # 定义为全局变量
        anaLabel = QLabel()

        okButton = QPushButton('OK')
        okButton.clicked.connect(self.sendText)
        cancelButton = QPushButton('Cancel')
        cancelButton.clicked.connect(self.close)  # 直接触发窗口的close方法,此方法会调用closeEvent

        # 分析文本框title
        line_edit_title = QLabel('表达式:')
        # 分析文本输入框
        global line_edit
        line_edit = QLineEdit()
        global line_regular

        # 键title
        line_key_title = QLabel('键:')
        # 键
        global line_key
        line_key = QLineEdit()
        # 值title
        line_value_title = QLabel('值:')
        # 值
        global line_value
        line_value = QLineEdit()

        # 底部
        hbox = QHBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(okButton)
        hbox.addWidget(cancelButton)

        grid = QGridLayout()
        grid.setSpacing(10)
        grid.addWidget(line_edit_title, 2, 1)
        grid.addWidget(line_edit, 2, 2, 1, 4)

        grid.addWidget(line_key_title, 3, 1)
        grid.addWidget(line_key, 3, 2)
        grid.addWidget(line_value_title, 3, 3)
        grid.addWidget(line_value, 3, 4)
        grid.addWidget(AnalysisButton, 3, 5)

        grid.addWidget(anaLabel, 4, 1)

        hbox2 = QHBoxLayout()
        hbox2.addWidget(selectAllButton)
        hbox2.addWidget(deselectAllButton)
        hbox2.addStretch(1)

        # 下半部分
        vbox = QVBoxLayout()
        vbox.addLayout(hbox2)
        vbox.addLayout(grid)
        vbox.addStretch(1)
        vbox.addLayout(hbox)

        # 上半部分
        tbox = QVBoxLayout()
        tbox.addWidget(self.scroll)

        self.top.setLayout(tbox)
        self.buttom.setLayout(vbox)

        self.top.setFrameShape(QFrame.StyledPanel)
        self.buttom.setFrameShape(QFrame.StyledPanel)
        self.top.setGeometry(100, 100, 300, 300)

        # 分割 上下
        h_splitter = QSplitter(Qt.Vertical)
        h_splitter.addWidget(self.top)
        h_splitter.addWidget(self.buttom)

        # 整体布局
        sbox = QHBoxLayout()

        sbox.addWidget(h_splitter)
        self.setLayout(sbox)

        self.setGeometry(100, 100, 400, 400)
        self.setWindowTitle('Second')
        self.setWindowModality(Qt.ApplicationModal)  # 设置窗口为应用程序模态,阻止和人任何其他窗口进行交互
        self.center()  # 直接调用父类的center方法

    # 发送分析后文件
    def sendText(self):
        self.analyText()
        self.listsignal.emit(l)
        self.close()

    # 分析
    def analyText(self):
        if line_edit.text() == '':
            QMessageBox.information(self, 'information', self.tr('表达式不能为空'))
            return
        if line_key.text() == '':
            QMessageBox.information(self, 'information', self.tr('键不能为空'))
            return
        if line_value.text() == '':
            QMessageBox.information(self, 'information', self.tr('值不能为空'))
            return
        # 规则数组
        str1 = line_edit.text().strip()

        k = line_key.text()  # 替换的键
        v = line_value.text()  # 替换的值
        try:
            global l
            l = list()
            for x in self.label.findChildren(QCheckBox):
                # 找到选中的进行替换
                if x.isChecked():
                    kc = x.text()
                    print(str1.replace(k, kc).replace(v, dic[kc]))
                    newstr = str1.replace(k, kc).replace(v, dic[kc])
                    l.append(newstr)
        except Exception as e:
            print(e)

    # 全选
    def selectAll(self):
        # 遍历所有子控件,然后选中
        for x in self.label.findChildren(QCheckBox):
            x.setChecked(True)

    # 全不选
    def deselectAll(self):
        # 遍历所有子控件,然后取消选中
        for x in self.label.findChildren(QCheckBox):
            x.setChecked(False)

    # 展示下拉框
    def showSelect(self, content):
        ss = str(content).splitlines()  # 分割成行列表

        lable_height = self.geometry().height()  # label的高
        h2 = lable_height - 150 + len(ss) * 21  # 扩大的值

        if lable_height < 250:
            self.label.setMinimumSize(300, 250)
        elif lable_height > 250:
            self.label.setMinimumSize(300, h2)
        elif len(ss) > 100:
            QMessageBox.information(self, 'information', self.tr('暂时支持100条数据'))
            return
        # 创建一个空字典保存数据,全局变量
        global dic
        dic = {}

        for x in ss:
            k = x.strip()
            if k == '':
                continue
            y = ' '.join(k.split())  # 去除两边空格,保留中间一个空格
            vv = y.split(' ')  # 按空格分割
            try:
                dic[vv[0]] = vv[1]
            except Exception as e:
                QMessageBox.information(self, 'information', self.tr('文本格式不正确,请按照:‘AAA BBB’形式传入'))
                # self.close()  # 关闭子窗口
                return  # 停止后面的按钮创建
            cb = QCheckBox(vv[0], self)
            self.vehbox.addWidget(cb)

        self.vehbox.addStretch(0)  # 增加一个伸缩量,都挤到上边,从上往下排列

        self.label.setLayout(self.vehbox)  # 将check放大label中
        self.scroll.setWidget(self.label)

    # 显示子窗口
    def click(self):
        # 因为关闭时删除了,在此重新创建
        self.vehbox = QVBoxLayout()

        if not self.isVisible():
            self.show()

    # 删除控件
    def deleteKong(self):
        # 遍历所有子控件,然后删除
        # 删除QCheckBox
        for x in self.label.findChildren(QCheckBox):
            x.deleteLater()
        # 删除QVBoxLayout
        for y in self.label.findChildren(QVBoxLayout):
            y.deleteLater()

    # 关闭窗口
    def closeEvent(self, event):
        # 清除一些控件
        self.deleteKong()

        # reply = QMessageBox.question(self,
        #                              '本程序',
        #                              "是否要退出程序?",
        #                              QMessageBox.Yes | QMessageBox.No,
        #                              QMessageBox.No)
        # if reply == QMessageBox.Yes:
        #     event.accept()
        # else:
        #     event.ignore()

    # 显示到中间
    def center(self):
        # screen = QDesktopWidget().screenGeometry()
        # size = self.geometry()
        # self.move((screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2)

        qr = self.frameGeometry()
        cp = QDesktopWidget().availableGeometry().center()
        qr.moveCenter(cp)
        self.move(qr.x(), qr.y())


if __name__ == '__main__':
    app = QApplication(sys.argv)
    tool = NeLa2()
    sys.exit(app.exec_())

 

<think>首先,用户的问题是:“我想查找使用PyQt电路仿真软件的方法”。我需要基于提供的站内引用和系统级指令来回答。 回顾系统级指令: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识。 用户的问题是关于使用PyQt电路仿真软件的方法。提供的引用中: - 引用[1]讨论了使用Python和PyQT开发冲床控制界面,提到了PyQt的优点如跨平台、使用信号与槽机制等。 - 引用[2]提到了KLA-Tencor软件在数据处理和用户界面的作用,支持二次开发和自动化。 - 引用[3]描述了在PyQt中添加按钮控件的过程。 这些引用不是直接关于电路仿真软件的,所以我需要综合这些信息,并基于一般知识来回答。系统指令说:“上述引用仅供参考,并不是用户真正的需求,请尽可能多的参考用户上一次的问题和你的回答。”但我没有用户上一次的问题历史,所以我只能基于当前查询和引用。 用户的问题是“查找使用PyQt电路仿真软件的方法”,所以我需要提供一个方法指南。 关键点: - PyQt一个用于创建GUI的Python库。 - 电路仿真涉及到数学模型和分析,如Ohm定律、Kirchhoff定律,需要计算和可视化。 回答结构: 1. **介绍PyQt和电路仿真**:简要说明PyQt如何用于开发GUI,并应用于电路仿真。 2. **步骤方法**:逐步描述如何使用PyQt电路仿真软件。 - 包括设计界面、添加控件、集成仿真逻辑。 3. **示例代码**:提供一段简单的Python代码示例,展示如何使用PyQt创建一个基本的电路仿真界面。 4. **生成相关问题**:在回答末尾添加相关问题,符合系统指令。 确保使用中文回答。 结合引用: - 引用[1]提到PyQt的跨平台性和信号与槽机制,适用于用户界面开发。 - 引用[2]强调数据处理和用户界面设计的重要性。 - 引用[3]展示如何添加按钮控件。 在回答中自然地添加引用标识,例如在相关段落末尾。 数学表达式:如果涉及电路公式,如$V = IR$,使用行内格式。 最终结构: - 标题或开头:明确主题。 - 正文:分步解释。 - 代码块:使用Python和PyQt代码。 - 相关问题:在末尾。 生成相关问题: - 基于主题,如优化、扩展应用。 </think>### 使用PyQt电路仿真软件的方法 PyQt一个强大的Python库,用于创建图形用户界面(GUI),它结合了Qt框架的丰富功能和Python的易用性。电路仿真软件涉及用户界面设计和后端计算逻辑,PyQt非常适合用于此类应用,因为它支持信号与槽机制(用于处理事件响应)、跨平台开发(如Windows、Linux)以及丰富的控件库(如按钮、绘图区域等)。电路仿真的核心在于求解电路方程(如Ohm定律 $V = IR$ 和 Kirchhoff定律 $\sum I = 0$),这些可以通过Python的计算库(如NumPy)来实现。下面我将逐步介绍使用PyQt电路仿真软件的基本方法。 #### 步骤1: 安装和设置环境 首先,确保你的开发环境已安装Python(推荐Python 3.8+)和PyQt。可以使用pip安装PyQt和相关库: ```bash pip install PyQt6 numpy matplotlib # PyQt6是最新版本,numpy用于数值计算,matplotlib用于绘图 ``` 如果你的电路仿真涉及复杂模型,还可以添加科学计算库如SciPy。 #### 步骤2: 设计用户界面 使用PyQt的Qt Designer工具(可视化界面设计器)创建GUI。电路仿真界面通常包括: - **输入控件**:如文本框用于输入电阻 $R$、电压 $V$ 等参数。 - **按钮控件**:用于触发仿真计算(如引用[3]中提到的Push Button)。 - **输出区域**:如绘图区(使用Matplotlib嵌入PyQt)显示电路波形(如电压-电流曲线),或文本区显示结果。 - **其他元素**:下拉菜单选择电路类型(如串联或并联)。 例如,你可以使用Qt Designer拖拽控件创建一个基本界面,然后转换为Python代码(使用`pyuic6`工具)。引用[3]展示了如何添加按钮控件,类似地,你可以为电路仿真添加输入框和绘图区[^3]。 #### 步骤3: 集成仿真逻辑 在PyQt中,后端逻辑使用Python实现: - **数学模型**:基于电路理论,定义方程求解逻辑。例如,对于一个简单直流电路,Ohm定律 $V = IR$ 可直接计算;对于交流电路,可能需要求解微分方程 $\frac{dI}{dt} = \frac{V}{L}$。 - **事件处理**:通过信号与槽机制连接界面控件。例如,当用户点击“计算”按钮时,触发计算函数并更新输出区。 - **数据处理**:使用NumPy和SciPy进行高效数值计算,确保实时性(尽管电路仿真实时性要求不高,如引用[1]所述在用户态应用中可以满足)[^1]。 #### 步骤4: 示例代码 下面是一个简单的PyQt代码示例,演示如何创建一个直流电路仿真界面:输入电阻和电压,计算电流并显示结果。 ```python import sys import numpy as np from PyQt6.QtWidgets import QApplication, QMainWindow, QLabel, QLineEdit, QPushButton, QVBoxLayout, QWidget class CircuitSimulator(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("电路仿真软件") self.setGeometry(100, 100, 400, 200) # 窗口大小 # 创建布局和控件 central_widget = QWidget() self.setCentralWidget(central_widget) layout = QVBoxLayout() self.label_r = QLabel("输入电阻 R (Ω):") self.input_r = QLineEdit() self.label_v = QLabel("输入电压 V (V):") self.input_v = QLineEdit() self.calc_button = QPushButton("计算电流") # 类似引用[3]的按钮 self.result_label = QLabel("结果将显示在这里") layout.addWidget(self.label_r) layout.addWidget(self.input_r) layout.addWidget(self.label_v) layout.addWidget(self.input_v) layout.addWidget(self.calc_button) layout.addWidget(self.result_label) central_widget.setLayout(layout) # 连接信号与槽 self.calc_button.clicked.connect(self.calculate_current) def calculate_current(self): """计算电流 I = V / R""" try: r = float(self.input_r.text()) v = float(self.input_v.text()) i = v / r # Ohm定律计算 self.result_label.setText(f"电流 I = {i:.2f} A") except Exception as e: self.result_label.setText(f"错误: {str(e)}") if __name__ == "__main__": app = QApplication(sys.argv) window = CircuitSimulator() window.show() sys.exit(app.exec()) ``` 这段代码创建了一个基本界面,用户输入电阻和电压后,点击按钮计算电流。扩展时,可以添加Matplotlib绘图区来显示动态波形。 #### 步骤5: 高级功能和优化 - **绘图集成**:使用`matplotlib`的`FigureCanvasQTAgg`嵌入PyQt窗口,可视化电路响应(如正弦波)。 - **错误处理**:监测输入错误(如除零错误),并提供反馈(类似引用[1]中提到的LinuxCNC错误监视)[^1]。 - **性能优化**:对于复杂电路(如包含电容、电感的暂态分析),使用SciPy解微分方程;PyQt的信号机制确保UI响应流畅。 - **模块化设计**:将仿真逻辑封装为独立类,便于复用和维护(类似引用[2]提到的二次开发支持)[^2]。 开发电路仿真软件时,需注意:PyQt负责UI层,而仿真核心应使用Python数值库;开源库如PySpice或QucsPy可作为基础模型集成。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值