注:原创不易,转载请务必注明原作者和出处,感谢支持!

一 写在开头

1.1 本文内容

本文的主要内容:PyQt中的窗口部件:QMainWindow,QWidget,QDialog。

上述三种窗口部件都是用来创建窗口的,可以直接使用,也可以继承后再使用。它们的异同如下:

  • QMainWindow窗口可以包含菜单栏、工具栏、状态栏、标题栏等,是最常见的窗口形式,是GUI程序的主窗口。
  • QDialog是对话框窗口的基类。对话框主要用来执行短期任务,或者与用户进行互动,它可以是模态的,也可是非模态的。QDialog窗口没有菜单栏、工具栏、状态栏等。
  • QWidget即可以用来作为顶层窗口(QMainWindow),可以嵌入到其他窗口中。

三者之间的继承关系如下图:

graph TD;
QWidget-->QMainWindow;
QWidget-->QDialog;

二 QMainWindow

2.1 知识铺垫

何为顶层窗口?如果一个窗口包含一个或多个窗口,那么这个窗口就是父窗口,被包含的窗口则是子窗口。没有父窗口的窗口则是顶层窗口。QMainWindow就是一个顶层窗口,它可以包含很多界面元素,如菜单栏、工具栏、状态栏、子窗口等等。QMainWindow元素布局如下图(来自Qt文档)。

QMainWindow常用的方法有:

方法 描述
addToolBar() 添加工具栏
centralWidget() 返回窗口中心的控件,未设置时返回NULL
menuBar() 返回主窗口的菜单栏
setCentralWidget() 设置窗口中心的控件
setStatusBar() 设置状态栏
statusBar() 获得状态栏对象后,调用状态栏对象的showMessage()方法显示状态栏信息

2.2 QMainWindow实例

什么也不设置的“空白”QMainWindow,代码及效果图如下所示。

#!/usr/bin/env python3
# -*- coding: utf-8 -*- import sys
from PyQt5.QtWidgets import QApplication, QMainWindow if __name__ == '__main__':
app = QApplication(sys.argv)
w = QMainWindow()
w.show()
sys.exit(app.exec_())

我们通过一个仿照Windows系统的中记事本程序的小实例来了解QMainWindow的使用。

