python 制作 打字练习程序

这篇博客介绍了如何构建一个简单的打字练习程序。通过该程序,用户可以加载一个文本文件并进行打字练习,同时实时统计每分钟输入的字符数、正确字符数、错误字符数和准确率。程序使用了 PyQt5 库来创建图形用户界面。

依赖项

在开始之前,请确保你的环境中已经安装了 PyQt5。如果尚未安装,请运行以下命令:

 
pip install PyQt5

程序结构

程序主要由以下几个部分组成:

  1. 初始化UI界面
  2. 加载文本文件
  3. 处理用户输入
  4. 更新统计信息

初始化UI界面

首先,我们需要创建一个主窗口并初始化UI组件,包括显示统计信息的标签、加载文件的按钮和打字区域。

import sys
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QVBoxLayout, QLabel, QLineEdit, QPushButton,
    QWidget, QFileDialog, QHBoxLayout, QScrollArea
)
import time

class TypingPracticeApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle('Typing Practice')
        self.setGeometry(100, 100, 800, 600)

        self.total_characters = 0
        self.correct_characters = 0
        self.wrong_characters = 0
        self.start_time = None
        self.timer = QTimer()
        self.timer.timeout.connect(self.update_stats)

        # Main layout
        main_layout = QHBoxLayout()

        # Stats layout
        stats_layout = QVBoxLayout()
        self.chars_per_min_label = QLabel('每分钟字: 0')
        self.elapsed_time_label = QLabel('时间: 0s')
        self.total_chars_label = QLabel('总字数: 0')
        self.correct_chars_label = QLabel('正确字数: 0')
        self.wrong_chars_label = QLabel('错误字数: 0')
        self.accuracy_label = QLabel('准确率: 0.00%')
        stats_layout.addWidget(self.chars_per_min_label)
        stats_layout.addWidget(self.elapsed_time_label)
        stats_layout.addWidget(self.total_chars_label)
        stats_layout.addWidget(self.correct_chars_label)
        stats_layout.addWidget(self.wrong_chars_label)
        stats_layout.addWidget(self.accuracy_label)

        # Typing layout
        self.typing_layout = QVBoxLayout()
        self.load_button = QPushButton('加载文件')
        self.load_button.clicked.connect(self.load_file)
        self.typing_area = QWidget()
        self.typing_area.setLayout(self.typing_layout)

        scroll_area = QScrollArea()
        scroll_area.setWidget(self.typing_area)
        scroll_area.setWidgetResizable(True)

        typing_area_layout = QVBoxLayout()
        typing_area_layout.addWidget(self.load_button)
        typing_area_layout.addWidget(scroll_area)

        # Add layouts to main layout
        main_layout.addLayout(stats_layout)
        main_layout.addLayout(typing_area_layout)

        # Set central widget
        central_widget = QWidget()
        central_widget.setLayout(main_layout)
        self.setCentralWidget(central_widget)

加载文本文件

当用户点击“加载文件”按钮时,我们会打开一个文件对话框,允许用户选择一个文本文件。选中的文件内容会被加载到打字区域。

 
    def load_file(self):
        options = QFileDialog.Options()
        options |= QFileDialog.ReadOnly
        file_path, _ = QFileDialog.getOpenFileName(self, "Select Text File", r"D:\opt\pythonProject\bak",
                                                   "Text Files (*.txt);;All Files (*)", options=options)
        if file_path:
            with open(file_path, 'r', encoding='utf-8') as file:
                text = file.readlines()
                while self.typing_layout.count():
                    child = self.typing_layout.takeAt(0)
                    if child.widget():
                        child.widget().deleteLater()

                for line in text:
                    line_label = QLabel(line.strip())
                    line_input = QLineEdit()
                    line_input.textChanged.connect(
                        lambda _, lbl=line_label, inp=line_input: self.text_changed(lbl, inp))
                    self.typing_layout.addWidget(line_label)
                    self.typing_layout.addWidget(line_input)

                self.total_characters = 0
                self.correct_characters = 0
                self.wrong_characters = 0
                self.start_time = time.time()
                self.timer.start(1000)  # Update stats every second
                self.update_stats()

处理用户输入

