先给出两个初学者的入门网址:
http://www.riverbankcomputing.co.uk/software/pyqt/intro
http://www.cs.usfca.edu/~afedosov/qttut/
1.窗体(QWidget、QMainWindow、QDialog)之间的区别
QWidget类是所有用户界面对象的基类。窗口部件是用户界面的一个原子:它从窗口系统接收鼠标、键盘和其它事件,并且在屏幕上绘制自己的表现。每一个窗口部件都是矩形,并且它们按Z轴顺序排列的。一个窗口部件可以被它的父窗口部件或者它前面的窗口部件盖住一部分。
QMainWindow 类提供一个有菜单条、锚接窗口(例如工具条)和一个状态条的主应用程序窗口。主窗口通常用在提供一个大的中央窗口部件(例如文本编辑或者绘制画布)以及周围菜单、工具条和一个状态条。QMainWindow常常被继承,因为这使得封装中央部件、菜单和工具条以及窗口状态变得更容易。继承使创建当用户点击菜单项或者工具条按钮时被调用的槽成为可能。你也可以使用Qt设计器来创建主窗口。
QDialog类是对话框窗口的基类。对话框窗口是主要用于短期任务以及和用户进行简要通讯的顶级窗口。QDialog可以是模式的也可以是非模式的。QDialog支持扩展性并且可以提供返回值。它们可以有默认按钮。QDialog也可以有一个QSizeGrip在它的右下角,使用setSizeGripEnabled()。
QDialog 是最普通的顶级窗口。不被嵌入到一个父窗口部件的窗口部件被叫做顶级窗口部件。通常情况下,顶级窗口部件是有框架和标题栏的窗口(尽管如果使用了一定的窗口部件标记,创建顶级窗口部件时也可能没有这些装饰)。在Qt中,QMainWindow和和不同的QDialog的子类是最普通的顶级窗口。
如果是顶级对话框,那就基于QDialog创建,如果是主窗体,那就基于QMainWindow,如果不确定,或者有可能作为顶级窗体,或有可能嵌入到其他窗体中,则基于QWidget创建。当然了,实际中,你还可以基于任何其他部件类来派生。看实际需求了,比如QFrame、QStackedWidget等等。
全局变量是一个使用有争议的变量。首先,全局变量方便了变量之间的共享。但同时也带来了许多问题:降低了函数或模块之间的通用性,不同的函数或模块都要依赖于全局变量。比如不同模块之间都可以自由的访问全局变量,可能会导致全局变量的不可预知性,当程序猿A修改了全局变量global_x的值,可能其他使用全局变量的地方就会出现错误,然而这种错误往往是很难发现和更正的。所以,我们应该尽量避免使用全局变量,但是全局变量的好处也是很明显的,所以某些时候全局变量能够解决局部变量很难解决的问题,所以要合理使用全局变量。
全局变量的使用有2中方式。第一种方式为:声明法,把要定义的全局变量直接定义在所使用文件的开始;第二种方法为:模块法,把要定义的全局变量单独定义在一个文件中,这种方法适用于不同文件之间的变量共享。下面对这两种方式分别进行讲解:
(1).声明法(直接定义在所使用文件的开始)
使用方法:首先在所使用的文件开头定义全局变量variable;然后在具体的使用函数中进行全局变量说明: global variable,因为只有在函数内经过说明的全局变量才能使用,否则系统将该变量视为局部变量。
注:将全局变量大写便于识别,eg:CONSTANT = 0
eg:
#test1.py CONSTANT = 0 #定义全局变量 def modifyConstant() : global CONSTANT #全局变量的声明 print CONSTANT CONSTANT += 1 return if __name__ == '__main__' : modifyConstant() print CONSTANT #在主函数中使用全局变量
(2).模块法(推荐使用这种方法)
使用方法:将需要定义的全局变量单独定义在一个文件中,当使用全局变量的时候,只需将该文件给import进来即可。然后通过类似下面的方法调用:global_test1.gl_1
eg:
#全局变量所在文件的定义 #global_test1.py gl_1 = 'hello' gl_2 = 'world' 在其它模块test2.py中使用 #test2.py import global_test1 def hello_world() print global_test1.gl_1, global_test1.gl_2 def fun1() global_test1.gl_1 = 'HELLO' global_test1.gl_2 = 'WORLD' if __name__ == '__main__' : fun1() hello_world()
3.图片的设置
pyqt中如果想要在窗体中添加图片,首先需要在Qt Designer中的资源浏览器中,添加图片资源,具体过程如下:点击“编辑资源”,点击“新建资源文件”,点击添加“前缀”,点击添加“文件”,将图片添加进去。然后,添加一个label元素,点击右键,选择“更改样式表”,选择“添加资源”,就为窗体成功添加了一张图片。
添加图片成功之后,在Eric中的Project-Viewer中的第三个tab,即“Resources”tab中可以看到添加的图片资源,以“*.qrc”形式命名的。右键点击该资源,选择“Compile resource”,即编译资源,之后运行,图片才能正常显示。无图无真相,下面给出2张图片,一目了然:
左侧的图为资源浏览器,在这里添加图片资源;右侧的图为Eric中添加图片资源后的,通过“Compile resource”进行编译资源。
总结:pyqt中图片的添加需要以资源的形式添加,当添加完资源之后,还需要将资源进行编译才能正常使用。
4.主窗体弹出一个对话框
主窗体弹出对话框,我花费了一上午才搞定。下面给出代码,重要的地方我都给出了注释:
# -*- coding: utf-8 -*- """ Module implementing MainWindow. """ from PyQt4.QtGui import QMainWindow from PyQt4.QtCore import pyqtSignature from Ui_MainWindow import Ui_MainWindow # UI_MainWindow是主窗体的界面 from Ui_ValidateWidget import * # UI_ValidateWidget是验证码对话框的界面类 #ValidateDialog类是将验证码对话框进行封装。验证码对话框的事件全部都是 #采用动态事件绑定到按钮上的。因为如果采用在对话框的实现类里定义事件的话,当从主窗体MainWindow跳转到 #验证码对话框时,对话框的实现类里的事件是不执行的。但是当只执行验证码对话框时,其实现类里的事件是执行的。所以, #我们这里采用在MainWindow里动态绑定元素和事件的方法。说明如下: class ValidateDialog(QtGui.QDialog): username='' password='' validate_num = '' #存放用户输入的验证码 def __init__(self, ui, username, password): self.username=username; self.password=password; QtGui.QDialog.__init__(self) self.ui=ui; ui.setupUi(self); #动态绑定验证码对话框的pushBtnConfirm按钮的clicked()事件,到该类的confirm方法上 QtCore.QObject.connect(self.ui.pushBtnConfirm, QtCore.SIGNAL("clicked()"), self.confirm) def confirm(self): #该类的成员接受验证码对话框的用户输入的验证码的值 self.validate_num = self.ui.lineEditValidateNum.text() class MainWindow(QMainWindow, Ui_MainWindow): """ Class documentation goes here. """ def __init__(self, parent = None): """ Constructor """ QMainWindow.__init__(self, parent) self.setupUi(self) @pyqtSignature("") def on_pushButton_clicked(self): """ Slot documentation goes here. """ # TODO: not implemented yet #raise NotImplementedError validate_ui = Ui_Form() validate_window = ValidateWindow(validate_ui,"zhao", "sean") validate_window.exec_() #将获取到的验证码的值,显示在主窗口的界面上 self.label.setText(validate_window.validate_num) #通过登陆对话框的类直接访问其验证码的数值 if __name__ == '__main__': import PyQt4, sys app = PyQt4.QtGui.QApplication(sys.argv) mainWin = MainWindow() mainWin.show() sys.exit(app.exec_())5.文字链接按钮和QTreeWidget
(1)文字链接按钮的实现
PyQt中没有像.NET那样的文字链接的按钮,但是如果想实现这种效果:点击一个具有下划线的文字,就执行一个事件,该如何实现呢?这需要通过QLabel实现,首先将QLabel的文本设置为<a></a>的内容,即:self.label_1.setText(u"<a href=‘’>监控</a>")。然后为其绑定事件:LinkActivated事件,即QtCore.QObject.connect(self.label_1,QtCore.SIGNAL("linkActivated(QString)"),self.monitor)。
(2)QTreeWidget实现
该控件用来显示树形菜单,可以通过图形界面编辑该控件中的内容,编辑好内容后,我们可以动态绑定事件给具体的子项,即:QtCore.QObject.connect(self.treewidget,QtCore.SIGNAL("itemClicked(QTreeWidgetItem*,int)",self.data_query))。
两者的代码,下面一块给出,读者可以自行查找相关的代码。
class MainWindow(QMainWindow, Ui_MainWindow): """ Class documentation goes here. """ def __init__(self, parent = None): """ Constructor """ QMainWindow.__init__(self, parent) self.setupUi(self) #设置tool box颜色 self.page_1.setStyleSheet("background-color: rgb(255, 255, 255);") self.page_2.setStyleSheet("background-color: rgb(255, 255, 255);") self.page_3.setStyleSheet("background-color: rgb(255, 255, 255);") self.page_4.setStyleSheet("background-color: rgb(255, 255, 255);") #设置label为链接文本 self.label_1.setText(u"<a href = ‘’>监控</a>") self.label_2.setText(u"<a href = ‘’>查询</a>") self.label_3.setText(u"<a href = ‘’>监控</a>") #元素和事件的动态绑定,将QLabel和事件linkActivated绑定,具体的执行函数为monitor QtCore.QObject.connect(self.label_1, QtCore.SIGNAL("linkActivated(QString)"), self.monitor) QtCore.QObject.connect(self.treeWidget, QtCore.SIGNAL("itemClicked(QTreeWidgetItem*,int)"), self.data_query) #将QTreeWidet的子项目和data_query进行绑定 #监控 def monitor(self): quit_msg = u"QLabel?" reply = QtGui.QMessageBox.question(self, u'提示', quit_msg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) ; #数据查询 def data_query(self, item, column): if item == self.treeWidget.topLevelItem(0).child(2): quit_msg = u"treeWidget?" reply = QtGui.QMessageBox.question(self, u'提示', quit_msg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) ;
6.Stacked Widget堆栈窗口
statcked widget是堆栈窗口,可以呈现好几个窗口。具体的使用方法:将stacked widget拖到界面上,然后通过下面的方法来调用第几个堆栈窗口:self.stackedWidget.setCurrentIndex(0)。
堆栈窗口的效果样式,大约如下,下面给出一个图片,该图片是我借用别人的,在此说明一下:
给出一个参考网址:http://blog.csdn.net/chumpklutz/article/details/6075484
7. 在主窗口中嵌入ui
在主窗口中嵌入ui,就是将一个对话框嵌入到主窗体中。其最终的效果和stacked widget效果一样,都是在主窗体里可以显示多个窗体。下面先给出几张我的实现的效果图:
这是程序启动后,默认加载第一个窗口。
这是点击’第二个窗口‘按钮后,显示第二个窗口
这是点击’第三个窗口‘按钮后,显示第三个窗口
这是点击第一个窗口中的’打开第四个窗口‘按钮后,显示第四个窗口
下面给出其具体的mainwindow.py的实现代码,有兴趣的朋友,可以在代码中找到相关的实现函数:
# -*- coding: utf-8 -*- """ Module implementing MainWindow. """ from PyQt4 import QtGui, QtCore from PyQt4.QtGui import * from PyQt4.QtCore import * import PyQt4 import sys from Ui_mainwindow import Ui_MainWindow #导入3个对话框的界面类 import Ui_test1, Ui_test2, Ui_test3, Ui_test4 class ForthDialog(QtGui.QDialog): def __init__(self, ui): QtGui.QDialog.__init__(self) self.ui = ui; ui.setupUi(self); QtCore.QObject.connect(self.ui.pushButton, QtCore.SIGNAL("clicked()"), self.confirm) def confirm(self): #self.ui.lineEditValidateNum.setText("XXXXXX") #测试给弹出的对话框里的元素赋值 self.reject() #关闭窗口 class MainWindow(QMainWindow, Ui_MainWindow): """ Class documentation goes here. """ firstUi = None secondUi = None thridUi = None def __init__(self, parent = None): """ Constructor """ QMainWindow.__init__(self, parent) self.setupUi(self) self.btn1_click() #打开第一个窗口 def btn1_click(self): self.initMainWinEvent() #初始化主界面的事件 self.firstUi = Ui_test1.Ui_Dialog() w1 = QWidget(self.widget) self.firstUi.setupUi(w1) QtCore.QObject.connect(self.firstUi.pushButton, QtCore.SIGNAL("clicked()"), self.PopUp_forthDlg) #打开第二个窗口 def btn2_click(self): self.initMainWinEvent() self.secondUi = Ui_test2.Ui_Dialog() w2 = QWidget(self.widget) self.secondUi.setupUi(w2) #打开第三个窗口 def btn3_click(self): self.initMainWinEvent() #将窗体定义成类成员变量 self.thridUi = Ui_test3.Ui_Dialog() w3 = QWidget(self.widget) self.thridUi.setupUi(w3) #通过单击第一个窗口里的按钮,弹出第四个窗口 def PopUp_forthDlg(self): self.firstUi.label.setText("hh,the forthDlg!") forthUi = Ui_test4.Ui_Dialog() forth_dlg = ForthDialog(forthUi) forth_dlg.exec_() #初始化主界面,进行按钮的动态绑定 def initMainWinEvent(self): self.setupUi(self) QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL("clicked()"), self.btn1_click) QtCore.QObject.connect(self.pushButton_2, QtCore.SIGNAL("clicked()"), self.btn2_click) QtCore.QObject.connect(self.pushButton_3, QtCore.SIGNAL("clicked()"), self.btn3_click) if __name__ == "__main__": app = PyQt4.QtGui.QApplication(sys.argv) mainWin = MainWindow() mainWin.show() sys.exit(app.exec_())
这种效果的实现步骤,主要有以下几点:
(1)导入产生的dialog,如:import Ui_test1
(2)实例化该dialog,如self.firstUi = Ui_test1.Ui_Dialog()
(3)通过Widget Container实例化一个QWidget对象,如:w1 = QWidget(self.widget)
这里self.widget是通过在主界面Ui_MainWindow上添加一个Widget Container容器。
(4)将dialog的ui设定到QWidget上。如self.firstUi.setupUi(w1)
下面给出一个参考链接:http://blog.csdn.net/chumpklutz/article/details/6061077
8.实现动态网格式地添加按钮,即 动态一行行地添加按钮
def init_dlg(self): QTextCodec.setCodecForTr(QTextCodec.codecForName("utf8")) add_rule_pushBtn = QPushButton(self.tr("添加")) detail_widget = QWidget() detail_layout = QGridLayout(detail_widget) detail_layout.setHorizontalSpacing(5) detail_layout.setVerticalSpacing(10) detail_layout.setMargin(5) #设定对话框的控件总是最优化显示, #并且用户无法改变对话框的大小,即控件都按其sizeHint()的大小显示 detail_layout.setSizeConstraint(QLayout.SetFixedSize) #动态添加rule_nums个组件 rule_nums = 5 i = 1 rule_pushBtn = {} rule_edit_pushBtn = {} rule_status_pushBtn = {} while(i <= rule_nums): rule_pushBtn[i] = QPushButton(self.tr("Sean"+str(i))) rule_edit_pushBtn[i] = QPushButton(self.tr("编辑")) rule_status_pushBtn[i] = QPushButton(self.tr("启/停")) detail_layout.addWidget(rule_pushBtn[i],i,0) detail_layout.addWidget(rule_edit_pushBtn[i],i,1) detail_layout.addWidget(rule_status_pushBtn[i],i,2) i = i +1 detail_layout.addWidget(add_rule_pushBtn, rule_nums+1, 1) # self.first_ui.scrollArea.setLayout(detail_layout) self.first_ui.rule_scrollArea.setWidget(detail_widget) #初始化按钮事件 QObject.connect(add_rule_pushBtn, SIGNAL("clicked()"), self.open_rule_dlg)该函数的起到的效果如下:
下面给出一个简单的讲解:
主要是通过QGridLayout实现该效果的布局。
(1)通过一个QWidget初始化QGridLayout,这样QGridLayout就可以调用addWidget方法了;(2)动态地生成要添加的元素,比如QPushButton;
(3)通过QGridLayout的addWidget方法,来添加动态生成的元素,并且可以指定该元素添加在第几行第几列。
比如:detail_layout.addWidget(rule_edit_pushBtn[i],i,1),表示将rule_edit_pushBtn[i]添加到第i+1行、第2列。
下面给出一个参考链接:http://blog.csdn.net/chumpklutz/article/details/6079243