# text-editor.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*- import sys
import webbrowser
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QMainWindow, QTextEdit, QAction, QApplication, \
QMessageBox, QFileDialog, QDesktopWidget class TextEditor(QMainWindow):
'''
TextEditor : 一个简单的记事本程序
'''
def __init__(self):
super().__init__()
self.copiedText = ''
self.initUI() # 初始化窗口界面
def initUI(self):
# 设置中心窗口部件为QTextEdit
self.textEdit = QTextEdit()
self.setCentralWidget(self.textEdit)
self.textEdit.setText('') # 定义一系列的Action
# 退出
exitAction = QAction(QIcon('./images/exit.png'), 'Exit', self)
exitAction.setShortcut('Ctrl+Q')
exitAction.setStatusTip('Exit application')
exitAction.triggered.connect(self.close) # 新建
newAction = QAction(QIcon('./images/new.png'), 'New', self)
newAction.setShortcut('Ctrl+N')
newAction.setStatusTip('New application')
newAction.triggered.connect(self.__init__) # 打开
openAction = QAction(QIcon('./images/open.png'), 'Open', self)
openAction.setShortcut('Ctrl+O')
openAction.setStatusTip('Open Application')
openAction.triggered.connect(self.open) # 保存
saveAction = QAction(QIcon('./images/save.png'), 'Save', self)
saveAction.setShortcut('Ctrl+S')
saveAction.setStatusTip('Save Application')
saveAction.triggered.connect(self.save) # 撤销
undoAction = QAction(QIcon('./images/undo.png'), 'Undo', self)
undoAction.setShortcut('Ctrl+Z')
undoAction.setStatusTip('Undo')
undoAction.triggered.connect(self.textEdit.undo) # 重做
redoAction = QAction(QIcon('./images/redo.png'), 'Redo', self)
redoAction.setShortcut('Ctrl+Y')
redoAction.setStatusTip('Redo')
redoAction.triggered.connect(self.textEdit.redo) # 拷贝
copyAction = QAction(QIcon('./images/copy.png'), 'Copy', self)
copyAction.setShortcut('Ctrl+C')
copyAction.setStatusTip('Copy')
copyAction.triggered.connect(self.copy) # 粘贴
pasteAction = QAction(QIcon('./images/paste.png'), 'Paste', self)
pasteAction.setShortcut('Ctrl+V')
pasteAction.setStatusTip('Paste')
pasteAction.triggered.connect(self.paste) # 剪切
cutAction = QAction(QIcon('./images/cut.png'), 'Cut', self)
cutAction.setShortcut('Ctrl+X')
cutAction.setStatusTip('Cut')
cutAction.triggered.connect(self.cut) # 关于
aboutAction = QAction(QIcon('./images/about.png'), 'About', self)
aboutAction.setStatusTip('About')
aboutAction.triggered.connect(self.about) # 添加菜单
# 对于菜单栏,注意menuBar,menu和action三者之间的关系
# 首先取得QMainWindow自带的menuBar:menubar = self.menuBar()
# 然后在menuBar里添加Menu:fileMenu = menubar.addMenu('&File')
# 最后在Menu里添加Action:fileMenu.addAction(newAction)
menubar = self.menuBar() fileMenu = menubar.addMenu('&File')
fileMenu.addAction(newAction)
fileMenu.addAction(openAction)
fileMenu.addAction(saveAction)
fileMenu.addAction(exitAction) editMenu = menubar.addMenu('&Edit')
editMenu.addAction(undoAction)
editMenu.addAction(redoAction)
editMenu.addAction(cutAction)
editMenu.addAction(copyAction)
editMenu.addAction(pasteAction) helpMenu = menubar.addMenu('&Help')
helpMenu.addAction(aboutAction) # 添加工具栏
# 对于工具栏,同样注意ToolBar和Action之间的关系
# 首先在QMainWindow中添加ToolBar:tb1 = self.addToolBar('File')
# 然后在ToolBar中添加Action:tb1.addAction(newAction)
tb1 = self.addToolBar('File')
tb1.addAction(newAction)
tb1.addAction(openAction)
tb1.addAction(saveAction) tb2 = self.addToolBar('Edit')
tb2.addAction(undoAction)
tb2.addAction(redoAction)
tb2.addAction(cutAction)
tb2.addAction(copyAction)
tb2.addAction(pasteAction) tb3 = self.addToolBar('Exit')
tb3.addAction(exitAction) # 添加状态栏,以显示每个Action的StatusTip信息
self.statusBar() self.setGeometry(0, 0, 600, 600)
self.setWindowTitle('Text Editor')
self.setWindowIcon(QIcon('./images/text.png'))
self.center()
self.show() # 主窗口居中显示
def center(self):
screen = QDesktopWidget().screenGeometry()
size = self.geometry()
self.move((screen.width() - size.width()) / 2, (screen.height() - size.height()) / 2) # 定义Action对应的触发事件,在触发事件中调用self.statusBar()显示提示信息
# 重写closeEvent
def closeEvent(self, event):
reply = QMessageBox.question(self, 'Confirm', \
'Are you sure to quit without saving ?', \
QMessageBox.Yes | QMessageBox.No, \
QMessageBox.No) if reply == QMessageBox.Yes:
self.statusBar().showMessage('Quiting...')
event.accept()
else:
event.ignore()
self.save()
event.accept() # open
def open(self):
self.statusBar().showMessage('Open Text Files')
fname = QFileDialog.getOpenFileName(self, 'Open file', '/home')
self.statusBar().showMessage('Open File')
if fname[0]:
f = open(fname[0], 'r')
with f:
data = f.read()
self.textEdit.setText(data) # save
def save(self):
self.statusBar().showMessage('Add extension to file name')
fname = QFileDialog.getSaveFileName(self, 'Save File')
if (fname[0]):
data = self.textEdit.toPlainText()
f = open(fname[0], 'w')
f.write(data)
f.close() # copy
def copy(self):
cursor = self.textEdit.textCursor()
textSelected = cursor.selectedText()
self.copiedText = textSelected # paste
def paste(self):
self.textEdit.append(self.copiedText) # cut
def cut(self):
cursor = self.textEdit.textCursor()
textSelected = cursor.selectedText()
self.copiedText = textSelected
self.textEdit.cut() # about
def about(self):
url = 'https://en.wikipedia.org/wiki/Text_editor'
self.statusBar().showMessage('Loading url...')
webbrowser.open(url) if __name__ == '__main__':
app = QApplication(sys.argv)
w = TextEditor()
sys.exit(app.exec_())

