这个例子相对综合一些,包括qt的布局,实现无边框效果,无边框也就是没有了窗口的title栏,没有title栏就不能拖动了,

所以我们进一步讲如何实现拖动。通过这边文章你可以掌握qt的布局,窗口定制,重写qt方法,QSS样式,事件信号

先上例子,后面在分析代码

#!/usr/bin/python3
# -*- coding: utf-8 -*- import sys
from PyQt5.QtWidgets import (QApplication, QWidget,QPushButton,
QLineEdit,QHBoxLayout, QVBoxLayout,QColorDialog,QInputDialog,QFileDialog)
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QCursor,QColor class Example(QWidget): def __init__(self):
super().__init__()
self.style = """
QPushButton{background-color:grey;color:white;}
#window{ background:pink; }
#test{ background-color:black;color:white; }
"""
self.setStyleSheet(self.style)
self.setWindowFlags(Qt.FramelessWindowHint)
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 300, 220)
self.setWindowTitle('test')
self.setObjectName("window") btn1 = QPushButton("关闭",self)
btn1.clicked.connect(self.close)
btn1.setObjectName('test')
btn2 = QPushButton("最小化",self)
btn2.clicked.connect(self.showMinimized)
btn3 = QPushButton("最大化",self)
btn3.clicked.connect(self.showMaximized) btn11 = QPushButton("改变背景",self)
btn11.clicked.connect(self.showColor)
btn22 = QPushButton("选择文件",self)
btn22.clicked.connect(self.showFile)
btn33 = QPushButton("对话框",self)
btn33.clicked.connect(self.showDialog)
self.linet1 = QLineEdit("",self)
self.linet2 = QLineEdit("ssssssss",self) hbox1 = QHBoxLayout() #水平布局
hbox1.addWidget(btn1)
hbox1.addWidget(btn2)
hbox1.addWidget(btn3)
hbox2 = QHBoxLayout() #水平布局
hbox2.addWidget(btn11)
hbox2.addWidget(btn22)
hbox2.addWidget(btn33)
vbox = QVBoxLayout() #垂直布局
vbox.addLayout(hbox1)
vbox.addLayout(hbox2)
vbox.addWidget(self.linet1)
vbox.addWidget(self.linet2)
self.setLayout(vbox) self.show()
#重写三个方法使我们的Example窗口支持拖动,上面参数window就是拖动对象
def mousePressEvent(self, event):
if event.button()==Qt.LeftButton:
self.m_drag=True
self.m_DragPosition=event.globalPos()-self.pos()
event.accept()
self.setCursor(QCursor(Qt.OpenHandCursor))
def mouseMoveEvent(self, QMouseEvent):
if Qt.LeftButton and self.m_drag:
self.move(QMouseEvent.globalPos()-self.m_DragPosition)
QMouseEvent.accept()
def mouseReleaseEvent(self, QMouseEvent):
self.m_drag=False
self.setCursor(QCursor(Qt.ArrowCursor))
def showColor(self):
col = QColorDialog.getColor()
if col.isValid():
self.setStyleSheet(self.style+"#window{background:%s}" % col.name())
def showDialog(self):
text, ok = QInputDialog.getText(self, '对话框',
'请输入你的名字:') if ok:
self.linet1.setText(str(text))
def showFile(self):
fname = QFileDialog.getOpenFileName(self, 'Open file', '/home') if fname[0]:
f = open(fname[0], 'r') with f:
data = f.readline()
self.linet1.setText(data) if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

运行效果:

上面导入的一大堆类我就不细说了,都是下面需要用到的,在我的上一篇文章中介绍了相关知识,这里只说一下,不要这样导入

from PyQt5.QtWidgets import *

这样子会把大量你没有用到的类都导入进来,占内存,所以尽量按需导入

self.style = """
QPushButton{background-color:grey;color:white;}
#window{ background:pink; }
#test{ background-color:black;color:white; }
"""
self.setStyleSheet(self.style)

这就是qt的css样式,和css基本是一样的写法,调用setStyleSheet方法把样式应用到当前self对象,也就是Example窗口

样式是可以继承的,和html/css是一个道理,我这个地方把样式绑定到顶层窗口,所以下面我添加的button也会去这个style里面去继承样式

和css一个道理,你在下面的button上可以再次调用setStyleSheet方法来覆盖继承的方法,

每一个窗口元素(比如按钮,输入框等等都算)都可以使用setObjectName(idname)来为一个对象取别名,然后我们就可以在样式里面单独指定样式,

