一、dialog、widget、mainwindow的区别 和 使用

Widget、Dialog和MainWindow三者都可以独立创建用户界面。
1)、dialog有exec函数,如果是dialog窗口,后边的窗口时不可选的;
2)、widget和dialog都有show函数,如果通过这个函数显示这两种类型的窗口,则两个窗口都是可选的;
3)、widget主要是在上面放置布局和控件;
4)、mainwindow可以显示菜单,工具栏,状态栏、托盘等功能。
1. PyQt5类继承关系


可以看出:
1. QWidget类是所有用户界面对象的基类。窗口部件是用户界面的一个基本单元:它从窗口系统接收鼠标、键盘和其它事件,并且在屏幕上绘制自己。每一个窗口部件都是矩形的,并且它们按Z轴顺序排列。一个窗口部件可以被它的父窗口部件或者它前面的窗口部件盖住一部分。
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
2. QMainWindow 类提供一个有菜单条、锚接窗口(例如工具条)和一个状态条的主应用程序窗口。主窗口通常用在提供一个大的中央窗口部件(例如文本编辑或者绘制画布)以及周围菜单、工具条和一个状态条。QMainWindow常常被继承,因为这使得封装中央部件、菜单和工具条以及窗口状态条变得更容易,当用户点击菜单项或者工具条按钮时,槽会被调用。
3. QDialog类是对话框窗口的基类。QDialog 是最普通的顶级窗口,主要用于短期任务以及和用户进行简要通讯。一个不会被嵌入到父窗口部件的窗口部件叫做顶级窗口部件。通常情况下,顶级窗口部件是有框架和标题栏的窗口(尽管使用了一定的窗口部件标记,创建顶级窗口部件时也可能没有这些装饰)。QDialog可以是模式的也可以是非模式的。QDialog支持扩展性并且可以提供返回值。它们可以有默认按钮。QDialog也可以有一个QSizeGrip在它的右下角,使用setSizeGripEnabled()。
注意:QDialog(以及其它使用Qt::Dialog类型的widget)使用父窗口部件的方法和Qt中其它类稍微不同。对话框总是顶级窗口部件,但是如果它有一个父对象,它的默认位置就是父对象的中间。它也将和父对象共享工具条条目。
4. Widget小部件包括窗口小部件(可以称为独立窗口或者顶级窗口小部件,见图1)和非窗口小部件。
没有父窗体的Widget小部件始终是一个独立的窗口(顶级窗口部件)。
QWidget *parent = 0
非窗口的Widget小部件为子部件,它们在父窗口中显示。Qt中大多数部件主要被用作子部件。例如:可以显示一个按钮作为顶层窗口,但大多数人更喜欢将按钮内置于其它部件,如QDialog。在Qt中,QMainWindow和不同的QDialog的子类是最普通的顶级窗口。
2. 使用原则
- 如果需要嵌入到其他窗体中,则基于QWidget创建。
- 如果是顶级对话框,则基于QDialog创建。
- 如果是主窗体,则基于QMainWindow创建。
3. PyQt5实现从主窗口打开子窗口
第一步:在Qt Designer中设计两个简单窗口