三 QWidget

QWidget类是所有用户界面对象的基类,所有的窗口和控件都直接或间接继承自QWidget类。QWidget类相关的方法。

#!/usr/bin/env python3
# -*- coding: utf-8 -*- import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QToolTip
from PyQt5.QtGui import QIcon, QFont if __name__ == '__main__':
app = QApplication(sys.argv) w = QWidget()
btn = QPushButton(w)
btn.setText('Button')
btn.move(20, 20) w.resize(300, 200)
w.move(250, 200)
w.setWindowTitle('QWidget') # setWindowIcon()用于设置应用程序图标
w.setWindowIcon(QIcon('./icon.png')) # setFont()为QToolTip设定字体
QToolTip.setFont(QFont('Monospace Regular', 20))
w.setToolTip('这是一个<b>气泡提示!</b>') w.show() print('QWidget:')
print('w.x() = %d' % w.x())
print('w.y() = %d' % w.y())
print('w.width() = %d' % w.width())
print('w.height() = %d' % w.height()) print('QWidget.geometry')
print('w.geometry().x() = %d' % w.geometry().x())
print('w.geometry().y() = %d' % w.geometry().y())
print('w.geometry().width() = %d' % w.geometry().width())
print('w.geometry().height() = %d' % w.geometry().height()) sys.exit(app.exec_())

脚本输出为:

QWidget:
w.x() = 250
w.y() = 200
w.width() = 300
w.height() = 200
QWidget.geometry
w.geometry().x() = 250
w.geometry().y() = 200
w.geometry().width() = 300
w.geometry().height() = 200

四 QDialog

QDialog的各种子类提供了各种标准对话框,比如QMessageBox, QFileDialog, QInputDialog, QFontDialog等等。它们之间的继承关系如下图所示。

graph TD;
QDialog-->QMessageBox;
QDialog-->QColorDialog;
QDialog-->QFileDialog;
QDialog-->QFontDialog;
QDialog-->QInputDialog;

4.1 QDialog

QDialog类中常用方法:

方法 描述
setWindowTitle() 设置对话框标题
setWindowModality() 设置窗口模态。取值如下:
Qt.NonModal - 非模态
Qt.WindowModal - 窗口模态
Qt.ApplicationModal - 应用程序模态
#!/usr/bin/env python3
# -*- coding: utf-8 -*- import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QDialog
from PyQt5.QtCore import Qt class DialogWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('Dialog')
self.resize(350, 300) self.btn = QPushButton(self)
self.btn.setText('弹出对话框')
self.btn.move(50, 50)
self.btn.clicked.connect(self.showDialog) self.show() def showDialog(self):
dialog = QDialog()
btn = QPushButton('ok', dialog)
btn.move(50, 50)
dialog.setWindowTitle('Dialog')
dialog.setWindowModality(Qt.ApplicationModal)
dialog.exec_() if __name__ == '__main__':
app = QApplication(sys.argv)
w = DialogWindow()
sys.exit(app.exec_())

4.2 QMessageBox

QMessageBox是一种通用的弹出式对话框,用于显示消息,允许用户通过单击不同的标准按钮对消息进行反馈。每个标准按钮都有一个预定义的文本、角色和十六进制数。QMessageBox类提供了许多常用的弹出式对话框,比如提示、警告、错误、询问、关于等对话框。这些不同类型的QMessageBox对话框只是显示时得图标不同,其他功能是一样的。QMessageBox类中常用的方法有:

方法 描述
information(QWidget parent, title, text, buttons, defaultButton) parent:父窗口
title:对话框标题
text:对话框文本
buttons:多个标准按钮
defaultButton:默认选中的标准按钮
question(QWidget parent, title, text, buttons, defaultButton) 问答对话框
warning(QWidget parent, title, text, buttons, defaultButton) 警告对话框
critical(QWidget parent, title, text, buttons, defaultButton) 严重错误对话框
about(QWidget parent, title, text) 关于对话框
setTitle() 设置标题
setText() 设置消息正文
setIcon() 设置对话框的图片

