PyQt5 系统化学习: 创建简单窗口

3 基本功能

参考自:pyqt5/firstprograms

在 PyQt5 教程的这一部分中,我们学习一些基本功能。这些示例显示了一个提示窗口(tooltip)和一个图标,关闭了一个窗口,显示了一个消息框,并在桌面上将窗口居中。

3.1 创建一个简单的窗口

每个 PyQt5 应用都必须创建一个应用对象 QApplication

app = QApplication(sys.argv)

其中 sys.argv 是一组命令行参数的列表。Python 可以在 shell 里运行,这个参数提供对脚本控制的功能。这是一种通过参数来选择启动脚本的方式。如果不需要传入参数,可以使用 [] 代替 sys.argv

QApplication 管理 GUI 程序的控制流和主要设置。它包含由窗口系统和其他来源处理过和发送过的主事件循环。它也处理应用程序的初始化和收尾工作,并提供对话管理。它还可以对系统和应用的大部分设置项进行设置。对于用 Qt 写的任何一个 GUI 应用,不管这个应用有没有窗口或多少个窗口,有且只有一个 QApplication 对象。而对于用 Qt 写的非 GUI 应用,则有且只有一个 QCoreApplication 对象,并且这个应用不依赖 QtGui 库。

为了让 GUI 启动,需要使用 app.exec_() 启动事件循环(启动应用,直至用户关闭它)。app.exec_() 的作用是运行主循环,必须调用此函数才能开始事件处理,调用该方法进入程序的主循环直到调用 exit() 结束。主事件循环从窗口系统接收事件,并将其分派给应用程序小部件。如果没有该方法,那么在运行的时候还没有进入程序的主循环就直接结束了,所以运行的时候窗口会闪退。

app.exec_() 在退出时会返回状态代码(如果程序运行成功,则返回 0,否则为非 0)。也可以用 sys.exit(app.exec_())sys.exit(n) 的作用是退出应用程序并返回 n 到父进程)。我们进入了应用的主循环中,事件处理器这个时候开始工作。主循环从窗口上接收事件,并把事件传入到派发到应用控件里。当调用 exit() 方法或直接销毁主控件时,主循环就会结束。sys.exit() 方法能确保主循环安全退出。外部环境能通知主控件怎么结束。

这样便可以写出最小化的 PyQt5 代码:

import sys
from PyQt5.QtWidgets import QApplication

# You need one (and only one) QApplication instance per application.
# Pass in sys.argv to allow command line arguments for your app.
# If you know you won't use command line arguments QApplication([]) is fine.
app = QApplication(sys.argv)

# Start the event loop.
sys.exit(app.exec_())

# Your application won't reach here until you exit and the event
# loop has stopped.

此时运行,什么也没有出现?这是因为,我们没有创建一个可视化的窗口。

QWidget 控件(所有的窗口和控件都直接或者间接继承自 QWidget)是一个用户界面的基础控件,它提供了基本的应用构造器。默认情况下,构造器是没有父级的,没有父级的构造器被称为窗口(window)。

这样,我们可以创建一个简单的窗口:

import sys
from PyQt5.QtWidgets import QApplication, QWidget

app = QApplication(sys.argv)
window = QWidget()
window.show() # IMPORTANT!!!!! Windows are hidden by default.
# Start the event loop.
app.exec_()

展示如下:

图1 一个简单的窗口

PyQt5 创建的窗口默认是隐藏的,需要调用 show() 显示。

QMainWindowQWidgetQDialog 三个类都是用来创建窗口的,可以直接使用也可以继承后来使用。QMainWindow 窗口可以包含菜单栏、工具栏、状态栏和标题栏等,是最常见的窗口形式,是 GUI 程序的主窗口。QDialog 是对话框的基类,对话框主要用来执行短期任务和与用户进行互动任务,有模态和非模态两种形式。QWidget 可以用作嵌入其他窗口。

本节仅仅介绍 QMainWindowQWidget

3.2 自定义窗口

