Python 图形界面

easygui

(用户图形界面,不建议在IDLE上打开)

下载和安装

去下载,在命令行下:/路径/python.exe easygui.py install,然后就可以在Lib\site-packages下看到安装好的easygui.py了,可以用python.exe easygui.py 打开该文档帮助

字体

如果要改字体什么的内容都可以去easygui.py里找到相应位置修改,比如字体是:PROPORTIONAL_FONT

控件

(1)msgbox('内容'):弹出一个通知框并显示内容,一般都是先import easygui后在easygui.msgbox的,不过可以:from easygui import *,输入后就可以直接用函数了,比如:msgbox('内容'),此时就直接弹出内容了,并且成功弹出后会返回一个'OK'

更多参考

http://bbs.fishc.com/thread-46069-1-1.html

tkinter

(自带,且比前面那个要高级美观)

1.基本配置语句

(1)Tk()

顶层窗口的对象,举例:

root = tkinter.Tk() #生成一个顶层窗口的示例,用于容纳所有内容
(2)title()

设置标题,举例:

root.title('game')
(3)pack()

按添加顺序排列组件,设置某个控件位置,不设置这个,控件就显示不出来,里面有anchor(方位,N-north,W,E,S)side(位置,LEFT,RIGHT,CENTER),padx,pady(相对x,y距离,比如padx=10),fill(填充,=X则X轴上都填满,=Y...),其中anchor是在pack里设置方位才能用的,stickyanchor功能一样,参数也是那四个,是在grid里面才能用的

(4)grid(row='',column=''[,sticky=''])

如果不用上面的pack(),也可以用gridgrid是按行/列形式排列组件,他所在的那个框架就变成类似表格形式,然后就可以给每个控件放到几行几列去,举例:

Label(root, text='abc').grid(row=0, column=0,)  #第一行第一列的label
(5)place(relx='',rely=''[relheight='',relwidth='',anchor=''])

运行指定组件的大小和位置,relx/y代表相对父组件的x/y轴位置(0代表最左边,0.5代表中间,1表示右边),relheight代表相对父组件大小的百分比(比如0.5代表父组件的一半大),因为place需要设置的东西很多,一般用不到,但在某些情况下还是很好用的,举例:

Button(root, text='一定在最中间', bg='blue').place(relx=0.5, rely=0.5, relheight=0.75, relwidth=0.75, anchor=CENTER)
#最中间占原来0.75大的button
Button(root, text='一定在最中间', bg='green').place(relx=0.5, rely=0.5, relheight=0.5, relwidth=0.5, anchor=CENTER)
#最中间占原来0.5大的button
Button(root, text='一定在最中间', bg='red').place(relx=0.5, rely=0.5, relheight=0.25, relwidth=0.25, anchor=CENTER)
#最中间占原来0.25大的button

最终看起来是3个不同颜色的框框嵌套

(6)mainloop()

写完窗口以后最后要有这一句才能显示这整个窗口

(7)quit()

退出窗口

示例
from tkinter import *
class APP:
    def __init__(self, master):
        frame = Frame(master)
        frame.pack(side=left,padx=100,pady=100)
        #设置调整尺寸和显示位置,如果括号里没东西就按默认来 
        self.hi_there = Button(frame, text="abc",bg='black', fg="green", command=self.doone)
        #设置一个button,frame是只在哪个框里,text是文本内容,bg是button的背景颜色
        #fg是button文本颜色,command是事件,这里调用了下面的doone方法
        self.hi_there.pack()    #这里就默认位置了
        self.hi_here = Label(frame, text='bbb') #设置一个标签
        self.hi_here.pack() 
    def doone(self):
        print('111')
root = Tk()     #生成一个顶层窗口的示例,用于容纳所有内容
root.title('game')  #设置标题
app = APP(root)
root.mainloop()     #显示这整个窗口

2.常用插件

(1)label

label(frame[,text='文本信息',textvariable='变量文本信息',image='',compound='图片和文本混合模式',fg='字体颜色',bg='背景颜色',font='字体',justify='位置']),文本标签,举例:

label = Label(root, text='hello')
label.pack()

注:
text的内容是不会变的,如果想要变化就可以使用textvariable,举例:

var = StringVar() #定义一个可变字符串
var.set('aaa') #设置字符串内容
label = Label(root, textvariable=var) #文本内容为可变变量
label.pack()
var.set('bbb') #改变文本显示内容
root.mainloop()

