Pyqt5系列(二)
五基本界面组件之inputDialog
QInputDialog类提供了一种简单方面的对话框来获得用户的单个输入信息,可以是一个字符串,一个Int类型数据,一个double类型数据或是一个下拉列表框的条目。
对应的Dialog其中包括一个提示标签,一个输入控件(若是调用字符串输入框,则为一个QLineEdit,若是调用Int类型或double类型,则为一个QSpinBox,若是调用列表条目输入框,则为一个QComboBox),还包括一个确定输入(Ok)按钮和一个取消输入(Cancel)按钮。
QInputDialog:
classQInputDialog(QDialog)
|QInputDialog(QWidgetparent=None,Qt.WindowFlagsflags=0)
QInputDialog同样继承自QDialog,提供简单输入的对话框,
代码示例:
示例代码如下:
#--coding:utf-8--
''''''
inputDialog
''''''
__author__=''TonyZhu''
fromPyQt5.QtWidgetsimportQApplication,QWidget,QLineEdit,QInputDialog,QGridLayout,QLabel,QPushButton,QFrame
classInputDialog(QWidget):
def__init__(self):
super(InputDialog,self).__init__()
self.initUi()
definitUi(self):
self.setWindowTitle("项目信息")
self.setGeometry(400,400,300,260)
label1=QLabel("项目名称:")
label2=QLabel("项目类型:")
label3=QLabel("项目人员:")
label4=QLabel("项目成本:")
label5=QLabel("项目介绍:")
self.nameLable=QLabel("PyQt5")
self.nameLable.setFrameStyle(QFrame.Panel|QFrame.Sunken)
self.styleLable=QLabel("外包")
self.styleLable.setFrameStyle(QFrame.Panel|QFrame.Sunken)
self.numberLable=QLabel("40")
self.numberLable.setFrameStyle(QFrame.Panel|QFrame.Sunken)
self.costLable=QLabel("400.98")
self.costLable.setFrameStyle(QFrame.Panel|QFrame.Sunken)
self.introductionLable=QLabel("服务外包第三方公司")
self.introductionLable.setFrameStyle(QFrame.Panel|QFrame.Sunken)
nameButton=QPushButton("...")
nameButton.clicked.connect(self.selectName)
styleButton=QPushButton("...")
styleButton.clicked.connect(self.selectStyle)
numberButton=QPushButton("...")
numberButton.clicked.connect(self.selectNumber)
costButton=QPushButton("...")
costButton.clicked.connect(self.selectCost)
introductionButton=QPushButton("...")
introductionButton.clicked.connect(self.selectIntroduction)
mainLayout=QGridLayout()
mainLayout.addWidget(label1,0,0)
mainLayout.addWidget(self.nameLable,0,1)
mainLayout.addWidget(nameButton,0,2)
mainLayout.addWidget(label2,1,0)
mainLayout.addWidget(self.styleLable,1,1)
mainLayout.addWidget(styleButton,1,2)
mainLayout.addWidget(label3,2,0)
mainLayout.addWidget(self.numberLable,2,1)
mainLayout.addWidget(numberButton,2,2)
mainLayout.addWidget(label4,3,0)
mainLayout.addWidget(self.costLable,3,1)
mainLayout.addWidget(costButton,3,2)
mainLayout.addWidget(label5,4,0)
mainLayout.addWidget(self.introductionLable,4,1)
mainLayout.addWidget(introductionButton,4,2)
self.setLayout(mainLayout)
defselectName(self):
name,ok=QInputDialog.getText(self,"项目名称","输入项目名称:",
QLineEdit.Normal,self.nameLable.text())
ifokand(len(name)!=0):
self.nameLable.setText(name)
defselectStyle(self):
list=["外包","自研"]
style,ok=QInputDialog.getItem(self,"项目性质","请选择项目性质:",list)
ifok:
self.styleLable.setText(style)
defselectNumber(self):
number,ok=QInputDialog.getInt(self,"项目成员","请输入项目成员人数:",int(self.numberLable.text()),20,100,2)
ifok:
self.numberLable.setText(str(number))
defselectCost(self):
cost,ok=QInputDialog.getDouble(self,"项目成本","请输入项目成员人数:",float(self.costLable.text()),100.00,500.00,2)
ifok:
self.costLable.setText(str(cost))
defselectIntroduction(self):
introduction,ok=QInputDialog.getMultiLineText(self,"项目介绍","介绍:","服务外包第三方公司\nPythonproject")
ifok:
self.introductionLable.setText(introduction)
if__name__=="__main__":
importsys
app=QApplication(sys.argv)
myshow=InputDialog()
myshow.show()
sys.exit(app.exec_())
示例说明:
通过点击不同的按钮,来选择不同类型的输入对话框,从而选择所需的数据。
代码分析:
L18~22:
label1=QLabel("项目名称:")
label2=QLabel("项目类型:")
label3=QLabel("项目人员:")
label4=QLabel("项目成本:")
label5=QLabel("项目介绍:")
定义了数据项名称的标签。
L24~33:
self.nameLable=QLabel("PyQt5")
self.nameLable.setFrameStyle(QFrame.Panel|QFrame.Sunken)
self.styleLable=QLabel("外包")
self.styleLable.setFrameStyle(QFrame.Panel|QFrame.Sunken)
self.numberLable=QLabel("40")
self.numberLable.setFrameStyle(QFrame.Panel|QFrame.Sunken)
self.costLable=QLabel("400.98")
self.costLable.setFrameStyle(QFrame.Panel|QFrame.Sunken)
self.introductionLable=QLabel("服务外包第三方公司")
self.introductionLable.setFrameStyle(QFrame.Panel|QFrame.Sunken)
定义了项目数据项中的数据内容,数据内容显示在对应的标签中。
setFrameStyle()设定标签的样式,有如下的样式:
QFrame.Box
QFrame.Panel
QFrame.WinPanel
QFrame.HLine
QFrame.VLine
QFrame.StyledPanel
QFrame.Sunken
QFrame.Raised
L35~L44:
nameButton=QPushButton("...")
nameButton.clicked.connect(self.selectName)
styleButton=QPushButton("...")
styleButton.clicked.connect(self.selectStyle)
numberButton=QPushButton("...")
numberButton.clicked.connect(self.selectNumber)
costButton=QPushButton("...")
costButton.clicked.connect(self.selectCost)
introductionButton=QPushButton("...")
introductionButton.clicked.connect(self.selectIntroduction)
实例化QPushButton对象,并将对应的clicked信号和自定义的槽函数绑定起来。
L46~61:
实例化网格布局,并将对应的控件添加到网格布局中。
功能分析:
1:获取项目名称:
defselectName(self):
name,ok=QInputDialog.getText(self,"项目名称","输入项目名称:",QLineEdit.Normal,self.nameLable.text())
ifokand(len(name)!=0):
self.nameLable.setText(name)
QInputDialog中很多方法均为静态方法,因此不需要实例化直接可以调用。调用QInputDialog的getText()函数弹出标准字符串输入对话框,getText()函数原型如下:
|getText(...)
|QInputDialog.getText(QWidget,str,str,QLineEdit.EchoModeecho=QLineEdit.Normal,strtext=QString(),Qt.WindowFlagsflags=0,Qt.InputMethodHintsinputMethodHints=Qt.ImhNone)->(str,bool)
第1个参数parent,用于指定父组件;
第2个参数str,是标准输入对话框的标题名;
第3个参数str,标准输入对话框的标签提示;
第4个参数echo,mode指定标准输入对话框中QLineEdit控件的输入模式;
第5个参数str,标准输入对话框中QLineEdit控件的默认值;
第6个参数flags,指明标准输入对话框的窗体标识;
第7个参数inputMethodHints,通过选择不同的inputMethodHints值来实现不同的键盘布局;
单击nameButton之后的效果:
若用户单击了“OK”按钮,则把新输入的名称更新至显示标签。
2:获取项目属性:
defselectStyle(self):
list=["外包","自研"]
style,ok=QInputDialog.getItem(self,"项目性质","请选择项目性质:",list)
ifok:
self.styleLable.setText(style)
调用QInputDialog的getItem()函数弹出标准条目选择对话框,getItem()函数原型如下:
|getItem(...)
|QInputDialog.getItem(QWidget,str,str,list-of-str,intcurrent=0,booleditable=True,Qt.WindowFlagsflags=0,Qt.InputMethodHintsinputMethodHints=Qt.ImhNone)->(str,bool)
第1个参数parent,用于指定父组件;
第2个参数str,是标准条目选择对话框的标题名;
第3个参数str,标准条目选择对话框的标签提示;
第4个参数list-of-str,标准条目选择对话框中对应条目的list;
第5个参数editable,标准条目选择对话框条目是否可编辑标识,默认为不可编辑;
第6个参数flags,指明标准输入对话框的窗体标识;
第7个参数inputMethodHints,通过选择不同的inputMethodHints值来实现不同的键盘布局.;
单击styleButton之后的效果:
若用户单击了“OK”按钮,则把新选择的类型更新至显示标签。
3:获取项目成员:
defselectNumber(self):
number,ok=QInputDialog.getInt(self,"项目成员","请输入项目成员人数:",int(self.numberLable.text()),20,100,2)
ifok:
self.numberLable.setText(str(number))
调用QInputDialog的getInt()函数弹出标准int类型输入对话框,getInt()函数原型如下:
|getInt(...)
|QInputDialog.getInt(QWidget,str,str,intvalue=0,intmin=-2147483647,intmax=2147483647,intstep=1,Qt.WindowFlagsflags=0)->(int,bool)
第1个参数parent,用于指定父组件;
第2个参数str,是标准int类型输入对话框的标题名;
第3个参数str,标准int类型输入对话框的标签提示;
第4个参数value,标准int类型输入对话框中的默认值;
第5个参数min,标准int类型输入对话框中的最小值;
第6个参数max,标准int类型输入对话框中的最大值;
第7个参数step,标准int类型输入对话框中的步长,即QSpinBox中上下选择是数据变化的步长;
第8个参数inputMethodHints,通过选择不同的inputMethodHints值来实现不同的键盘布局;
单击numberButton之后的效果:
若用户单击了“OK”按钮,则把新选择的成员数据更新至显示标签。
4:获取项目成本:
defselectCost(self):
cost,ok=QInputDialog.getDouble(self,"项目成本","请输入项目成员人数:",float(self.costLable.text()),100.00,500.00,2)
ifok:
self.costLable.setText(str(cost))
调用QInputDialog的getDouble()函数弹出标准float类型输入对话框,getDouble()函数原型如下:
|getDouble(...)
|QInputDialog.getDouble(QWidget,str,str,floatvalue=0,floatmin=-2147483647,floatmax=2147483647,intdecimals=1,Qt.WindowFlagsflags=0)->(float,bool)
第1个参数parent,用于指定父组件;
第2个参数str,输入对话框的标题名;
第3个参数str,输入对话框的标签提示;
第4个参数value,标准float类型输入对话框中的默认值;
第5个参数min,标准float类型输入对话框中的最小值;
第6个参数max,标准float类型输入对话框中的最大值;
第7个参数decimals,小数点后面保留的位数;
第8个参数inputMethodHints,通过选择不同的inputMethodHints值来实现不同的键盘布局;
单击costButton之后的效果:
若用户单击了“OK”按钮,则把新选择的成本数据更新至显示标签
5:获取项目介绍:
defselectIntroduction(self):
introduction,ok=QInputDialog.getMultiLineText(self,"项目介绍","介绍:","服务外包第三方公司\nPythonproject")
ifok:
self.introductionLable.setText(introduction)
调用QInputDialog的getMultiLineText()函数弹出标准多行文本类型输入对话框,getMultiLineText()函数原型如下:
|getMultiLineText(...)
|QInputDialog.getMultiLineText(QWidget,str,str,strtext='''',Qt.WindowFlagsflags=0,Qt.InputMethodHintsinputMethodHints=Qt.ImhNone)->(str,bool)
第1个参数parent,用于指定父组件;
第2个参数str,输入对话框的标题名;
第3个参数str,输入对话框的标签提示;
第4个参数text,输入对话框中LineEdit的默认值;
第5个参数flags,指明标准输入对话框的窗体标识;
第6个参数inputMethodHints,通过选择不同的inputMethodHints值来实现不同的键盘布局;
单击introductionButton之后的效果:
若用户单击了“OK”按钮,则把新修改的项目介绍信息更新至显示标签
六基本界面组件之MessageBox
消息框针对某个场景以文本的形式向用户进行提示,为了获取用户的响应消息框可以显示图标和标准按钮。在实际的界面交互中,经常会看到各种类型的消息框,显示关于消息框,显示严重错误消息框,显示警告消息框等等。由于这些对话框在各个程序中都是一样的,所以QT中就统一提供了一个QMessageBox的类,这样在所有程序中都可以直接使用。
QMessageBox提供两套接口来实现,一种是staticfunctions(静态方法调用),另外一种theproperty-baseAPI(基于属性的API)。直接调用静态方法是一种比较简单的途径,但是没有基于属性API的方式灵活。在QT的官网上推荐使用theproperty-baseAPI。
Staticfunctions方式:
QMessageBox用于显示消息提示。一般会使用到其提供的几个static函数(C++层的函数原型,其参数类型和python中的一样):
通过一个示例来进行说明各个方法的使用:
#--coding:utf-8--
''''''
MessageBox
''''''
__author__=''TonyZhu''
fromPyQt5.QtWidgetsimportQApplication,QWidget,QLineEdit,QMessageBox,QGridLayout,QLabel,QPushButton,QFrame
classMessageBox(QWidget):
def__init__(self):
super(MessageBox,self).__init__()
self.initUi()
definitUi(self):
self.setWindowTitle("MessageBox")
self.setGeometry(400,400,300,290)
self.questionLabel=QLabel("Question:")
self.questionLabel.setFrameStyle(QFrame.Panel|QFrame.Sunken)
self.infoLabel=QLabel("Information:")
self.infoLabel.setFrameStyle(QFrame.Panel|QFrame.Sunken)
self.warningLabel=QLabel("Warning:")
self.warningLabel.setFrameStyle(QFrame.Panel|QFrame.Sunken)
self.criticalLabel=QLabel("Critical:")
self.criticalLabel.setFrameStyle(QFrame.Panel|QFrame.Sunken)
self.aboutLabel=QLabel("About:")
self.aboutLabel.setFrameStyle(QFrame.Panel|QFrame.Sunken)
self.aboutQtLabel=QLabel("AboutQT:")
self.aboutQtLabel.setFrameStyle(QFrame.Panel|QFrame.Sunken)
self.resultLabel=QLabel("Result:")
self.resultLabel.setFrameStyle(QFrame.Panel|QFrame.Sunken)
questButton=QPushButton("...")
questButton.clicked.connect(self.selectQuestion)
infoButton=QPushButton("...")
infoButton.clicked.connect(self.selectInfo)
warningButton=QPushButton("...")
warningButton.clicked.connect(self.selectWarning)
criticalButton=QPushButton("...")
criticalButton.clicked.connect(self.selectCritical)
aboutButton=QPushButton("...")
aboutButton.clicked.connect(self.selectAbout)
aboutQtButton=QPushButton("...")
aboutQtButton.clicked.connect(self.selectAboutQt)
mainLayout=QGridLayout()
mainLayout.addWidget(self.questionLabel,0,0)
mainLayout.addWidget(questButton,0,1)
mainLayout.addWidget(self.infoLabel,1,0)
mainLayout.addWidget(infoButton,1,1)
mainLayout.addWidget(self.warningLabel,2,0)
mainLayout.addWidget(warningButton,2,1)
mainLayout.addWidget(self.criticalLabel,3,0)
mainLayout.addWidget(criticalButton,3,1)
mainLayout.addWidget(self.aboutLabel,4,0)
mainLayout.addWidget(aboutButton,4,1)
mainLayout.addWidget(self.aboutQtLabel,5,0)
mainLayout.addWidget(aboutQtButton,5,1)
mainLayout.addWidget(self.resultLabel,6,1)
self.setLayout(mainLayout)
defselectQuestion(self):
button=QMessageBox.question(self,"Question","检测到程序有更新,是否安装最新版本?",
QMessageBox.Ok|QMessageBox.Cancel,QMessageBox.Ok)
ifbutton==QMessageBox.Ok:
self.resultLabel.setText("Question:OK")
elifbutton==QMessageBox.Cancel:
self.resultLabel.setText("Question:Cancel")
else:
return
defselectInfo(self):
QMessageBox.information(self,"Information","程序当前版本为V3.11")
self.resultLabel.setText("Information")
4
defselectWarning(self):
button=QMessageBox.warning(self,"Warning","恢复出厂设置将导致用户数据丢失,是否继续操作?",
QMessageBox.Reset|QMessageBox.Help|QMessageBox.Cancel,QMessageBox.Reset)
ifbutton==QMessageBox.Reset:
self.resultLabel.setText("Warning:Reset")
elifbutton==QMessageBox.Help:
self.resultLabel.setText("Warning:Help")
elifbutton==QMessageBox.Cancel:
self.resultLabel.setText("Warning:Cancel")
else:
return
defselectCritical(self):
QMessageBox.critical(self,"Critical","服务器宕机!")
self.resultLabel.setText("Critical")
defselectAbout(self):
QMessageBox.about(self,"About","Copyright2015Tonyzhu.\nAllRightreserved.")
self.resultLabel.setText("About")
defselectAboutQt(self):
QMessageBox.aboutQt(self,"AboutQt")
self.resultLabel.setText("AboutQt")
if__name__=="__main__":
importsys
app=QApplication(sys.argv)
myshow=MessageBox()
myshow.show()
sys.exit(app.exec_())
示例说明:
通过点击不同的按钮,来选择不同类型的消息框,并将处理的结果显示在resultLabel中。
代码分析:
L19~32:
self.questionLabel=QLabel("Question:")self.questionLabel.setFrameStyle(QFrame.Panel|QFrame.Sunken)
.......
self.resultLabel=QLabel("Result:")self.resultLabel.setFrameStyle(QFrame.Panel|QFrame.Sunken)
定义不同消息类型的标签,其中resultLabel显示不同messagebox执行的结果。
L34~45:
questButton=QPushButton("...")
questButton.clicked.connect(self.selectQuestion)
.....
aboutQtButton=QPushButton("...")
aboutQtButton.clicked.connect(self.selectAboutQt)
定义针对不同类型操作的按钮,并且将对应按钮的clicked信号和自定义的槽函数绑定在一起。
L47~60:
mainLayout=QGridLayout()
mainLayout.addWidget(self.questionLabel,0,0)
mainLayout.addWidget(questButton,0,1)
.......
mainLayout.addWidget(self.aboutQtLabel,5,0)
mainLayout.addWidget(aboutQtButton,5,1)
mainLayout.addWidget(self.resultLabel,6,1)
实例化网格布局,并将定义的标签和按钮添加到布局的对应位置。
1、question类型
question类型的执行代码段如下:
defselectQuestion(self):
button=QMessageBox.question(self,"Question","检测到程序有更新,是否安装最新版本?",
QMessageBox.Ok|QMessageBox.Cancel,QMessageBox.Ok)
ifbutton==QMessageBox.Ok:
self.resultLabel.setText("Question:OK")
elifbutton==QMessageBox.Cancel:
self.resultLabel.setText("Question:Cancel")
else:
return
调用static方法question()生产question类型的消息框(Ok和cancel按钮,默认选择Ok按钮),该执行之后返回用户选择的按钮。通过判断返回的按钮类型,在resultLabel中显示对应的内容。
question(QWidgetparent,constQString&title,constQString&text,StandardButtonsbuttons=StandardButtons(Yes|No),StandardButtondefaultButton=NoButton)
第1个参数parent,用于指定父组件;
第2个参数title,是消息框中的标题;
第3个参数text,消息框中显示的内容。
第4个参数buttons,消息框中显示的button,它的取值是StandardButtons,每个选项可以使用|运算组合起来。如QMessageBox.Ok|QMessageBox.Cancel,
第5个参数button,消息框中默认选中的button。
这个函数有一个返回值,用于确定用户点击的是哪一个按钮。我们可以直接获取其返回值。如果返回值是Ok,也就是说用户点击了Ok按钮,
QLabel支持HTML形式的文本显示,在resultLabel中是通过HTML的语法形式进行显示的。具体可以参考一下HTML语法。
执行的结果:
2、information类型
information类型的执行代码段如下:
defselectInfo(self):
QMessageBox.information(self,"Information","程序当前版本为V3.11")
self.resultLabel.setText("Information")
调用static方法information()生产information类型的消息框,该类型默认有一个Ok按钮。
information(QWidgetparent,constQString&title,constQString&text,StandardButtonsbuttons=Ok,StandardButtondefaultButton=NoButton)
第1,2,3参数,同question类型的说明。
第4个参数buttons,默认参数,默认为Ok按钮。
执行的结果:
3、warning类型
warning类型的执行代码段如下:
defselectWarning(self):
button=QMessageBox.warning(self,"Warning","恢复出厂设置将导致用户数据丢失,是否继续操作?",
QMessageBox.Reset|QMessageBox.Help|QMessageBox.Cancel,QMessageBox.Reset)
ifbutton==QMessageBox.Reset:
self.resultLabel.setText("Warning:Reset")
elifbutton==QMessageBox.Help:
self.resultLabel.setText("Warning:Help")
elifbutton==QMessageBox.Cancel:
self.resultLabel.setText("Warning:Cancel")
else:
return
调用static方法warning()生产warning类型的消息框(Reset、Help和Cancel按钮,默认选择Reset按钮),该执行之后返回用户选择的按钮。通过判断返回的按钮类型,在resultLabel中显示对应的内容。
warning(QWidgetparent,constQString&title,constQString&text,StandardButtonsbuttons=Ok,StandardButtondefaultButton=NoButton)
4、critical类型
critical类型的执行代码段如下:
defselectCritical(self):
QMessageBox.critical(self,"Critical","服务器宕机!")
self.resultLabel.setText("Critical")
调用static方法critical()生产critical类型的消息框。
critical(QWidgetparent,constQString&title,constQString&text,StandardButtonsbuttons=Ok,StandardButtondefaultButton=NoButton)
参数说明同information类型。
5、about类型
about类型的执行代码段如下:
defselectAbout(self):
QMessageBox.about(self,"About","Copyright2015Tonyzhu.\nAllRightreserved.")
self.resultLabel.setText("About")
调用static方法about()生产about类型的消息框。
about(QWidgetparent,constQString&title,constQString&text)
第1个参数parent,用于指定父组件;
第2个参数title,是消息框中的标题;
第3个参数text,消息框中显示的内容。
执行的结果:
6、aboutQt类型
aboutQt类型的执行代码段如下:
defselectAboutQt(self):
QMessageBox.aboutQt(self,"AboutQt")
self.resultLabel.setText("AboutQt")
调用static方法aboutQt()生产aboutQt类型的消息框。
aboutQt(QWidgetparent,constQString&title=QString())
第1个参数parent,用于指定父组件;
第2个参数title,是消息框中的标题;
其中提示内容来自QT的about中的信息。
执行的结果:
Theproperty-baseAPI方式:
通过上述的例子可以看出直接调用QMessageBox的static方法可以很方便的生成各种类型的消息框,但是这种方式是一种既定的显示风格。
QMessageBox类的static函数优点是方便使用,缺点也很明显:非常不灵活。我们只能使用简单的几种形式。为了能够定制QMessageBox细节,我们必须使用QMessageBox的属性设置API。
实例说明:
#--coding:utf-8--
''''''
MessageBox
''''''
__author__=''TonyZhu''
fromPyQt5.QtWidgetsimportQApplication,QWidget,QLineEdit,QMessageBox,QHBoxLayout,QLabel,QPushButton,QFrame
classMessageBox(QWidget):
def__init__(self):
super(MessageBox,self).__init__()
self.initUi()
definitUi(self):
self.setWindowTitle("MessageBox")
self.setGeometry(400,400,300,290)
mainLayout=QHBoxLayout()
self.displayLabel=QLabel("")
self.displayLabel.setFrameStyle(QFrame.Panel|QFrame.Sunken)
mainLayout.addWidget(self.displayLabel)
self.setLayout(mainLayout)
msgBox=QMessageBox()
msgBox.setIcon(QMessageBox.Information)
msgBox.setWindowTitle("Theproperty-baseAPI")
msgBox.setText("ThePythonfilehasbeenmodified.");
msgBox.setInformativeText("Doyouwanttosaveyourchanges?");
msgBox.setDetailedText("Pythonispowerful...andfast;\nplayswellwithothers;\n\
runseverywhere;\nisfriendly&easytolearn;\nisOpen.")
msgBox.setStandardButtons(QMessageBox.Save|QMessageBox.Discard|QMessageBox.Cancel);
msgBox.setDefaultButton(QMessageBox.Save);
ret=msgBox.exec()
ifret==QMessageBox.Save:
self.displayLabel.setText("Save")
elifret==QMessageBox.Discard:
self.displayLabel.setText("Discard")
elifret==QMessageBox.Cancel:
self.displayLabel.setText("Cancel")
else:
pass
if__name__=="__main__":
importsys
app=QApplication(sys.argv)
myshow=MessageBox()
myshow.show()
sys.exit(app.exec_())
执行的结果:
示例说明:
程序启动的时候直接显示自定义的messagebox,并且在resultLabel中显示选择的结果。
代码分析:
L26:
msgBox.setWindowTitle(“Theproperty-baseAPI”)
通过setWindowTitle()设定消息框的标题。
L27:
msgBox.setText(“ThePythonfilehasbeenmodified.”);
通过setText()设定消息框的提示信息。
L28:
msgBox.setInformativeText(“Doyouwanttosaveyourchanges?”)
setInformativeText(),在对话框中显示的简单说明文字
L29:
msgBox.setDetailedText(“Pythonispowerful…andfast;\nplayswellwithothers;\n\
runseverywhere;\nisfriendly&easytolearn;\nisOpen.”)
setDetailedText(),设定消息框中的详细文本信息。当设定详细文本的时候,对话框自动增加“ShowDetails”按钮。
通过上述的例子,可以发现通过theproperty-baseAPI的方式,可以更灵活的定义messagebox。
QMessageBox常用属性:
七信号与槽机制
信号和槽机制是QT的核心机制,要精通QT编程就必须对信号和槽有所了解。信号和槽是一种高级接口,应用于对象之间的通信,它是QT的核心特性,也是QT区别于其它工具包的重要地方。
在linux、windows等GUI工具包中,GUI组件都会注册回调函数用于处理组件所触发的动作,通常是注册对应的函数的函数指针。在之前关于Button的文章中提到了信号与槽的机制的使用,通过该机制可以很好的将组件的信号(如button的clocked、toggled、pressed等)和处理该信号的槽关联起来。通过信号与槽机制,能够让我们很简洁和快速的来完成相关的功能。
信号和槽是用来在对象间传递数据的方法:当一个特定事件发生的时候,signal会被emit出来,slot调用是用来响应相应的signal的。Qt中对象已经包含了许多预定义的signal(基本组件都有各自特有的预定义的信号),根据使用的场景我们可以添加新的signal。Qt的对象中已经包含了许多预定义的槽函数,但我们也根据使用的场景添加新的槽函数。
信号:
当对象的状态发生改变的时候,信号就由该对象发射(emit)出去。当一个信号被发射(emit)时候,与其关联的槽函数被立刻执行。其中该对象只负责发送信号,发射该信号的对象并不知道是那个对象在接收这个信号。这样保证了对象与对象之间的低耦合。
如果存在信号和多个槽函数相关联的时候,当信号被发射时,这些槽的执行顺序将会是随机的、不确定的。
槽:
用于接受信号,而且槽只是普通的对象成员函数。当和槽连接的信号被发射时,槽会被调用。一个槽并不知道是否有任何信号与自己相连接。
信号和槽的绑定:
通过调用QObject对象的connect函数来将某个对象的信号与另外一个对象的槽函数相关联,这样当发射者发射信号时,接收者的槽函数将被调用。该函数的定义如下::
connect(slot[,type=PyQt5.QtCore.Qt.AutoConnection[,no_receiver_check=False]])
Parameters:
slot–theslottoconnectto,eitheraPythoncallableoranotherboundsignal.
type–thetypeoftheconnectiontomake.
no_receiver_check–suppressthecheckthattheunderlyingC++receiverinstancestillexistsanddeliverthesignalanyway.
当信号与槽没有必要继续保持关联时,我们可以使用disconnect函数来断开连接。其定义如下:
disconnect([slot])
Parameters:slot–theoptionalslottodisconnectfrom,eitheraPythoncallableoranotherboundsignal.Ifitisomittedthenallslotsconnectedtothesignalaredisconnected.
信号和槽的特点:
1、一个信号可以连接到多个槽;
当信号发出后,槽函数都会被调用,但是调用的顺序是随机的,不确定的。
self.slider.valueChanged.connect(self.pBar.setValue)self.slider.valueChanged.connect(self.lcdNumber.display)
QSlider数据的变化同时绑定在setValue()和display()两个槽上。
2、多个信号可以连接到同一个槽;
其中任何一个信号发出,槽函数都会被执行。
self.buttonOn.clicked.connect(self.showMessage)
self.buttonOff.clicked.connect(self.showMessage)
showMessage()同时绑定在两个button的clicked信号上。
3、信号的参数可以是任何的Python类型;
如list,dict等python独有的类型。自定义信号的时候举例说明。
4、信号和槽的连接可以被移除;
比如断开某个特定信号的关联。
self.buttonOn.clicked.connect(self.showMessage)
5、信号可以和另外一个信号进行关联;
第一个信号发出后,第二个信号也同时发送。比如关闭系统的信号发出之后,同时会发出保存数据的信号。
代码示例:
关于信号和槽的式样代码如下:
#--coding:utf-8--
''''''
Signal&Slot
''''''
__author__=''TonyZhu''
importsys
fromPyQt5.QtCoreimportQt
fromPyQt5.QtWidgetsimport(QWidget,QLCDNumber,QSlider,QGridLayout,QLabel,QHBoxLayout,QGroupBox,
QVBoxLayout,QApplication,QProgressBar,QPushButton,QMessageBox)
classSignalSlot(QWidget):
def__init__(self):
super(SignalSlot,self).__init__()
self.initUI()
definitUI(self):
self.controlsGroup=QGroupBox("运行样本")
self.lcdNumber=QLCDNumber(self)
self.slider=QSlider(Qt.Horizontal,self)
self.pBar=QProgressBar(self)
vbox=QVBoxLayout()
vbox.addWidget(self.pBar)
vbox.addWidget(self.lcdNumber)
vbox.addWidget(self.slider)
self.controlsGroup.setLayout(vbox)
controlsLayout=QGridLayout()
self.label1=QLabel("保存状态:")
self.saveLabel=QLabel()
self.label2=QLabel("运行状态:")
self.runLabel=QLabel()
self.buttonSave=QPushButton("保存")
self.buttonRun=QPushButton("运行")
self.buttonStop=QPushButton("停止")
self.buttonDisconnect=QPushButton("解除关联")
self.buttonConnect=QPushButton("绑定关联")
controlsLayout.addWidget(self.label1,0,0)
controlsLayout.addWidget(self.saveLabel,0,1)
controlsLayout.addWidget(self.label2,1,0)
controlsLayout.addWidget(self.runLabel,1,1)
controlsLayout.addWidget(self.buttonSave,2,0)
controlsLayout.addWidget(self.buttonRun,2,1)
controlsLayout.addWidget(self.buttonStop,2,2)
controlsLayout.addWidget(self.buttonDisconnect,3,0)
controlsLayout.addWidget(self.buttonConnect,3,1)
layout=QHBoxLayout()
layout.addWidget(self.controlsGroup)
layout.addLayout(controlsLayout)
self.setLayout(layout)
self.buttonRun.clicked.connect(self.buttonSave.clicked)
self.slider.valueChanged.connect(self.pBar.setValue)
self.slider.valueChanged.connect(self.lcdNumber.display)
self.buttonSave.clicked.connect(self.showMessage)
self.buttonRun.clicked.connect(self.showMessage)
self.buttonDisconnect.clicked.connect(self.unbindConnection)
self.buttonConnect.clicked.connect(self.bindConnection)
self.buttonStop.clicked.connect(self.stop)
self.setGeometry(300,500,500,180)
self.setWindowTitle(''信号和槽'')
defshowMessage(self):
ifself.sender().text()=="保存":
self.saveLabel.setText("Saved")
elifself.sender().text()=="运行":
self.saveLabel.setText("Saved")
self.runLabel.setText("Running")
defunbindConnection(self):
self.slider.valueChanged.disconnect()
defbindConnection(self):
self.slider.valueChanged.connect(self.pBar.setValue)
self.slider.valueChanged.connect(self.lcdNumber.display)
defstop(self):
self.saveLabel.setText("")
self.runLabel.setText("")
if__name__==''__main__'':
app=QApplication(sys.argv)
ex=SignalSlot()
ex.show()
sys.exit(app.exec_())
示例说明:
程序样本运行的界面逻辑,先设定运行的程序样本数量,然后先保存后运行的逻辑状态。通过slider的滑动来改变progressBar和LCD的显示数据;“保存”按钮保存运行的样本;“运行”按钮运行程序样本;“解除关联”解除slider.valueChanged信号的绑定,此时slider的滑动,不会改变progressBar和LCD的显示
示例说明:
L22~30:
self.controlsGroup=QGroupBox("运行样本")
self.lcdNumber=QLCDNumber(self)
self.slider=QSlider(Qt.Horizontal,self)
self.pBar=QProgressBar(self)
vbox=QVBoxLayout()
vbox.addWidget(self.pBar)
vbox.addWidget(self.lcdNumber)
vbox.addWidget(self.slider)
self.controlsGroup.setLayout(vbox)
实例化一个QGroupBox,在其中添加QSlider,QProgressBar,QLCDNumber控件。
L32~41:
controlsLayout=QGridLayout()
self.label1=QLabel("保存状态:")
.....
self.buttonDisconnect=QPushButton("解除关联")
self.buttonConnect=QPushButton("绑定关联")
实例化,界面中右半部分的控件。
L58~65:
self.buttonRun.clicked.connect(self.buttonSave.clicked)
self.slider.valueChanged.connect(self.pBar.setValue)
self.slider.valueChanged.connect(self.lcdNumber.display)
self.buttonSave.clicked.connect(self.showMessage)
self.buttonRun.clicked.connect(self.showMessage)
self.buttonDisconnect.clicked.connect(self.unbindConnection)
self.buttonConnect.clicked.connect(self.bindConnection)
self.buttonStop.clicked.connect(self.stop
signal和slot进行绑定。
1、一个信号绑定多个槽:
self.slider.valueChanged.connect(self.pBar.setValue)self.slider.valueChanged.connect(self.lcdNumber.display)
slider控件的valueChanged信号,同时与QProgressBar的setValue(),QLCDNumber的display()槽函数绑定,当valueChanged信号触发的时候,这两个槽函数均会被调用。
2、多个信号绑定到一个槽:
self.buttonSave.clicked.connect(self.showMessage)
self.buttonRun.clicked.connect(self.showMessage)
buttonSave和buttonRun这两个对象的clicked信号,同时绑定到showMessage()这个槽函数。无论哪一个信号被触发,showMessage()这个槽函数均会被调用。
3、信号和槽的连接可以被移除:
self.buttonDisconnect.clicked.connect(self.unbindConnection)
当buttonDisconnect信号触发之后,与其关联的槽函数unbindConnection()中就会执行disconnect()方法,如下:
defunbindConnection(self):
self.slider.valueChanged.disconnect()
其中执行disconnect()的时候可以指定解除与某个特定的slot槽的关联,比如self.slider.valueChanged.disconnect(self.pBar.setValue),此时解除和QProgressBar的setValue()的关联;或者不指定,在不指定slot的场景下这样将解除和这个信号所有关联的槽。
4、信号与信号的关联:
self.buttonRun.clicked.connect(self.buttonSave.clicked)
在示例说明中提到,在运行之前要对样本进行保存,所以为了保证运行的时候执行了保存的操作,所以将buttonRun.clicked信号和buttonSave.clicked信号关联起来。
示例中在没有执行“保存”(buttonSave)的时候,执行“运行”(buttonRun),此时由于两个对象的clicked信号已经关联,所以buttonSave的clicked同样会执行。
八自定义信号
PyQt5已经自动定义了很多QT内建的信号。但是在实际的使用中为了灵活使用信号与槽机制,我们可以根据需要自定义signal。可以使用pyqtSignal()方法定义新的信号,新的信号作为类的属性。
自定义signal说明:
pyqtSignal()方法原型(PyQt官网的定义):
PyQt5.QtCore.pyqtSignal(types[,name[,revision=0[,arguments=[]]]])
Createoneormoreoverloadedunboundsignalsasaclassattribute.
Parameters:
types–thetypesthatdefinetheC++signatureofthesignal.EachtypemaybeaPythontypeobjectorastringthatisthenameofaC++type.Alternativelyeachmaybeasequenceoftypearguments.Inthiscaseeachsequencedefinesthesignatureofadifferentsignaloverload.Thefirstoverloadwillbethedefault.
name–thenameofthesignal.Ifitisomittedthenthenameoftheclassattributeisused.Thismayonlybegivenasakeywordargument.
revision–therevisionofthesignalthatisexportedtoQML.Thismayonlybegivenasakeywordargument.
arguments–thesequenceofthenamesofthesignal’sargumentsthatisexportedtoQML.Thismayonlybegivenasakeywordargument.
Returntype:anunboundsignal
新的信号应该定义在QObject的子类中。新的信号必须作为定义类的一部分,不允许将信号作为类的属性在类定义之后通过动态的方式进行添加。通过这种方式新的信号才能自动的添加到QMetaObject类中。这就意味这新定义的信号将会出现在QtDesigner,并且可以通过QMetaObjectAPI实现内省。
通过下面的例子,了解一下关于signal的定义:
fromPyQt5.QtCoreimportQObject,pyqtSignal
classNewSignal(QObject):
#定义了一个“closed”信号,该信号没有参数据
closed=pyqtSignal()
#定义了一个"range_changed"信号,该信号有两个int类型的参数
range_changed=pyqtSignal(int,int,name=''rangeChanged'')
自定义信号的发射,通过emit()方法类实现,具体参见该函数的原型:
emit(args)
Parameters:args–theoptionalsequenceofargumentstopasstoanyconnectedslots.
通过下面的例子,了解一下关于emit()的使用:
fromPyQt5.QtCoreimportQObject,pyqtSignal
classNewSignal(QObject):
#一个valueChanged的信号,该信号没有参数.
valueChanged=pyqtSignal()
defconnect_and_emit_valueChanged(self):
#绑定信号和槽函数
self.valueChanged.connect(self.handle_valueChanged)
#发射信号.
self.trigger.emit()
defhandle_valueChanged(self):
print("triggersignalreceived")
示例说明:
自定义信号的一般流程如下:
1、定义信号
2、定义槽函数
3、绑定信号和槽
4、发射信号
通过代码示例来了解一下信号的自定义过程:
#--coding:utf-8--
''''''
definedSignal
''''''
__author__=''TonyZhu''
importsys
fromPyQt5.QtCoreimportpyqtSignal,QObject,Qt,pyqtSlot
fromPyQt5.QtWidgetsimwww.sm136.comportQWidget,QApplication,QGroupBox,QPushButton,QLabel,QCheckBox,QSpinBox,QHBoxLayout,QComboBox,QGridLayout
classSignalEmit(QWidget):
helpSignal=pyqtSignal(str)
printSignal=pyqtSignal(list)
#声明一个多重载版本的信号,包括了一个带int和str类型参数的信号,以及带str参数的信号
previewSignal=pyqtSignal([int,str],[str])
def__init__(self):
super().__init__()
self.initUI()
definitUI(self):
self.creatContorls("打印控制:")
self.creatResult("操作结果:")
layout=QHBoxLayout()
layout.addWidget(self.controlsGroup)
layout.addWidget(self.resultGroup)
self.setLayout(layout)
self.helpSignal.connect(self.showHelpMessage)
self.printSignal.connect(self.printPaper)
self.previewSignal[str].connect(self.previewPaper)
self.previewSignal[int,str].connect(self.previewPaperWithArgs)
self.printButton.clicked.connect(self.emitPrintSignal)
self.previewButton.clicked.connect(self.emitPreviewSignal)
self.setGeometry(300,300,290,150)
self.setWindowTitle(''definedsignal'')
self.show()
defcreatContorls(self,title):
self.controlsGroup=QGroupBox(title)
self.printButton=QPushButton("打印")
self.previewButton=QPushButton("预览")
numberLabel=QLabel("打印份数:")
pageLabel=QLabel("纸张类型:")
self.previewStatus=QCheckBox("全屏预览")
self.numberSpinBox=QSpinBox()
self.numberSpinBox.setRange(1,100)
self.styleCombo=QComboBox(self)
self.styleCombo.addItem("A4")
self.styleCombo.addItem("A5")
controlsLayout=QGridLayout()
controlsLayout.addWidget(numberLabel,0,0)
controlsLayout.addWidget(self.numberSpinBox,0,1)
controlsLayout.addWidget(pageLabel,0,2)
controlsLayout.addWidget(self.styleCombo,0,3)
controlsLayout.addWidget(self.printButton,0,4)
controlsLayout.addWidget(self.previewStatus,3,0)
controlsLayout.addWidget(self.previewButton,3,1)
self.controlsGroup.setLayout(controlsLayout)
defcreatResult(self,title):
self.resultGroup=QGroupBox(title)
self.resultLabel=QLabel("")
layout=QHBoxLayout()
layout.addWidget(self.resultLabel)
self.resultGroup.setLayout(layout)
defemitPreviewSignal(self):
ifself.previewStatus.isChecked()==True:
self.previewSignal[int,str].emit(1080,"FullScreen")
elifself.previewStatus.isChecked()==False:
self.previewSignal[str].emit("Preview")
defemitPrintSignal(self):
pList=[]
pList.append(self.numberSpinBox.value())
pList.append(self.styleCombo.currentText())
self.printSignal.ewww.shanxiwang.netmit(pList)
defprintPaper(self,list):
self.resultLabel.setText("Print:"+"份数:"+str(list[0])+"纸张:"+str(list[1]))
defpreviewPaperWithArgs(self,style,text):
self.resultLabel.setText(str(style)+text)
defpreviewPaper(self,text):
self.resultLabel.setText(text)
defkeyPressEvent(self,event):
ifevent.key()==Qt.Key_F1:
self.helpSignal.emit("helpmessage")
defshowHelpMessage(self,message):
self.resultLabel.setText(message)
#self.statusBar().showMessage(message)
if__name__==''__main__'':
app=QApplication(sys.argv)
dispatch=SignalEmit()
sys.exit(app.exec_())
示例说明:
通过一个模拟打印的界面来详细说明一下关于信号的自定义,在打印的时候可以设定打印的分数,纸张类型,触发“打印”按钮之后,将执行结果显示到右侧;通过全屏预览QCheckBox来选择是否通过全屏模式进行预览,将执行结果显示到右侧。
通过点击F1快捷键,可以显示helpMessage信息。
代码分析:
L12~15:
helpSignal=pyqtSignal(str)
printSignal=pyqtSignal(list)
#声明一个多重载版本的信号,包括了一个带int和str类型参数的信号,以及带str参数的信号
previewSignal=pyqtSignal([int,str],[str])
通过pyqtSignal()定义了三个信号,helpSignal,printSignal,previewSignal。其中:
helpSignal为str参数类型的信号;
printSignal为list参数类型的信号;
previewSignal为一个多重载版本的信号,包括了一个带int和str类型参数的信号,以及str类行的参数。
L31~36:
self.helpSignal.connect(self.showHelpMessage)
self.printSignal.connect(self.printPaper)
self.previewSignal[str].connect(self.previewPaper)self.previewSignal[int,str].connect(self.previewPaperWithArgs)self.printButton.clicked.connect(self.emitPrintSignal)self.previewButton.clicked.connect(self.emitPreviewSignal)
绑定信号和槽;着重说明一下多重载版本的信号的绑定,previewSignal有两个版本previewSignal(str),previewSignal(int,str)。由于存在两个版本,从因此在绑定的时候需要显式的指定信号和槽的绑定关系。
具体如下:
self.previewSignal[str].connect(self.previewPaper)self.previewSignal[int,str].connect(self.previewPaperWithArgs)
其中[str]参数的previewSignal信号绑定previewPaper();[int,str]的previewSignal信号绑定previewPaperWithArgs()
L72~76:
defemitPreviewSignal(self):
ifself.previewStatus.isChecked()==True:
self.previewSignal[int,str].emit(1080,"FullScreen")
elifself.previewStatus.isChecked()==False:
self.previewSignal[str].emit("Preview")
多重载版本的信号的发射也需要制定对应发射的版本,类似同信号的版定。
L78~82:
defemitPrintSignal(self):
pList=[]
pList.append(self.numberSpinBox.value())
pList.append(self.styleCombo.currentText())
self.printSignal.emit(pList)
如代码中所示,在信号发射的时候可以传递python数据类型的参数,在本例中传递list类型的参数pList.
L93~96:
defkeyPressEvent(self,event):
ifevent.key()==Qt.Key_F1:
self.helpSignal.emit("helpmessage")
通过复写keyPressEvent()方法,将F1快捷键进行功能的拓展。在windows的大部分应用,我们都会使用一些快捷键来快速的完成某些特定的功能。比如F1键,会快速调出帮助界面。那我们就可以复写keyPressEvent()方法来模拟发送所需的信号,来完成我们的对应任务.
注意事项:
1、自定义的信号在init()函数之前定义;
2、自定义型号可以传递,str、int、list、object、float、tuple、dict等很多类型的参数;
3、注意signal和slot的调用逻辑,避免signal和slot之间出现死循环。如在slot方法中继续发射该信号;
九基本布局管理
GUI的布局管理是GUI开发中非常重要的一个环节,一个设计良好的GUI界面,其对应的布局排布也是非常必须的。其中布局管理就是要管理窗口中部件的放置。常用两种方式来实现布局:绝对位置布局(AbsoluteLayout)实现,布局类(QLayout)实现。
绝对位置布局(AbsoluteLayout)主要是在程序中通过指定每一个组件显示的坐标和大小。由于影响绝对布局显示的因素很多(平台的差异,窗口大小的差异,显示字体大小等因素),所以在本文中主要以QLayout的基本布局进行说明。
布局定义
常用到的布局类有QHBoxLayout,QVBoxLayout,QGridLayout,QFormLayout4种,分别水平排列布局,垂直排列布局,表格排列布局,以及。布局中最常用的方法有addWidget()和addLayout(),addWidget()方法用于在布局中插入控件,addLayout()用于在布局中插入子布局。
水平布局管理器(QHBoxLayout)可以把添加的控件以水平的顺序依次排开;
垂直布局管理器(QVBoxLayout)可以把添加的控件以垂直的顺序依次排开;
网格布局管理器(QGridLayout)可以以网格的形式,把添加的控件以一定矩阵排列;
窗体布局管理器(QFormLayout)可以以两列的形式排列所添加的控件
-水平(垂直)布局管理:
QHBoxLayout,按照从左到右的顺序进行添加控件。
QVBoxLayout,按照从上到下的顺序进行添加控件。
QHBoxLayout和QVBoxLayout用法基本相同。这里以水平布局管理器QHBoxLayout为例来说明。
classQHBoxLayout(QBoxLayout)
|QHBoxLayout()
|QHBoxLayout(QWidget)
常用方法:
|addLayout(…)
|QBoxLayout.addLayout(QLayout,intstretch=0)
在box的底部添加布局,其中默认的拉伸因子为0
|addWidget(…)
|QBoxLayout.addWidget(QWidget,intstretch=0,Qt.Alignmentalignment=0)
为布局中添加控件,stretch(拉伸因子)只适用与QBoxLayout,widget和box会随着stretch的变大而增大;alignment指定对齐的方式
|addSpacing(…)
|QBoxLayout.addSpacing(int)
通过该方法增加额外的space。
-网格布局管理器:
将窗体分隔成行和列的网格来进行排列(可以认为是二维的数据排布)。通常可以使用函数addWidget()或者addLayout()来将被管理的widget或者layout添加到窗格中。也可以通过重载的函数addWidget()或者addLayout()的行和列跨度实现占据多个窗格。
classQGridLayout(QLayout)
|QGridLayout(QWidget)
|QGridLayout()
常用方法:
添加组件
|addWidget(…)
|QGridLayout.addWidget(QWidget)
|QGridLayout.addWidget(QWidgetwidget,introw,intcolumn,Qt.Alignmentalignment=0)
QWidget:为所添加的组件
row:为组件要添加的行数,默认从0开始
column:为组件要添加到的列数,默认从0开始
alignment:对齐的方式
|QGridLayout.addWidget(QWidgetwidget,intfromRow,intfromColumn,introwSpan,intcolumnSpan,Qt.Alignmentalignment=0)
当添加的组件跨越很多行或者列的时候,使用该方法。
QWidget:为所添加的组件
fromRow:为组件起始的行数
fromColumn:为组件起始的列数
rowSpan:为组件跨越的行数
columnSpan:为组件跨越的列数
alignment:对齐的方式
|addLayout(…)
|QGridLayout.addLayout(QLayout,int,int,Qt.Alignmentalignment=0)
|QGridLayout.addLayout(QLayout,int,int,int,int,Qt.Alignmentalignment=0)
其中参数说明同addWidget.
-窗体布局管理器:
在窗口中按照两列的形式排列控件,两列控件的类型可以根据使用的场景不同而不同。
classQFormLayout(QLayout)
|QFormLayout(QWidgetparent=None)
常用方法:
|addRow(…)
|QFormLayout.addRow(QWidget,QWidget)
|QFormLayout.addRow(QWidget,QLayout)
|QFormLayout.addRow(str,QWidget)
|QFormLayout.addRow(str,QLayout)
|QFormLayout.addRow(QWidget)
|QFormLayout.addRow(QLayout)
示例说明
QVBoxLayout(mainLayout)中包含QHBoxLayout和QFormLayout.其中QHBoxLayout中嵌套了QGridLayout和QVBoxLayout.
看一下具体的代码实现:
#--coding:utf-8--
''''''
BasicLayout
''''''
__author__=''TonyZhu''
importsys
fromPyQt5.QtGuiimportQPixmap
fromPyQt5.QtWidgetsimportQWidget,QApplication,QGroupBox,QPushButton,QLabel,QHBoxLayout,QVBoxLayout,QGridLayout,QFormLayout,QLineEdit,QTextEdit
classTianGong(QWidget):
def__init__(self):
super(TianGong,self).__init__()
self.initUi()
definitUi(self):
self.createGridGroupBox()
self.creatVboxGroupBox()
self.creatFormGroupBox()
mainLayout=QVBoxLayout()
hboxLayout=QHBoxLayout()
hboxLayout.addStretch()
hboxLayout.addWidget(self.gridGroupBox)
hboxLayout.addWidget(self.vboxGroupBox)
mainLayout.addLayout(hboxLayout)
mainLayout.addWidget(self.formGroupBox)
self.setLayout(mainLayout)
defcreateGridGroupBox(self):
self.gridGroupBox=QGroupBox("Gridlayout")
layout=QGridLayout()
nameLabel=QLabel("中文名称")
nameLineEdit=QLineEdit("天宫二号")
emitLabel=QLabel("发射地点")
emitLineEdit=QLineEdit("酒泉中心")
timeLabel=QLabel("发射时间")
timeLineEdit=QLineEdit("9月15日")
imgeLabel=QLabel()
pixMap=QPixmap("tiangong.png")
imgeLabel.setPixmap(pixMap)
layout.setSpacing(10)
layout.addWidget(nameLabel,1,0)
layout.addWidget(nameLineEdit,1,1)
layout.addWidget(emitLabel,2,0)
layout.addWidget(emitLineEdit,2,1)
layout.addWidget(timeLabel,3,0)
layout.addWidget(timeLineEdit,3,1)
layout.addWidget(imgeLabel,0,2,4,1)
layout.setColumnStretch(1,10)
self.gridGroupBox.setLayout(layout)
self.setWindowTitle(''BasicLayout'')
defcreatVboxGroupBox(self):
self.vboxGroupBox=QGroupBox("Vboxlayout")
layout=QVBoxLayout()
nameLabel=QLabel("科研任务:")
bigEditor=QTextEdit()
bigEditor.setPlainText("搭载了空间冷原子钟等14项应用载荷,以及失重心血管研究等航天医学实验设备"
"开展空间科学及技术试验.")
layout.addWidget(nameLabel)
layout.addWidget(bigEditor)
self.vboxGroupBox.setLayout(layout)
defcreatFormGroupBox(self):
self.formGroupBox=QGroupBox("Formlayout")
layout=QFormLayout()
performanceLabel=QLabel("性能特点:")
performanceEditor=QLineEdit("舱内设计更宜居方便天宫生活")
planLabel=QLabel("发射规划:")
planEditor=QTextEdit()
planEditor.setPlainText("2020年之前,中国计划初步完成空间站建设")
layout.addRow(performanceLabel,performanceEditor)
layout.addRow(planLabel,planEditor)
self.formGroupBox.setLayout(layout)
if__name__==''__main__'':
app=QApplication(sys.argv)
ex=TianGong()
ex.show()
sys.exit(app.exec_())
代码分析:
L28~51:
defcreateGridGroupBox(self):
self.gridGroupBox=QGroupBox("Gridlayout")
layout=QGridLayout()
nameLabel=QLabel("中文名称")
nameLineEdit=QLineEdit("天宫二号")
emitLabel=QLabel("发射地点")
emitLineEdit=QLineEdit("酒泉中心")
timeLabel=QLabel("发射时间")
timeLineEdit=QLineEdit("9月15日")
imgeLabel=QLabel()
pixMap=QPixmap("tiangong.png")
imgeLabel.setPixmap(pixMap)
layout.setSpacing(10)
layout.addWidget(nameLabel,1,0)
layout.addWidget(nameLineEdit,1,1)
layout.addWidget(emitLabel,2,0)
layout.addWidget(emitLineEdit,2,1)
layout.addWidget(timeLabel,3,0)
layout.addWidget(timeLineEdit,3,1)
layout.addWidget(imgeLabel,0,2,4,1)
layout.setColumnStretch(1,10)
self.gridGroupBox.setLayout(layout)
self.setWindowTitle(''BasicLayout'')
定义QGridLayout布局。其中增加QGroupBox(有标题的组合框在它里面地其它不同窗口部件),将QGridLayout添加到QGroupBox中。
在本例中使用了不同参数重载的addWidget()方法。
在QLabel中显示图片。
pixMap=QPixmap(“tiangong.png”)
imgeLabel.setPixmap(pixMap)
layout.setColumnStretch(1,10)指定的行,设定其拉伸因子为10。
addWidget(self,QWidget,int,int,Qt.Alignmentalignment=0)
addWidget(self,QWidget,int,int,int,int,Qt.Alignmentalignment=0)
QWidget参数为需插入的控件对象,后面的两个int参数为插入的行和列,再后面两上int参数为跨度的行数和跨度的列数,alignment参数描述各控件的对齐方式。
L53~62:
defcreatVboxGroupBox(self):
self.vboxGroupBox=QGroupBox("Vboxlayout")
layout=QVBoxLayout()
nameLabel=QLabel("科研任务:")
bigEditor=QTextEdit()
bigEditor.setPlainText("搭载了空间冷原子钟等14项应用载荷,以及失重心血管研究等航天医学实验设备"
"开展空间科学及技术试验.")
layout.addWidget(nameLabel)
layout.addWidget(bigEditor)
self.vboxGroupBox.setLayout(layout)
定义QVBoxLayout布局。将QVBoxLayout添加到QGroupBox中。通过addWidget()方法增加所需的控件。
L64~75:
defcreatFormGroupBox(self):
self.formGroupBox=QGroupBox("Formlayout")
layout=QFormLayout()
performanceLabel=QLabel("性能特点:")
performanceEditor=QLineEdit("舱内设计更宜居方便天宫生活")
planLabel=QLabel("发射规划:")
planEditor=QTextEdit()
planEditor.setPlainText("2020年之前,中国计划初步完成空间站建设")
layout.addRow(performanceLabel,performanceEditor)
layout.addRow(planLabel,planEditor)
self.formGroupBox.setLayout(layout
定义QFormLayout布局。将QFormLayout添加到QGroupBox中。通过addRow()方法增加所需的控件。
L19~25:
mainLayout=QVBoxLayout()
hboxLayout=QHBoxLayout()
hboxLayout.addStretch()
hboxLayout.addWidget(self.gridGroupBox)
hboxLayout.addWidget(self.vboxGroupBox)
mainLayout.addLayout(hboxLayout)
mainLayout.addWidget(self.formGroupBox)
定义QVBoxLayout类型的mainLayout,并将定义好的各个layout和groupbox按照嵌套的关系添加到mainLayout中。
十QtWidget的使用
在很多应用使用的场景中我们需要和各种类型的数据进行交互,通过表格的形式进行操作和呈现。在PyQt中提供了QTableWidget默认模式的表格类。
QTableWidget是QTableViewer的子类,其中QTableViewer可以使用自定义的数据模型来显示内容(通过setModel
()来绑定数据源),而QTableWidget提供了一套标准的数据模型,QTableWidgetItem对象作为QTableWidget中的单元数据来显示。使用QTableWidget就依赖于QTableWidgetItem。QTableWidgetItem用来表示表格中的一个单元格,通过一个个单元格组成整体的表。
QTableWidget简介:
如上图是QTableWidget的显示。
1.QTableWidgets实例化
根据QTableWidget的构造函数,我们在定义实例化的时候可以指定显示的行数和列数,也可以在QTableWidget实例化之后通过成员函数进行设定:
self.table=QTableWidget(5,2)
或者
self.table=QTableWidget()
self.table.setColumnCount(5)
self.table.setRowCount(2)
2.表头操作:
在table表头分为水平和垂直两种,及horizontalheader和verticalheader两类。
添加表头:
可以添加水平和垂直表头,QtWidgets提供两个方法(setHorizontalHeaderLabels()和setVerticalHeaderLabels())来添加,如下为添加水平表头。
horizontalHeader=["工号","姓名","性别","年龄","职称"]
self.table=QTableWidget()
self.table.setHorizontalHeaderLabels(horizontalHeader)
表头的隐藏和显示:
根据不同的应用场景可能需要对于表头进行隐藏和显示的操作,直接对表头进行操作。
如下隐藏了垂直的表头:
self.table=QTableWidget()
self.table.verticalHeader().setVisible(False)
表头字体,颜色的设定:
由于表头也是由多个item构成的,所以通过循环操作对每一个item进行操作。
self.table=QTableWidget()
forindexinrange(self.table.columnCount()):
headItem=self.table.horizontalHeaderItem(index)
headItem.setFont(QFont("song",12,QFont.Bold))
headItem.setForeground(QBrush(Qt.gray))
headItem.setTextAlignment(Qt.AlignLeft|Qt.AlignVCenter)
3.表格设置
在表格的应用中,我们需要对表格的样式,编辑模式,选择行为进行设置。
编辑方式:
对于表格中的数据,默认只要双击就可以修改其中的数据。如果文档是处于预览状态或者不可编辑状态,那就需要对表格设定为不可编辑模式。
self.table=QTableWidget()
self.table.setEditTriggers(QTableWidget.NoEditTriggers)
对于表格的编辑的设定通过setEditTriggers()方法来实现。如下都是触发修改单元格内容的条件:
QTableWidget.NoEditTriggers0Noeditingpossible.不能对表格内容进行修改
QTableWidget.CurrentChanged1Editingstartwhenevercurrentitemchanges.任何时候都能对单元格修改
QTableWidget.DoubleClicked2Editingstartswhenanitemisdoubleclicked.双击单元格
QTableWidget.SelectedClicked4Editingstartswhenclickingonanalreadyselecteditem.单击已选中的内容
QTableWidget.EditKeyPressed8Editingstartswhentheplatformeditkeyhasbeenpressedoveranitem.
QTableWidget.AnyKeyPressed16Editingstartswhenanykeyispressedoveranitem.按下任意键就能修改
QTableWidget.AllEditTriggers31Editingstartsforallaboveactions.以上条件全包括
单元格选择:
比如我们在单击某个单元格的时候,此时默认的行为是选中单元格,还是单元格所在的行或列,这个可以通过setSelectionBehavior()方法设定。如下为默认选中列:
self.table=QTableWidget()
self.table.setSelectionBehavior(QTableWidget.SelectColumns)
QTableWidget.SelectItems0Selectingsingleitems.选中单个单元格
QTableWidget.SelectRows1Selectingonlyrows.选中一行
QTableWidget.SelectColumns2Selectingonlycolumns.选中一列
行选择方式:
比如我们需要同时选择不相邻的多个函数的时候,在excell中我们通过按shift然后点击鼠标来选择多行。在QtWidget也存在类似行为,我们可以通过setSelectionMode()方法来实现:
self.table=QTableWidget()
self.table.setSelectionMode(QTableWidget.SingleSelection)
可以设定的选择模式:
QTableWidget.NoSelection不能选择
QTableWidget.SingleSelection选中单个目标
QTableWidget.MultiSelection选中多个目标
QTableWidget.ExtendedSelectionshift键的连续选择
QTableWidget.ContiguousSelectionctrl键的不连续的多个选择
网格的显示
通常默认的情况下需要显示表格的网格线,在一些场景下不需要显示网格线。则需要将对应的横竖线进行隐藏:
self.table=QTableWidget()
self.table.setShowGrid(False)
setShowGrid(),False不显示网格线,True显示网格线
添加表项
由于整个表格是由一个个单元格组成,所以需要将单个的表格项添加到整个表格中。通过setItem()进行操作,如下为添加一个为str类型内容的表格:
self.table=QTableWidget()
self.table.setItem(0,0,QTableWidgetItem("001"))
setItem(int,int,QTableWidgetItem)
第1个参数行号,从0开始
第2个参数列号,从0开始
第3个参数QTableWidgetItem对象。
表项添加自定义控件
比如在有些表项中需要QComboBox来实现下拉框的功能,比如性别选择的时候就可以通过下拉框来实现选择。
self.table=QTableWidget()
genderComb=QComboBox()
genderComb.addItem("男性")
genderComb.addItem("女性")
genderComb.setCurrentIndex(0)
self.table.setCellWidget(0,2,genderComb)
实例化一个QComboBox对象,通过setCellWidget()将QComboBox添加到指定的单元格中。通过行号和列号唯一确定一个单元格。
setCellWidget(intint,QWidget)
第1个参数行号,从0开始
第2个参数列号,从0开始
第3个参数QWidget对象。
4.单元格操作
单元格对齐方式
在单元格中操作字符显示的是否,常常需要操作各种对齐,比如水平的左对齐、右对齐、居中等,垂直的靠上、靠下对齐等方式。
headItem.setTextAlignment(Qt.AlignLeft|Qt.AlignVCenter)
通过setTextAlignment()方法来设定,由于需要同时考虑水平和垂直方向,所以通过或‘|’的方式将两个方向的对齐组合起来,如Qt.AlignLeft|Qt.AlignVCenter。
水平方向:
Qt.AlignLeft0x0001Alignswiththeleftedge.
Qt.AlignRight0x0002Alignswiththerightedge.
Qt.AlignHCenter0x0004Centershorizontallyintheavailablespace.
Qt.AlignJustify0x0008Justifiesthetextintheavailablespace.
垂直方向:
Qt.AlignTop0x0020Alignswiththetop.
Qt.AlignBottom0x0040Alignswiththebottom.
Qt.AlignVCenter0x0080Centersverticallyintheavailablespace.
单元格大小设定
有时候需要根据显示的要求来调整单元格的大小,行的宽度和列的高度。
self.table=QTableWidget()
self.table.setColumnWidth(4,200)
self.table.setRowHeight(0,40)
通过setColumnWidth()和setRowHeight()设定特定行或者列上的大小。
有时候需要根据显示的内容自动调整单元格的大小,类似office中的内容相匹配。
self.table=QTableWidget()
self.table.resizeColumnsToContents()
self.table.resizeRowsToContents()
动态插入行列
当初始的行数或者列数不能满足需要的时候,我们需要动态的调整表格的大小,如入动态的插入行:
self.table=QTableWidget()
row_count=self.table.rowCount()
self.table.insertRow(row_count)
本例中为插入到最后一行的后面。insertColumn()动态插入列。
insertRow(int)、insertColumn(int),指定位置插入行或者列
动态移除行列
removeColumn(intcolumn)移除column列及其内容。
removeRow(introw)移除第row行及其内容。
self.table=QTableWidget()
row_count=self.table.rowCount()
self.table.removeRow(row_count-1)
本例中为移除最后一行。
其他操作
clear()清除所有表项及表头
setSpan(int,int,int,int),合并单元格
代码示例
#--coding:utf-8--
''''''
TableWidget
''''''
__author__=''TonyZhu''
importsys
fromPyQt5.QtCoreimportQt
fromPyQt5.QtWidgetsimportQWidget,QApplication,QLabel,QTableWidget,QHBoxLayout,QTableWidgetItem,QComboBox,QFrame
fromPyQt5.QtGuiimportQFont,QColor,QBrush,QPixmap
classTableSheet(QWidget):
def__init__(self):
super().__init__()
self.initUi()
definitUi(self):
horizontalHeader=["工号","姓名","性别","年龄","职称"]
self.setWindowTitle(''TableWidgetUsage'')
self.table=QTableWidget()
self.table.setColumnCount(5)
self.table.setRowCount(2)
self.table.setHorizontalHeaderLabels(horizontalHeader)
self.table.setEditTriggers(QTableWidget.NoEditTriggers)
self.table.setSelectionBehavior(QTableWidget.SelectColumns)
self.table.setSelectionMode(QTableWidget.SingleSelection)
forindexinrange(self.table.columnCount()):
headItem=self.table.horizontalHeaderItem(index)
headItem.setFont(QFont("song",12,QFont.Bold))
headItem.setForeground(QBrush(Qt.gray))
headItem.setTextAlignment(Qt.AlignLeft|Qt.AlignVCenter)
self.table.setColumnWidth(4,200)
self.table.setRowHeight(0,40)
#self.table.setFrameShape(QFrame.HLine)#设定样式
#self.table.setShowGrid(False)#取消网格线
#self.table.verticalHeader().setVisible(False)#隐藏垂直表头
self.table.setItem(0,0,QTableWidgetItem("001"))
self.table.setItem(0,1,QTableWidgetItem("Tom"))
genderComb=QComboBox()
genderComb.addItem("男性")
genderComb.addItem("女性")
genderComb.setCurrentIndex(0)
self.table.setCellWidget(0,2,genderComb)
self.table.setItem(0,3,QTableWidgetItem("30"))
self.table.setItem(0,4,QTableWidgetItem("产品经理"))
self.table.setItem(1,0,QTableWidgetItem("005"))
self.table.setItem(1,1,QTableWidgetItem("Kitty"))
genderComb=QComboBox()
genderComb.addItem("男性")
genderComb.addItem("女性")
genderComb.setCurrentIndex(1)
self.table.setCellWidget(1,2,genderComb)
self.table.setItem(1,3,QTableWidgetItem("24"))
self.table.setItem(1,4,QTableWidgetItem("程序猿安慰师"))
row_count=self.table.rowCount()
self.table.insertRow(row_count)
mainLayout=QHBoxLayout()
mainLayout.addWidget(self.table)
self.setLayout(mainLayout)
if__name__==''__main__'':
app=QApplication(sys.argv)
table=TableSheet()
table.show()
sys.exit(app.exec_())
|
|