窗口是整个程序的整体界面,有边框、标题栏、菜单栏、工具栏、关闭按钮、最小化按钮、最大化按钮等。控件是指按钮、复选框、文本框、表格、进度条等这些组成 GUI 的基本元素。一个程序可以有多个窗口,一个窗口可以有多个控件。

3.2.1 窗口坐标系统

PyQt5 使用统一的坐标系统来定义窗口控件的位置和大小。以屏幕(或窗口)的左上角为坐标原点 (0,0),从左到右为 x 轴的正方向,从上到下为 y 轴的正方向。一般称窗口的原点与坐标轴围成的区域为客户区(Client Area)。

QWidget 的成员函数可分为三类:

  1. QWidget 直接提供的成员函数:x()y() 获得窗口左上角坐标,width()height() 获得客户区的宽度和高度。
  2. QWidgetgeometry() 提供的成员函数:x()y() 获得客户区左上角的坐标,width()height() 获得客户区的宽度和高度。
  3. QWidgetframeGeometry() 提供的成员函数:x()y() 获得窗口左上角,width()height() 获得客户区、标题栏和边框的整个窗口的的宽度和高度。

Qt 提供 Window and Dialog Widgets 详细说明了坐标系统,下图是其截图:

图2 Window and Dialog Widgets

3.2.2 常用的几何结构

QWidget 包含两种常见结构:不包含边框的结构与包含边框的结构。

一般情况下,不包含边框的部分是客户区,即用户操作的界面,可以添加子控件。在 Qt 中使用 QRect 类保存了它的位置和大小。您可以对其进行修改:

  1. 改变客户区的大小:QWidget.resize(width, height)。可以通过鼠标的来改变尺寸。
  2. 获得客户区的大小,宽度、高度分别使用:QWidget.size()QWidget.width()QWidget.height()
  3. 设定不可使用鼠标修改的宽度或者高度:QWidget.setFixedWidth(int width)QWidget.setFixedHeight(int height)
  4. 同时修改客户区的大小和位置,可以使用 QWidget.setGeometry(int x, int y, int width, int height)

包含边框的结构是窗口在屏幕上显示的整个区域。它包含如下函数:

  1. 获得窗口的大小和位置:QWidget.frameGeometry()
  2. 设置窗口的位置:QWidget.move(int x, int y)
  3. 获得窗口左上角坐标:QWidget.pos()

下面是一个简单的例子:

from PyQt5.QtWidgets import QApplication, QWidget


if __name__ == '__main__':
    app = QApplication([])
    w = QWidget()
    #不同操作系统可能对窗口最小宽度有规定,若设置宽度小于规定值,则会以规定值进行显示
    w.resize(250, 150)
    # 以 QWidget 左上角为(0, 0)点
    w.move(300, 300)
    w.setWindowTitle('PyQt5 坐标系统例子') # 修改窗口的标题
    w.show()
    print('控件的左上角坐标,宽度,高度,以及尺寸分别为', (w.x(), w.y()), w.width(), w.height(), w.size())
    print('客户区的左上角坐标,宽度,高度,以及尺寸分别为', (w.geometry().x(), w.geometry().y()), 
          w.geometry().width(), w.geometry().height(), w.geometry().size())
    print('窗口的左上角坐标,宽度,高度分别为', w.pos(), w.frameGeometry().width(), 
          w.frameGeometry().height())

    app.exec_()

展示效果如下:

图2 简单的窗口的常用属性

其中 QWidget.setWindowTitle 用于修改窗口的标题。

3.2.3 设置窗口的图标

