python 制作串口工具(一)

個人博客

所有文章除特別聲明外振愿,均采用 CC BY-NC-SA 4.0 許可協(xié)議。轉載請注明來自 nixgnauhcuy's blog弛饭!

如需轉載冕末,請標明出處!

Life is short, you need Python. —— Bruce Eckel

前言

工作中偶爾會用到 python 來制作一些小工具侣颂,所以針對這些小工具档桃,做了些簡化,移除了一些比較復雜的功能憔晒,拿來分享藻肄。


UI 界面

在實現(xiàn)具體邏輯之前,我們要先設計好串口工具的 UI 界面拒担,這里我直接使用的 Qt Designer 來設計串口界面的布局嘹屯。

最終效果布置好布局后是這樣的:

image

實際預覽效果:

image

實現(xiàn)

打開 Qt Designer,點擊新建 Main Window 窗體从撼,

image

進入項目界面后州弟,我們需要往里面拖入我們需要的控件,先添加兩個 QGroupBox 控件并且設置文本為串口接收設置和串口發(fā)送設置低零, 一個作為我們的接收區(qū)婆翔,一個作為我們的發(fā)送區(qū)。

image

上面操作完成后掏婶,我們先來布置我們的接收區(qū)浙滤,先添加 Label 控件,分別設置文本為串口選擇气堕、波特率、停止位畔咧、數(shù)據(jù)位茎芭、校驗位的五個 Label 控件。

image

然后誓沸,我們要增加組合框梅桩,方便后面選擇串口的參數(shù),同樣從左邊拖出五個 Combo Box 控件拜隧,然后雙擊控件宿百,這里我只拿波特率的組合框來描述趁仙,其他的例如停止位數(shù)據(jù)位還有校驗位的操作是一樣的,除了串口選擇的組合框不用設置外垦页,其他的都要設置雀费。

image

雙擊波特率的組合框控件后,點擊左下的 + 號痊焊,增加我們可選的波特率就可以了盏袄。

image

其他的 Combo Box 控件設置如下:

停止位分別設置 1、1.5薄啥、2 三個選項

數(shù)據(jù)位分別設置 8辕羽、7、6垄惧、5 四個選項

校驗位分別設置 None刁愿、Odd、Even 三個選項

這樣就把常用的波特率到逊、停止位铣口、數(shù)據(jù)位和校驗位的選項框設置好了。

接下來蕾管,我們增加兩個 RadioButton 和一個 Check Box 控件枷踏,分別設置兩個 RadioButton 文本為 ASCIIHEX,設置 Check Box 文本為時間戳掰曾。

image

最后旭蠕,增加兩個 Push Button 控件還有一個 TextEdit 控件,Push Button 分別將文本命名為清除接收打開串口旷坦。

image

這樣基本上接收區(qū)就設置完畢了掏熬。


接下來是發(fā)送區(qū),發(fā)送區(qū)中 Label秒梅、TextEdit旗芬、RadioButton、 Push Button 還有 Check Box 上面已經(jīng)說過了捆蜀,同樣設置一下就可以了疮丛,這里就不占用太多篇幅了。

image

隨后辆它,我們要添加一個 LineEdit 控件誊薄,后面可以作為定時發(fā)送的時間。

image

這樣锰茉,發(fā)送區(qū)也設置完畢了呢蔫。


上面的接收區(qū)和發(fā)送區(qū)做完后,我們要將控件擺放整齊飒筑,并且設置控件的 objectName片吊,方便后面編寫程序調(diào)用控件時绽昏,一眼就知道編輯的是哪個控件。

控件的擺放我就不過多贅述了俏脊,無非就是調(diào)整位置和寬高全谤,這里我標注一下我設置的控件 objectName,不然后面看代碼的時候就不知道我是對哪個控件操作联予。

image

生成對應的 .py 文件

完成后啼县,我們保存我們做好的 UI 到工程下,這里我將文件命名為 uart_tool_ui.ui 然后保存到后面要編寫串口工具的工程目錄下沸久。保存的 .ui 文件還不能直接使用季眷,要將它轉為 .py 文件,方便后續(xù)調(diào)用卷胯,這里我使用的編譯器是 vscode子刮,使用 vscode 將 .ui 轉為 .py 輸出,vscode 要安裝 pyqt 的擴展窑睁,這里我就不多說了挺峡,網(wǎng)上搜一下就可以了,我就直接貼上轉化好的 .py 代碼担钮。