比如我们有两个按钮,第一个按钮指定了别名test,看一下上面的写法是不是和css的id写法一样。就像个html中div加了一个id一样,然后在css文件里面用id来唯一标识样式

后面的按钮都没有指定别名,所以就默认继承 QPushButton{background-color:grey;color:white;}  样式,当然你还可以在button上调用setStyleSheet方法覆盖之前的样式

比如你在btn2下面加一行 btn2.setStyleSheet("QPushButton{background:green }")  就可以覆盖以前的样式了

怎么写样式就和css里面的一样,比如有这些: background,color,border,background-image,width,height等等

掌握了qss就可以写出各种花式界面了。

self.setWindowFlags(Qt.FramelessWindowHint)

这句话就是去掉窗口的顶部title栏了一级边框那些,对比一下去掉边框和没有去掉的区别

这个图片好像还看不出无边框的优越性,假设qq如果加上边框会是怎么的画面呢。。。

通常一些工具软件有无边框都无所谓,但是对于一些要求界面美观的软件来说带一个操作系统提供的外壳会显得略丑。。

加上上面那句代码后边框已经不见了,等等,以前移动都是鼠标按住顶部的title栏拖动的,现在title栏不见了还怎么拖动呢?

    def mousePressEvent(self, event):
if event.button()==Qt.LeftButton:
self.m_drag=True
self.m_DragPosition=event.globalPos()-self.pos()
event.accept()
self.setCursor(QCursor(Qt.OpenHandCursor))
def mouseMoveEvent(self, QMouseEvent):
if Qt.LeftButton and self.m_drag:
self.move(QMouseEvent.globalPos()-self.m_DragPosition)
QMouseEvent.accept()
def mouseReleaseEvent(self, QMouseEvent):
self.m_drag=False
self.setCursor(QCursor(Qt.ArrowCursor))

这三个方法是窗口对象自带的,默认情况下他好像什么都没干,所以我们可以大胆的重写这三个方法来实现拖动,

我相信看函数名大概也知道什么意思了吧,如果你写过js的拖动效果其实就不难理解了,

mousePressEvent流程:鼠标左键按下,设置拖动标识true,记录点击坐标,设置鼠标样式

mouseMoveEvent流程:判断当前数遍仍处于按下状态 ,调用move函数设置当前对标位置,

mouseReleaseEvent流程:释放拖动标示false

这下可以正常拖动了,等等,以前的最小化,最大化,关闭都在title栏上,现在也不见了,没有我们就自己实现呗

        btn1 = QPushButton("关闭",self)
btn1.clicked.connect(self.close)
btn1.setObjectName('test')
btn2 = QPushButton("最小化",self)
btn2.clicked.connect(self.showMinimized)
btn3 = QPushButton("最大化",self)
btn3.clicked.connect(self.showMaximized)

第一句:btn1 = QPushButton("关闭",self)  定义一个按钮对象,并指定他的容器是self,也就是放到Example窗口里面,

第二句是关键:当btn1被点击后会产生一个点击信号,然后把这个信号连接到self.close这个处理函数来处理这次事件

这个三个按钮连接的处理函数都是内建的函数,分别实现了关闭,最小最大化,

除了连接到qt提供的函数外,也可以连接到我们自己的函数,就像下面这样

    btn11 = QPushButton("改变背景",self)
btn11.clicked.connect(self.showColor)
btn22 = QPushButton("选择文件",self)
btn22.clicked.connect(self.showFile)
btn33 = QPushButton("对话框",self)
   btn33.clicked.connect(self.showDialog) def showColor(self):
col = QColorDialog.getColor()
if col.isValid():
self.setStyleSheet(self.style+"#window{background:%s}" % col.name())
def showDialog(self):
text, ok = QInputDialog.getText(self, '对话框',
'请输入你的名字:')
if ok:
self.linet1.setText(str(text))
def showFile(self):
fname = QFileDialog.getOpenFileName(self, 'Open file', '/home')
if fname[0]:
f = open(fname[0], 'r')
with f:
data = f.readline()
self.linet1.setText(data)

事件的作用就是用来发射信号,有些信号默认已经连接到处理函数,现在我们有这样的需求,就是我们要手动发出一个信号,换句话说就是我们自定义一个事件,

系统本身内部提供了很多事件,比如,click,mousemove,valuechange等等,除了这些我们仍然可以自定义事件,比如我把 鼠标向上移动接着向右移动 定义为一个事件,