最后会发现窗口显示的是bbb

(2)PhotoImage

PhotoImage(file='xxx.gif'),图片对象(貌似除了gif以外的都会失败,而且gif图在界面中还是静态显示),举例:

from tkinter import * #不这样的话每加一个控件就要thinker.一次,很麻烦,后面也都默认将tkinter的内容全部导入
photo = PhotoImage(file='e75a115bgy1fij374q7nrg20b40694qr.gif') #别忘了加上file=
img = Label(root, image=photo) #这里选择的框架是整个窗口,也可以放在其他定义的框架里
img.pack(side=RIGHT,padx=10,pady=10) #这句是设置控件位置的,不弄会显示不出来
root.mainloop()

注:
一个label如果放了图片在放文本可能就会把文本盖住,所以需要用到混合模式,此时文字就会在图片上方,举例:

photo = PhotoImage(file='e75a115bgy1fij374q7nrg20b40694qr.gif')
img = Label(root,justify=LEFT,image=photo,text='你好呀',compound=CENTER,font=('楷体',20),fg='white')
#设置了图片和文本的混合模式,文字在中央
img.pack(side=RIGHT,padx=10,pady=10)
root.mainloop()
(3)Button

Button (frame[, text='', textvariable='',bg='', fg='', command='事件,一般是调用方法、函数'])
按钮,举例:

def abc():
    print('hello')
button = Button(root, textvariable=var, command=abc)    #点击后会输出hello
button.pack()

如果函数需要传值,可以用匿名函数,举例:

def abc(x):
    print(x)
button = Button(root, textvariable=var, command=lambda: abc('hello'))   #点击后会输出hello
button.pack()

注:
事件的函数只要名字不要加括号,如果加了括号到时候button会自动运行一次这个函数,而且以后按都没效果了,就相当于init一样

(4)Checkbutton

Checkbutton (frame[text='',variable='变量,代表是哪一个框',...]),复选框,举例:

root.title('game')
alpha = ['a','b','c','d']   #存放每个框内容
al = []         #存放每个框的变量
lab = []        #存放显示每个框是否被选中
for each in alpha:
    al.append(IntVar())
    #al是个整数变量列表,用于到时候判断是哪一个变量,该变量选中时自动会变1,否则为0
    b = Checkbutton(root, text=each, variable=al[-1])
    #设置文本框内容为alpha内容,变量内容为每加上的最后一个,也就是最新加上的那个
    b.pack(anchor=N)        #设置方位为north
for each in range(len(alpha)):
    lab.append(each)        #设置和复选框同样多大的变量
    lab[each] = Label(root, textvariable=al[each])
    lab[each].pack(anchor=S)
(5)Radiobutton

Radiobutton (frame[text='',variable='',value='这个变量的值,要和其他单选框的不同',indicatoron='False'...]),单选框,indicatoron默认为True,也就是传统的那个样子,改成False就会变成按钮的样子,举例:

v = IntVar()        #设置一个数字变量等会儿随着选中框的值变化
alpha = [('a',1),('b',2),('c',3)]
for al, num in alpha:
    Radiobutton(root, text=al, variable=v, value=num).pack()    #value是每个单选框独一无二的值
Label(root, textvariable=v).pack()      #单选框选中哪个就会展示几,比如选中2就会显示2
v.set(1)    #默认选中value为1的
(6)Frame