QMessageBox中的标准按钮类型有:

类型 描述
QMessageBox.Ok 确定
QMessageBox.Cancel 取消
QMessageBox.Yes
QMessageBox.No
QMessageBox.Abort 终止
QMessageBox.Retry 重试
QMessageBox.Ignore 忽略
#!/usr/bin/env python3
# -*- coding: utf-8 -*- import sys
from PyQt5.QtWidgets import QApplication, QMessageBox, QWidget, QVBoxLayout, \
QPushButton class MessageBoxWindow(QWidget):
def __init__(self):
super().__init__()
self.initUI() def initUI(self):
vbox = QVBoxLayout()
btn = QPushButton('点击弹出消息框')
btn.clicked.connect(self.showMessageBox)
vbox.addWidget(btn)
self.setLayout(vbox) self.setWindowTitle('QMessageBox')
self.resize(300, 200)
self.show() def showMessageBox(self):
QMessageBox.question(self, '标题', '正文内容', QMessageBox.Yes | \
QMessageBox.No, QMessageBox.Yes)
QMessageBox.warning(self, '标题', '正文内容', QMessageBox.Yes | \
QMessageBox.No, QMessageBox.Yes)
QMessageBox.critical(self, '标题', '正文内容', QMessageBox.Yes | \
QMessageBox.No, QMessageBox.Yes)
QMessageBox.about(self, '标题', '正文内容') if __name__ == '__main__':
app = QApplication(sys.argv)
w = MessageBoxWindow()
sys.exit(app.exec_())







4.3 QInputDialog

QInputDialog控件是一个标准对话框,由一个文本框和两个按钮(OK和Cancel)组成。当用户单击OK按钮后,在父窗口可以接受通过QInputDialog控件输入的信息。在QInputDialog控件中可以输入数字、字符串或者列表中的选择。标签用于提示必要的信息。QInputDialog类常用的方法有:

方法 描述
getInt() 从控件中获取标准整型输入
getDouble() 从控件中获取标准浮点数输入
getText() 从控件中获取标准字符串输入
getItem() 从控件中获取列表里的选项输入
#!/usr/bin/env python3
# -*- coding: utf-8 -*- import sys
from PyQt5.QtWidgets import QWidget, QFormLayout, QPushButton, QLineEdit, \
QInputDialog, QApplication class InputDialogWindow(QWidget):
def __init__(self):
super().__init__()
self.initUI() def initUI(self):
layout = QFormLayout() self.btn1 = QPushButton('获得列表里的选项')
self.btn1.clicked.connect(self.getItem)
self.le1 = QLineEdit()
layout.addRow(self.btn1, self.le1) self.btn2 = QPushButton('获得字符串')
self.btn2.clicked.connect(self.getText)
self.le2 = QLineEdit()
layout.addRow(self.btn2, self.le2) self.btn3 = QPushButton('获得整数')
self.btn3.clicked.connect(self.getInt)
self.le3 = QLineEdit()
layout.addRow(self.btn3, self.le3) self.setLayout(layout)
self.setWindowTitle('QInputDialog')
self.show() def getItem(self):
items = ('C', 'C++', 'Java', 'Python')
item, ok = QInputDialog.getItem(self, 'Select Input Dialog', \
'语言列表', items, 0, False)
if ok and item:
self.le1.setText(item) def getText(self):
text, ok = QInputDialog.getText(self, 'Text Input Dialog', \
'输入姓名:')
if ok:
self.le2.setText(str(text)) def getInt(self):
num, ok = QInputDialog.getInt(self, 'Integer Input Dialog', \
'输入数字:')
if ok:
self.le3.setText(str(num)) if __name__ == '__main__':
app = QApplication(sys.argv)
w = InputDialogWindow()
sys.exit(app.exec_())





4.4 QFontDialg

QFontDialog控件是一个常用的字体选择对话框,可以让用户选择显示文本的字体样式、字号大小和格式。