uart_tool_ui.py

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'd:\test\my\python_uart_tool\uart_tool_ui.ui'
#
# Created by: PyQt5 UI code generator 5.13.0
#
# WARNING! All changes made in this file will be lost!


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 506)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
        self.groupBox.setGeometry(QtCore.QRect(10, 10, 781, 291))
        self.groupBox.setObjectName("groupBox")
        self.timestamp_check_box = QtWidgets.QCheckBox(self.groupBox)
        self.timestamp_check_box.setGeometry(QtCore.QRect(10, 225, 61, 16))
        self.timestamp_check_box.setObjectName("timestamp_check_box")
        self.label_7 = QtWidgets.QLabel(self.groupBox)
        self.label_7.setGeometry(QtCore.QRect(10, 175, 54, 12))
        self.label_7.setObjectName("label_7")
        self.rec_hex_radio_button = QtWidgets.QRadioButton(self.groupBox)
        self.rec_hex_radio_button.setGeometry(QtCore.QRect(70, 200, 41, 16))
        self.rec_hex_radio_button.setObjectName("rec_hex_radio_button")
        self.com_combo_box = QtWidgets.QComboBox(self.groupBox)
        self.com_combo_box.setGeometry(QtCore.QRect(10, 50, 141, 22))
        self.com_combo_box.setObjectName("com_combo_box")
        self.stopbit_combo_box = QtWidgets.QComboBox(self.groupBox)
        self.stopbit_combo_box.setGeometry(QtCore.QRect(58, 110, 91, 22))
        self.stopbit_combo_box.setObjectName("stopbit_combo_box")
        self.stopbit_combo_box.addItem("")
        self.stopbit_combo_box.addItem("")
        self.stopbit_combo_box.addItem("")
        self.label_6 = QtWidgets.QLabel(self.groupBox)
        self.label_6.setGeometry(QtCore.QRect(10, 145, 54, 12))
        self.label_6.setObjectName("label_6")
        self.baud_combo_box = QtWidgets.QComboBox(self.groupBox)
        self.baud_combo_box.setGeometry(QtCore.QRect(58, 80, 91, 22))
        self.baud_combo_box.setObjectName("baud_combo_box")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.baud_combo_box.addItem("")
        self.label_5 = QtWidgets.QLabel(self.groupBox)
        self.label_5.setGeometry(QtCore.QRect(10, 115, 54, 12))
        self.label_5.setObjectName("label_5")
        self.label_4 = QtWidgets.QLabel(self.groupBox)
        self.label_4.setGeometry(QtCore.QRect(10, 85, 54, 12))
        self.label_4.setObjectName("label_4")
        self.checkbit_combo_box = QtWidgets.QComboBox(self.groupBox)
        self.checkbit_combo_box.setGeometry(QtCore.QRect(58, 170, 91, 22))
        self.checkbit_combo_box.setObjectName("checkbit_combo_box")
        self.checkbit_combo_box.addItem("")
        self.checkbit_combo_box.addItem("")
        self.checkbit_combo_box.addItem("")
        self.label_3 = QtWidgets.QLabel(self.groupBox)
        self.label_3.setGeometry(QtCore.QRect(10, 22, 54, 20))
        self.label_3.setObjectName("label_3")
        self.databit_combo_box = QtWidgets.QComboBox(self.groupBox)
        self.databit_combo_box.setGeometry(QtCore.QRect(58, 140, 91, 22))
        self.databit_combo_box.setObjectName("databit_combo_box")
        self.databit_combo_box.addItem("")
        self.databit_combo_box.addItem("")
        self.databit_combo_box.addItem("")
        self.databit_combo_box.addItem("")
        self.uart_en_push_button = QtWidgets.QPushButton(self.groupBox)
        self.uart_en_push_button.setGeometry(QtCore.QRect(10, 250, 141, 23))
        self.uart_en_push_button.setObjectName("uart_en_push_button")
        self.rec_ascii_radio_button = QtWidgets.QRadioButton(self.groupBox)
        self.rec_ascii_radio_button.setGeometry(QtCore.QRect(10, 200, 51, 16))
        self.rec_ascii_radio_button.setObjectName("rec_ascii_radio_button")
        self.uart_rec_show = QtWidgets.QTextEdit(self.groupBox)
        self.uart_rec_show.setGeometry(QtCore.QRect(170, 10, 601, 271))
        self.uart_rec_show.setFocusPolicy(QtCore.Qt.NoFocus)
        self.uart_rec_show.setObjectName("uart_rec_show")
        self.uart_clear_rec_push_button = QtWidgets.QPushButton(self.groupBox)
        self.uart_clear_rec_push_button.setGeometry(QtCore.QRect(70, 220, 71, 23))
        self.uart_clear_rec_push_button.setObjectName("uart_clear_rec_push_button")
        self.groupBox_2 = QtWidgets.QGroupBox(self.centralwidget)
        self.groupBox_2.setGeometry(QtCore.QRect(10, 300, 781, 151))
        self.groupBox_2.setObjectName("groupBox_2")
        self.send_ascii_radio_button = QtWidgets.QRadioButton(self.groupBox_2)
        self.send_ascii_radio_button.setGeometry(QtCore.QRect(10, 20, 51, 16))
        self.send_ascii_radio_button.setObjectName("send_ascii_radio_button")
        self.send_hex_radio_button = QtWidgets.QRadioButton(self.groupBox_2)
        self.send_hex_radio_button.setGeometry(QtCore.QRect(70, 20, 41, 16))
        self.send_hex_radio_button.setObjectName("send_hex_radio_button")
        self.uart_timer_check_box = QtWidgets.QCheckBox(self.groupBox_2)
        self.uart_timer_check_box.setGeometry(QtCore.QRect(10, 47, 47, 16))
        self.uart_timer_check_box.setObjectName("uart_timer_check_box")
        self.uart1_ms_label = QtWidgets.QLabel(self.groupBox_2)
        self.uart1_ms_label.setGeometry(QtCore.QRect(140, 45, 20, 20))
        self.uart1_ms_label.setObjectName("uart1_ms_label")
        self.uart_timer_line_edit = QtWidgets.QLineEdit(self.groupBox_2)
        self.uart_timer_line_edit.setGeometry(QtCore.QRect(70, 45, 61, 20))
        self.uart_timer_line_edit.setObjectName("uart_timer_line_edit")
        self.uart_send_push_button = QtWidgets.QPushButton(self.groupBox_2)
        self.uart_send_push_button.setGeometry(QtCore.QRect(80, 70, 75, 23))
        self.uart_send_push_button.setObjectName("uart_send_push_button")
        self.uart_send_clear_push_button = QtWidgets.QPushButton(self.groupBox_2)
        self.uart_send_clear_push_button.setGeometry(QtCore.QRect(0, 70, 75, 23))
        self.uart_send_clear_push_button.setObjectName("uart_send_clear_push_button")
        self.uart_send_show = QtWidgets.QTextEdit(self.groupBox_2)
        self.uart_send_show.setGeometry(QtCore.QRect(170, 10, 601, 131))
        self.uart_send_show.setFocusPolicy(QtCore.Qt.NoFocus)
        self.uart_send_show.setObjectName("uart_send_show")
        self.label = QtWidgets.QLabel(self.groupBox_2)
        self.label.setGeometry(QtCore.QRect(10, 100, 18, 12))
        self.label.setObjectName("label")
        self.uart_tx_data_count_label = QtWidgets.QLabel(self.groupBox_2)
        self.uart_tx_data_count_label.setGeometry(QtCore.QRect(30, 120, 100, 12))
        self.uart_tx_data_count_label.setObjectName("uart_tx_data_count_label")
        self.uart_rx_data_count_label = QtWidgets.QLabel(self.groupBox_2)
        self.uart_rx_data_count_label.setGeometry(QtCore.QRect(30, 100, 100, 12))
        self.uart_rx_data_count_label.setObjectName("uart_rx_data_count_label")
        self.label_2 = QtWidgets.QLabel(self.groupBox_2)
        self.label_2.setGeometry(QtCore.QRect(10, 120, 18, 12))
        self.label_2.setObjectName("label_2")
        MainWindow.setCentralWidget(self.centralwidget)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        self.menuBar = QtWidgets.QMenuBar(MainWindow)
        self.menuBar.setGeometry(QtCore.QRect(0, 0, 800, 23))
        self.menuBar.setObjectName("menuBar")
        self.menu = QtWidgets.QMenu(self.menuBar)
        self.menu.setObjectName("menu")
        MainWindow.setMenuBar(self.menuBar)
        self.actionguanyu = QtWidgets.QAction(MainWindow)
        self.actionguanyu.setObjectName("actionguanyu")
        self.menu.addAction(self.actionguanyu)
        self.menuBar.addAction(self.menu.menuAction())

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.groupBox.setTitle(_translate("MainWindow", "串口接收設置"))
        self.timestamp_check_box.setText(_translate("MainWindow", "時間戳"))
        self.label_7.setText(_translate("MainWindow", "校驗位"))
        self.rec_hex_radio_button.setText(_translate("MainWindow", "HEX"))
        self.stopbit_combo_box.setItemText(0, _translate("MainWindow", "1"))
        self.stopbit_combo_box.setItemText(1, _translate("MainWindow", "1.5"))
        self.stopbit_combo_box.setItemText(2, _translate("MainWindow", "2"))
        self.label_6.setText(_translate("MainWindow", "數(shù)據(jù)位"))
        self.baud_combo_box.setItemText(0, _translate("MainWindow", "110"))
        self.baud_combo_box.setItemText(1, _translate("MainWindow", "300"))
        self.baud_combo_box.setItemText(2, _translate("MainWindow", "600"))
        self.baud_combo_box.setItemText(3, _translate("MainWindow", "1200"))
        self.baud_combo_box.setItemText(4, _translate("MainWindow", "2400"))
        self.baud_combo_box.setItemText(5, _translate("MainWindow", "4800"))
        self.baud_combo_box.setItemText(6, _translate("MainWindow", "9600"))
        self.baud_combo_box.setItemText(7, _translate("MainWindow", "14400"))
        self.baud_combo_box.setItemText(8, _translate("MainWindow", "19200"))
        self.baud_combo_box.setItemText(9, _translate("MainWindow", "38400"))
        self.baud_combo_box.setItemText(10, _translate("MainWindow", "43000"))
        self.baud_combo_box.setItemText(11, _translate("MainWindow", "57600"))
        self.baud_combo_box.setItemText(12, _translate("MainWindow", "76800"))
        self.baud_combo_box.setItemText(13, _translate("MainWindow", "115200"))
        self.baud_combo_box.setItemText(14, _translate("MainWindow", "128000"))
        self.baud_combo_box.setItemText(15, _translate("MainWindow", "230400"))
        self.baud_combo_box.setItemText(16, _translate("MainWindow", "256000"))
        self.baud_combo_box.setItemText(17, _translate("MainWindow", "460800"))
        self.baud_combo_box.setItemText(18, _translate("MainWindow", "921600"))
        self.baud_combo_box.setItemText(19, _translate("MainWindow", "1000000"))
        self.baud_combo_box.setItemText(20, _translate("MainWindow", "2000000"))
        self.baud_combo_box.setItemText(21, _translate("MainWindow", "3000000"))
        self.label_5.setText(_translate("MainWindow", "停止位"))
        self.label_4.setText(_translate("MainWindow", "波特率"))
        self.checkbit_combo_box.setItemText(0, _translate("MainWindow", "None"))
        self.checkbit_combo_box.setItemText(1, _translate("MainWindow", "Odd"))
        self.checkbit_combo_box.setItemText(2, _translate("MainWindow", "Even"))
        self.label_3.setText(_translate("MainWindow", "串口選擇"))
        self.databit_combo_box.setItemText(0, _translate("MainWindow", "8"))
        self.databit_combo_box.setItemText(1, _translate("MainWindow", "7"))
        self.databit_combo_box.setItemText(2, _translate("MainWindow", "6"))
        self.databit_combo_box.setItemText(3, _translate("MainWindow", "5"))
        self.uart_en_push_button.setText(_translate("MainWindow", "打開串口"))
        self.rec_ascii_radio_button.setText(_translate("MainWindow", "ASCII"))
        self.uart_clear_rec_push_button.setText(_translate("MainWindow", "清除接收"))
        self.groupBox_2.setTitle(_translate("MainWindow", "串口發(fā)送設置"))
        self.send_ascii_radio_button.setText(_translate("MainWindow", "ASCII"))
        self.send_hex_radio_button.setText(_translate("MainWindow", "HEX"))
        self.uart_timer_check_box.setText(_translate("MainWindow", "定時"))
        self.uart1_ms_label.setText(_translate("MainWindow", "ms"))
        self.uart_send_push_button.setText(_translate("MainWindow", "發(fā)送數(shù)據(jù)"))
        self.uart_send_clear_push_button.setText(_translate("MainWindow", "清除發(fā)送"))
        self.label.setText(_translate("MainWindow", "R:"))
        self.uart_tx_data_count_label.setText(_translate("MainWindow", "0"))
        self.uart_rx_data_count_label.setText(_translate("MainWindow", "0"))
        self.label_2.setText(_translate("MainWindow", "T:"))
        self.menu.setTitle(_translate("MainWindow", "幫助"))
        self.actionguanyu.setText(_translate("MainWindow", "關于"))