这样我们可以做一些手势功能,这个要说起来又是一篇文章,就是提到这里吧,后面的文章在专门分析,初学者基本上用不到,

下面还是抛一个简单的模板列子

import sys
from PyQt5.QtCore import pyqtSignal, QObject
from PyQt5.QtWidgets import QMainWindow, QApplication class Communicate(QObject):
closeApp = pyqtSignal()
class Example(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.c = Communicate()
self.c.closeApp.connect(self.close)
self.setGeometry(300, 300, 290, 150)
self.setWindowTitle('Emit signal')
self.show()
def mousePressEvent(self, event):
self.c.closeApp.emit()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

提示:发射信号的对象必须继承QObject类

说到这里突然发现漏了什么,对,就是布局

        hbox1 = QHBoxLayout()   #水平布局
hbox1.addWidget(btn1)
hbox1.addWidget(btn2)
hbox1.addWidget(btn3)
hbox2 = QHBoxLayout() #水平布局
hbox2.addWidget(btn11)
hbox2.addWidget(btn22)
hbox2.addWidget(btn33)
vbox = QVBoxLayout() #垂直布局
vbox.addLayout(hbox1)
vbox.addLayout(hbox2)
vbox.addWidget(self.linet1)
vbox.addWidget(self.linet2)
self.setLayout(vbox)

在qt中布局有三种,绝对定位,水平布局, 垂直布局, 网格布局

我上面使用的水平布局加垂直布局。通常一个软件会多种布局混合使用,布局是可以嵌套的。绝对定位是使用moveto函数来确定控件的位置,这种方式就把位置定死了,正常窗口下(非无边框),用户可以拖动边角进行放大窗口,或者点击最大化,

假设你的按钮的位置是(100,100),不管窗口变多大,按钮都是相对于窗口的左上角(0.0)位置,

绝对定位例子:

import sys
from PyQt5.QtWidgets import QWidget, QPushButton, QApplication app = QApplication(sys.argv)
wg = QWidget()
lbl1 = QPushButton('test', wg)
lbl1.move(15, 10)
wg.setGeometry(300, 300, 250, 150)
wg.setWindowTitle('Absolute')
wg.show()
sys.exit(app.exec_())

如果你的软件采用无边框,用户就无法改变窗口大小了,这种情况下采用绝对定位还是不错的。

如果你的软件允许用户改变大小,那么推荐使用流式布局,也就是水平布局和垂直布局以及网格布局都是流式布局

水平布局 就不需要例子了,最上面的综合例子就是采用水平布局加垂直布局

水平布局就是把所有的元素按照水平方向平铺,占满软件整个宽度,垂直布局一样的理解

说一下网格布局:

网格布局就是把你的软件花分成x*x的表格,比如5*5或者5x8等,然后你把控件插到相应位置就可以了,

网格布局例子:

import sys
from PyQt5.QtWidgets import (QWidget, QGridLayout,
QPushButton, QApplication) class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
grid = QGridLayout()
self.setLayout(grid)
names = ['Cls', 'Bck', '', 'Close',
'', '', '', '/',
'', '', '', '*',
'', '', '', '-',
'', '.', '=', '+']
positions = [(i,j) for i in range(5) for j in range(4)]
for position, name in zip(positions, names):
if name == '':
continue
button = QPushButton(name)
grid.addWidget(button, *position) self.move(300, 150)
self.setWindowTitle('Calculator')
self.show() if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())

运行效果:

PyQt之布局&无边框&信号的更多相关文章

  1. 如何在pyqt中自定义无边框窗口

    前言 之前写过很多关于无边框窗口并给窗口添加特效的博客,按照时间线罗列如下: 如何在pyqt中实现窗口磨砂效果 如何在pyqt中实现win10亚克力效果 如何在pyqt中通过调用SetWindowCo ...

  2. 如何在pyqt中给无边框窗口添加DWM环绕阴影

    前言 在之前的博客<如何在pyqt中通过调用SetWindowCompositionAttribute实现Win10亚克力效果>中,我们实现了窗口的亚克力效果,同时也用SetWindowC ...

  3. 如何在pyqt中在实现无边框窗口的同时保留Windows窗口动画效果(一)

    无边框窗体的实现思路 在pyqt中只要 self.setWindowFlags(Qt.FramelessWindowHint) 就可以实现边框的去除,但是没了标题栏也意味着窗口大小无法改变.窗口无法拖 ...

  4. PyQt:无边框自定义标题栏及最大化最小化窗体大小调整

    环境 Python3.5.2 PyQt5 陈述 隐藏掉系统的控制栏,实现了自定义的标题控制栏,以及关闭/最大化/最小化的功能,自由调整窗体大小的功能(跟随一个大佬学的),代码内有详细注释 只要把Mai ...

  5. pyside pyqt QPushbuttion 无边框 stylesheet border:none

    pyside pyqt QPushbuttion 无边框 stylesheet border:none 在 stylesheet 中添加 border:none 即可 效果是字体到边缘之间的间隙为0, ...

  6. PYQT设计无边框窗体

    #UI.py,通过UI设计师制作后直接转换为UI.py脚本 # -*- coding: utf-8 -*-from PyQt4 import QtCore, QtGui try:    _fromUt ...

  7. Qt之界面(自定义标题栏、无边框、可移动、缩放)

    效果 自定义标题栏 titleBar.h #ifndef TITLEBAR_H #define TITLEBAR_H #include <QLabel> #include <QPus ...

  8. 无边框窗体、用户控件、Timer控件

    一.无边框窗体1 最大化.最小化以及关闭按钮制作实际上就是更换点击前.指向时.点击时的图片 (1)将图片放在该文件夹的Debug中,获取图片的路径Application.StartupPath + & ...

  9. pyqt4制作透明无边框窗体

    用PyQt做了一个无边框登陆窗口,效果如下: 下面是代码: # -*- coding: utf-8 -*- from PyQt4 import QtGui ,Qt ,QtCore image=QtGu ...

随机推荐

  1. AC日记——输出亲朋字符串 openjudge 1.7 05

    05:输出亲朋字符串 总时间限制:  1000ms 内存限制:  65536kB 描述 编写程序,求给定字符串s的亲朋字符串s1. 亲朋字符串s1定义如下:给定字符串s的第一个字符的ASCII值加第二 ...

  2. Android RecyclerView 动画展开item显示详情

    stackoverflow上看到这个问题,答主给了个demo http://stackoverflow.com/questions/27446051/recyclerview-animate-item ...

  3. Oracle 行转列,列转行

    一.行转列1.1.初始测试数据表结构:TEST_TB_GRADESql代码:1    create table TEST_TB_GRADE2    (3      ID        NUMBER(1 ...

  4. browserify使用手册

    简介 这篇文档用以说明如何使用browserify来构建模块化应用 browserify是一个编译工具,通过它可以在浏览器环境下像nodejs一样使用遵循commonjs规范的模块化编程. 你可以使用 ...

  5. Mysql优化系列(1)--Innodb引擎下mysql自身配置优化

    1.简单介绍InnoDB给MySQL提供了具有提交,回滚和崩溃恢复能力的事务安全(ACID兼容)存储引擎.InnoDB锁定在行级并且也在SELECT语句提供一个Oracle风格一致的非锁定读.这些特色 ...

  6. Discuz! X2.5判断会员登录状态及外部调用注册登录框

    Discuz! X2.5判断会员登录状态及外部调用注册登录框 有关discuz论坛会员信息,收集的一些资料: 用dedecms+discuz做了个门户加论坛形式的网站,但是dedecms顶部目前只能q ...

  7. spring: 加载远程配置

    通常在spring应用中,配置中的properties文件,都是打包在war包里的,部署规模较小,只有几台服务器时,这样并没有什么大问题.如果服务器多了,特别是集群部署时,如果要修改某一项配置,得重新 ...

  8. hadoop: hbase1.0.1.1 伪分布安装

    环境:hadoop 2.6.0 + hbase 1.0.1.1 + mac OS X yosemite 10.10.3 安装步骤: 一.下载解压 到官网 http://hbase.apache.org ...

  9. Hadoop: MapReduce2多个job串行处理

    复杂的MapReduce处理中,往往需要将复杂的处理过程,分解成多个简单的Job来执行,第1个Job的输出做为第2个Job的输入,相互之间有一定依赖关系.以上一篇中的求平均数为例,可以分解成三个步骤: ...

  10. Python 操作 MongoDB

    原文 这篇文章主要介绍了使用Python脚本操作MongoDB的教程,MongoDB作为非关系型数据库得到了很大的宣传力度,而市面上的教程一般都是讲解JavaScript的脚本操作,本文则是基于Pyt ...