#!/usr/bin/env python3
# -*- coding: utf-8 -*- import sys
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QFontDialog, QApplication, \
QPushButton, QLabel class FontDialogWindow(QWidget):
def __init__(self):
super().__init__()
self.initUI() def initUI(self):
layout = QVBoxLayout()
self.btn = QPushButton('选择字体')
self.btn.clicked.connect(self.chooseFont)
self.lb = QLabel('Hello, 测试字体例子')
layout.addWidget(self.btn)
layout.addWidget(self.lb)
self.setLayout(layout)
self.setWindowTitle('FontDialog')
self.show() def chooseFont(self):
font, ok = QFontDialog.getFont()
if ok:
self.lb.setFont(font) if __name__ == '__main__':
app = QApplication(sys.argv)
w = FontDialogWindow()
sys.exit(app.exec_())



4.5 QFileDialog

QFileDialog是用于打开和保存文件的标准对话框。QFileDialog在打开文件时使用了文件过滤器,用于显示指定扩展名的文件。也可以设置使用QFileDialog打开文件时的起始目录和指定扩展名的文件。QFileDialog类的常用方法有:

方法 描述
getOpenFileName() 返回用户所选择文件的名称,并打开该文件
getSaveFileName() 使用用户选择的文件名并保存文件
setFileMode() 可以选择的文件类型,可选枚举常量有:
QFileDialog.AnyFile:任何文件
QFileDialog.ExistingFile:已存在的文件
QFileDialog.Directory:文件目录
QFileDialog.ExistingFiles:已存在的多个文件
setFilter() 设置过滤器,只显示过滤器允许的文件类型
#!/usr/bin/env python3
# -*- coding: utf-8 -*- import sys
from PyQt5.QtWidgets import QWidget, QApplication, QVBoxLayout, QPushButton, \
QLabel, QTextEdit, QFileDialog
from PyQt5.QtCore import QDir
from PyQt5.QtGui import QPixmap class FileDialogWindow(QWidget):
def __init__(self):
super().__init__()
self.initUI() def initUI(self):
layout = QVBoxLayout()
self.btn1 = QPushButton('加载图片')
self.btn1.clicked.connect(self.chooseImage)
self.lb = QLabel()
layout.addWidget(self.btn1)
layout.addWidget(self.lb) self.btn2 = QPushButton('加载文本文件')
self.btn2.clicked.connect(self.chooseTextFile)
self.content = QTextEdit()
layout.addWidget(self.btn2)
layout.addWidget(self.content) self.setLayout(layout)
self.setWindowTitle('FileDialg')
self.show() def chooseImage(self):
fname, _ = QFileDialog.getOpenFileName(self, 'Open file', '/home', \
"Image files (*.jpg *.png *.gif)")
self.lb.setPixmap(QPixmap(fname)) def chooseTextFile(self):
dlg = QFileDialog()
dlg.setFileMode(QFileDialog.AnyFile)
dlg.setFilter(QDir.Files)
if dlg.exec_():
fname = dlg.selectedFiles()
f = open(fname[0], 'r')
with f:
data = f.read()
self.content.setText(data) if __name__ == '__main__':
app = QApplication(sys.argv)
w = FileDialogWindow()
sys.exit(app.exec_())