窗口图标通常是显示在窗口的左上角,标题栏的最左边。QWidget.setWindowIcon(QIcon('cartoon1.ico') 提供了设置图标的方法。在某些环境下,图标显示不出来。如果你遇到了这个问题,看我在Stackoverfolw的回答

import sys
from PyQt5.QtGui import QIcon  
from PyQt5.QtWidgets  import QWidget, QApplication


class Icon(QWidget):  
    def __init__(self,  parent = None):  
        super(Icon,self).__init__(parent)    
        self.initUI()
      
    def initUI(self):
        self.setGeometry(500, 500, 450, 150)  
        self.setWindowTitle('演示程序图标例子')  
        self.setWindowIcon(QIcon('7092.gif'))  
              
if __name__ == '__main__':   
    app = QApplication(sys.argv)
    icon = Icon()  
    icon.show()
    sys.exit(app.exec_())
图3 设置窗口图标

3.3 显示气泡提示信息

import sys
from PyQt5.QtWidgets import QWidget, QToolTip, QApplication
from PyQt5.QtGui import QFont

class Winform(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        QToolTip.setFont(QFont('SansSerif', 10))
        self.setToolTip('这是一个<b>气泡提示</b>')
        self.setGeometry(200, 300, 400, 400)
        self.setWindowTitle('气泡提示')           
        
if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = Winform()
    win.show()
    sys.exit(app.exec_())

效果:

图4 气泡提示

3.4 创建主窗口类

QWidget 可以作为嵌套型的窗口存在,结构简单,而 QMainWindow 是一个程序框架,有自己的布局,可以在布局中添加控件,如将工具栏添加到布局管理器中。它常常作为 GUI 的主窗口。

主窗口在 GUI 程序是唯一的,是所有窗口中的最顶层窗口,其他窗口都是它的直接或间接子窗口。PyQt5 中,主窗口中会有一个控件(QWidget)占位符来占着中心窗口,可以使用 setCentralWidget() 来设置中心窗口。QMainWindow 继承自 QWidget 类,拥有 QWidget 所有的派生方法和属性。QMainWindow 类中比较重要的方法,如下表:

方法 描述
addToolBar() 添加工具栏
centralWidget() 返回窗口中心的一个控件,未设置时返回 NULL
menuBar() 返回主窗口的菜单栏
setCentralWidget() 设置窗口中心的控件
setStatusBar() 设置状态栏
statusBar() 获得状态栏对象后,电泳状态栏对象的 showMessage(message, int timeout=0) 方法,显示状态栏信息。其中第一个参数是要显示的状态栏信息;第二个参数是信息要停留的时间,单位是毫秒,默认是 0,表示一直显示状态栏信息

QMainWindow 不能设置布局(使用 setLayout() 方法),因为它有自己的布局。

3.4.1 创建状态栏

使用脚本创建简单的主窗口,代码如下:

import sys
from PyQt5.QtWidgets import QMainWindow, QApplication
class MainWidget(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        # 设置主窗体标签
        self.setWindowTitle("QMainWindow 例子")         
        self.resize(400, 200) 
        self.status = self.statusBar() 
        # 5 秒后状态栏消失
        self.status.showMessage("这是状态栏提示", 5000)

if __name__ == "__main__": 
    app = QApplication(sys.argv)
    main = MainWidget()
    main.show()
    sys.exit(app.exec_())

3.4.2 菜单栏

菜单栏是一组命令的集合:

import sys
from PyQt5.QtWidgets import QMainWindow, QAction, qApp, QApplication
from PyQt5.QtGui import QIcon

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

    def initUI(self):
        # 创建一个图标、一个 exit 的标签和一个快捷键组合,都执行了一个动作
        exitAct = QAction(QIcon('7092.gif'), '&Exit', self)
        exitAct.setShortcut('Ctrl+Q')
        # 创建了一个状态栏,当鼠标悬停在菜单栏的时候,能显示当前状态
        exitAct.setStatusTip('Exit application')
        # 当执行这个指定的动作时,就触发了一个事件。
        ## 这个事件跟 QApplication 的 quit() 行为相关联,所以这个动作就能终止这个应用。
        exitAct.triggered.connect(qApp.quit)
       
        self.statusBar()
        # 创建菜单栏
        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&File')
        fileMenu.addAction(exitAct)

        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('Simple menu')
        self.show()

def main():
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

我们创建了只有一个命令的菜单栏,这个命令就是终止应用。同时也创建了一个状态栏。而且还能使用快捷键 Ctrl+Q 退出应用。QAction 是菜单栏、工具栏或者快捷键的动作的组合。

3.4.3 子菜单

子菜单是嵌套在菜单里面的二级或者三级等的菜单。


import sys
from PyQt5.QtWidgets import QMainWindow, QAction, QMenu, QApplication


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

    def initUI(self):
        menubar = self.menuBar()
        fileMenu = menubar.addMenu('File')
        # 使用 QMenu 创建一个新菜单
        impMenu = QMenu('Import', self)
        impAct = QAction('Import mail', self)
        impMenu.addAction(impAct)
        newAct = QAction('New', self)
        fileMenu.addAction(newAct)
        fileMenu.addMenu(impMenu)
        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('Submenu')
        self.show()

def main():
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

显示:

图5 创建菜单栏

3.4.4 勾选菜单

下面是一个能勾选菜单的例子。

import sys
from PyQt5.QtWidgets import QMainWindow, QAction, QApplication

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

    def initUI(self):
        self.statusbar = self.statusBar()
        self.statusbar.showMessage('Ready')
        menubar = self.menuBar()
        viewMenu = menubar.addMenu('View')
        viewStatAct = QAction('View statusbar', self, checkable=True)
        viewStatAct.setStatusTip('View statusbar')
        viewStatAct.setChecked(True)  # 默认设置为选中状态
        viewStatAct.triggered.connect(self.toggleMenu)
        viewMenu.addAction(viewStatAct)
        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('Check menu')
        self.show()

    def toggleMenu(self, state):
        if state:
            self.statusbar.show()
        else:
            self.statusbar.hide()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

本例创建了一个行为菜单。这个行为/动作能切换状态栏显示或者隐藏。用 checkable 选项创建一个能选中的菜单。

3.4.5 context 菜单

context menu 也叫弹出框,是在某些场合下显示的一组命令。例如,Opera 浏览器里,网页上的右键菜单里会有刷新,返回或者查看页面源代码。如果在工具栏上右键,会得到一个不同的用来管理工具栏的菜单。

为了使 context menu 生效,需要实现 contextMenuEvent() 方法。

import sys
from PyQt5.QtWidgets import QMainWindow, qApp, QMenu, QApplication

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

    def initUI(self):
        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('Context menu')
        self.show()

    def contextMenuEvent(self, event):
        cmenu = QMenu(self)
        newAct = cmenu.addAction("New")
        openAct = cmenu.addAction("Open")
        quitAct = cmenu.addAction("Quit")
        # 使用 exec_() 方法显示菜单。从鼠标右键事件对象中获得当前坐标。
        # mapToGlobal() 方法把当前组件的相对坐标转换为窗口(window)的绝对坐标。
        action = cmenu.exec_(self.mapToGlobal(event.pos()))
        if action == quitAct:
            qApp.quit()

def main():
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()
图6 右键菜单

3.4.6 工具栏

菜单栏包含了所有的命令,工具栏就是常用的命令的集合。

import sys
from PyQt5.QtWidgets import QMainWindow, QAction, qApp, QApplication
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import QFileInfo

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

    def initUI(self):
        #root = QFileInfo(__file__).absolutePath() # 避免图标不显示,而使用绝对路径
        exitAct = QAction(QIcon('paper.png'), 'Exit', self)
        exitAct.setShortcut('Ctrl+Q')
        exitAct.triggered.connect(qApp.quit)
        self.toolbar = self.addToolBar('Exit')
        self.toolbar.addAction(exitAct)
        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('Toolbar')
        self.show()

def main():
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()
图7 工具栏

3.5 主窗口居中显示

QMainWindow 利用 QDesktopWidget 类实现窗口居中显示,如下示例:

from PyQt5.QtWidgets import QDesktopWidget, QApplication, QMainWindow
import sys

class Winform(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setWindowTitle('主窗口放在屏幕中间例子')
        self.resize(300, 200)
        self.center()

    def center(self):
        # 获取屏幕信息
        screen = QDesktopWidget().screenGeometry()
        size = self.geometry()
        x = int((screen.width() - size.width()) / 2)
        y = int((screen.height() - size.height()) / 2)
        self.move(x, y)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    win = Winform()
    win.show()
    sys.exit(app.exec_())

也可以直接使用 QDesktopWidget().availableGeometry().center() 设置窗口居中:

import sys
from PyQt5.QtWidgets import QWidget, QDesktopWidget, QApplication

class CenterWin(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):               
        self.resize(250, 150)
        self.center()
        self.setWindowTitle('Center')    
        self.show()

    def center(self):
        qr = self.frameGeometry() # 获得主窗口所在的框架
        # 获取显示器的分辨率,然后得到屏幕中间点的位置
        cp = QDesktopWidget().availableGeometry().center()
        # 然后把主窗口框架的中心点放置到屏幕的中心位置
        qr.moveCenter(cp)
        # 然后通过 move 函数把主窗口的左上角移动到其框架的左上角,这样就把窗口居中了
        self.move(qr.topLeft())

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = CenterWin()
    sys.exit(app.exec_())

3.6 关闭窗口

关闭一个窗口最直观的方式就是点击标题栏的那个叉,接下来,我们展示的是如何用程序关闭一个窗口。这里我们将接触到一点 signalsslots 的知识。本例使用的是 QPushButton 组件类。

QPushButton(string text, QWidget parent = None)

text 参数是想要显示的按钮名称,parent 参数是放在按钮上的组件,在我们的例子里,这个参数是 QWidget。应用中的组件都是一层一层的,在这个层里,大部分的组件都有自己的父级,没有父级的组件,是顶级的窗口(即主窗口)。

下面创建一个点击之后就退出窗口的按钮:

import sys
from PyQt5.QtWidgets import QWidget, QPushButton, QApplication

class Example(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        qbtn = QPushButton('Quit', self)
        qbtn.clicked.connect(QApplication.instance().quit)
        qbtn.resize(qbtn.sizeHint())
        qbtn.move(50, 50)
        self.setGeometry(300, 300, 350, 250)
        self.setWindowTitle('Quit button')
        self.show()

def main():
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

事件传递系统在 PyQt5 内建的 signal 和 slot 机制里面。点击按钮之后,信号会被捕捉并给出既定的反应。QCoreApplication 包含了事件的主循环,它能添加和删除所有的事件,instance() 创建了一个它的实例。QCoreApplication 是在 QApplication 里创建的。点击事件和能终止进程并退出应用的 quit 函数绑定在了一起。在发送者和接受者之间建立了通讯,发送者就是按钮,接受者就是应用对象。

3.7 消息盒子

默认情况下,我们点击标题栏的 X 按钮,QWidget 就会关闭。但是有时候,我们修改默认行为。比如,如果我们打开的是一个文本编辑器,并且做了一些修改,我们就会想在关闭按钮的时候让用户进一步确认操作。

import sys
from PyQt5.QtWidgets import QWidget, QMessageBox, QApplication


class Example(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Message box')
        self.show()

    def closeEvent(self, event):
        # 第一个字符串显示在消息框的标题栏,
        # 第二个字符串显示在对话框,第三个参数是消息框的俩按钮,
        # 最后一个参数是默认按钮,这个按钮是默认选中的。
        reply = QMessageBox.question(self, 'Message',
                                     "Are you sure to quit?", QMessageBox.Yes |
                                     QMessageBox.No, QMessageBox.No)
        # 这里判断返回值,如果点击的是Yes按钮,我们就关闭组件和应用,否者就忽略关闭事件。
        if reply == QMessageBox.Yes:
            event.accept()
        else:
            event.ignore()

def main():
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

如果关闭 QWidget,就会产生一个 QCloseEvent,并且把它传入到 closeEvent 函数的 event 参数中。改变控件的默认行为,就是替换掉默认的事件处理。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351