第二步:将.ui文件转换成.py文件
第三步:新建**.py文件
#-*- coding:utf-8 -*-
from PyQt5.QtWidgets import QMainWindow, QApplication
from window import Ui_MainWindow
from child import Ui_Child
import sys
class Main(QMainWindow,Ui_MainWindow):
def __init__(self):
super(Main, self).__init__()
self.setupUi(self)
class Child(QMainWindow,Ui_Child):
def __init__(self):
super(Child, self).__init__()
self.setupUi(self)
self.pushButton.clicked.connect(self.close)
def OPEN(self):
self.show()
if __name__ =="__main__":
app = QApplication(sys.argv)
main = Main()
ch = Child()
main.show()
main.pushButton.clicked.connect(ch.OPEN)
sys.exit(app.exec_())二、mainwindow程序框架
import os, sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QTableWidgetItem, QFileDialog, QApplication, QMainWindow, QDialog, QWidget, QHBoxLayout
from PyQt5.QtGui import QIcon
class Ui_MainWindow(QMainWindow):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1900, 900)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.scrollArea = QtWidgets.QScrollArea(self.centralwidget) # 滚动条区域
self.scrollArea.setGeometry(QtCore.QRect(0, 288, 1900, 850))
self.scrollArea.setMinimumSize(QtCore.QSize(1900, 850))
self.scrollArea.setMaximumSize(QtCore.QSize(1900, 850))
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setObjectName("scrollArea")
self.scrollAreaWidgetContents = QtWidgets.QWidget()
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 1900, 30000))
self.scrollAreaWidgetContents.setMinimumSize(QtCore.QSize(1900, 30000))
self.scrollAreaWidgetContents.setMaximumSize(QtCore.QSize(1900, 30000))
self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
self.tableWidget = QtWidgets.QTableWidget(self.scrollAreaWidgetContents) #表格关联滚动条
self.tableWidget.setGeometry(QtCore.QRect(2, 0, 1730, 30000))
self.tableWidget.setMinimumSize(QtCore.QSize(1730, 30000))
self.tableWidget.setMaximumSize(QtCore.QSize(1730, 30000))
font = QtGui.QFont()
font.setPointSize(6)
font.setKerning(True)
self.tableWidget.setFont(font)
self.tableWidget.setObjectName("tableWidget")
self.tableWidget.setColumnCount(13)
self.tableWidget.setRowCount(130)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(1, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(2, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(3, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(4, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(5, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(6, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(7, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(8, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(9, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(10, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(11, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(12, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(13, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(14, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(15, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(16, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(17, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(18, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(19, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setVerticalHeaderItem(20, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(1, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(2, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(3, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(4, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(5, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(6, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(7, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(8, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(9, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(10, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(11, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(12, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setItem(0, 9, item) # 在指定行列的单元控件内添加控件
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setItem(1, 9, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setItem(1, 10, item)
self.tableWidget.horizontalHeader().setVisible(False)
self.tableWidget.horizontalHeader().setCascadingSectionResizes(False)
self.tableWidget.horizontalHeader().setDefaultSectionSize(130)
self.tableWidget.horizontalHeader().setHighlightSections(False)
self.tableWidget.horizontalHeader().setMinimumSectionSize(30)
self.tableWidget.verticalHeader().setVisible(True)
self.tableWidget.verticalHeader().setDefaultSectionSize(200)
self.tableWidget.verticalHeader().setHighlightSections(False)
self.tableWidget.verticalHeader().setMinimumSectionSize(30)
self.layoutWidget = QtWidgets.QWidget(self.scrollAreaWidgetContents)
self.layoutWidget.setGeometry(QtCore.QRect(1744, -30, 112, 26131))
self.layoutWidget.setObjectName("layoutWidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.layoutWidget)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setSpacing(60)
self.verticalLayout.setObjectName("verticalLayout")
self.pushButton_send_1 = QtWidgets.QPushButton(self.layoutWidget)
self.pushButton_send_1.setMinimumSize(QtCore.QSize(110, 40))
self.pushButton_send_1.setMaximumSize(QtCore.QSize(110, 40))
font = QtGui.QFont()
font.setFamily("微软雅黑")
font.setPointSize(8)
self.pushButton_send_1.setFont(font)
self.pushButton_send_1.setObjectName("pushButton_send_1")
self.verticalLayout.addWidget(self.pushButton_send_1)
self.pushButton_com_open = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_com_open.setGeometry(QtCore.QRect(1355, 203, 80, 45))
self.pushButton_com_open.setMinimumSize(QtCore.QSize(80, 45))
self.pushButton_com_open.setMaximumSize(QtCore.QSize(80, 45))
font = QtGui.QFont()
font.setFamily("微软雅黑")
font.setPointSize(8)
self.pushButton_com_open.setFont(font)
self.pushButton_com_open.setObjectName("pushButton_com_open")
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "微循环2.0故障诊断自动化测试工具 1.0"))
item = self.tableWidget.verticalHeaderItem(0)
item.setText(_translate("MainWindow", "1"))
item = self.tableWidget.verticalHeaderItem(1)
item.setText(_translate("MainWindow", "2"))
item = self.tableWidget.verticalHeaderItem(2)
item.setText(_translate("MainWindow", "3"))
item = self.tableWidget.verticalHeaderItem(3)
item.setText(_translate("MainWindow", "4"))
item = self.tableWidget.verticalHeaderItem(4)
item.setText(_translate("MainWindow", "5"))
item = self.tableWidget.verticalHeaderItem(5)
item.setText(_translate("MainWindow", "6"))
item = self.tableWidget.verticalHeaderItem(6)
item.setText(_translate("MainWindow", "7"))
item = self.tableWidget.verticalHeaderItem(7)
item.setText(_translate("MainWindow", "8"))
item = self.tableWidget.verticalHeaderItem(8)
item.setText(_translate("MainWindow", "9"))
item = self.tableWidget.verticalHeaderItem(9)
item.setText(_translate("MainWindow", "10"))
item = self.tableWidget.verticalHeaderItem(10)
item.setText(_translate("MainWindow", "11"))
item = self.tableWidget.verticalHeaderItem(11)
item.setText(_translate("MainWindow", "12"))
if __name__ == "__main__":
app = QApplication(sys.argv)
mainW = QMainWindow() # 设置一个空类,建立一个空窗口mainW
app.setWindowIcon(QIcon("icon.ico"))
form = Ui_MainWindow() # 要对窗口进行设置,增减控件和增减功能等,这些功能都有由类Ui_MainWindow完成
form.setupUi(mainW) # 此选择的窗口是先前建立的空白窗口mainW,即在mainW上添加控件
mainW.show() # 显示窗口
sys.exit(app.exec_()) # GUI程序运行主循环三、Pyqt5 Designer 布局管理
以mainwindow窗口为例:
1. 菜单(Tool Bar)
点击“Type here”,添加选项卡与快捷键(注意编辑快捷键时使用&),例如菜单(&F),编辑完毕后,必须按下回车来确认。

2. 工具栏(Menu Bar)和II级菜单


在新建的窗体中点击鼠标右键,选择“添加工具栏”。
工具栏和II级菜单栏,都要现在右下角的“Action Editor”中编辑。

“Action”编辑完成后。
如果添加工具栏直接鼠标左键单击,比如选择“actionAbout”,将编辑好的动作拖动过去即可,然后发现“actionAbout”对应的“使用”已经打勾,表示已经在用;
如果是二级菜单,则在对应一级菜单下,选择“actionAbout”,拖动过去即可。
如果想为改Action设置响应函数,可以将该Action的Triggered()信号与想要的槽函数相连。
如,connect(ui.actionInputFlightData,SIGNAL(triggered()),this,SLOT(testTra())); //连接信号和槽
3.状态栏(Status Bar)
QMainWindow中默认提供了一个状态栏。
QStatusBar类提供一个水平条来显示状态信息。
状态信息可以分为三类:
临时信息,如一般的提示信息;
正常信息,如页数;
永久信息,如版本信息。
我们可以使用showMessage()来显示一个临时消息,它会出现在状态栏的最左边。
我们一般用addWidget()将一个QLabel加到状态栏上用于显示正常信息,它会生成到状态栏的最左边,可能会被临时消息覆盖。
我们使用addPermanentWidget()来添加一个QLabel来在状态栏的最右边显示永久信息。它不会被临时信息所掩盖。
在状态栏的最右端还有一个QSizeGrip部件用来调整窗口大小,我们可以通过setSizeGripEnabled()函数来禁用它。
也许你想通过使用Qt Designer来可视化地完成窗口布局。但是事与愿违,目前的设计器还不支持直接向状态栏中拖放部件,所以我们就不能偷懒了,必须使用代码来设置了,见最后代码框架。
4. 布局管理

①布局框中控件的大小和位置属性,是由布局框自动设置的,不能在 “属性编辑器” 中编辑修改。
②修改控件属性。通过修改控件的属性,比如最小尺寸、最大尺寸、长、宽、字体等等。比如我想针对小工具的需求我会经常使用固定最小尺寸、最大尺寸保持一致的方式,使主窗口及控件不受拉伸影响。
③如果自动布局的按钮位置不合适,可以在布局框中添加间隔控制器 “Vertical Spacer”,以调整按钮控件的间隔。
④一些显示控件还可以设置控件在布局中占若干行和列。
- 鼠标选中待调整的文本框,移动到右侧边界的蓝色方块,出现左右拉伸光标,点击拖动控件向右拉动,可以使控件占据栅格布局的第一列和第二列;
- 鼠标选中待调整的文本框,移动到下方边界的蓝色方块,出现上下拉伸光标,点击拖动控件向下拉动,可以使控件占据栅格布局的第一行至第三行。

4.1 垂直布局QVBoxLayout
①选中所有的控件然后右键选择layout中的Vertical即可;②先拖动⼀个容器Vertical Layout到主窗⼝上,然后再拖动控件到容器中,最后右键容器,此时可以将其转成各种布局⽅式,当然你也
可以在外⾯先布局后,然后拖到容器中也是可以的。

1)水平布局或垂直等布局内部控件之间默认是等间距的,那么如果想让两个控件之间有一定的距离,这时要用到间隔线spacer。
2)同样,可以利用垂直间隔线Vertical Line控制垂直布局中两个控件之间的间隔。
3)另外,建议添加进容器前,先设置好控件的最大最小尺寸。因为当你将一个控件拖动到主窗口后,这个控件会有自己的默认属性,尺寸会发生变化很大,虽然可以通过调节整个容器的宽度和高度来调整,但是比较麻烦。

4)当你拖动一个控件到主窗口中时,这个控件已经有自己默认的尺寸了,这个默认尺寸就是控件的期望尺寸,那么我们可以改变其期望尺寸策略:
可以看到这个控件有四种尺⼨策略,分别为Horizontal Policy、Vertical Policy、Horizontal Stretch、Vertical Stretch。其中Horizontal Policy策略中是Minimum,也就是控件默认的期望尺⼨取最⼩值。
其中Horizontal Policy中的Expanding与Horizontal Stretch配合使⽤可以达到很好的布局效果,第⼀个控件占这个⽔平布局两份,其余
两个控件也设置Expanding的尺⼨策略,但是Horizontal Stretch为1,仅占⼀份。
5)控件伙伴关系的设定实际上就是设置热键,⽐如:

上述是⼀个表单布局,现在给labei控件与对应的line Edit设置伙伴的关系,也就是⽐如通过Alt+A热键给姓名的输⼊框聚焦,Alt+B热键给密
码的输⼊框的热键聚焦:
这个地方需要注意的是在label中加入如上内容&A和&B。通过Edit-> buddies进行设置伙伴关系:

这样就完成了伙伴关系,在生成的页面中通过Alt+A或者Alt+B进行切换输入框。
6)修改控件Tab顺序
这地⽅有4个控件,现在修改其排列的位置,通过Edit-->Edit Tab Order
可以通过双击序号改变顺序,或者右键主窗⼝空⽩处选择Tab顺序编辑即可。
最后,通过工具栏切换回“编辑窗口部件”。
4.2 水平布局QHBoxLayout
同上。

4.3 混合使用QVBoxLayout和QHBoxLayout

TBD.
4.4 表单布局QFormLayout
- 以表单(Form)的方式管理界面组件。
- 表单布局中的标签和组件是相互对应的关系。



显示控件可以调整大小。
按钮也可以放在Form Layout内,但是大小会根据Label 和Editor大小自动设定。
5. ScrollArea 实现滚动界面
①先拖入ScrollArea控件到窗口,设置好尺寸;②拖入其他要嵌入的控件,比如Table Widget控件;③这时ScrollArea控件Object下有一个QWidget类型的子控件,如scrollAreaWidgetContents。设置ScrollArea控件的尺寸小于scrollAreaWidgetContents的尺寸时,ScrollArea将会显示滚动条。
注意的是,这时候如果鼠标点击控件是不能选中scrollAreaWidgetContents的, 只能选中ScrollArea。需要先在对象监控窗口(Object Inspector)中选中scrollAreaWidgetContents,再切换到属性编辑窗口(Property Editer)。

对窗口用layout的时候,也要注意一下策略,它会影响你的scroolArea的滚动条出现的位置。这里使用了水平布局让ScrollArea填充整个窗口,也让生成的窗口和ScrollArea具备拉伸性,可以随窗口大小自适应变化。
Table Widget控件 取消垂直和水平滚动条显示,在property下设置,还可以设置行数和列数,以及行高和列宽。