PyQt5之窗口类型的更多相关文章

  1. Qt学习之路2---窗口组件及窗口类型

    窗口组件: 图形用户界面由不同的窗口和窗口组件构成: Qt以组件对象的方式,构建图形用户界面. 组件的类型包括: ---容器类(父组件):用于包含其他的界面组件 ---功能类(子组件):用于实现特定的 ...

  2. html5-6 Frame框架窗口类型

    html5-6  Frame框架窗口类型 一.总结 一句话总结: 1.点左侧的a链接如何打开右侧页面? <a href='user/index.html' target='right'>& ...

  3. QObject提供了QMetaObject元类信息(相当于RTTI和反射),信号与连接,父子关系,调试信息,属性,事件,继承关系,窗口类型,线程属性,时间器,对象名称,国际化

    元类信息(相当于RTTI和反射),信号与连接,父子关系,调试信息,属性,事件,继承关系,窗口类型,线程属性,时间器,对象名称,国际化其中元类又提供了:classInfo,className,构造函数, ...

  4. WPF 判断一个对象是否是设计时的窗口类型,而不是运行时的窗口

    原文:WPF 判断一个对象是否是设计时的窗口类型,而不是运行时的窗口 当我们对 Window 类型写一个附加属性的时候,在属性变更通知中我们需要判断依赖对象是否是一个窗口.但是,如果直接判断是否是 W ...

  5. wxWidgets窗口类型

    如果在创建窗口的时候你没有指定窗口的边框类型,那么在不同的平台上将会有不同的边框类型的缺省值.在windows平台上,控件边框的缺省值为 wxSUNKEN_BORDER,意为使用当前系统风格的边框.你 ...

  6. pyqt5实现窗口跳转并关闭上一个窗口

    关键在于要定义一个关闭窗体的函数colsewin() 然后将按键与该函数连接(connect)在一起即可 import sys from PyQt5.QtWidgets import QMainWin ...

  7. pyqt5 设置窗口按钮等可用与不可用

    setEnabled(True) 设置窗口或者按钮可用,Flase不可用

  8. 窗口类型(Widget, Window, Dialog, Desktop, SubWindow等等)

    http://doc.qt.io/qt-5/qwidget.html#windowFlags-prop http://doc.qt.io/qt-5/qtwidgets-widgets-windowfl ...

  9. 解决qt5窗口不刷新(测试窗口类型,测试窗口属性)

    QApplication::notify #if QT_VERSION >= 0x050000        if (QEvent::Show == pEvent->type())     ...

随机推荐

  1. webstorm 的 .后缀名-tab快捷键

    if (key) {}//key.if tab if (!key) {}//key.else tab if (key != null) {}//key.notnull tab if (typeof k ...

  2. 我的第一个python web开发框架(32)——定制ORM(八)

    写到这里,基本的ORM功能就完成了,不知大家有没有发现,这个ORM每个方法都是在with中执行的,也就是说每个方法都是一个完整的事务,当它执行完成以后也会将事务提交,那么如果我们想要进行一个复杂的事务 ...

  3. echarts堆叠图添加总量

    echarts在使用中往往会遇到需要展示总量信息的情况,比较典型的就是3维统计的堆叠柱状图 堆叠是在柱状图的基础上,给几项设置同一stack来实现的.不考虑在tips中实现总和,有两种方式可以实现总和 ...

  4. C# for循环或者foreach往List中添加对象的时候前面的数据总被最后加入的覆盖

    昨天我旁边小姐姐遇到一个问题,就是在执行for循环往list添加数据的时候,前面的数据信息总是被后面的数据信息所覆盖.  这样编写就会造成这样的数据效果:(所有的数据都会被覆盖)     问题原因:对 ...

  5. UVA10054-The Necklace(无向图欧拉回路——套圈算法)

    Problem UVA10054-The Necklace Time Limit: 3000 mSec Problem Description Input The input contains T t ...

  6. Django模板语言(Template)

    1.变量 变量相关用 { { } }   逻辑相关用{% %} 2.Filter过滤器 (1)default 如果一个变量是false或者为空,使用给定的默认值. 否则,使用变量的值.   {{ va ...

  7. HRBUST - 2069-萌萌哒十五酱的衣服~-multiset-lower_bound

    众所周知,十五酱有很多的衣服,而且十五酱东西收拾的非常糟糕. 所以十五酱经常找不到合适的衣服穿,于是她觉得收拾一下屋子,把衣服配成一套一套的~(即一件衬衫一件裤子. 十五酱一共有n件衣服,有衬衫有裤子 ...

  8. BZOJ3711 Druzyny 最大值分治、线段树

    传送门 被暴力包菜了,然而还不会卡-- 有一个很暴力的DP:设\(f_i\)表示给\(1\)到\(i\)分好组最多可以分多少组,转移枚举最后一个组.接下来考虑优化这个暴力. 考虑:对于每一个位置\(i ...

  9. ORM框架SQLAlchemy

    SQLAlchemy orm英文全称object relational mapping,就是对象映射关系程序,简单来说就是类似python这种面向对象的程序来说一切皆对象,但是使用的数据库却都是关系型 ...

  10. max-height、min-height、height优先级的问题

    前言 我们在实际开发中可能会限制元素的最大高度,那么我们使用的属性必定是max-height,那么不知道大家有没有考虑过如果同时设置max-height和height会发生什么呢? max-heigh ...