我们需要实时监测用户输入,并根据用户输入的正确性更新UI组件的背景颜色。每当用户正确输入一行的所有字符后,焦点会自动跳转到下一行。

 
    def text_changed(self, label, input_field):
        input_text = input_field.text()
        label_text = label.text()

        if len(input_text) > len(label_text):
            input_field.setText(input_text[:len(label_text)])  # Limit input to label length

        if input_text == label_text:
            input_field.setStyleSheet("background-color: lightgreen;")
        else:
            input_field.setStyleSheet("background-color: lightcoral;")

        self.total_characters = sum(
            len(self.typing_layout.itemAt(i * 2 + 1).widget().text()) for i in range(self.typing_layout.count() // 2))
        self.correct_characters = sum(
            1 for i in range(self.typing_layout.count() // 2)
            for a, b in
            zip(self.typing_layout.itemAt(i * 2).widget().text(), self.typing_layout.itemAt(i * 2 + 1).widget().text())
            if a == b
        )
        self.wrong_characters = self.total_characters - self.correct_characters

        # Move to the next line's input field if the current line is completed
        if input_text == label_text:
            current_index = self.typing_layout.indexOf(input_field)
            next_index = current_index + 2  # Move to the next line's input field
            if next_index < self.typing_layout.count():
                next_input_field = self.typing_layout.itemAt(next_index).widget()
                next_input_field.setFocus()

更新统计信息

每秒钟更新一次统计信息,包括每分钟字符数、总字数、正确字数、错误字数和准确率。

 
    def update_stats(self):
        elapsed_time = time.time() - self.start_time
        elapsed_minutes = elapsed_time / 60
        chars_per_minute = self.total_characters / elapsed_minutes if elapsed_minutes > 0 else 0
        accuracy = (self.correct_characters / self.total_characters * 100) if self.total_characters > 0 else 0

        self.chars_per_min_label.setText(f'每分钟字: {chars_per_minute:.2f}')
        self.elapsed_time_label.setText(f'时间: {int(elapsed_time)}s')
        self.total_chars_label.setText(f'总字数: {self.total_characters}')
        self.correct_chars_label.setText(f'正确字数: {self.correct_characters}')
        self.wrong_chars_label.setText(f'错误字数: {self.wrong_characters}')
        self.accuracy_label.setText(f'准确率: {accuracy:.2f}%')

运行程序

最后,添加以下代码以运行程序:

 
if __name__ == '__main__':
    app = QApplication(sys.argv)
    typing_app = TypingPracticeApp()
    typing_app.show()
    sys.exit(app.exec_())

完整代码

import sys
from PyQt5.QtCore import QTimer
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QVBoxLayout, QLabel, QLineEdit, QPushButton,
    QWidget, QFileDialog, QHBoxLayout, QScrollArea
)
import time


class TypingPracticeApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle('Typing Practice')
        self.setGeometry(100, 100, 800, 600)

        self.total_characters = 0
        self.correct_characters = 0
        self.wrong_characters = 0
        self.start_time = None
        self.timer = QTimer()
        self.timer.timeout.connect(self.update_stats)

        # Main layout
        main_layout = QHBoxLayout()

        # Stats layout
        stats_layout = QVBoxLayout()
        self.chars_per_min_label = QLabel('每分钟字: 0')
        self.elapsed_time_label = QLabel('0s')
        self.total_chars_label = QLabel('总字数: 0')
        self.correct_chars_label = QLabel('正确字数: 0')
        self.wrong_chars_label = QLabel('错误字数: 0')
        self.accuracy_label = QLabel('准确率: 0.00%')
        stats_layout.addWidget(self.chars_per_min_label)
        stats_layout.addWidget(self.elapsed_time_label)
        stats_layout.addWidget(self.total_chars_label)
        stats_layout.addWidget(self.correct_chars_label)
        stats_layout.addWidget(self.wrong_chars_label)
        stats_layout.addWidget(self.accuracy_label)

        # Typing layout
        self.typing_layout = QVBoxLayout()
        self.load_button = QPushButton('加载文件')
        self.load_button.clicked.connect(self.load_file)
        self.typing_area = QWidget()
        self.typing_area.setLayout(self.typing_layout)

        scroll_area = QScrollArea()
        scroll_area.setWidget(self.typing_area)
        scroll_area.setWidgetResizable(True)

        typing_area_layout = QVBoxLayout()
        typing_area_layout.addWidget(self.load_button)
        typing_area_layout.addWidget(scroll_area)

        # Add layouts to main layout
        main_layout.addLayout(stats_layout)
        main_layout.addLayout(typing_area_layout)

        # Set central widget
        central_widget = QWidget()
        central_widget.setLayout(main_layout)
        self.setCentralWidget(central_widget)

    def load_file(self):
        options = QFileDialog.Options()
        options |= QFileDialog.ReadOnly
        file_path, _ = QFileDialog.getOpenFileName(self, "Select Text File", r"D:\opt\pythonProject\bak",
                                                   "Text Files (*.txt);;All Files (*)", options=options)
        if file_path:
            with open(file_path, 'r', encoding='utf-8') as file:
                text = file.readlines()
                while self.typing_layout.count():
                    child = self.typing_layout.takeAt(0)
                    if child.widget():
                        child.widget().deleteLater()

                for line in text:
                    line_label = QLabel(line.strip())
                    line_input = QLineEdit()
                    line_input.textChanged.connect(
                        lambda _, lbl=line_label, inp=line_input: self.text_changed(lbl, inp))
                    self.typing_layout.addWidget(line_label)
                    self.typing_layout.addWidget(line_input)

                self.total_characters = 0
                self.correct_characters = 0
                self.wrong_characters = 0
                self.start_time = time.time()
                self.timer.start(1000)  # Update stats every second
                self.update_stats()

    def text_changed(self, label, input_field):
        input_text = input_field.text()
        label_text = label.text()

        if len(input_text) > len(label_text):
            input_field.setText(input_text[:len(label_text)])  # Limit input to label length

        if input_text == label_text:
            input_field.setStyleSheet("background-color: lightgreen;")
        else:
            input_field.setStyleSheet("background-color: lightcoral;")

        self.total_characters = sum(
            len(self.typing_layout.itemAt(i * 2 + 1).widget().text()) for i in range(self.typing_layout.count() // 2))
        self.correct_characters = sum(
            1 for i in range(self.typing_layout.count() // 2)
            for a, b in
            zip(self.typing_layout.itemAt(i * 2).widget().text(), self.typing_layout.itemAt(i * 2 + 1).widget().text())
            if a == b
        )
        self.wrong_characters = self.total_characters - self.correct_characters

    def update_stats(self):
        elapsed_time = time.time() - self.start_time
        elapsed_minutes = elapsed_time / 60
        chars_per_minute = self.total_characters / elapsed_minutes if elapsed_minutes > 0 else 0
        accuracy = (self.correct_characters / self.total_characters * 100) if self.total_characters > 0 else 0

        self.chars_per_min_label.setText(f'每分钟字: {chars_per_minute:.2f}')
        self.elapsed_time_label.setText(f'时间: {int(elapsed_time)}s')
        self.total_chars_label.setText(f'总字数: {self.total_characters}')
        self.correct_chars_label.setText(f'正确字数: {self.correct_characters}')
        self.wrong_chars_label.setText(f'错误字数: {self.wrong_characters}')
        self.accuracy_label.setText(f'准确率: {accuracy:.2f}%')


if __name__ == '__main__':
    app = QApplication(sys.argv)
    typing_app = TypingPracticeApp()
    typing_app.show()
    sys.exit(app.exec_())

效果图

扩展功能

  1. 多语言支持:添加对多种语言的支持,用户可以选择不同的语言进行打字练习。
  2. 难度级别:根据用户的打字速度和准确率,提供不同的难度级别,如初级、中级和高级。
  3. 打字游戏:将打字练习与游戏结合,增加趣味性。例如,用户可以通过打字来控制游戏中的角色或完成任务。
  4. 统计分析:提供更详细的统计分析,如每个字符的输入速度、错误率等,帮助用户找到自己的弱点并加以改进。
  5. 用户管理:支持多个用户,每个用户可以保存自己的打字记录和进度。
  6. 自定义文本:允许用户上传自己的文本文件进行打字练习,增加练习的多样性。
  7. 音效和提示:添加音效和视觉提示,帮助用户在打字时保持专注和提高效率。

相关资源

  1. PyQt5 官方文档:详细介绍 PyQt5 的使用方法和 API 参考。
  2. Python GUI 编程书籍:推荐一些关于 Python GUI 编程的书籍,如《Python GUI Programming with PyQt5》。
  3. 在线打字练习网站:参考一些在线打字练习网站,了解它们的功能和设计思路,如 TypingClub、Keybr 等。
  4. 开源项目:查找和学习一些开源的打字练习项目,了解它们的实现方式和代码结构。

代码优化

  1. 代码重构:将代码中的功能模块化,提升代码的可读性和可维护性。
  2. 性能优化:优化程序的性能,确保在处理大量文本时依然能够流畅运行。
  3. 界面美化:使用 CSS 样式表美化界面,提升用户体验。

相关类型推荐

  1. PyQt5 编程指南:全面介绍 PyQt5 的使用,包括窗口管理、控件使用、信号与槽等。
  2. Python GUI 编程实例教程:通过实例学习 Python GUI 编程的各个方面,从基础到高级应用。
  3. Python 数据分析与可视化:学习如何使用 Python 进行数据分析和可视化,包括统计分析、图表绘制等。
  4. Python 项目实战:通过实际项目学习 Python 编程,包括项目设计、代码实现、调试优化等。

相关类型推荐

  1. 使用Python和Selenium爬取QQ新闻热榜-CSDN博客
  2. 使用 Python 并发获取系统进程信息-CSDN博客
  3. 使用Python 进行文本情感分析-CSDN博客
  4. Python 文件搜索程序详解与实现-CSDN博客
  5. 使用Selenium 和 Python 抓取快手网页大量评论-CSDN博客

总结

通过上述步骤,我们构建了一个简单的打字练习程序。该程序可以加载文本文件并进行打字练习,同时实时统计每分钟输入的字符数、正确字符数、错误字符数和准确率。这是一个很好的小项目,可以帮助你提高打字速度和准确性。希望你能从中学到一些有用的技巧并享受这个过程。

结论

通过本文的介绍,你可以学习到如何使用 PyQt5 创建一个打字练习程序。该程序不仅可以帮助用户提高打字速度和准确率,还能实时显示统计信息,提供即时反馈,如果你有任何问题或建议,欢迎在评论区留言。继续探索和学习,祝你在深度学习的旅程中取得更多的成果!🚀


希望这个结论对你有所帮助!如果你有任何其他问题或需要进一步的帮助,请随时告诉我。😊

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LIY若依

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值