查看效果

在工程中編寫我們的 main.py橱赠,運行看看效果,

main.py 代碼如下

import os
import sys

from Ui_uart_tool_ui import Ui_MainWindow
from PyQt5.QtWidgets import (QApplication, QMainWindow)


class MyPyQT_Form(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super().__init__()
        self.setupUi(self)

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

然后運行效果如下:

image

結語

python 串口邏輯代碼的編寫箫津,得留到下一篇了狭姨,平時工作忙不是特別有空,等我空閑的時候再補上苏遥!我本身不是學 python 的饼拍,所以難免會有出錯或者你認為代碼不合理的地方,這些也希望多多諒解和指教田炭,我會及時修改的师抄!

關于本篇的相關代碼我也上傳到 github 和 csdn 上去了教硫,有興趣的可以訪問 github csdn 查看叨吮,后面的代碼也會在這個倉庫中補充瞬矩,不介意也可以點個 star。

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末丧鸯,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子嫩絮,更是在濱河造成了極大的恐慌围肥,老刑警劉巖蜂怎,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件穆刻,死亡現(xiàn)場離奇詭異,居然都是意外死亡杠步,警方通過查閱死者的電腦和手機氢伟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門朵锣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來甸私,“玉大人,你說我怎么就攤上這事皇型。” “怎么了绞吁?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵唬格,是天一觀的道長。 經(jīng)常有香客問我员舵,道長藕畔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任韭邓,我火速辦了婚禮溶弟,結果婚禮上,老公的妹妹穿的比我還像新娘辜御。我一直安慰自己,他們只是感情好袱巨,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著场绿,像睡著了一般嫉入。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上熬拒,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天映九,我揣著相機與錄音,去河邊找鬼件甥。 笑死引有,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的譬正。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼粉怕,長吁一口氣:“原來是場噩夢啊……” “哼抒巢!你這毒婦竟也來了?” 一聲冷哼從身側響起稚晚,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤型诚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后也搓,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡楚昭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年拍顷,在試婚紗的時候發(fā)現(xiàn)自己被綠了塘幅。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡踏揣,死狀恐怖匾乓,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情娱局,我是刑警寧澤咧七,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站耻涛,受9級特大地震影響瘟檩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜墨辛,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一背蟆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧带膀,春花似錦、人聲如沸伦糯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽淤翔。三九已至,卻和暖如春旁壮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背裁奇。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工麦撵, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人音五。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓莫瞬,卻偏偏與公主長得像寇窑,于是被迫代替她去往敵國和親栈戳。 傳聞我的和親對象是個殘疾皇子碍粥,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354