Frame (frame[text='',padx='',...),设置一个框架,举例:

frame = Frame(root)  #在这窗口里弄一个框架,可以把别的内容放这框架里
(7)LabelFrame

LabelFrame (frame[text='',...]),也是框架,但是有边界显示

(8)Entry

Entry (frame),输入框,用get()读取内容,用delete()清除内容,举例:

def abc():
    print('content is:%s' % (e1.get()))     #输出e1里的内容
e1 = Entry(root)        #输入框
e1.grid(row=0, column=1)        #注意这里不能直接在上面一行同时定义了文本框和位置,否则等会儿消息会读不出来
Button(root, text='click', command=abc).grid(row=2, column=0)       #点击后输出内容
Button(root, text='quit', command=root.quit).grid(row=2, column=1)      #点击后退出,quit()可以退出程序

注:
对于像密码框那样我们想要显示的内容是*那样的话,只要在Entry里面加上show的参数就好了,举例:

e1 = Entry(root, show='*')

注2:
其他比如想要验证Entry框里的内容可以通过设置validate选项,focus-获得或失去焦点时验证、focusin-获得时验证、focusout-失去时验证、key-输入框编辑时验证、all-上面任一情况时验证,none-不验证,也是默认情况,不过说是验证,其实就是返回TrueFalse,然后还需要一个validatecommandinvalidcommand(invalidcommand事件只有在返回为False时触发)事件来触发,举例:

def test():     #如果内容为abc后台就输出right,否则输出wrong,并清空文本框内容
    if e1.get() == 'abc':
        print('right')
        return True
    else:
        print('wrong')
        e1.delete(0, END)   #从第0个删除到最后一个字符
        return False
def wrong():
        print('返回为False')
e1 = Entry(root, textvariable=v, validate='focusout', validatecommand=test, invalidcommand=wrong)
#设置当移出这个框时触发,以及对应触发事件test,还有返回为False出发wrong
e1.grid(row=0, column=1)
(9)Listbox

Listbox (),列表框,就是一大堆的那种,用insert()插入内容,delete()删除内容,举例:

lb = Listbox(root)
lb.grid(row=1)
for item in ['one','two','three','four']:
    lb.insert(END,item)
    #往Listbox插入内容,这里END表示从最后一个字符后面添加内容
    #你也可以设置比如:0,代表从起始位置开始添加内容等
button = Button(root, text='删除', command=lambda x=lb:x.delete(ACTIVE))
#点击按钮后会删除对应的listbox选项,lambda参考前面匿名函数
#所以把lb传到右边x进行delete,ACTIVE表示当前选中的值,就像END表示最后一个字符所在位置
button.grid(row=2)

注:
这个列表框可以选择单选或者多选,通过selectmode设置,其中:SINGLE表示单选,BROWSE也是单选(默认值),不过可以通过拖动鼠标或者方向键来改变选项,MULTIPLE表示多选,EXTENDED也是多选,但是需要按住shift才能实现,举例:

lb = Listbox(root, selectmode=MULTIPLE)

当感觉内容过多没有全部显示又想全部显示时,可以设置height(默认是10),举例:

lb = Listbox(root, selectmode=MULTIPLE, height=20)
(10) Scollbar

Scollbar(frame),滚动条,一般和别的组件一起使用,只要在需要使用滚动条的组件里加入yscrollcommand='实例化的滚动条'.set就行了,举例:

sb = Scrollbar(root)        #实例化滚动条
sb.pack(side=RIGHT, fill=Y) #滚动条在右边的整个Y轴
lb = Listbox(root, yscrollcommand=sb.set)   #lb的Y轴使用滚动条,X轴就xscrollcommand
lb.pack(side=LEFT, fill=BOTH)
for item in range(1000):
    lb.insert(END,item)
sb.config(command=lb.yview) #原来只能通过滚轮滚动,加上这句可以用鼠标拖动滚动条
(11) Scall

Scall(frame[from_='',to='',tickinterval='',...]),有刻度的滚动条,用来提供一个确切的值,举例:

Scale(root, from_=0, to=100, tickinterval=10, resolution=5, length=200).pack()
#因为要和from分开,所以用from_,跟class_一个道理
#然后from到to代表范围,tickinterval是显示精度,这里就是每10显示一次
#resolution就是点滚动条一次移动多少,默认是1
#length代表像素长度,就是滚动条界面多长
(12) Text

Text(frame[,width='',height='行数',...),文本框,可以输入东西的,但是比前面那个输入框Entry强大,用insert()插入,get()获取值举例:

text = Text(root, width=10, height=2) #一行10个字符,共2行
text.pack()
text.insert(INSERT, 'ONE') #END表示在末尾,这个表示在输入光标处
print(text.get('0.0', 'end'))  #获取所有文本框里值,如果不设置第二个参数则只能获取值的第一位

注:
之所以说比Entry那些强大是因为其还可以插入其他组件在里面,比如插入一个Button

text = Text(root, width=10, height=5)
text.insert(INSERT, 'ONE')
text.pack()
button = Button(text, text='我在text里面') #在text里新建一个Button
text.window_create(INSERT, window=button)
#text里面新建时要创建一个控件窗口用来显示前面的Button,此时就相当于pack()了
#所以就不需要像原来那样再有一个button.pack()了
插入图片举例
text = Text(root, width=10, height=5)
text.insert(INSERT, 'ONE')
text.pack()
photo = PhotoImage(file='a.gif')
text.image_create(END, image=photo) #插入的是图片所以image_create

注:
还有好多功能,比如Index索引、Marks标记(选择在文本的哪个地方插入,因为行列都是从1开始,所以1.2代表从第一行第二个字符后面插入)、Tags标签(设置文本的那些内容的格式)

(13) Menu

Menu(frame),菜单,举例:

def abc():
    print('hello')
menubar = Menu(root)
menubar.add_command(label='hello',command=abc)  #这里菜单栏上有一个hello的按钮,按了就输出hello
root.config(menu=menubar)   #需要把frame和菜单关联后才能显示菜单

注:
前面那样他们都是一个个单独显示,如果想象一般文件那样点击一个然后出来一排,例如点文件,出来保存、另存为啥的可以在原来的菜单里再加个菜单,举例:

menubar = Menu(root)
filemenu = Menu(menubar, tearoff=False) #在原来的菜单里再加个菜单,tearoff设置为False免得菜单可以单独一个界面
filemenu.add_command(label='新建',command=abc)
filemenu.add_command(label='保存',command=abc)
filemenu.add_separator()  #一个分割线
filemenu.add_command(label='退出',command=root.quit)
filemenu.add_cascade(label='文件',menu=filemenu) #这一行就是显示这一个菜单的名称,‘文件’显示在哪,想想就知道了
root.config(menu=menubar)
(14) Menubutton

Menubutton(frame[,text='',relief='样式',...]),按钮菜单,点下会出现菜单,举例:

mb = Menubutton(root, text='list', relief=RAISED)
mb.pack()
filemenu = Menu(mb, tearoff=False)
filemenu.add_command(label='hello',command=abc)
filemenu.add_command(label='hi',command=abc)
mb.config(menu=filemenu)
(15) OptionMenu

OptionMenu(frame[,variable,'var1','var2',...]),可选菜单,举例:

var = StringVar()
var.set('a') #设置默认值为a
w = OptionMenu(root, var, 'a', 'b', 'c') #有a、b、c三个变量可选
w.pack()

上面那个可选变量如果传入的是个列表,需要在前面加*,举例:

content = ['a', 'b', 'c', 'd', 'e']
var = StringVar()
var.set(content[0])
w = OptionMenu(root, var, *content) #在content列表前加*
w.pack()
(16) Message

Message(frame[,text='',width='']),消息框,举例:

mes = Message(root, text='this is message', width=100)  #这里width是一行的长度
mes.pack()
(17) Spinbox

Spinbox(frame,from_='',to=''[,increment='每次的增/减度']),就是像一个文本框,旁边有上下键,来增加/减少值,举例:

w = Spinbox(root, from_=0, to=10, increment=2)
w.pack()

也可以是几个内容在那里换:

w = Spinbox(root, values=('a','b','c','d','e'))
w.pack()
(18) PanedWindow

PanedWindow(),跟frame一样也是个框架,但是这个的分布还有改变格式很方便

(19) messagebox

messagebox,对话框,都不需要Tk定义,举例:

messagebox.askokcancel('game', '你确定?')
#第一个参数是标题,第二个是对话内容,可以print这个语句,当选择确定输出就是True

注:
除了askokcancel(),还有askquestion(),返回的是yesno,还有askyesno()返回也是True

(20)filedialog

文件对话框,打开、保存文件用,举例:

print(filedialog.askopenfilename(filetypes=[('TXT','.txt'),('PNG','.png'),('GIF','.gif')]))
#会出现一个要你打开文件的框,并且打开的文件类型从.txt/.png/.gif中选,返回的是路径+文件名
print(filedialog.asksaveasfilename(defaultextension='.py'))
#会出现一个要你另存为文件的框,并指定了默认保存后缀为.py,返回的是路径+文件名
(21) colorchooser

colorchooser,颜色选择框,举例:

print(colorchooser.askcolor()) #会打开打开一个颜色选择框,返回颜色值

3.画布

可以在上面添加直线、图形啥的图案,

定义
Canvas(frame[,width='',height='',...])
(1)图形支持对象

包括arc-弧形、image-PhotoImage实例的对象、line-线、oval-椭圆、polygon-多边形(传入一个包含多个坐标的列表,他会自动连起来形成一个多边形)、rectangle-矩形、text-文本、window-组件,举例:

from tkinter import *

root = Tk()
w = Canvas(root, width=200, height=200)
w.pack()
w.create_line(0, 50, 200, 50, fill='red')  #一条坐标从(0,50)到(200,50)的红线
w.create_line(100, 0, 100, 100, fill='blue', dash=(4,4)) #一条虚线
w.create_rectangle(50, 25, 150, 75, fill='black', dash=(4,4))
#一个方形,前四个参数代表:padx,pady,lengthx,lengthy
w.create_oval(50, 25, 150, 75, fill='pink')
#椭圆,这里特地参数和上面方形的一样,运行会发现这个椭圆的顶边刚好和方形四边贴合
#实际四个参数为:x-r,y-r,x+r,y+r,如果要圆形,就第一、四个参数和和第二、三个参数值的和一样就行了
w.create_text(100, 50, text='content') #创建一个文本
root.mainloop()
(2)绑定事件

bind('绑定内容', '函数'),比如绑定鼠标左键按住:

from tkinter import *

root = Tk()
def paint(event):
    x1, y1 = (event.x - 1), (event.y - 1)
    x2, y2 = (event.x + 1), (event.y + 1)
    w.create_oval(x1, y1, x2, y2, fill='red')
    #描绘出鼠标左键点的地方,因为canvas没有提供点,所以要画点就可以用无敌小的圆来替代
w = Canvas(root, width=200, height=200)
w.pack()
w.bind('<B1-Motion>', paint)
#当按住鼠标左键时触发paint事件,按住鼠标右键是<B3-Motion>
root.mainloop()
其他绑定

语法-<modifier-type-detail>

modifier

(可选,一般用于组合键)

<Alt>
<Control>
<Shift>
<Lock>:caps lock键(大小写切换)
<Double>:后面那个事件执行两次,比如双击两次——<Double-Button>
type
<Button>:鼠标随便哪个键点击
<Button-1>:鼠标左键点击,和上面按住鼠标左键不一样,前面那个按住移动能画画,这个只有点击的那一下有东西
<Button-2>:鼠标中间滚轮点击
<Button-3>:鼠标右键点击
<ButtonRelease>:鼠标点击松开时触发,比Button用的更多,因为Button在按下那一刻就触发,万一突然发现不对劲...,然后对应的1是左键,2...
<Motion>:鼠标移动时
<Key>:键盘输入
<KeyPress-A>:用户按A键,其他同理
<KeyRelease>:松开按键时触发
<MouseWheel>:鼠标滚轮时触发
detail

可选,一般用于指定鼠标、键盘特定键

组合示例
<Control-Shift-KeyPress-A>:同时按control+shift+A
event对象:就是event的属性,像event.x就是事件触发时的坐标
x,y:当前鼠标位置坐标
char: 按键对应字符(键盘事件专属)
keysym: 按键名(键盘事件专属)
keycode: 按键码(键盘事件专属)
num:按钮数字(鼠标事件专属)
type: 事件类型
实例1.点击左边左键显示当前点击坐标
from tkinter import *

def location(event):    #event是固定写进去的
    print('%d\t%d' % (event.x,event.y))     #事件的坐标

root = Tk()
frame = Frame(root, width=200, height=200)
frame.bind('<Button-1>', location)  #绑定点击左键时触发
frame.pack()
root.mainloop()
实例2.鼠标实时位置
from tkinter import *

def location(event):    #event是固定写进去的
    print('%d\t%d' % (event.x,event.y))     #事件的坐标

root = Tk()
frame = Frame(root, width=200, height=200)
frame.bind('<Motion>', location)    #绑定点击左键时触发
frame.pack()
root.mainloop()
实例3.输入键盘时显示输入字符
from tkinter import *

def location(event):
    print(event.char)       #输入的字符

root = Tk()
frame = Frame(root, width=200, height=200)
frame.bind('<Key>', location)   #绑定键盘输入内容触发
frame.focus_set()   #当在frame里面输入时才触发
frame.pack()
root.mainloop()

画图板

自带的turtle模块可以进行画图,比如贪食蛇举例:

import turtle

def drawSnake(rad, angle, len, neckrad):
   for _ in range(len):
      turtle.circle(rad, angle)
      turtle.circle(-rad, angle)
   turtle.circle(rad, angle / 2)
   turtle.forward(rad / 2)  # 直线前进
   turtle.circle(neckrad, 180)
   turtle.forward(rad / 4)

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

推荐阅读更多精彩内容